UNPKG

3.74 kBPlain TextView Raw
1import uniq from "lodash/uniq";
2
3import { Dict, LocaleResolver } from "./typing";
4import { I18n } from "./I18n";
5
6/**
7 * The default locale resolver.
8 *
9 * This resolver will add `options.locale` if provided (this function receives
10 * it inlined). In case nothing is set, then `i18n.locale` will be used.
11 * Additionally, adds the default locale to the list if `i18n.enableFallback` is
12 * set.
13 *
14 * Every locale added to the list will then be split apart; if `pt-BR` is the
15 * locale, then the list will be returned as `["pt-BR", "pt"]`.
16 *
17 * The default in case nothing is defined is `["en"]`.
18 *
19 * @type {LocaleResolver}
20 *
21 * @param {I18n} i18n The I18n instance.
22 *
23 * @param {string} locale The locale that being analysed.
24 *
25 * @returns {string[]} The resolved locales.
26 */
27export const defaultLocaleResolver: LocaleResolver = (
28 i18n: I18n,
29 locale: string,
30): string[] => {
31 const locales = [];
32 const list: string[] = [];
33
34 // Handle the inline locale option that can be provided to
35 // the `I18n.t` options.
36 locales.push(locale);
37
38 // Add the current locale to the list.
39 if (!locale) {
40 locales.push(i18n.locale);
41 }
42
43 // Add the default locale if fallback strategy is enabled.
44 if (i18n.enableFallback) {
45 locales.push(i18n.defaultLocale);
46 }
47
48 // Compute each locale with its country code.
49 // So this will return an array containing both
50 // `de-DE` and `de` locales.
51 //
52 // We also need to support locales with region code (e.g. zh-Hant-TW).
53 // In that case, the list should be `["zh-hant-tw", "zh-hant", "zh"]`.
54 locales
55 .filter(Boolean)
56 .map((entry) => entry.toString())
57 .forEach(function (currentLocale: string) {
58 if (!list.includes(currentLocale)) {
59 list.push(currentLocale);
60 }
61
62 if (!i18n.enableFallback) {
63 return;
64 }
65
66 const codes = currentLocale.split("-");
67
68 if (codes.length === 3) {
69 list.push(`${codes[0]}-${codes[1]}`);
70 }
71
72 list.push(codes[0]);
73 });
74
75 return uniq(list);
76};
77
78export class Locales {
79 private i18n: I18n;
80 private registry: Dict;
81
82 constructor(i18n: I18n) {
83 this.i18n = i18n;
84 this.registry = {};
85
86 this.register("default", defaultLocaleResolver);
87 }
88
89 /**
90 * You can define custom rules for any locale. Just make sure you return an
91 * array containing all locales.
92 *
93 * ```js
94 * // Default the Wookie locale to English.
95 * i18n.locales.register("wk", (_i18n, locale) => {
96 * return ["en"];
97 * });
98 * ```
99 *
100 * @param {string} locale The locale's name.
101 *
102 * @param {LocaleResolver|string|string[]} localeResolver The locale resolver
103 * strategy.
104 *
105 * @returns {void}
106 */
107 public register(
108 locale: string,
109 localeResolver: LocaleResolver | string | string[],
110 ): void {
111 if (typeof localeResolver !== "function") {
112 const result = localeResolver;
113 localeResolver = (() => result) as LocaleResolver;
114 }
115
116 this.registry[locale] = localeResolver;
117 }
118
119 /**
120 * Return a list of all locales that must be tried before returning the
121 * missing translation message. By default, this will consider the inline
122 * option, current locale and fallback locale.
123 *
124 * ```js
125 * i18n.locales.get("de-DE");
126 * // ["de-DE", "de", "en"]
127 * ```
128 *
129 * @param {string} locale The locale query.
130 *
131 * @returns {string[]} The list of locales.
132 */
133 public get(locale: string): string[] {
134 let locales =
135 this.registry[locale] ||
136 this.registry[this.i18n.locale] ||
137 this.registry.default;
138
139 if (typeof locales === "function") {
140 locales = locales(this.i18n, locale);
141 }
142
143 if (!(locales instanceof Array)) {
144 locales = [locales];
145 }
146 return locales;
147 }
148}
149
\No newline at end of file