All files / src/strings index.ts

100% Statements 25/25
75% Branches 3/4
100% Functions 9/9
100% Lines 19/19

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64                            1x             56x   1x 1x   1x               1x 14x 14x 4x     10x 10x 10x       4x           17x   1x 2x   2x 2x       3x  
import { useSyncExternalStore } from 'react';
 
import { LocaleDetails, findLocaleDetails, supportedLocales } from './locales';
import { strings as en } from './strings-en';
import { strings as es } from './strings-es';
import { strings as fr } from './strings-fr';
import { strings as gx } from './strings-gx';
 
/**
 * The set of strings every locale provides. The English table is the source of truth for the list
 * of keys.
 */
export type ComponentStrings = typeof en;
 
const tables: Partial<Record<string, ComponentStrings>> = { en, es, fr, gx };
 
/**
 * Locales we have a bundled string table for. A locale can be supported -- listed in a locale
 * selector -- before its table lands, and resolving against the tables we actually have keeps
 * `getLocale` and `getStrings` describing the same language.
 */
const localesWithTables = (): LocaleDetails[] => supportedLocales.filter((locale) => locale.id in tables);
 
let currentLocale = 'en';
let currentStrings = en;
 
const listeners = new Set<() => void>();
 
/**
 * Sets the locale these components render in. Consumers own the locale -- a component library has
 * no reliable way to know whether the browser's language or a user's profile setting should win --
 * so nothing here changes until an application calls this. Accepts a bare language tag or one with
 * a region ('es' or 'es-MX').
 */
export const setLocale = (locale: string): void => {
  const resolved = findLocaleDetails(localesWithTables(), locale).id;
  if (resolved === currentLocale) {
    return;
  }
 
  currentLocale = resolved;
  currentStrings = tables[resolved] ?? en;
  listeners.forEach((notify) => notify());
};
 
/** The resolved locale, which is also the locale to hand to Intl and other formatters. */
export const getLocale = (): string => currentLocale;
 
/**
 * The current string table. For components, prefer `useStrings`, which re-renders on a locale
 * change; this is for the imperative code that can't hold a hook, such as PlayCanvas scripts.
 */
export const getStrings = (): ComponentStrings => currentStrings;
 
const subscribe = (notify: () => void): (() => void) => {
  listeners.add(notify);
 
  return () => {
    listeners.delete(notify);
  };
};
 
export const useStrings = (): ComponentStrings => useSyncExternalStore(subscribe, getStrings, getStrings);