{"id":13810986,"url":"https://github.com/cibernox/svelte-intl-precompile","last_synced_at":"2025-05-15T09:02:45.328Z","repository":{"id":37267918,"uuid":"358303190","full_name":"cibernox/svelte-intl-precompile","owner":"cibernox","description":"I18n library for Svelte.js that analyzes your keys at build time for max performance and minimal footprint","archived":false,"fork":false,"pushed_at":"2024-11-03T22:53:11.000Z","size":239,"stargazers_count":276,"open_issues_count":10,"forks_count":13,"subscribers_count":8,"default_branch":"main","last_synced_at":"2025-04-07T03:15:57.980Z","etag":null,"topics":["formatting","i18n","internationalization","localization","svelte","translation"],"latest_commit_sha":null,"homepage":"https://svelte-intl-precompile.com","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"isc","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cibernox.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":["cibernox"]}},"created_at":"2021-04-15T15:15:15.000Z","updated_at":"2025-02-16T13:34:15.000Z","dependencies_parsed_at":"2024-06-18T15:30:40.101Z","dependency_job_id":"352d60c1-e909-49e6-a351-8c30d1abe019","html_url":"https://github.com/cibernox/svelte-intl-precompile","commit_stats":{"total_commits":110,"total_committers":10,"mean_commits":11.0,"dds":"0.30000000000000004","last_synced_commit":"14c900fb08ead39ee83c1729fbd7dfd628465f16"},"previous_names":[],"tags_count":39,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cibernox%2Fsvelte-intl-precompile","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cibernox%2Fsvelte-intl-precompile/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cibernox%2Fsvelte-intl-precompile/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cibernox%2Fsvelte-intl-precompile/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cibernox","download_url":"https://codeload.github.com/cibernox/svelte-intl-precompile/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248890433,"owners_count":21178430,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["formatting","i18n","internationalization","localization","svelte","translation"],"created_at":"2024-08-04T03:00:34.708Z","updated_at":"2025-04-14T13:45:04.210Z","avatar_url":"https://github.com/cibernox.png","language":"JavaScript","funding_links":["https://github.com/sponsors/cibernox"],"categories":["Sites"],"sub_categories":[],"readme":"![Svelte Intl Precompile](https://raw.githubusercontent.com/cibernox/svelte-intl-precompile/main/logos/svelte-intl-precompile-double-line.svg)\n\n## Svelte-intl-precompile\n\nThis i18n library for Svelte.js has an API identical (or at least very similar) to https://github.com/kaisermann/svelte-i18n but has\na different approach to processing translations.\n\nInstead of doing all the work in the client, much like Svelte.js acts as a compiler for your app, this library acts as a compiler\nfor your translations.\n\n## Check the documentation page, it's better than this Readme\n\nGo to [https://svelte-intl-precompile.com](https://svelte-intl-precompile.com)\n\nStill, there you have the rest of the Readme.\n\n### Why would I want to use it? How does it work?\nThis approach is different than the taken by libraries like intl-messageformat or format-message, which do all the work in the browser. The approach taken by those libraries is more flexible as you can just load json files with translations in plain text and that's it, but it also means the library needs to ship a parser for the ICU message syntax, and it always has to have ship code for all the features that the ICU syntax supports, even features you might not use, making those libraries several times bigger.\n\nThis process spares the browser of the burden of doing the same process in the user's devices, resulting in smaller and faster apps.\n\nFor instance if an app has the following set of translations:\n```json\n{\n  \"plain\": \"Some text without interpolations\",\n  \"interpolated\": \"A text where I interpolate {count} times\",\n  \"time\": \"Now is {now, time}\",\n  \"number\": \"My favorite number is {n, number}\",\n  \"pluralized\": \"I have {count, plural,=0 {no cats} =1 {one cat} other {{count} cats}}\",\n  \"pluralized-with-hash\": \"I have {count, plural, zero {no cats} one {just # cat} other {# cats}}\",\n  \"selected\": \"{gender, select, male {He is a good boy} female {She is a good girl} other {They are good fellas}}\",\n  \"numberSkeleton\": \"Your account balance is {n, number, ::currency/CAD sign-always}\",\n  \"installProgress\": \"{progress, number, ::percent scale/100 .##} completed\"\n}\n```\n\nThe babel plugin will analyze and understand the strings in the ICU message syntax and transform them into something like:\n```js\nimport { __interpolate, __number, __plural, __select, __time } from \"precompile-intl-runtime\";\nexport default {\n  plain: \"Some text without interpolations\",\n  interpolated: count =\u003e `A text where I interpolate ${__interpolate(count)} times`,\n  time: now =\u003e `Now is ${__time(now)}`,\n  number: n =\u003e `My favorite number is ${__number(n)}`,\n  pluralized: count =\u003e `I have ${__plural(count, { 0: \"no cats\", 1: \"one cat\", h: `${__interpolate(count)} cats`})}`,\n  \"pluralized-with-hash\": count =\u003e `I have ${__plural(count, { z: \"no cats\", o: `just ${count} cat`, h: `${count} cats`})}`,\n  selected: gender =\u003e __select(gender, { male: \"He is a good boy\", female: \"She is a good girl\", other: \"They are good fellas\"}),\n  numberSkeleton: n =\u003e `Your account balance is ${__number(n, { style: 'currency', currency: 'CAD', signDisplay: 'always' })}`,\n  installProgress: progress =\u003e `${__number(progress / 100, { style: 'percent', maximumFractionDigits: 2 })} completed`\n}\n```\n\nNow the translations are either strings or functions that take some arguments and generate strings using some utility helpers. Those utility helpers are very small and use the native Intl API available in all modern browsers and in node. Also, unused helpers are tree-shaken by rollup.\n\nWhen the above code is minified it will results in an output that compact that often is shorter than the original ICU string:\n\n```\n\"pluralized-with-hash\": \"I have {count, plural, zero {no cats} one {just # cat} other {# cats}}\",\n--------------------------------------------------------------------------------------------------\n\"pluralized-with-hash\":t=\u003e`I have ${jt(t,{z:\"no cats\",o:`just ${t} cat`,h:`${t} cats`})}`\n```\n\nThe combination of a very small and treeshakeable runtime with moving the parsing into the build step results in an extremely small footprint and\nextremely fast performance.\n\n**How small, you may ask?** \nUsually adds less than 2kb to your final build size after compression and minification, when compared with nearly 15kb that alternatives with\na runtime ICU-message parser like `svelte-i18n` add.\n\n**How fast, you may also ask?** \nWhen rendering a key that has also been rendered before around 25% faster. For initial rendering or rendering a keys that haven't been rendered \nbefore, around 400% faster.\n\n### Setup\nFirst of all, you can find a working sveltekit app configured to use `svelte-intl-precompile` in https://github.com/cibernox/sample-app-svelte-intl-precompile.\nIf you struggle with any of the following steps you can always use that app to compare it with yours:\n\n1. Install `svelte-intl-precompile` as a runtime dependency.\n\n2. Create a folder to put your translations. I like to use a `/messages` or `/locales` folder on the root. On that folder, create `en.json`, `es.json` (you can also create JS files exporting objects with the translations) and as many files as languages you want. On each file, export an object with your translations:\n```json\n{\n  \"recent.aria\": \"Find recently viewed tides\",\n  \"menu\": \"Menu\",\n  \"foot\": \"{count} {count, plural, =1 {foot} other {feet}}\",\n}\n```\n\n3. In your `svelte.config.js` import the function exported by `svelte-intl-precompile/sveltekit-plugin` and invoke with the folder where you've placed\nyour translation files it to your list of Vite plugins:\n```js\nimport precompileIntl from \"svelte-intl-precompile/sveltekit-plugin\";\n\n/** @type {import('@sveltejs/kit').Config} */\nmodule.exports = {\n  kit: {\n    target: '#svelte',\n    vite: {\n      plugins: [\n        // if your translations are defined in /locales/[lang].js\n        precompileIntl('locales')\n        // precompileIntl('locales', '$myprefix') // also you can change import path prefix for json files ($locales by default)\n      ]\n    }\n  }\n};\n```\n\nIf you are using CommonJS, you can instead use `const precompileIntl = require(\"svelte-intl-precompile/sveltekit-plugin\");`.\n\nFrom this step onward the library almost identical to use and configure to the popular `svelte-i18n`. It has the same features and only the import path is different. You can check the docs of `svelte-i18n` for examples and details in the configuration options.\n\n4. Now you need some initialization code to register your locales and configure your preferences. You can import your languages statically (which will add them to your bundle) or register loaders that will load the translations lazily. The best place to put this configuration is inside a `\u003cscript context=\"module\"\u003e` on your `src/$layout.svelte`\n```html\n\u003cscript\u003e\n  import { addMessages, init, getLocaleFromNavigator /*, register */ } from 'svelte-intl-precompile';\n  import en from '$locales/en.js';  // If using typescript you can also use the .ts extension.\n  import es from '$locales/es.js'   // load from $myprefix/es.js you configured a custom import path.\n  // if you put your translations in js files, import then usin the relative path. E.g. `import en from '../../locales/en.js'`\n  // @ts-ignore\n  addMessages('en', en);\n  addMessages('es', es);\n  // register('es', () =\u003e import('$locales/es.js')); \u003c-- use this approach if you want locales to be load lazily\n\n  init({\n    fallbackLocale: 'en',\n    initialLocale: getLocaleFromNavigator()\n  });\n\u003c/script\u003e\n\n\u003cscript\u003e\n  import '../app.css';\n\u003c/script\u003e\n\n\u003cslot /\u003e\n```\n\n5. Now on your `.svelte` files you start translating using the `t` store exported from `svelte-intl-precompile`:\n```html\n\u003cscript\u003e\n\timport { t } from 'svelte-intl-precompile'\n\u003c/script\u003e\n\u003cfooter class=\"l-footer\"\u003e\n\t\u003cp class=\"t-footer\"\u003e{$t(\"hightide\")} {$t(\"footer.cta\")}\u003c/p\u003e\n\u003c/footer\u003e\n```\n\n\n## Note for automatic browser locale detection when server side rendering\n\nIf you want to automatically detect your user's locale from the browser using `getLocaleFromNavigator()` but you are\nserver side rendering your app (which sveltekit does by default), you need to take some extra steps for the\nlocale used when SSR matches the locale when hydrating the app which would cause texts to change.\n\nYou can pass to `getLocaleFromNavigator` an optional argument which is the locale to use when SSR'ing your app.\nHow you get that value depends on how you run your app, but for instance using sveltekit you can extract it from the\n`accept-language` HTTP header of the request, using [Hooks](https://kit.svelte.dev/docs#hooks)\n\nYou can use `getSession` to extract the preferred locale from the request headers and store it in the session object,\nwhich is made available to the client:\n```js\n// src/hooks.js\nexport function getSession(request) {\n  let acceptedLanguage = request.headers[\"accept-language\"] \u0026\u0026 request.headers[\"accept-language\"].split(',')[0];`\n  return { acceptedLanguage };\n}\n```\n\nThen you can use the `session` store to pass it to the `init` function:\n```html\n\u003c!-- __layout.svelte --\u003e\n\u003cscript context=\"module\"\u003e\n  import { register, init, waitLocale, getLocaleFromNavigator } from 'svelte-intl-precompile';\n  register('en', () =\u003e import('$locales/en-us'));\n  register('en-US', () =\u003e import('$locales/en-US'));\n  register('es-GB', () =\u003e import('$locales/es-GB'));\t\n\t\n  export async function load({session}) {\n    init({\n      fallbackLocale: 'en',\n      initialLocale: session.acceptedLanguage || getLocaleFromNavigator(),\n    });\n    await waitLocale(); // awaits for initialLocale language pack to finish loading;\n    return {};\n  }\n\u003c/script\u003e\n```\n\nIf you have a lot of languages or want to register all available languages, you can use the `registerAll` function:\n\n```html\n\u003c!-- __layout.svelte --\u003e\n\u003cscript context=\"module\"\u003e\n  import { register, init, waitLocale, getLocaleFromNavigator } from 'svelte-intl-precompile';\n  import { registerAll } from '$locales';\n\n  // Equivalent to a `register(\"lang\", () =\u003e import('$locales/lang'))` fro each lang file in localesRoot.\n  registerAll();\n\n  export async function load({session}) {\n    init({\n      fallbackLocale: 'en',\n      initialLocale: session.acceptedLanguage || getLocaleFromNavigator(),\n    });\n    await waitLocale(); // awaits for initialLocale language pack to finish loading;\n    return {};\n  }\n\u003c/script\u003e\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcibernox%2Fsvelte-intl-precompile","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcibernox%2Fsvelte-intl-precompile","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcibernox%2Fsvelte-intl-precompile/lists"}