{"_id":"@dialpad/i18n-services","_rev":"6-04ca59fb5eb4549e1cfeb5d2e2e23e3e","name":"@dialpad/i18n-services","dist-tags":{"latest":"1.11.0"},"versions":{"1.2.0":{"name":"@dialpad/i18n-services","version":"1.2.0","_id":"@dialpad/i18n-services@1.2.0","maintainers":[{"name":"jawrey","email":"awreyjustin@gmail.com"},{"name":"dlovero-dialpad","email":"daniel.lovero@dialpad.com"}],"homepage":"https://github.com/dialpad/web-clients#readme","bugs":{"url":"https://github.com/dialpad/web-clients/issues"},"dp":{"nodpend":true},"bin":{"should-pull":"dist/translation-service/should-pull.js","pull-translations":"dist/translation-service/pull.js","translate-dialpadistan":"dist/dialpadistan.js","upload-translation-service":"dist/translation-service/push.js","translation-screenshots-check":"dist/translation-service/screenshots-check.js"},"dist":{"shasum":"866dc5a0be56ff79f1aa2f11318836fb46962c98","tarball":"https://registry.npmjs.org/@dialpad/i18n-services/-/i18n-services-1.2.0.tgz","fileCount":82,"integrity":"sha512-DSfAtPoVb/uJHMj0ATaf2cu/DOFAGGdJfZPiJMVMsIV2+SRNwkH0gfX2h+MOrSEZACc3i6gZu7mzy73UZPd+8w==","signatures":[{"sig":"MEUCIQD/Dd1m+ROjMjwL5bI56CQw6TAtU4Q2LyB9uC/hDjC5tAIgRqVCq+lF4X6REoGnhyE+BrOjPwlwixRmhCm+2c4OBFU=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1426745},"type":"module","exports":{"./bundle-source":{"types":"./bundle/bundle-source/index.d.ts","import":"./bundle/bundle-source/index.js","default":"./src/bundle-source/index.ts"},"./locale-manager":{"types":"./bundle/locale-manager/base-locale-manager.d.ts","import":"./bundle/locale-manager/base-locale-manager.js","default":"./src/locale-manager/base-locale-manager.ts"}},"gitHead":"1046d670db20f19e4d020054cc22c48974194fa1","private":false,"scripts":{"lint":"eslint ./ --fix","test":"vitest","build":"run-p build:*","format":"prettier ./ --write","lint:ci":"eslint ./ --output-file eslint_report.json --format json","coverage":"vitest run --coverage --passWithNoTests","format:ci":"prettier ./ --check","translate":"node ./src/translate-dialpadistani/check-and-translate.js","build:main":"vite build","build:types":"run-p types:*","build:utils":"vite build --config vite.config.utils.ts","should-pull":"pnpm run build && node ./dist/translation-service/should-pull.js","types:build":"tsc","types:utils":"tsc --project tsconfig.utils.json","coverage:open":"pnpm run coverage && open coverage/index.html","pull-translations":"pnpm run build && node ./dist/translation-service/pull.js","translate:dialpadistan":"pnpm run build && node ./dist/dialpadistan.js","upload-translation-service":"pnpm run build && node ./dist/translation-service/push.js","translation-screenshots-check":"pnpm run build && node ./dist/translation-service/screenshots-check.js"},"_npmUser":{"name":"dlovero-dialpad","email":"daniel.lovero@dialpad.com"},"repository":{"url":"git+https://github.com/dialpad/web-clients.git","type":"git"},"_npmVersion":"10.1.0","description":"i18n common services and functionality","directories":{},"_nodeVersion":"20.9.0","dependencies":{"vue-demi":"0.14.10","csv-parse":"5.5.6","fluent-vue":"3.6.0","@fluent/bundle":"0.17.1","@fluent/syntax":"^0.19.0"},"_hasShrinkwrap":false,"devDependencies":{"vite":"5.0.4","jsdom":"21.1.1","vitest":"1.0.0-beta.6","vue-tsc":"1.8.8","fast-glob":"^3.3.3","typescript":"5.0.4","@types/node":"20.9.0","npm-run-all":"4.1.5","@vitejs/plugin-vue":"4.5.0"},"peerDependencies":{"vue":"^2.0.0 || >=3.0.0","@vue/composition-api":"1.7.2"},"_npmOperationalInternal":{"tmp":"tmp/i18n-services_1.2.0_1747852556750_0.6095363837684369","host":"s3://npm-registry-packages-npm-production"}},"1.5.0":{"name":"@dialpad/i18n-services","version":"1.5.0","_id":"@dialpad/i18n-services@1.5.0","maintainers":[{"name":"jawrey","email":"awreyjustin@gmail.com"},{"name":"dlovero-dialpad","email":"daniel.lovero@dialpad.com"},{"name":"juliodialpad","email":"julio.ortega@dialpad.com"}],"homepage":"https://github.com/dialpad/web-clients#readme","bugs":{"url":"https://github.com/dialpad/web-clients/issues"},"dp":{"nodpend":true},"bin":{"should-pull":"dist/translation-service/should-pull.js","pull-translations":"dist/translation-service/pull.js","check-and-translate":"src/translate-dialpadistani/check-and-translate.js","translate-dialpadistan":"dist/dialpadistan.js","upload-translation-service":"dist/translation-service/push.js","translation-screenshots-check":"dist/translation-service/screenshots-check.js"},"dist":{"shasum":"7e0e9d472da5f3233389439c3eb64b2e60070690","tarball":"https://registry.npmjs.org/@dialpad/i18n-services/-/i18n-services-1.5.0.tgz","fileCount":84,"integrity":"sha512-De1ZHqTd49O06hzWyKkBBVM8PvGyXGstUpOE0GHiBNRrWUw9uAUjHucAoWXrBVa7Q3h+j+EDxMsa21Fm3jlUAA==","signatures":[{"sig":"MEQCIGu4MULPPs+ArQS/iMfKTgSj95QQBs7wRRVlTbOMs1AjAiATUEyfYEbYYrSGHuP1abzO3WnBF5+Tnkt/SoFb0LPSPw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1564668},"type":"module","exports":{"./storage":{"types":"./dist/types/storage/index.d.ts","import":"./dist/storage/index.js","default":"./src/storage/index.ts"},"./bundle-source":{"types":"./dist/types/bundle-source/index.d.ts","import":"./dist/bundle-source/index.js","default":"./src/bundle-source/index.ts"},"./locale-manager":{"types":"./dist/types/locale-manager/base-locale-manager.d.ts","import":"./dist/locale-manager/base-locale-manager.js","default":"./src/locale-manager/base-locale-manager.ts"}},"gitHead":"31db1db6323c4cabe8b551dae8a28b1c9dbaed25","private":false,"scripts":{"lint":"eslint ./ --fix","test":"vitest","build":"run-p build:*","format":"prettier ./ --write","lint:ci":"eslint ./ --output-file eslint_report.json --format json","prepare":"pnpm run build","coverage":"vitest run --coverage --passWithNoTests","format:ci":"prettier ./ --check","build:main":"vite build","build:types":"run-p types:*","should-pull":"pnpm run build && node ./dist/translation-service/should-pull.js","types:build":"tsc","coverage:open":"pnpm run coverage && open coverage/index.html","pull-translations":"pnpm run build && node ./dist/translation-service/pull.js","check-and-translate":"node ./src/translate-dialpadistani/check-and-translate.js","translate:dialpadistan":"pnpm run build && node ./dist/dialpadistan.js","upload-translation-service":"pnpm run build && node ./dist/translation-service/push.js","translation-screenshots-check":"pnpm run build && node ./dist/translation-service/screenshots-check.js"},"_npmUser":{"name":"dlovero-dialpad","actor":{"name":"dlovero-dialpad","type":"user","email":"daniel.lovero@dialpad.com"},"email":"daniel.lovero@dialpad.com"},"repository":{"url":"git+https://github.com/dialpad/web-clients.git","type":"git"},"_npmVersion":"10.1.0","description":"i18n common services and functionality","directories":{},"_nodeVersion":"20.9.0","dependencies":{"vue-demi":"0.14.10","csv-parse":"5.5.6","fluent-vue":"3.6.0","@fluent/bundle":"0.17.1","@fluent/syntax":"^0.19.0"},"_hasShrinkwrap":false,"devDependencies":{"vite":"5.0.4","jsdom":"21.1.1","vitest":"1.0.0-beta.6","vue-tsc":"1.8.8","fast-glob":"^3.3.3","typescript":"5.0.4","@types/node":"20.9.0","npm-run-all":"4.1.5","@vitejs/plugin-vue":"4.5.0"},"peerDependencies":{"vue":"^2.0.0 || >=3.0.0","@vue/composition-api":"1.7.2"},"_npmOperationalInternal":{"tmp":"tmp/i18n-services_1.5.0_1751482373030_0.14843546422949916","host":"s3://npm-registry-packages-npm-production"}},"1.8.0":{"name":"@dialpad/i18n-services","version":"1.8.0","_id":"@dialpad/i18n-services@1.8.0","maintainers":[{"name":"jawrey","email":"awreyjustin@gmail.com"},{"name":"dlovero-dialpad","email":"daniel.lovero@dialpad.com"},{"name":"juliodialpad","email":"julio.ortega@dialpad.com"}],"homepage":"https://github.com/dialpad/web-clients#readme","bugs":{"url":"https://github.com/dialpad/web-clients/issues"},"dp":{"nodpend":true},"bin":{"should-pull":"dist/translation-service/should-pull.js","pull-translations":"dist/translation-service/pull.js","check-and-translate":"src/translate-dialpadistani/check-and-translate.js","translate-dialpadistan":"dist/dialpadistan.js","force-pull-translations":"dist/translation-service/force-pull.js","upload-translation-service":"dist/translation-service/push.js","translation-screenshots-check":"dist/translation-service/screenshots-check.js"},"dist":{"shasum":"7b28fdf0c0949615290e3e6f66a04d3a9d9d8f68","tarball":"https://registry.npmjs.org/@dialpad/i18n-services/-/i18n-services-1.8.0.tgz","fileCount":97,"integrity":"sha512-qnJgWeATJstZwLV+kVLeG4LzQ+8p4Ri6A5vVxkCMMBvooFRCoIPzFNynG/a1krzPw99avNBrfsKdsqZI7YPVsw==","signatures":[{"sig":"MEQCIC10n3+v9sm/18Hv33ruDuUwhJVvWUi/ZDdWsJ1vDKzzAiBnLGz8yCN0ocPbPkEKA4Ae8GglDZV6cPcH9A8akeLfkg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1357862},"type":"module","exports":{"./storage":{"types":"./dist/types/storage/index.d.ts","import":"./dist/storage/index.js","default":"./src/storage/index.ts"},"./bundle-source":{"types":"./dist/types/bundle-source/index.d.ts","import":"./dist/bundle-source/index.js","default":"./src/bundle-source/index.ts"},"./locale-manager":{"types":"./dist/types/locale-manager/base-locale-manager.d.ts","import":"./dist/locale-manager/base-locale-manager.js","default":"./src/locale-manager/base-locale-manager.ts"}},"gitHead":"6fb9694f3811c582924a950c96390a1c52dfa970","private":false,"scripts":{"lint":"eslint ./ --fix","test":"vitest","build":"run-p build:*","format":"prettier ./ --write","lint:ci":"eslint ./ --output-file eslint_report.json --format json","coverage":"vitest run --coverage --passWithNoTests","format:ci":"prettier ./ --check","build:main":"vite build","build:types":"run-p types:*","should-pull":"rushx build && node ./dist/translation-service/should-pull.js","types:build":"tsc","coverage:open":"rushx coverage && open coverage/index.html","pull-translations":"rushx build && node ./dist/translation-service/pull.js","check-and-translate":"node ./src/translate-dialpadistani/check-and-translate.js","translate:dialpadistan":"rushx build && node ./dist/dialpadistan.js","force-pull-translations":"rushx build && node ./dist/translation-service/force-pull.js","upload-translation-service":"rushx build && node ./dist/translation-service/push.js","translation-screenshots-check":"rushx build && node ./dist/translation-service/screenshots-check.js"},"_npmUser":{"name":"dlovero-dialpad","email":"daniel.lovero@dialpad.com"},"repository":{"url":"git+https://github.com/dialpad/web-clients.git","type":"git"},"_npmVersion":"10.7.0","description":"i18n common services and functionality","directories":{},"_nodeVersion":"20.14.0","dependencies":{"vue-demi":"0.14.10","csv-parse":"5.5.6","fluent-vue":"3.7.2","@fluent/bundle":"0.17.1","@fluent/syntax":"^0.19.0"},"_hasShrinkwrap":false,"devDependencies":{"vite":"~5.4.10","jsdom":"21.1.1","vitest":"~2.1.4","vue-tsc":"1.8.8","fast-glob":"^3.3.3","typescript":"~5.6.3","@types/node":"^24.0.4","npm-run-all":"4.1.5","@vitejs/plugin-vue":"~5.1.4"},"peerDependencies":{"vue":"^2.0.0 || >=3.0.0"},"peerDependenciesMeta":{"@vue/composition-api":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/i18n-services_1.8.0_1756146239890_0.12461002286270983","host":"s3://npm-registry-packages-npm-production"}},"1.9.0":{"name":"@dialpad/i18n-services","version":"1.9.0","_id":"@dialpad/i18n-services@1.9.0","maintainers":[{"name":"jawrey","email":"awreyjustin@gmail.com"},{"name":"dlovero-dialpad","email":"daniel.lovero@dialpad.com"},{"name":"juliodialpad","email":"julio.ortega@dialpad.com"}],"homepage":"https://github.com/dialpad/web-clients#readme","bugs":{"url":"https://github.com/dialpad/web-clients/issues"},"dp":{"nodpend":true},"bin":{"should-pull":"dist/translation-service/should-pull.js","pull-translations":"dist/translation-service/pull.js","check-and-translate":"src/translate-dialpadistani/check-and-translate.js","translate-dialpadistan":"dist/dialpadistan.js","force-pull-translations":"dist/translation-service/force-pull.js","upload-translation-service":"dist/translation-service/push.js","translation-screenshots-check":"dist/translation-service/screenshots-check.js"},"dist":{"shasum":"30563adccb38b74dee7c0fa2908ba2af951163b0","tarball":"https://registry.npmjs.org/@dialpad/i18n-services/-/i18n-services-1.9.0.tgz","fileCount":98,"integrity":"sha512-wNofunyK3yga6puumAWO0qwSPBYg1rs603jeEgkQskwsNl4iMplvgRttiWmrBSd+d0aAJvrie2mllrPfg+Hsdw==","signatures":[{"sig":"MEUCIQC8pYF9G4bGqocMyJabRG0zZYXK5ktdEpT6XoRsDkv/pwIgBWyc7ElxeY8yifhRpmQkxb8NRFewrbT+5uz4ecJJZkY=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1346273},"type":"module","_from":"file:dialpad-i18n-services-1.9.0.tgz","exports":{"./storage":{"types":"./dist/types/storage/index.d.ts","import":"./dist/storage/index.js","default":"./src/storage/index.ts"},"./bundle-source":{"types":"./dist/types/bundle-source/index.d.ts","import":"./dist/bundle-source/index.js","default":"./src/bundle-source/index.ts"},"./locale-manager":{"types":"./dist/types/locale-manager/base-locale-manager.d.ts","import":"./dist/locale-manager/base-locale-manager.js","default":"./src/locale-manager/base-locale-manager.ts"}},"private":false,"scripts":{"lint":"eslint ./ --fix","test":"vitest","build":"run-p build:*","format":"prettier ./ --write","lint:ci":"eslint ./ --output-file eslint_report.json --format json","coverage":"vitest run --coverage --passWithNoTests","format:ci":"prettier ./ --check","build:main":"vite build","build:types":"run-p types:*","should-pull":"rushx build && node ./dist/translation-service/should-pull.js","types:build":"tsc","coverage:open":"rushx coverage && open coverage/index.html","pull-translations":"rushx build && node ./dist/translation-service/pull.js","check-and-translate":"node ./src/translate-dialpadistani/check-and-translate.js","translate:dialpadistan":"rushx build && node ./dist/dialpadistan.js","force-pull-translations":"rushx build && node ./dist/translation-service/force-pull.js","upload-translation-service":"rushx build && node ./dist/translation-service/push.js","translation-screenshots-check":"rushx build && node ./dist/translation-service/screenshots-check.js"},"_npmUser":{"name":"dlovero-dialpad","email":"daniel.lovero@dialpad.com"},"_resolved":"/private/var/folders/_h/0t2pz_gd6tz1mcbflq5jhj580000gn/T/f786bc618a93b3013ad738f8424999ee/dialpad-i18n-services-1.9.0.tgz","_integrity":"sha512-wNofunyK3yga6puumAWO0qwSPBYg1rs603jeEgkQskwsNl4iMplvgRttiWmrBSd+d0aAJvrie2mllrPfg+Hsdw==","repository":{"url":"git+https://github.com/dialpad/web-clients.git","type":"git"},"_npmVersion":"10.7.0","description":"i18n common services and functionality","directories":{},"_nodeVersion":"20.14.0","dependencies":{"vue-demi":"0.14.10","csv-parse":"5.5.6","fluent-vue":"3.7.2","@fluent/bundle":"0.17.1","@fluent/syntax":"^0.19.0"},"_hasShrinkwrap":false,"devDependencies":{"vite":"~5.4.10","jsdom":"21.1.1","vitest":"~2.1.4","vue-tsc":"1.8.8","fast-glob":"^3.3.3","typescript":"~5.6.3","@types/node":"^24.0.4","npm-run-all":"4.1.5","@vitejs/plugin-vue":"~5.1.4"},"peerDependencies":{"vue":"^2.0.0 || >=3.0.0"},"peerDependenciesMeta":{"@vue/composition-api":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/i18n-services_1.9.0_1760550563096_0.5119911952605318","host":"s3://npm-registry-packages-npm-production"}},"1.11.0":{"name":"@dialpad/i18n-services","version":"1.11.0","description":"i18n common services and functionality","type":"module","private":false,"scripts":{"typecheck":"echo 'no typecheck specified'","typecheck:ci":"rushx typecheck","lint":"echo 'needs migration to use @dialpad/eslint-config'","lint:ci":"echo 'needs migration to use @dialpad/eslint-config'","format":"prettier ./ --write","format:ci":"prettier ./ --check","test":"vitest","test:ci":"rushx test 2>&1","coverage":"vitest run --coverage --passWithNoTests","coverage:open":"rushx coverage && open coverage/index.html","build":"run-p build:*","build:types":"run-p types:*","build:main":"vite build","types:build":"tsc","translate:dialpadistan":"rushx build && node ./dist/dialpadistan.js","check-and-translate":"node ./src/translate-dialpadistani/check-and-translate.js","translation-screenshots-check":"rushx build && node ./dist/translation-service/screenshots-check.js","upload-translation-service":"rushx build && node ./dist/translation-service/push.js","pull-translations":"rushx build && node ./dist/translation-service/pull.js","force-pull-translations":"rushx build && node ./dist/translation-service/force-pull.js","should-pull":"rushx build && node ./dist/translation-service/should-pull.js"},"bin":{"translate-dialpadistan":"dist/dialpadistan.js","check-and-translate":"src/translate-dialpadistani/check-and-translate.js","translation-screenshots-check":"dist/translation-service/screenshots-check.js","upload-translation-service":"dist/translation-service/push.js","pull-translations":"dist/translation-service/pull.js","force-pull-translations":"dist/translation-service/force-pull.js","should-pull":"dist/translation-service/should-pull.js"},"dependencies":{"@fluent/bundle":"0.17.1","@fluent/syntax":"^0.19.0","vue-demi":"0.14.10","fluent-vue":"3.7.2","csv-parse":"5.5.6"},"devDependencies":{"@types/node":"^24.0.4","@vitejs/plugin-vue":"~5.1.4","fast-glob":"^3.3.3","jsdom":"21.1.1","npm-run-all":"4.1.5","prettier":"~2.8.8","typescript":"~5.6.3","vite":"~5.4.10","vitest":"~2.1.4","vue-tsc":"1.8.8","eslint":"~9.13.0"},"dp":{"nodpend":true},"peerDependencies":{"vue":"^2.0.0 || >=3.0.0"},"peerDependenciesMeta":{"@vue/composition-api":{"optional":true}},"exports":{"./locale-manager":{"types":"./dist/types/locale-manager/base-locale-manager.d.ts","import":"./dist/locale-manager/base-locale-manager.js","default":"./src/locale-manager/base-locale-manager.ts"},"./bundle-source":{"types":"./dist/types/bundle-source/index.d.ts","import":"./dist/bundle-source/index.js","default":"./src/bundle-source/index.ts"},"./storage":{"types":"./dist/types/storage/index.d.ts","import":"./dist/storage/index.js","default":"./src/storage/index.ts"}},"repository":{"type":"git","url":"git+https://github.com/dialpad/web-clients.git"},"_id":"@dialpad/i18n-services@1.11.0","gitHead":"9c9d72af52e7e08e26d21d5a3eee9ca64478e033","bugs":{"url":"https://github.com/dialpad/web-clients/issues"},"homepage":"https://github.com/dialpad/web-clients#readme","_nodeVersion":"20.14.0","_npmVersion":"10.7.0","dist":{"integrity":"sha512-vXXU2I7oJ+06yoMYBpBVYEZo+hubHgUsK+8yydFzOxNbIs7KOuH8s0gT36hdWdkM0kPWKUn3X/TaMcTu+At9Ww==","shasum":"2c44106a3113cae3a5cb64cb76c4601f481d6217","tarball":"https://registry.npmjs.org/@dialpad/i18n-services/-/i18n-services-1.11.0.tgz","fileCount":105,"unpackedSize":1367667,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIEVrXf9UTzH6KR8jlfDDpCksbj0qyLZDhnDsmGv9gyajAiEAl1R45CnZXAjRHgz05b6ZjDQl6DtST7GdfEIYagX3BZ8="}]},"_npmUser":{"name":"dlovero-dialpad","email":"daniel.lovero@dialpad.com"},"directories":{},"maintainers":[{"name":"jawrey","email":"awreyjustin@gmail.com"},{"name":"dlovero-dialpad","email":"daniel.lovero@dialpad.com"},{"name":"juliodialpad","email":"julio.ortega@dialpad.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/i18n-services_1.11.0_1763661144676_0.29149301068095124"},"_hasShrinkwrap":false}},"time":{"created":"2025-05-21T18:35:56.699Z","modified":"2025-11-20T17:52:25.164Z","1.2.0":"2025-05-21T18:35:57.084Z","1.5.0":"2025-07-02T18:52:53.232Z","1.8.0":"2025-08-25T18:24:00.084Z","1.9.0":"2025-10-15T17:49:23.287Z","1.11.0":"2025-11-20T17:52:24.950Z"},"bugs":{"url":"https://github.com/dialpad/web-clients/issues"},"homepage":"https://github.com/dialpad/web-clients#readme","repository":{"type":"git","url":"git+https://github.com/dialpad/web-clients.git"},"description":"i18n common services and functionality","maintainers":[{"name":"jawrey","email":"awreyjustin@gmail.com"},{"name":"dlovero-dialpad","email":"daniel.lovero@dialpad.com"},{"name":"juliodialpad","email":"julio.ortega@dialpad.com"}],"readme":"# i18n-services\n\n## Introduction\n\n`@dialpad/i18n-services` contains all the tooling needed to manage the resources\nfor our i18n packages, i.e.\n[`@dialpad/i18n-vue2` for legacy apps](../i18n-vue2/README.md) and\n[`@dialpad/i18n` for modern apps](../i18n/README.md). this includes:\n\n- Uploading new strings to a translation service.\n- Downloading translated strings from a translation service.\n- Loading bundled resources at runtime for a given locale.\n- Generating a \"Dialpadistan\" locale from `en-US`.\n\n## How it works?\n\nThere are essentially two main concepts behind the scenes:\n\n### BaseLocaleManager\n\nThe BaseLocaleManager having the common logic that oversees internationalization\n(i18n) in a Vue2.js and a Vue3.js application using the\n[Fluent localization framework](https://projectfluent.org/). Its\nresponsibilities include:\n\n- **Loading and caching translation bundles:** Manages the `.ftl` data, which\n  maps keys to text for each locale.\n- **Switching the current locale:** Provides methods to change the active\n  language dynamically.\n- **Handling bundle namespaces:** Manages potential duplicate bundle requests\n  from multiple sources, though this feature is still being refined.\n- **Initializing the Vue plugin:** Exposes translation methods (`$t`, `$ta`) to\n  `Vue` templates, enabling localized content within the application.\n\n### BundleSource\n\nThe second key concept is the BundleSource interface, which abstracts the\nloading and management of localization resources. This interface has two primary\nimplementations: `RawBundleSource` and `HTTPBundleSource`, each designed for\ndifferent use cases.\n\n- `RawBundleSource`: This implementation handles localization resources defined\n  within the application. It organizes these resources defined directly in the\n  application, and imported directly at runtime (for example, using\n  `import(./[locale].ftl`). This approach is ideal for applications with mostly\n  static content.\n\n- `HTTPBundleSource`: This implementation fetches localization resources\n  dynamically from a server. It caches these resources locally, allowing for\n  efficient access while still being flexible enough to load translations on\n  demand.\n\n**Disclaimer:** _Both implementations are provisional and may change as we\nbetter understand our needs. Currently, `RawBundleSource` is the preferred\noption for most applications._\n\n#### Synchronous Resource Loading with [builtResources](cci:1://file:///Users/daniellovero/src/web-clients/packages/i18n-services/bundle/bundle-source/raw.js:28:2-34:3)\n\nWhile the\n[dynamicResources](cci:1://file:///Users/daniellovero/src/web-clients/packages/i18n-services/bundle/bundle-source/raw.js:2:2-17:3)\nmethod is used for asynchronously loading resources, the\n[RawBundleSource](cci:2://file:///Users/daniellovero/src/web-clients/packages/i18n-services/bundle/bundle-source/raw.d.ts:14:0-30:1)\nclass also provides a\n[builtResources](cci:1://file:///Users/daniellovero/src/web-clients/packages/i18n-services/bundle/bundle-source/raw.js:28:2-34:3)\nmethod for synchronous resource loading. This is useful when you have the\nlocalization resources available at compile time and prefer to import them\ndirectly without dealing with promises.\n\n##### How to use [builtResources](cci:1://file:///Users/daniellovero/src/web-clients/packages/i18n-services/bundle/bundle-source/raw.js:28:2-34:3)\n\nInstead of dynamically importing `.ftl` files, you can import them directly and\nuse the\n[builtResources](cci:1://file:///Users/daniellovero/src/web-clients/packages/i18n-services/bundle/bundle-source/raw.js:28:2-34:3)\nmethod to process the resources. Here's an example:\n\n```typescript\nimport { RawBundleSource } from '@dialpad/i18n-services';\n// Import your .ftl files directly\nimport enUSResource from './locales/en-US.ftl';\nimport esResource from './locales/es.ftl';\n\n// Create an array of BuiltResource objects\nconst builtResourcesArray: BuiltResource[] = [\n  ['en-US', 'namespace', enUSResource],\n  ['es', 'namespace', esResource],\n  // ... add other locales and namespaces as needed\n];\n\n// Convert BuiltResource objects to Resource objects using builtResources\nconst resources: Resource[] =\n  RawBundleSource.builtResources(builtResourcesArray);\n\n// Now, resources can be used to instantiate RawBundleSource or for any other purpose\nconst bundleSource = new RawBundleSource({ resources });\n```\n\n**If you're looking for the 'Dialpadistan' translator, please\n[skip to this section](#dialpadistan-translator).**\n\n## Setup\n\n### Installation\n\n```sh\npnpm add @dialpad/i18n-services\n```\n\n### Configuration\n\nYou can find the needed configuration for using `$t` and `$ta` functions in your\napplication in the [i18n for vue2](../i18n-vue2/README.md) and\n[i18n for vue3](../i18n/README.md) documentation. In both cases the needed\nconfiguration should be the same.\n\n## Usage\n\n### Adding Resources at Runtime with `addSources`\n\n#### API Method: `addSources`\n\nThe `addSources` method allows you to add multiple translation resources to the\n`LocaleManager` at runtime. Once all resources are loaded, it triggers the\n`ready` promise indicating that the locale manager is fully initialized and\nready to handle localization requests.\n\n##### Parameters\n\n- `sources`: An array of `BuiltResource` items where each item contains:\n  - `locale`: The locale code for the translation resource.\n  - `namespace`: The namespace associated with the resource.\n  - `source`: The actual source string or a promise that resolves to the source\n    string.\n\n##### Example\n\n```typescript\n// Assuming you have a LocaleManager instance\nconst manager = new LocaleManager(...);\n\n// Define your resources\nconst resourcesToAdd: BuiltResource[] = [\n  // Array of [locale, namespace, source] tuples\n  ['en-US', 'namespace1', sourceStringOrPromise],\n  ['es-ES', 'namespace1', anotherSourceStringOrPromise],\n  // Add more resources as needed\n];\n\n// Add the resources to the LocaleManager\nmanager.addSources(resourcesToAdd);\n```\n\n### I18n interface\n\nThe API for our i18n tools is the same either for the vue3 or vue2 supported\nversions. You can find the more details about how to use the tool in the\n[i18n for vue2](../i18n-vue2/README.md) and [i18n for vue3](../i18n/README.md)\ndocumentation.\n\n### Dialpadistan translator\n\nThis feature uses the `@fluent/syntax` parser and a set of regex and grammar\nrules to convert an `en-US.ftl` file into an `dp-DP.ftl` inside the same\ndirectory. The \"dialpadistani\" language is just the original language\ntransformed character-per-character to non-latin characters which is useful to\ntest the proper render of different fonts.\n\nFor example:\n\n```ftl\n# src/localization/en-US.ftl\n\nMESSAGE_INPUT_LABEL = New message input\nFEED_NEW_SEPARATOR = Beginning of unread items\n```\n\nWill translate to:\n\n```ftl\n# src/localization/dp-DP.ftl\n\nMESSAGE_INPUT_LABEL = Ŋάŵ ɱάššëğά īŋþø†\nFEED_NEW_SEPARATOR = Sάğīŋŋīŋğ ůƒ øŋřάëḍ ī†άɱš\n```\n\nTo execute a Dialpadistan translation you should run the following script\npointing to your Fluent English file: _(Note: it can either be a relative path\nor an absolute path)_\n\n```sh\npnpm pnpm --filter=@dialpad/i18n-services run translate:dialpadistan /your/english/fluent/file/en-US.ftl\n```\n\nWhen succeeding translating, you will notice a message on your terminal stating\nthe folder where the output file will be placed. This folder is _the same as\nyour English Fluent file_.\n\ne.g. in this case you will see\n`File transformed and saved as /your/english/fluent/file/dp-DP.ftl`.\n\n#### Commit hook\n\nThis translator includes a post-commit that automatically translates english\nfiles to dialpadistani. This hook checks the commit for changed `en-US.ftl`\nfiles and will only run the translator against those files that had changes in\nthe commit.\n\nIf this script finally makes any change to `dp-DP.ftl` files, it will\nautomatically commit those changes with the message:\n`chore(auto-generated): translate en-US.ftl files to dialpadistani`\n\n#### Known issues\n\nThere is one specific scenario where this translator is failing, and we don't\nconsider it to be harmful. This is because of a bug on `@fluent/syntax` parser.\n\nAnd this is when having a comment right in the middle between an equal sign and\na value, and that comment has at least one placeholder, whatever's after the\ntext of the first placeholder will be translated (and if the comment it's\nmulti-lined every comment line will be squashed and inlined after that\nplaceholder as well)\n\ne.g.\n\n```ftl\nMY_KEY =\n    # My awesome comment\n    # And here the {$placeholder} is present\n        .aria-label = { $name } ({ $muted ->\n        [true] Muted{\" \"}\n        *[other] {\"\"}\n    })\n```\n\nwill be translated to:\n\n```ftl\nMY_KEY =\n    # My awesome comment\n    # And here the {$placeholder} os sintirp\n        .aria-label = { $name } ({ $muted ->\n        [true] Muted{\" \"}\n        *[other] {\"\"}\n    })\n```\n\nThis is because the way`@fluent/syntax` parser works at the current version. In\norder to fix this it would require an amount of effort that is probably not\nworth it. It will imply either to patch the parser behavior somehow or extra\nusage of regex pre and post processing files, which will not only increase\ncomplexity of the solution but also reduce the robustness of it. And given the\nfact that is just a comment, we prefer not to solve it in-house and wait until\nthey fix or improve this behavior on upcoming versions.\n\n**But keep in mind that whenever adding comments, it should be before the whole\nKEY = VALUE and not in between.**\n\n## Context screenshots\n\nContext screenshots are, as their name suggest, screenshots that provide context\nto recognize where each translation is used in each app.\n\nEach screenshot should contain visual information of where the translation can\nbe found in the app with enough context to be easily located. If other dev looks\nat the screenshot they should be able to locate it fairly easily in your app.\n\nThere should be one screenshot per each translation key on each `.ftl` file. You\ncan reuse the same screenshot for multiple keys, but each file will correspond\nto one key, so you must make one copy for each translation key. The screenshot\nfilename will be `{translationKeyHere}.png`. We only support `.png` images for\nnow.\n\nThere is a PR check which will fail if any translation key is missing its\ncorresponding screenshot. There is an exception list for paths that should be\nignored by this check. Avoid using it unless it's completely necessary. If you\nstrictly need to use it, remember to mention in your commit message why you are\nusing it.\n\nThese screenshots will be located in a directory called `context-screenshots`\nsibling to each `.ftl` file in your project. If you have an `.ftl` file, it\nshould have a sibling screenshots directory. Each screenshot has a file size\nlimit of 20MB.\n\nThe screenshots are uploaded to smartling along with the CSV/FTL files through a\ngithub action when a PR to main is merged.\n\n## Resources\n\n- [Fluent docs](https://github.com/projectfluent/fluent/wiki)\n- [I18n best practices](https://localization.blog/2022/05/16/i18n-best-practices-keep-it-together/)\n- [i18n for vue2 docs](../i18n-vue2/README.md)\n- [i18n for vue3 docs](../i18n/README.md)\n\n## Translation Workflows\n\nThe following GitHub workflows handle various aspects of the translation\nprocess:\n\n### 1. Sync Translations Workflow\n\n**Name**: Pull translations from third party translation service\n\n**Purpose**: This workflow synchronizes translations by pulling them from a\nthird-party translation service (Smartling) and automatically creates a pull\nrequest if there are any changes.\n\n**Triggers**:\n\n- Push to the `main` branch\n- Daily scheduled run at midnight (cron: `0 0 * * *`)\n- Manual trigger (workflow_dispatch)\n\n**Configuration**:\n\n- Uses the `pull-translations.yml` workflow from `dialpad/wcf-sdk@v0.6.0`\n- Smartling project ID is retrieved from repository variables\n- Working directory is set to \"./packages/i18n\"\n- Node version is determined from the \".nvmrc\" file\n- Requires Smartling API credentials stored in GitHub secrets\n\n### 2. Force Pull Translations Workflow\n\n**Name**: Manual Force Pull Translations\n\n**Purpose**: This workflow allows for manual forced pulls of translations from\nthe translation service, with configurable options.\n\n**Triggers**:\n\n- Manual trigger only (workflow_dispatch)\n\n**Input Parameters**:\n\n- `USE_FTL_FLOW`: Option to use FTL flow (boolean, default: true)\n- `SKIP_UNAVAILABLE_LOCALES`: Option to skip unavailable locales without failing\n  (boolean, default: true)\n- `WORKING_DIRECTORY`: Specifies the working directory (string, default: \".\")\n- `NODE_VERSION_FILE`: Path to the Node version file (string, optional)\n\n**Configuration**:\n\n- Uses the `force-pull-translations.yml` workflow from `dialpad/wcf-sdk@v0.6.0`\n- Smartling project ID is retrieved from repository variables\n- Requires Smartling API credentials stored in GitHub secrets\n\n### 3. Translation Screenshots Check Workflow\n\n**Name**: Check translations screenshots\n\n**Purpose**: This workflow verifies if the screenshots for translations are\nup-to-date with their respective FTL files.\n\n**Triggers**:\n\n- Pull requests targeting the `main` branch\n\n**Configuration**:\n\n- Uses the `screenshots-translations.yml` workflow from `dialpad/wcf-sdk@v0.6.0`\n- Smartling project ID is retrieved from repository variables\n- Working directory is set to \"./packages/i18n\"\n- Node version is determined from the \".nvmrc\" file\n- Requires Smartling API credentials stored in GitHub secrets\n\n### 4. Upload to Translation Service Workflow\n\n**Name**: Push en-US.ftl to third party translation service\n\n**Purpose**: This workflow pushes the English (en-US.ftl) source files to the\nthird-party translation service (Smartling) for translation.\n\n**Triggers**:\n\n- Push to the `main` branch\n\n**Configuration**:\n\n- Uses the `push-translations.yml` workflow from `dialpad/wcf-sdk@v0.6.0`\n- Smartling project ID is retrieved from repository variables\n- Working directory is set to \"./packages/i18n\"\n- Node version is determined from the \".nvmrc\" file\n- Requires Smartling API credentials stored in GitHub secrets\n\nAll workflows use Smartling as the translation service and require proper API\ncredentials (`SMARTLING_API_USER` and `SMARTLING_API_SECRET`) stored as GitHub\nsecrets.\n","readmeFilename":"README.md"}