svelte-i18n

repository·main·Indexed 23 days ago

https://github.com/kaisermann/svelte-i18n

An internationalization library for Svelte (version 4.0.1) that provides reactive tools for managing locales and message dictionaries using Svelte stores. It includes support for ICU syntax, date, time, and number formatting, as well as a CLI for extracting translation messages from projects. The library supports both synchronous and asynchronous loading of JSON translation dictionaries.

Tokens
11.3K
Snippets
40
Records
71
Agent score
78%

What's inside svelte-i18n

  1. Introduction to svelte-i18n

    main
    svelte-i18n is an internationalization library for Svelte that leverages Svelte's reactive stores to manage the current locale, the dictionary of messages, and message formatting. This ensures that translations stay in sync with your UI components automatically.
  2. Migrate client locale detection from v2 to v3

    main

    In v2, the init method could automatically set the initial locale using heuristics via the navigator: true option. In v3, this logic has been moved to explicit utility functions to reduce bundle weight. You must import the specific utility you need and pass its result to init.

    Available utilities:

    • getLocaleFromHostname
    • getLocaleFromPathname
    • getLocaleFromNavigator
    • getLocaleFromQueryString
    • getLocaleFromHash
    import { init, getLocaleFromNavigator } from 'svelte-i18n'
    
    init({
      initialLocale: getLocaleFromNavigator(),
    })
  3. Migrate value interpolation from v1 to v2

    main

    In v1, interpolated values were passed as the second argument directly to the $_ (format) method. In v2, interpolated values must be wrapped in a values property within the options object.

    <h1>
      {$_('navigation.pagination', { values: { current: 2, max: 10 }})}
    </h1>
    <!-- Page: 2/10 -->
  4. Migrate adding dictionaries from v1 to v2

    main

    In v1, dictionaries were managed by calling .set() or .update() on the $dictionary store. In v2, use the addMessages(locale, messages) function. Note that calling addMessages for the same locale will merge the new messages into the existing dictionary.

    import { addMessages } from 'svelte-i18n'
    
    addMessages('en', { ... })
    addMessages('pt', { ... })
    addMessages('fr', { ... })
    
    // message dictionaries are merged together
    addMessages('en', { ... })
  5. Handle initial loading in Svelte and Sapper

    main

    Because asynchronous loaders (register) take time to resolve, you should manage the loading state to prevent rendering the app with missing translations.

    In Svelte

    Use the $isLoading store to delay showing your app until the initial load is complete.

    In Sapper

    Use the preload static method in your layout component combined with waitLocale to await the loading of dictionaries.

    <!-- src/_layout.svelte -->
    <script context="module">
      import { waitLocale } from 'svelte-i18n'
    
      export async function preload() {
        // awaits for the loading of the 'en-US' and 'en' dictionaries
        return waitLocale()
      }
    </script>
  6. Migrate adding custom formats from v1 to v2

    main

    In v1, custom formats were added using addCustomFormats(). In v2, custom formats are defined within the formats property of the init() configuration object.

    import { init } from 'svelte-i18n'
    
    init({
      fallbackLocale: ..., 
      initialLocale, ...,
      formats: {
        number: {
          EUR: { style: 'currency', currency: 'EUR' },
        },
      }
    })
  7. Extract messages using the svelte-i18n CLI

    main

    The svelte-i18n CLI allows you to extract all translation messages from your project to stdout or to a specific JSON file. Use the extract command followed by a glob pattern to specify which files to scan, and optionally provide an output file path.

    Usage:

    $ svelte-i18n extract [options] <glob-pattern> [output-file]
  8. Migrate casing utilities from v2 to v3

    main

    The built-in casing utilities $_.title, $_.capital, $_.lower, and $_.upper were removed in v3. To achieve the same results, use standard JavaScript string methods on the result of the translation store, or implement custom helper functions.

    Example of manual implementation for title and capital:

    function capital(str: string) {
      return str.replace(/(^|\s)\S/, l => l.toLocaleUpperCase())
    }
    
    function title(str: string) {
      return str.replace(/(^|\s)\S/g, l => l.toLocaleUpperCase())
    }

    Usage with the translation store:

    // Lowercase/Uppercase via native JS
    $_('message.id').toLocaleLowerCase()
    $_('message.id').toLocaleUpperCase()
    
    // Title/Capital via custom helpers
    title($_('message.id'))
    capital($_('message.id'))
    function capital(str: string) {
      return str.replace(/(^|\s)\S/, l => l.toLocaleUpperCase())
    }
    
    function title(str: string) {
      return str.replace(/(^|\s)\S/g, l => l.toLocaleUpperCase())
    }
    
    $_('message.id').toLocaleLowerCase()
    $_('message.id').toLocaleUpperCase()
    title($_('message.id'))
    capital($_('message.id'))
  9. Migrate setting initial and fallback locales from v1 to v2

    main

    In v1, locales were set by combining getClientLocale() with the locale store. In v2, both fallbackLocale and initialLocale are configured directly within the init() method.

    import { init } from 'svelte-i18n'
    
    init({
      fallbackLocale: 'en',
      initialLocale: {
        navigator: true,
      },
    })
  10. Initialize svelte-i18n

    main

    After adding messages or registering loaders, call init() to bootstrap the library. You can specify the fallbackLocale, the initialLocale, and other configuration options.

    Important: Ensure your initialization file is called in your app's entry point. If using Sapper, you must also call init() in your server-side code (server.js).

    import { register, init, getLocaleFromNavigator } from 'svelte-i18n';
    
    register('en', () => import('./en.json'));
    register('en-US', () => import('./en-US.json'));
    register('pt', () => import('./pt.json'));
    
    init({
      fallbackLocale: 'en',
      initialLocale: getLocaleFromNavigator(),
    });
  11. Initialize svelte-i18n for SvelteKit

    main

    To use svelte-i18n in a SvelteKit project, create an initialization file (e.g., src/lib/i18n/index.ts). Use register to map locale keys to their JSON translation files and init to configure the library.

    When initializing, use $app/environment to check if you are in the browser. This allows you to set the initialLocale to window.navigator.language on the client, while falling back to a defaultLocale on the server to ensure consistent SSR behavior.

    // src/lib/i18n/index.ts
    import { browser } from '$app/environment'
    import { init, register } from 'svelte-i18n'
    
    const defaultLocale = 'en'
    
    register('en', () => import('./locales/en.json'))
    register('de', () => import('./locales/de.json'))
    
    init({
    	fallbackLocale: defaultLocale,
    	initialLocale: browser ? window.navigator.language : defaultLocale,
    })
  12. Configure client-side locale in SvelteKit layout load

    main

    To ensure the client-side locale matches the user's browser settings and that translations are ready before rendering, use a +layout.ts load function.

    1. Import your initialization file (e.g., import '$lib/i18n') to trigger the init logic.
    2. In the load function, if browser is true, use locale.set(window.navigator.language) to sync the client locale.
    3. Crucially, await waitLocale() to ensure the translation files are fully loaded before the page renders, preventing flashes of untranslated content.
    // +layout.ts
    import { browser } from '$app/environment'
    import '$lib/i18n' // Import to initialize. Important :)
    import { locale, waitLocale } from 'svelte-i18n'
    import type { LayoutLoad } from './$types'
    
    export const load: LayoutLoad = async () => {
    	if (browser) {
    		locale.set(window.navigator.language)
    	}
    	await waitLocale()
    }