svelte-intl-precompile

repository·main·Indexed 43 days ago

https://github.com/cibernox/svelte-intl-precompile

An i18n library for Svelte.js (version 0.12.3) that moves ICU message syntax parsing from the browser to the build step. By transforming ICU strings into optimized JavaScript functions via a Babel plugin and a tiny runtime, it reduces bundle size (typically < 2kb) and improves rendering performance. It includes a SvelteKit Vite plugin for automated locale loading and supports .js, .ts, .json, and .yaml translation files.

Tokens
3.2K
Snippets
10
Records
11
Agent score
55%

What's inside svelte-intl-precompile

  1. How svelte-intl-precompile works

    main

    Unlike traditional i18n libraries that parse ICU message syntax in the browser, svelte-intl-precompile acts as a compiler for your translations.

    During the build step, a Babel plugin analyzes your ICU strings (e.g., {count, plural, ...}) and transforms them into highly optimized JavaScript functions. These functions use a tiny, tree-shakable runtime (precompile-intl-runtime) that leverages the native browser Intl API.

    Benefits:

    • Smaller Bundle Size: Typically adds < 2kb to your final build, compared to ~15kb for runtime parsers.
    • Faster Performance: Up to 25% faster for repeated renders and up to 400% faster for initial renders of new keys.
  2. Handle automatic browser locale detection with SSR

    main

    When using Server Side Rendering (SSR), getLocaleFromNavigator() cannot be used on the server because the browser's navigator object is unavailable. To prevent hydration mismatches (where the server text differs from the client text), you must ensure the server uses the same locale as the client.

    Recommended Pattern:

    1. Use SvelteKit hooks.js to extract the accept-language header from the request and store it in the session.
    2. In your root layout's load function, use the session's locale to initialize the library.
    3. Call await waitLocale() to ensure the language pack is loaded before rendering.
    // 1. src/hooks.js - Extract locale from headers
    export function getSession(request) {
      let acceptedLanguage = request.headers["accept-language"] && request.headers["accept-language"].split(',')[0];
      return { acceptedLanguage };
    }
    
    // 2. src/$layout.svelte - Initialize with session locale
    <script context="module">
      import { register, init, waitLocale, getLocaleFromNavigator } from 'svelte-intl-precompile';
    
      export async function load({ session }) {
        init({
          fallbackLocale: 'en',
          initialLocale: session.acceptedLanguage || getLocaleFromNavigator(),
        });
        await waitLocale();
        return {};
      }
    </script>
  3. Setup svelte-intl-precompile in SvelteKit

    main

    Follow these steps to integrate the library into a SvelteKit project:

    1. Install the runtime dependency:

      npm install svelte-intl-precompile
    2. Organize translations: Create a folder (e.g., /locales) and add language files like en.json, es.json, or .js files that export translation objects.

    3. Configure the Vite plugin: In svelte.config.js, import and add precompileIntl to your Vite plugins. You can specify the folder path and an optional import path prefix.

    4. Initialize the library: In your root layout (e.g., src/$layout.svelte), use addMessages or register to load your translations, then call init to set the fallback and initial locales.

    5. Use translations in components: Import the t store to access translated strings in your .svelte files.

    // 1. svelte.config.js setup
    import precompileIntl from "svelte-intl-precompile/sveltekit-plugin";
    
    /** @type {import('@sveltejs/kit').Config} */
    module.exports = {
      kit: {
        vite: {
          plugins: [
            precompileIntl('locales') // 'locales' is the folder containing your translations
          ]
        }
      }
    };
    
    // 2. src/$layout.svelte initialization
    <script>
      import { addMessages, init, getLocaleFromNavigator } from 'svelte-intl-precompile';
      import en from '$locales/en.js';
      import es from '$locales/es.js';
    
      addMessages('en', en);
      addMessages('es', es);
    
      init({
        fallbackLocale: 'en',
        initialLocale: getLocaleFromNavigator()
      });
    </script>
    
    // 3. Component usage
    <script>
      import { t } from 'svelte-intl-precompile';
    </script>
    
    <p>{$t("menu")}</p>
  4. Configure the svelte-intl-precompile Vite plugin

    main

    The svelte-intl-precompile/sveltekit-plugin is used in svelte.config.js to enable the build-time transformation of ICU messages.

    It accepts a folder path as the first argument. You can optionally provide a second argument to change the import path prefix for the generated JSON files (the default is $locales).

    import precompileIntl from "svelte-intl-precompile/sveltekit-plugin";
    
    // Basic usage
    precompileIntl('locales')
    
    // Custom import path prefix
    precompileIntl('locales', '$myprefix')
  5. Import locales via the virtual $locales module

    main

    Once the plugin is configured, you can use the virtual module prefix to import locales and manage available languages.

    Registering all locales

    You can import registerAll and availableLocales from the prefix module. Calling registerAll() will dynamically register all discovered locale files in the localesRoot.

    import { registerAll, availableLocales } from '$locales';
    
    // Call this to ensure all locales are loaded
    registerAll();
    
    console.log(availableLocales); // e.g., ['en', 'en-US', 'fr']

    Importing a specific locale

    You can import a specific locale directly using the prefix. The plugin is extension-agnostic for imports (e.g., $locales/en will match en.js, en.ts, or en.json).

    import en from '$locales/en';

    Locale Resolution Order

    When multiple files exist for a locale (e.g., en-US.json and en.json), the plugin sorts them so that more specific locales (those with more sub-tags) are prioritized.

    import { registerAll, availableLocales } from '$locales';
    
    registerAll();
    console.log(availableLocales);
  6. Configure the svelte-intl-precompile SvelteKit plugin

    main

    To use svelte-intl-precompile in a SvelteKit project, add the svelteIntlPrecompile function to your Vite configuration. This plugin automates the loading, transformation, and registration of locale files.

    Configuration Options

    When calling svelteIntlPrecompile(localesRoot, options), you can provide an options object:

    • prefix (string): The virtual module prefix used to import locales. Defaults to '$locales'.
    • transformers (Record<string, Function>): A map of file extensions to transformer functions for custom file types.
    • exclude (Function | RegExp): A way to exclude specific files from being detected as locales. If a function, it receives the filename; if a RegExp, it tests the filename.

    Supported File Extensions

    The plugin includes standard transformers for the following extensions:

    • .js, .ts, .mjs: Treated as scripts (no transformation other than ICU precompilation).
    • .json, .json5: Parsed via json5 and exported as a default object.
    • .yaml, .yml: Parsed via js-yaml and exported as a default object.

    Usage Example

    // svelte.config.js or vite.config.js
    import svelteIntlPrecompile from 'svelte-intl-precompile/sveltekit-plugin';
    
    export default {
      kit: {
        // ...
      },
      vite: {
        plugins: [
          svelteIntlPrecompile('./src/locales', {
            prefix: '$locales',
            exclude: /\.tmp$/
          })
        ]
      }
    };
    import svelteIntlPrecompile from 'svelte-intl-precompile/sveltekit-plugin';
    
    export default {
      vite: {
        plugins: [
          svelteIntlPrecompile('./src/locales', {
            prefix: '$locales',
            exclude: /\.tmp$/
          })
        ]
      }
    };
  7. Import locales using the virtual $locales module

    main

    Once the plugin is configured, you can interact with your locale files using the virtual module prefix (defaulting to $locales).

    Automatic Locale Registration

    You can import registerAll and availableLocales from the prefix module to automatically register all detected locale files in your application.

    import { registerAll, availableLocales } from '$locales';
    
    // Call this to register all found locales
    registerAll();
    
    console.log(availableLocales); // e.g., ['en-US', 'en', 'fr']

    Direct Locale Import

    You can import specific locales directly. The plugin normalizes imports, so you can omit the file extension.

    // These all resolve to the same locale via the plugin
    import en from '$locales/en';
    import en from '$locales/en.json';
    import en from '$locales/en.yaml';

    Note on ordering: The plugin sorts locales so that more specific locales (e.g., en-US) appear before general ones (e.g., en).

    import { registerAll, availableLocales } from '$locales';
    
    registerAll();
    console.log(availableLocales);
  8. Register locales for lazy loading

    main

    Instead of importing all translation files statically (which increases bundle size), you can register loaders to load locales lazily when needed.

    Use register(locale, loader) to define how a specific locale should be loaded. Alternatively, if you have a dedicated entry point for all registrations, you can use registerAll().

    import { register, init, waitLocale, getLocaleFromNavigator } from 'svelte-intl-precompile';
    
    // Registering individual locales for lazy loading
    register('en', () => import('$locales/en.js'));
    register('es', () => import('$locales/es.js'));
    
    // Using registerAll if you have a central registration file
    import { registerAll } from '$locales';
    registerAll();
    
    init({
      fallbackLocale: 'en',
      initialLocale: getLocaleFromNavigator()
    });
    await waitLocale();
  9. Access the precompile-intl-runtime API

    main

    The svelte-intl-precompile package acts as a re-export for precompile-intl-runtime. All public functions, classes, and types provided by the runtime are available directly through this package entrypoint.

    import { /* exported symbols from precompile-intl-runtime */ } from 'svelte-intl-precompile';
  10. Use transformCode to precompile ICU messages

    main

    The transformCode function is a public utility that applies the ICU precompilation plugin to a given string of code. This is useful if you need to manually precompile translation files outside of the standard SvelteKit plugin lifecycle.

    It uses @babel/core with the babel-plugin-precompile-intl plugin to transform ICU message syntax into optimized JavaScript code.

    import { transformCode } from './sveltekit-plugin.js';
    
    const code = `export default { greeting: "Hello {name}!" };`;
    const options = { filename: 'example.js' };
    
    const transformed = transformCode(code, options);
    // transformed will contain the precompiled version of the ICU string
  11. Use transformCode for manual ICU precompilation

    main

    The svelteIntlPrecompile plugin exports a transformCode function. This can be used to manually transform code containing ICU message strings using the underlying babel-plugin-precompile-intl logic.

    transformCode(code, options)

    • code: The raw string of code to transform.
    • options: Babel transformation options.
    const { transformCode } = require('svelte-intl-precompile/sveltekit-plugin');
    
    const transformed = transformCode('const msg = "{count, plural, one {# cat} other {# cats}}";', {});