logo
  • Guide
  • Config
  • Plugin
  • API
  • Examples
  • Community
  • Modern.js 2.x Docs
  • English
    • 简体中文
    • English
    • Start
      Introduction
      Quick Start
      Upgrading
      Glossary
      Tech Stack
      Core Concept
      Page Entry
      Build Engine
      Web Server
      Basic Features
      Routes
      Routing
      Config Routes
      Data Solution
      Data Fetching
      Data Writing
      Data Caching
      Rendering
      Server-Side Rendering
      Streaming SSR
      Rendering Cache
      Static Site Generation
      Render Preprocessing
      Styling
      Styling
      Use CSS Modules
      Using CSS-in-JS
      Using Tailwind CSS
      HTML Template
      Import Static Assets
      Import JSON Files
      Import SVG Assets
      Import Wasm Assets
      Debug
      Data Mocking
      Network Proxy
      Using Rsdoctor
      Using Storybook
      Testing
      Playwright
      Vitest
      Jest
      Cypress
      Path Alias
      Environment Variables
      Output Files
      Deploy Application
      Advanced Features
      Using Rspack
      Using BFF
      Basic Usage
      Runtime Framework
      Extend BFF Server
      Extend Request SDK
      File Upload
      Cross-Project Invocation
      Optimize Page Performance
      Code Splitting
      Inline Static Assets
      Bundle Size Optimization
      React Compiler
      Improve Build Performance
      Browser Compatibility
      Low-Level Tools
      Source Code Build Mode
      Server Monitor
      Monitors
      Logs Events
      Metrics Events
      Internationalization
      Basic Concepts
      Quick Start
      Configuration
      Locale Detection
      Resource Loading
      Routing Integration
      API Reference
      Advanced Usage
      Best Practices
      Custom Web Server
      Topic Detail
      Module Federation
      Introduction
      Getting Started
      Application-Level Modules
      Server-Side Rendering
      Deployment
      Integrating Internationalization
      FAQ
      Dependencies FAQ
      CLI FAQ
      Build FAQ
      HMR FAQ
      Deprecated
      📝 Edit this page
      Previous pageQuick StartNext pageLocale Detection

      #Configuration

      Plugin configuration is divided into two parts: CLI configuration (modern.config.ts) and runtime configuration (modern.runtime.ts). Both need to be used together - CLI configuration is for basic plugin settings, while runtime configuration is for i18next initialization options.

      Warning

      Function-type configurations (such as SDK loader functions) can only be set in runtime configuration (modern.runtime.ts), not in CLI configuration. This is because CLI configuration is executed at build time and cannot serialize functions.

      #CLI Configuration (modern.config.ts)

      Configure plugin options in modern.config.ts:

      import { i18nPlugin } from '@modern-js/plugin-i18n';
      
      export default defineConfig({
        plugins: [
          i18nPlugin({
            localeDetection: {
              // Language detection configuration
            },
            backend: {
              // Backend resource loading configuration
            },
          }),
        ],
      });

      #localeDetection Configuration

      localeDetection is used to configure language detection related options:

      Warning

      If localePathRedirect is enabled, the detection configuration must be placed in CLI configuration (modern.config.ts), because the server-side plugin needs to read this configuration to get language information and perform path redirection.

      interface BaseLocaleDetectionOptions {
        /** Whether to enable path redirection, adds language prefix to URL when enabled */
        localePathRedirect?: boolean;
      
        /** Whether to enable i18next language detector */
        i18nextDetector?: boolean;
      
        /** Supported language list */
        languages?: string[];
      
        /** Default fallback language */
        fallbackLanguage?: string;
      
        /** Custom detection configuration */
        detection?: LanguageDetectorOptions;
      
        /** Routes to ignore automatic redirection (array of path patterns or function)
         *
         * Can be a string array (path patterns) or a function to determine if redirection should be ignored.
         * Supports exact match and prefix match (e.g., '/api' will match '/api' and '/api/users').
         *
         * @example
         * // String array
         * ignoreRedirectRoutes: ['/api', '/admin']
         *
         * // Function
         * ignoreRedirectRoutes: (pathname) => pathname.startsWith('/api')
         */
        ignoreRedirectRoutes?: string[] | ((pathname: string) => boolean);
      }
      
      interface LocaleDetectionOptions extends BaseLocaleDetectionOptions {
        /** Configure language detection by entry (multi-entry scenarios) */
        localeDetectionByEntry?: Record<string, BaseLocaleDetectionOptions>;
      }

      Example:

      i18nPlugin({
        localeDetection: {
          localePathRedirect: true,
          i18nextDetector: true,
          languages: ['zh', 'en', 'ja'],
          fallbackLanguage: 'en',
          detection: {
            order: ['path', 'cookie', 'header'],
            lookupCookie: 'i18next',
            caches: ['cookie'],
          },
        },
      });

      #backend Configuration

      backend is used to configure resource loading methods:

      Info

      Auto-detection: The plugin automatically detects and enables backend in the following scenarios:

      1. If you configure loadPath or addPath: The backend will be automatically enabled (enabled: true) without checking for locales directory, since you've already specified the resource path.

      2. If you don't configure backend: The plugin will automatically detect if a locales directory exists in:

        • Project root: {projectRoot}/locales
        • Config public directory: {projectRoot}/config/public/locales
        • Public directory configured via server.publicDir: {projectRoot}/{publicDir}/locales

        If the directory exists and contains JSON files, the backend will be automatically enabled.

      3. If you explicitly set enabled: false: No auto-detection will be performed, and the backend will remain disabled.

      This automatic detection helps reduce unnecessary backend registration when locales directory doesn't exist, improving performance.

      interface BaseBackendOptions {
        /** Whether to enable backend resource loading */
        enabled?: boolean;
      
        /** Resource file loading path (HTTP backend) */
        loadPath?: string;
      
        /** Missing translation save path (optional) */
        addPath?: string;
      
        /** Cache hit mode for chained backend (only effective when both `loadPath` and `sdk` are provided)
         *
         * - `'none'` (default, only when chained backend is not configured): If the first backend returns resources, stop and don't try the next backend
         * - `'refresh'`: Try to refresh the cache by loading from the next backend and update the cache
         * - `'refreshAndUpdateStore'` (default for chained backend): Try to refresh the cache by loading from the next backend,
         *   update the cache and also update the i18next resource store. This allows FS/HTTP resources to be displayed first,
         *   then SDK resources will update them asynchronously.
         *
         * @default 'refreshAndUpdateStore' when both loadPath and sdk are provided
         */
        cacheHitMode?: 'none' | 'refresh' | 'refreshAndUpdateStore';
      
        /** SDK loader function (custom backend)
         *
         * Note: In CLI configuration, can only be set to `true` or a string identifier to enable SDK mode.
         * The actual SDK function must be provided through `initOptions.backend.sdk` in runtime configuration (`modern.runtime.ts`).
         *
         * When both `loadPath` (or FS backend) and `sdk` are provided, the plugin will automatically use `i18next-chained-backend`
         * to chain multiple backends. The loading order will be:
         * 1. HTTP/FS backend (primary) - loads from `loadPath` or file system first for quick initial display
         * 2. SDK backend (update) - loads from the SDK function to update/refresh translations
         *
         * With `cacheHitMode: 'refreshAndUpdateStore'` (default), FS/HTTP resources will be displayed immediately,
         * then SDK resources will be loaded asynchronously to update the translations.
         */
        sdk?: I18nSdkLoader | boolean | string;
      }
      
      interface BackendOptions extends BaseBackendOptions {
        /** Configure backend by entry (multi-entry scenarios) */
        backendOptionsByEntry?: Record<string, BaseBackendOptions>;
      }

      Examples:

      1. HTTP/FS backend only:

      You can explicitly enable backend:

      i18nPlugin({
        backend: {
          enabled: true,
          loadPath: '/locales/{{lng}}/{{ns}}.json',
        },
      });

      Or simply configure loadPath or addPath, and backend will be automatically enabled:

      i18nPlugin({
        backend: {
          // enabled will be automatically set to true
          loadPath: '/locales/{{lng}}/{{ns}}.json',
        },
      });

      Auto-detection without configuration:

      If you don't configure backend at all, the plugin will automatically detect locales directory:

      i18nPlugin({
        // No backend config - plugin will auto-detect locales directory
        localeDetection: {
          languages: ['zh', 'en'],
          fallbackLanguage: 'en',
        },
      });

      If locales directory exists with JSON files, backend will be automatically enabled with default loadPath: '/locales/{{lng}}/{{ns}}.json'.

      2. Chained backend (recommended): Use both HTTP/FS backend and SDK backend

      When backend.enabled = true and sdk is configured, if loadPath is not explicitly configured, the default loadPath will be used automatically and chained backend will be enabled:

      i18nPlugin({
        backend: {
          enabled: true,
          // When loadPath is not configured, default '/locales/{{lng}}/{{ns}}.json' will be used
          sdk: true, // SDK backend
          // cacheHitMode: 'refreshAndUpdateStore', // Default value, can be omitted
        },
      });

      You can also explicitly configure loadPath:

      i18nPlugin({
        backend: {
          enabled: true,
          loadPath: '/locales/{{lng}}/{{ns}}.json', // HTTP/FS backend
          sdk: true, // SDK backend
        },
      });

      Provide the SDK function in modern.runtime.ts:

      export default defineRuntimeConfig({
        i18n: {
          initOptions: {
            backend: {
              sdk: async options => {
                // SDK implementation
                if (options.lng && options.ns) {
                  return await mySdk.getResource(options.lng, options.ns);
                }
              },
            },
          },
        },
      });

      When using chained backend, the system will:

      1. First load resources from /locales/{{lng}}/{{ns}}.json and display immediately (quick initial display of basic translations)
      2. Then asynchronously load resources from SDK and update the i18next store (update/supplement translations)

      This ensures users see page content quickly while the latest translation resources are loaded in the background.

      3. SDK backend only:

      If you need to disable HTTP/FS backend and use only SDK backend, you can explicitly set loadPath: '':

      i18nPlugin({
        backend: {
          enabled: true,
          loadPath: '', // Explicitly disable HTTP/FS backend
          sdk: true, // Use SDK backend only
        },
      });
      Warning

      When using SDK backend only, you must provide the actual SDK function in modern.runtime.ts, otherwise it will fallback to HTTP/FS backend.

      #Multi-Entry Configuration

      If the project has multiple entries, you can configure each entry separately:

      i18nPlugin({
        localeDetection: {
          localePathRedirect: true,
          languages: ['zh', 'en'],
          fallbackLanguage: 'en',
          // Override configuration for specific entry
          localeDetectionByEntry: {
            admin: {
              localePathRedirect: false, // admin entry does not use path redirection
            },
          },
        },
        backend: {
          enabled: true,
          // Override configuration for specific entry
          backendOptionsByEntry: {
            admin: {
              loadPath: '/admin/locales/{{lng}}/{{ns}}.json',
            },
          },
        },
      });

      #Runtime Configuration (modern.runtime.ts)

      You can configure runtime options in src/modern.runtime.ts:

      import { defineRuntimeConfig } from '@modern-js/runtime';
      import i18next from 'i18next';
      
      // It's recommended to create a new i18next instance to avoid using the global default instance
      const i18nInstance = i18next.createInstance();
      
      export default defineRuntimeConfig({
        i18n: {
          // Use custom i18next instance (optional)
          i18nInstance: i18nInstance,
      
          // i18next initialization options
          initOptions: {
            fallbackLng: 'en',
            supportedLngs: ['zh', 'en'],
            // Other i18next configuration options
          },
        },
      });

      #i18nInstance Configuration

      If you need to use a custom i18next instance, you can provide it in runtime configuration:

      import { defineRuntimeConfig } from '@modern-js/runtime';
      import i18next from 'i18next';
      
      // Create custom instance
      const customI18n = i18next.createInstance({
        // Custom configuration
      });
      
      export default defineRuntimeConfig({
        i18n: {
          i18nInstance: customI18n,
        },
      });

      #initOptions Configuration

      initOptions will be passed to i18next's init method and supports all i18next configuration options:

      Info

      If localePathRedirect is enabled, the detection configuration should be set in CLI configuration, not in initOptions. This is because the server-side plugin needs to read the detection option from CLI configuration to perform language detection and path redirection.

      export default defineRuntimeConfig({
        i18n: {
          initOptions: {
            // Language related
            lng: 'en',
            fallbackLng: 'en',
            supportedLngs: ['zh', 'en'],
      
            // Namespace related
            ns: ['translation', 'common'],
            defaultNS: 'translation',
      
            // React related
            react: {
              useSuspense: false,
            },
      
            // Other i18next options
            interpolation: {
              escapeValue: false,
            },
          },
        },
      });

      #SDK Backend Configuration

      If using SDK backend, you need to provide the actual SDK function in runtime configuration:

      Info

      Function-type configurations can only be set in runtime configuration. In CLI configuration, sdk can only be set to true or a string identifier to enable SDK mode. The actual function implementation must be provided in modern.runtime.ts.

      Enable SDK mode in modern.config.ts:

      i18nPlugin({
        backend: {
          enabled: true,
          sdk: true, // Enable SDK mode
        },
      });

      Provide SDK function in modern.runtime.ts:

      import { defineRuntimeConfig } from '@modern-js/runtime';
      import type { I18nSdkLoader } from '@modern-js/plugin-i18n/runtime';
      
      const mySdkLoader: I18nSdkLoader = async options => {
        if (options.all) {
          // Load all resources
          return await fetchAllResources();
        }
      
        if (options.lng && options.ns) {
          // Load single resource
          const response = await fetch(`/api/i18n/${options.lng}/${options.ns}`);
          return response.json();
        }
      
        // Handle other cases
        return {};
      };
      
      export default defineRuntimeConfig({
        i18n: {
          initOptions: {
            backend: {
              sdk: mySdkLoader,
            },
          },
        },
      });