On this page
ranutsresolveLocale

resolveLocale

Pick which of your supported locales to use, from the usual chain: query → cookie → localStorage → navigator → fallback.

The catalogue of messages is yours; this only picks the key.

API

resolveLocale(options)

Option Description Type Default
supported Locales you actually ship, most specific first readonly string[] Required
fallback Returned when nothing matches string supported[0]
query Query parameter carrying an explicit choice, e.g. lang string —
cookie Cookie name carrying the choice string —
storageKey localStorage key carrying the choice the user last picked string —
useNavigator Consult navigator.languages / navigator.language before falling back boolean true
url URL to read the query from string Current location

Return

The matching entry of supported: always one of them, never an arbitrary string.

Example

Full chain

import { resolveLocale } from 'ranuts';

const locale = resolveLocale({
  supported: ['en', 'zh-CN'],
  query: 'lang',
  cookie: 'lang',
  storageKey: 'app-lang',
});

document.documentElement.lang = locale;
render(messages[locale]);

Region variants fall back to the base language

import { resolveLocale } from 'ranuts';

const supported = ['en', 'zh-CN'];

resolveLocale({ supported, query: 'lang', url: '?lang=en-GB' }); // 'en'
resolveLocale({ supported, query: 'lang', url: '?lang=zh' }); // 'zh-CN'
resolveLocale({ supported, query: 'lang', url: '?lang=de' }); // 'en'  (unsupported → fallback)

Pair with locale URLs

import { resolveLocale, createLocalePath } from 'ranuts';

const paths = createLocalePath({
  locales: [{ code: 'en' }, { code: 'zh-CN', prefix: 'zh' }],
});

// Prefer what the URL already says; fall back to the user's own preference.
const locale = paths.localeFromPath(location.pathname) ?? resolveLocale({ supported: ['en', 'zh-CN'] });

Notes

  1. The order is the point. A ?lang= in the URL is explicit, shareable and one-off, so it beats everything. A cookie is a server-visible decision, so it beats client-only state. localStorage is what the user last chose in-app. navigator.language is only a guess about a first-time visitor. Getting this backwards produces the classic bug where a shared ?lang=en link keeps rendering in the recipient's stored language.

  2. The result is always one of supported. A value outside the list is ignored rather than returned, so the result is safe to index a message catalogue with.

  3. Matching is case-insensitive and falls back by base language. With supported: ['en', 'zh-CN'], en-GB matches en and zh matches zh-CN.

  4. navigator.languages is consulted in order, not just navigator.language: the list is the user's actual ranked preference, and its head is often not the best available match.

  5. Every source degrades quietly. No window, no document.cookie, no localStorage: each simply contributes nothing, so the chain works under SSR and in build-time scripts.