Skip to content

Locale Detector

The Locale Detector reads a locale from browser sources such as query string, storage, cookies, and navigator.language. Core runs the registered detector during init(), after plugins have registered and before initial namespace loading.

Terminal window
npm install @comvi/plugin-locale-detector
import { createI18n } from "@comvi/core";
import { LocaleDetector } from "@comvi/plugin-locale-detector";
const i18n = createI18n({ locale: "en" })
.use(LocaleDetector());
await i18n.init();

The detected locale is used before initial translations are loaded.

Detection has two phases:

  1. Read the first configured cache. By default this is localStorage.
  2. If that cache is empty, check order from left to right.

Defaults:

LocaleDetector({
caches: ["localStorage"],
order: ["querystring", "localStorage", "sessionStorage", "cookie", "navigator"],
})
type DetectorType = "querystring" | "localStorage" | "sessionStorage" | "cookie" | "navigator";
type CacheType = "localStorage" | "sessionStorage" | "cookie";
interface LocaleDetectorOptions {
order?: DetectorType[];
caches?: CacheType[];
lookupQuerystring?: string;
lookupCookie?: string;
lookupLocalStorage?: string;
lookupSessionStorage?: string;
cookieOptions?: {
path?: string;
domain?: string;
sameSite?: "strict" | "lax" | "none";
secure?: boolean;
};
cookieMaxAge?: number;
fallbackLocale?: string;
supportedLocales?: string[];
convertDetectedLocale?: (locale: string) => string;
}

Persist the user’s choice in localStorage:

LocaleDetector()

Use cookies when your server or middleware also needs to read the selected locale:

LocaleDetector({
order: ["cookie", "navigator"],
caches: ["cookie"],
lookupCookie: "comvi_locale",
cookieOptions: { sameSite: "lax" },
})

The plugin itself reads browser APIs. For SSR, do locale detection in your framework middleware/server loader and use the cookie as shared state.

Restrict detected values to your supported locales:

LocaleDetector({
supportedLocales: ["en", "de", "fr", "pt-BR"],
fallbackLocale: "en",
})

With supportedLocales, detected tags are matched using BCP 47-style matching: exact match, base language match, then regional variant match.

  • Later setLocaleAsync() calls are persisted to all configured caches.
  • Storage access is guarded, so private mode and server-only runtimes fail gracefully.
  • Only one locale detector is active. Registering another detector replaces the previous one.