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. Cache read. Only the first entry in caches is read on init. With caches: ["localStorage", "cookie"], only localStorage is checked at startup; the cookie and any other entries are write-only persistence targets. If the first cache holds a value, detection stops there.
  2. Ordered scan. If the first cache is empty (or caches is []), each source in order is tried left to right; the first non-empty, valid tag wins.

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.