{"_id":"@dxv-systems/dynamic-translations","_rev":"3-cdc51d8a70d4dcf5274fb4fdfa8a5006","name":"@dxv-systems/dynamic-translations","dist-tags":{"latest":"0.1.2"},"versions":{"0.1.0":{"name":"@dxv-systems/dynamic-translations","version":"0.1.0","keywords":["dxv","i18n","translation","openrouter","claude"],"license":"MIT","_id":"@dxv-systems/dynamic-translations@0.1.0","maintainers":[{"name":"dxv-systems","email":"dunninkjesse1@gmail.com"}],"homepage":"https://github.com/dxv-systems/dxv-packages#readme","bugs":{"url":"https://github.com/dxv-systems/dxv-packages/issues"},"dist":{"shasum":"c49ca57bd88bc2857a417a302ae323bbcb33ff49","tarball":"https://registry.npmjs.org/@dxv-systems/dynamic-translations/-/dynamic-translations-0.1.0.tgz","fileCount":18,"integrity":"sha512-AjKQeLS9AB9bxXlWo+PDMNIqx/CtU8Mxdhek03OBnxUMxcqv7Y7MUI4jNWwkXl2YJDMecC/EizAFev7S65eQFw==","signatures":[{"sig":"MEUCIQDt6lnVp7XiPeK+H0VEGtwSqdgKdrEzNjYe35fuQ49VIwIgd2GAoL2uILT7Ql4svnG/mRKcnOZulrEGa5ZgGIon0jA=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":25411},"engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"}},"gitHead":"313c8e4f474044770ad4288e7baa60c88b6d45ca","scripts":{"test":"vitest run","build":"tsc","test:watch":"vitest","prepublishOnly":"npm run build"},"_npmUser":{"name":"dxv-systems","email":"dunninkjesse1@gmail.com"},"repository":{"url":"git+https://github.com/dxv-systems/dxv-packages.git","type":"git","directory":"packages/dynamic-translations"},"_npmVersion":"11.12.1","description":"DXV translation orchestrator — batched LLM translation of admin-configured DB content via OpenRouter, with a pluggable persistence layer and lock-aware rebuild modes.","directories":{},"_nodeVersion":"24.15.0","_hasShrinkwrap":false,"devDependencies":{"vitest":"^2.1.8","typescript":"^5.6.0","@types/node":"^20.19.0"},"_npmOperationalInternal":{"tmp":"tmp/dynamic-translations_0.1.0_1779264894123_0.32699214368522855","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@dxv-systems/dynamic-translations","version":"0.1.1","keywords":["dxv","i18n","translation","openrouter","claude"],"license":"MIT","_id":"@dxv-systems/dynamic-translations@0.1.1","maintainers":[{"name":"dxv-systems","email":"dunninkjesse1@gmail.com"}],"homepage":"https://github.com/dxv-systems/dxv-packages#readme","bugs":{"url":"https://github.com/dxv-systems/dxv-packages/issues"},"dist":{"shasum":"0a6eac87811e0cd62df307d54817496ae17fdda7","tarball":"https://registry.npmjs.org/@dxv-systems/dynamic-translations/-/dynamic-translations-0.1.1.tgz","fileCount":18,"integrity":"sha512-WjW/OJOwoBmHFame7OvCjM1vfKhCR2fB/ElZVioMSjS5CV+9wK4GQxSBbomsHiy8QcBQZUX/11XwapYa/1/poA==","signatures":[{"sig":"MEUCID7GWlqKTNf1y9TrSfzae38ZO14eXAFWVr9kxia8OhspAiEA5JzXVyKVOFLHsjdaXK9Nh5LNXLHvvcOoa07NZ3rHBF0=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":27939},"engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"}},"gitHead":"d7ea5913448da137c219b3485567e5fc82a964f9","scripts":{"test":"vitest run","build":"tsc","test:watch":"vitest","prepublishOnly":"npm run build"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:b0bebda9-a95d-4580-b3f2-ae0160ded849"}},"repository":{"url":"git+https://github.com/dxv-systems/dxv-packages.git","type":"git","directory":"packages/dynamic-translations"},"_npmVersion":"11.5.1","description":"DXV translation orchestrator — batched LLM translation of admin-configured DB content via OpenRouter, with a pluggable persistence layer and lock-aware rebuild modes.","directories":{},"_nodeVersion":"22.22.2","_hasShrinkwrap":false,"devDependencies":{"vitest":"^2.1.8","typescript":"^5.6.0","@types/node":"^20.19.0"},"_npmOperationalInternal":{"tmp":"tmp/dynamic-translations_0.1.1_1779270577635_0.8545663781718458","host":"s3://npm-registry-packages-npm-production"}},"0.1.2":{"name":"@dxv-systems/dynamic-translations","version":"0.1.2","description":"DXV translation orchestrator — batched LLM translation of admin-configured DB content via OpenRouter, with a pluggable persistence layer and lock-aware rebuild modes.","keywords":["dxv","i18n","translation","openrouter","claude"],"engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"}},"scripts":{"build":"tsc","test":"vitest run","test:watch":"vitest","prepublishOnly":"npm run build"},"devDependencies":{"@types/node":"^20.19.0","typescript":"^5.6.0","vitest":"^2.1.8"},"repository":{"type":"git","url":"git+https://github.com/dxv-systems/dxv-packages.git","directory":"packages/dynamic-translations"},"license":"MIT","_id":"@dxv-systems/dynamic-translations@0.1.2","gitHead":"e3d3e7e6089e061596e37196b0022277289cc4ba","bugs":{"url":"https://github.com/dxv-systems/dxv-packages/issues"},"homepage":"https://github.com/dxv-systems/dxv-packages#readme","_nodeVersion":"22.22.2","_npmVersion":"11.5.1","dist":{"integrity":"sha512-lIuXXviAxmQwp65XnQLB3bPGpPSCfVmyUj04pUFulKUPA5m2uoUHgl7Ahk1eHVOEkAQlUJO1M38qpJgm5IrS7g==","shasum":"461d52175e4fb967f69b59f9796a50effaf01631","tarball":"https://registry.npmjs.org/@dxv-systems/dynamic-translations/-/dynamic-translations-0.1.2.tgz","fileCount":18,"unpackedSize":30482,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQDNqIEInNIDH6obwwAUCoV1Hj/oYDQtuU+1MgNc6nKOewIhAOeZWfxzsZ19gC34PrUiRchPrBTpm2IViBKriUF9eTOq"}]},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:b0bebda9-a95d-4580-b3f2-ae0160ded849"}},"directories":{},"maintainers":[{"name":"dxv-systems","email":"dunninkjesse1@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/dynamic-translations_0.1.2_1779277544950_0.6911127101105699"},"_hasShrinkwrap":false}},"time":{"created":"2026-05-20T08:14:53.948Z","modified":"2026-05-20T11:45:45.200Z","0.1.0":"2026-05-20T08:14:54.343Z","0.1.1":"2026-05-20T09:49:37.780Z","0.1.2":"2026-05-20T11:45:45.091Z"},"bugs":{"url":"https://github.com/dxv-systems/dxv-packages/issues"},"license":"MIT","homepage":"https://github.com/dxv-systems/dxv-packages#readme","keywords":["dxv","i18n","translation","openrouter","claude"],"repository":{"type":"git","url":"git+https://github.com/dxv-systems/dxv-packages.git","directory":"packages/dynamic-translations"},"description":"DXV translation orchestrator — batched LLM translation of admin-configured DB content via OpenRouter, with a pluggable persistence layer and lock-aware rebuild modes.","maintainers":[{"name":"dxv-systems","email":"dunninkjesse1@gmail.com"}],"readme":"# @dxv-systems/dynamic-translations\n\nBatched LLM translation of admin-configured DB content via OpenRouter (default model: `anthropic/claude-haiku-4.5`), with a pluggable persistence layer and lock-aware rebuild modes.\n\nBuilt for the case where the source language is **Dutch** and the target language set is small (DE / EN). The package does not know or care about your database; you provide a `TranslationStore` implementation that reads from and writes to wherever you keep translations.\n\n## Why\n\nHardcoded `Dutch text → translated text` maps couple translations to seed data and silently fall back to the source the moment the admin edits anything. This package lets an admin run two operations on demand:\n\n- **Fill gaps** — translate sources that don't have a translation yet.\n- **Full rebuild** — re-translate every source, except rows the admin has locked.\n\n## Install\n\n```bash\nnpm install @dxv-systems/dynamic-translations\n```\n\n## Usage\n\n```ts\nimport {\n  makeTranslator,\n  rebuildTranslations,\n  type TranslationStore,\n} from \"@dxv-systems/dynamic-translations\";\n\nconst translator = makeTranslator({\n  apiKey: process.env.OPENROUTER_API_KEY!,\n  appName: \"Arcabo Checklist\",\n  appUrl: \"https://arcabo.example.com\",\n});\n\nconst store: TranslationStore = /* your DB-backed implementation */;\n\nawait rebuildTranslations({\n  sources: [\n    { source: \"Slaapkamers\", refs: [{ entity: \"ChecklistField\", field: \"bedrooms\" }] },\n    { source: \"Bouwnorm\", refs: [{ entity: \"ChecklistField\", field: \"bouwnorm\" }] },\n    // ...\n  ],\n  targetLangs: [\"de\", \"en\"],\n  mode: \"gaps\", // or \"full\"\n  store,\n  translator,\n  onProgress: (done, total, lang) => console.log(`${lang}: ${done}/${total}`),\n});\n```\n\n## Lock semantics\n\n`store.lockedSources(...)` returns the set of sources the admin has manually edited. `mode: \"full\"` excludes those rows from the translator call and never writes over them. `mode: \"gaps\"` doesn't touch them either (they aren't missing).\n\n## TranslationStore\n\nYou implement this. Methods are batch-oriented because every wizard page touches dozens of sources at once.\n\n```ts\ninterface TranslationStore {\n  getMany(sources: string[], lang: TargetLang): Promise<Map<string, string>>;\n  getAll(lang: TargetLang): Promise<TranslationRow[]>;\n  setMany(entries: Array<{ source; lang; translated; refs }>): Promise<void>;\n  setOne(args: { source; lang; translated; locked }): Promise<void>;\n  missing(sources: string[], lang: TargetLang): Promise<string[]>;\n  lockedSources(sources: string[], lang: TargetLang): Promise<Set<string>>;\n}\n```\n\n## Costs\n\nClaude Haiku 4.5 via OpenRouter is ~$0.25 / $1.25 per 1M input/output tokens. A label round-trips in ~10 tokens; ~200 labels × 2 languages costs ~$0.004 to translate the whole catalogue once. Locked rows and the `gaps` mode keep recurring costs near zero.\n","readmeFilename":"README.md"}