sveltekit-i18n

repository·master·Indexed 20 days ago

https://github.com/sveltekit-i18n/lib

A lightweight, SvelteKit-optimized internationalization library (v2.4.2) supporting SSR, lazy loading of translations via routes, and flexible parsing options. It provides a translation function $t, reactive stores for locale and loading states, and built-in modifiers for numbers, dates, and currency using Intl APIs. The library supports custom modifiers, conditional interpolation, and provides patterns for type-safe translations in TypeScript.

Tokens
22.5K
Snippets
69
Records
96
Agent score
68%

What's inside sveltekit-i18n

  1. Choose an integration pattern for sveltekit-i18n

    master

    The sveltekit-i18n library provides several integration patterns depending on your application's architecture and SEO requirements. Choose the one that matches your needs:

    Routing & Architecture

    • multi-page (Recommended): The most frequent use-case for applications with multiple routes. Translations are loaded based on locale and routes, preventing duplicate translation loads on both server and client.
    • one-page: Best for single-page applications (SPAs). Translations are loaded dynamically according to the current locale.
    • single-load: Loads all translations for all language mutations during initialization. Useful only if you require all translations to be immediately available.
    • locale-param: A multi-page approach where language is determined by a URL parameter (e.g., https://example.com/?lang=en).

    SEO & Adapter Optimization

    • locale-router-static: Uses locale-based routing (e.g., /en/about). Optimized for @sveltejs/adapter-static and great for SEO.
    • locale-router: Uses locale-based routing. Optimized for non-static adapters like @sveltejs/adapter-node.
    • locale-router-advanced: Similar to locale-router but optimized for non-static adapters where default locale routes do not have a language prefix in the path.

    Component-Scoped Translations

    • component-scoped-csr: Allows scoping translations to specific components. App translations load via SSR, but component translations are loaded via a component promise on the client side (CSR).
    • component-scoped-ssr: Uses an exported init method to initialize language mutations within the parent page's load method, delegating props back to the component instance.
  2. Explore @sveltekit-i18n/parser-default features

    master

    The @sveltekit-i18n/parser-default package provides parsing capabilities for internationalization strings. This specific example demonstrates:

    • Placeholders: Using dynamic values within translation strings.
    • Built-in Modifiers: Using pre-defined formatting modifiers.
    • Custom Modifiers: Implementing and using custom logic for string transformations.
  3. Advanced translation features: Placeholders, Modifiers, and Conditionals

    master

    The library supports advanced message formatting:

    • Placeholders: Use {{variable}} in JSON and pass an object to $t.
      • Example: $t('greeting', { name: 'Alice' })
    • Modifiers: Format data like currency or dates using a semicolon syntax.
      • Example: {{amount:currency;}} $\rightarrow$ $t('price', { amount: 99.99 }, { currency: 'USD' })
    • Conditionals: Handle plurals or variations using conditional syntax.
      • Example: {{count; 1:item; default:items;}} $ ightarrow$ $t('items', { count: 1 }) returns "1 item."
  4. Organize translations using Namespaces

    master

    Namespaces allow you to group translations into logical segments. This is highly recommended for larger applications to improve manageability and enable lazy loading.

    Common patterns for namespaces include:

    • common: Shared UI elements, navigation, and error messages.
    • home: Content specific to the homepage.
    • products: Product-related text.
    • checkout: Text specific to the checkout flow.
  5. Choose between sveltekit-i18n packages

    master

    The sveltekit-i18n ecosystem is split into three main packages. Choosing the right one depends on whether you want a turnkey solution or maximum control over message interpolation.

    1. sveltekit-i18n (The Complete Solution)

    Use when: You want the quickest setup and are happy with the default parser syntax.

    • Includes: Everything in @sveltekit-i18n/base plus @sveltekit-i18n/parser-default.
    • Pros: Sensible defaults, simplified API, and no external dependencies.

    2. @sveltekit-i18n/base (The Core Engine)

    Use when: You need maximum flexibility or want to use custom parsers.

    • Responsibilities: Managing translation state (Svelte stores), loading/caching translations, route matching, and coordinating with parsers.
    • Note: It does not include message interpolation or a default parser. You must provide one.

    3. @sveltekit-i18n/parsers (Message Interpolation)

    Use when: You need specific syntax for variables, formatting, or conditionals.

    • @sveltekit-i18n/parser-default: Simple placeholder and modifier syntax.
    • @sveltekit-i18n/parser-icu: Supports the ICU message format (requires intl-messageformat).
    • Responsibilities: Interpolating variables, formatting numbers/dates/currencies, and handling plurals or gender-based conditional rendering.
  6. How preprocessing transforms translation objects

    master

    The library can preprocess nested JSON objects into a flat dot notation. This is typically used to enable efficient lookups and simpler translation keys in your code.

    When using preprocess: 'full', a nested structure is flattened. For example, a nested user.profile.name object becomes a single key user.profile.name at the top level of the lookup object.

    // Input
    {
      "user": {
        "profile": {
          "name": "Name",
          "email": "Email"
        }
      }
    }
    
    // Output (preprocess: 'full')
    {
      "user.profile.name": "Name",
      "user.profile.email": "Email"
    }
  7. Use the locale-param pattern for URL parameter-based routing

    master
    The locale-param pattern is used for multi-page applications where the language is determined by a URL query parameter instead of a path segment (e.g., https://example.com/?lang=en). This approach allows you to manage localization by reading the lang parameter from the URL to drive the i18n state.
  8. Optimize performance with Route-based Loading

    master

    To prevent loading all translations at once, you can restrict specific translation keys to certain routes using the routes array in your configuration. This ensures translations are only fetched when the user visits the specified paths.

    const config = {
      loaders: [
        {
          locale: 'en',
          key: 'home',
          routes: ['/'], // Load only on homepage
          loader: async () => (await import('./en/home.json')).default,
        },
        {
          locale: 'en',
          key: 'about',
          routes: ['/about'], // Load only on about page
          loader: async () => (await import('./en/about.json')).default,
        },
      ],
    };
  9. Build a static site with language mutations and error pages

    master

    When running npm run build (or equivalent) with a static locale-router configuration, the output directory will contain separate folders for each language mutation. Each folder includes the translated content and the corresponding static error pages for various HTTP status codes.

    Example build output structure:

    build/
    ├─ _app/
    │  └– ...
    ├─ cs/
    │  ├─ 401/
    │  │  └– index.html
    │  ├─ 403/
    │  │  └– index.html
    │  ├─ 404/
    │  │  └– index.html
    │  ├─ 500/
    │  │  └– index.html
    │  ├─ about/
    │  │  └– index.html
    │  └─ index.html
    ├─ de/
    │  └─ ...
    ├─ en/
    │  └─ ...
    └─ ...
  10. Understand the sveltekit-i18n data flow

    master

    The library operates through four distinct phases:

    1. Configuration Phase: You initialize the i18n instance with a configuration object containing loaders. This registers loaders and initializes Svelte stores but does not execute the loaders yet.
    2. Loading Phase: Triggered by calling loadTranslations(locale, route). The system matches the current locale and route against registered loaders, executes the loader() functions, preprocesses the data (e.g., flattening to dot notation), and stores the results in a central translations store.
    3. Translation Phase: When you use the $t store in a Svelte component, the library looks up the key for the current locale and uses a parser to inject variables into the translation string.
    4. Locale Switch: When locale.set(newLocale) is called, the library checks if translations for the new locale exist. If they are missing, it automatically triggers the Loading Phase for that locale before updating the stores and triggering UI reactivity.
    import i18n from 'sveltekit-i18n';
    
    const config = {
      loaders: [
        {
          locale: 'en',
          key: 'common',
          routes: ['/'],
          loader: async () => (await import('./en/common.json')).default,
        },
      ],
    };
    
    const { t, locale, loadTranslations } = new i18n(config);
  11. Understand reactivity with Svelte stores

    master

    The library leverages Svelte stores to manage state and reactivity. When these stores update, all components using them re-render automatically.

    Readable stores (read-only)

    • $t: The translation function used in components.
    • $locales: A list of available locales.
    • $loading: Indicates the current loading state of translations.
    • $initialized: Indicates if the i18n system has been initialized.

    Writable stores (can be updated)

    • $locale: The current active locale.
    // Example of using stores in a Svelte component
    <script>
      import { t, locale } from '$lib/i18n';
    
      function switchLanguage(newLocale) {
        $locale = newLocale; // Updating the writable store
      }
    </script>
    
    <h1>{$t('welcome_message')}</h1>
    <p>Current locale: {$locale}</p>
  12. Organize translation files by locale and namespace

    master

    To ensure scalability and ease of maintenance, organize your translation files in a directory structure that separates locales and uses namespaces (e.g., common.json, home.json).

    src/lib/translations/
    ├── index.js              # i18n configuration
    ├── en/
    │   ├── common.json       # Shared UI, navigation
    │   ├── home.json         # Homepage
    │   ├── about.json        # About page
    │   └── errors.json       # Error messages
    ├── cs/
    │   ├── common.json
    │   └── ...

    Namespace Strategies

    1. Common Namespace: Keep essential, frequently used translations (like navigation or buttons) in a common namespace that loads on every page. Keep this file small (< 5 KB).
    2. Page-Specific Namespaces: Create separate namespaces for major routes to ensure translations load only when needed. Use the routes property in your config to target specific paths or regex patterns.
    3. Feature-Based Organization: For large applications, group translations by functional features (e.g., auth.json, checkout.json) rather than by page. This allows multiple routes to share a single feature-based namespace.
    const config = {
      loaders: [
        // Common (all pages)
        { locale: 'en', key: 'common', loader: async () => (await import('./en/common.json')).default },
        
        // Page-specific (route-based)
        { locale: 'en', key: 'home', routes: ['/'], loader: async () => (await import('./en/home.json')).default },
        { locale: 'en', key: 'about', routes: ['/about'], loader: async () => (await import('./en/about.json')).default },
        { locale: 'en', key: 'products', routes: [/^\/products/], loader: async () => (await import('./en/products.json')).default },
      ],
    };