Skip to content
Twilight React Playground
ثيم رائدaren

SUPPORTED_LOCALES & isLocale

constantBeginnerserverbrowserlive demo

The 39 language codes the engine accepts at the start of a URL, and isLocale(), which tells whether a string is one of them.

import { SUPPORTED_LOCALES, isLocale, Locale } from '@salla.sa/twilight-theme-engine/i18n';

In plain words

A store page carries its language at the start of its address: /ar/cart, /en/cart. SUPPORTED_LOCALES is the list of codes the engine accepts there, all lower-case: ar, en, fr, ind (Indonesian) and 35 more.

isLocale(value) answers "is this text one of those codes?" with true or false. Use it before trusting a language code that came from outside your code, such as a query string, a cookie or a form field. Locale is the TypeScript type meaning "one of those codes".

Signature

const SUPPORTED_LOCALES: readonly [
  'ar', 'bg', 'bn', 'cs', 'da', 'de', 'el', 'en', 'es', 'et', 'fa', 'fi', 'fr',
  'ga', 'he', 'hi', 'hr', 'hu', 'hy', 'ind', 'it', 'ja', 'ko', 'lv', 'ms', 'mt',
  'nl', 'pl', 'pt', 'ro', 'ru', 'sl', 'sq', 'sv', 'tl', 'tr', 'uk', 'ur', 'zh',
];

type Locale = (typeof SUPPORTED_LOCALES)[number];   // 'ar' | 'bg' | … | 'zh'

function isLocale(value?: string): value is Locale;  // SUPPORTED_LOCALES.includes(value)

Try it live

isLocale() checks a string against SUPPORTED_LOCALES, the language codes the engine accepts at the start of a URL.Try this: type EN, then id (Indonesian is ind here), then ar-SA.
Storefront canvas · ar · RTL

isLocale("en")true

  • ar
  • bg
  • bn
  • cs
  • da
  • de
  • el
  • en
  • es
  • et
  • fa
  • fi
  • fr
  • ga
  • he
  • hi
  • hr
  • hu
  • hy
  • ind
  • it
  • ja
  • ko
  • lv
  • ms
  • mt
  • nl
  • pl
  • pt
  • ro
  • ru
  • sl
  • sq
  • sv
  • tl
  • tr
  • uk
  • ur
  • zh
39 codes. Shaded: the right-to-left ones in RTL_LOCALES.
Controls
What a theme writes
import { FALLBACK_LOCALE, isLocale, type Locale } from '@salla.sa/twilight-theme-engine/i18n';

/** A language code from a query string, a cookie or a form: check it before using it. */
export function toLocale(value?: string): Locale {
  return isLocale(value) ? value : FALLBACK_LOCALE;
}

toLocale('en'); // 'en'

Example

app/lib/locale.ts
import { FALLBACK_LOCALE, isLocale, type Locale } from '@salla.sa/twilight-theme-engine/i18n';

/** A language code from a query string, a cookie or a form: check it before using it. */
export function toLocale(value?: string): Locale {
  return isLocale(value) ? value : FALLBACK_LOCALE;
}

How it behaves

  • The generated {-$locale} route wrapper uses it: when the URL's locale segment holds something that is not a supported code, its beforeLoad redirects to /ar followed by the path.

  • The engine Link uses it too: it adds the current locale to an internal path unless the first segment is already a supported code, so <Link to="/en"> switches the page to English.

  • On localhost and preview.salla.design, where the first segment names the store, a segment that is a supported code in any letter case is a language instead (isStoreBaseSegment lower-cases before calling isLocale).

  • The list is what a URL accepts, not what a store sells in. The store's own languages, with real names and an is_rtl flag, are useTwilight().settings.languages.

  • Every code has two letters except Indonesian, ind. There are no region variants such as ar-SA or pt-BR.

  • The same values are re-exported from @salla.sa/twilight-theme-engine/routes, where the generated route files import them. In theme code, import from /i18n.

Gotchas

  • isLocale is case-sensitive: isLocale('EN') is false. The engine Link inherits that, so on an Arabic page <Link to="/EN/cart"> goes to /ar/EN/cart (localizeDestination in src/tanstack/link.tsx). Fix: lower-case a code before testing it or building a path with it.

  • SUPPORTED_LOCALES.includes(value) with a value: string does not compile (TS2345): the array is typed as its 39 literals and only accepts those. Fix: call isLocale(value), which also narrows value to Locale.

  • Browser language codes rarely pass: navigator.language is usually a region variant such as ar-SA, and Indonesian browsers report id, not ind. Fix: take the part before -, lower-case it, and map id to ind before calling isLocale.

Related

Source and docs