@better-i18n/core 0.2.4 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -3
- package/dist/cdn.d.ts.map +1 -1
- package/dist/cdn.js +48 -11
- package/dist/cdn.js.map +1 -1
- package/dist/i18n/detection.d.ts +44 -1
- package/dist/i18n/detection.d.ts.map +1 -1
- package/dist/i18n/detection.js +187 -3
- package/dist/i18n/detection.js.map +1 -1
- package/dist/i18n/types.d.ts +20 -1
- package/dist/i18n/types.d.ts.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/manifest.d.ts.map +1 -1
- package/dist/manifest.js +1 -0
- package/dist/manifest.js.map +1 -1
- package/dist/types.d.ts +4 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/locale-ui.d.ts +67 -0
- package/dist/utils/locale-ui.d.ts.map +1 -0
- package/dist/utils/locale-ui.js +114 -0
- package/dist/utils/locale-ui.js.map +1 -0
- package/dist/utils/locale.d.ts +28 -9
- package/dist/utils/locale.d.ts.map +1 -1
- package/dist/utils/locale.js +20 -12
- package/dist/utils/locale.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@ Framework-agnostic core utilities for fetching translations from Better i18n CDN
|
|
|
8
8
|
- **Edge-Ready** - Optimized for edge environments (Cloudflare, Vercel, etc.)
|
|
9
9
|
- **Type-Safe** - Full TypeScript support
|
|
10
10
|
- **Cached** - Built-in manifest caching with configurable TTL
|
|
11
|
-
- **Offline Fallback** -
|
|
11
|
+
- **Offline Fallback** - 5-layer fallback chain: TtlCache → CDN (with ETag 304) → persistent storage → static data
|
|
12
12
|
- **Resilient** - Configurable fetch timeout and retry with exponential backoff
|
|
13
13
|
|
|
14
14
|
## Installation
|
|
@@ -69,12 +69,18 @@ interface I18nCoreConfig {
|
|
|
69
69
|
|
|
70
70
|
## Offline Fallback
|
|
71
71
|
|
|
72
|
-
|
|
72
|
+
Translations are resolved through a 5-layer fallback chain:
|
|
73
73
|
|
|
74
74
|
```
|
|
75
|
-
CDN (
|
|
75
|
+
TtlCache (in-memory) → CDN fetch → CDN 304 (ETag) → Storage (persistent cache) → Static Data (bundled) → throw
|
|
76
76
|
```
|
|
77
77
|
|
|
78
|
+
1. **TtlCache** — In-memory cache with configurable TTL (default: 5 minutes). Instant, no I/O.
|
|
79
|
+
2. **CDN fetch** — Fresh translation data from Better i18n CDN.
|
|
80
|
+
3. **CDN 304 (ETag)** — If CDN returns "not modified", reuse cached version.
|
|
81
|
+
4. **Storage** — Persistent cache (localStorage, AsyncStorage, etc.) survives app restarts.
|
|
82
|
+
5. **Static Data** — Bundled translations as absolute last resort.
|
|
83
|
+
|
|
78
84
|
### Storage Adapter
|
|
79
85
|
|
|
80
86
|
Persist translations locally so they survive CDN outages and app restarts:
|
package/dist/cdn.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cdn.d.ts","sourceRoot":"","sources":["../src/cdn.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,QAAQ,EACR,cAAc,EAMf,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"cdn.d.ts","sourceRoot":"","sources":["../src/cdn.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,QAAQ,EACR,cAAc,EAMf,MAAM,YAAY,CAAC;AAkVpB;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,eAAO,MAAM,cAAc,GAAI,QAAQ,cAAc,KAAG,QAmCvD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,kBAAkB,QAAO,IAErC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,kBAAkB,QAAO,IAErC,CAAC"}
|
package/dist/cdn.js
CHANGED
|
@@ -7,6 +7,8 @@ const STORAGE_PREFIX = "@better-i18n";
|
|
|
7
7
|
// Global caches (shared across instances)
|
|
8
8
|
const manifestCache = new TtlCache();
|
|
9
9
|
const messagesCache = new TtlCache();
|
|
10
|
+
// ETag cache — keyed same as messagesCache, stores last ETag for If-None-Match
|
|
11
|
+
const messagesETagCache = new TtlCache();
|
|
10
12
|
// ─── Storage helpers ────────────────────────────────────────────────
|
|
11
13
|
const buildManifestStorageKey = (project) => `${STORAGE_PREFIX}:manifest:${project}`;
|
|
12
14
|
const buildMessagesStorageKey = (project, locale) => `${STORAGE_PREFIX}:messages:${project}:${locale}`;
|
|
@@ -144,23 +146,33 @@ const getManifestWithCache = async (config, fetchFn, forceRefresh = false) => {
|
|
|
144
146
|
throw cdnError;
|
|
145
147
|
}
|
|
146
148
|
};
|
|
147
|
-
// ─── Messages fetching with fallback ────────────────────────────────
|
|
148
149
|
/**
|
|
149
|
-
* Fetch messages from CDN (raw, no cache)
|
|
150
|
+
* Fetch messages from CDN (raw, no cache).
|
|
151
|
+
* Passes If-None-Match when an ETag is known — returns { notModified: true } on 304.
|
|
150
152
|
*/
|
|
151
|
-
const fetchMessagesFromCdn = async (config, locale, fetchFn) => {
|
|
153
|
+
const fetchMessagesFromCdn = async (config, locale, fetchFn, ifNoneMatch) => {
|
|
152
154
|
const logger = createLogger(config, "messages");
|
|
153
155
|
const url = `${getProjectBaseUrl(config)}/${locale}/translations.json`;
|
|
154
156
|
logger.debug("fetching", url);
|
|
155
|
-
const
|
|
157
|
+
const headers = { "Cache-Control": "no-store" };
|
|
158
|
+
if (ifNoneMatch) {
|
|
159
|
+
headers["If-None-Match"] = ifNoneMatch;
|
|
160
|
+
}
|
|
161
|
+
const response = await fetchWithRetry(fetchFn, url, { headers }, config.fetchTimeout, config.retryCount);
|
|
162
|
+
// 304 Not Modified — cached content is still fresh
|
|
163
|
+
if (response.status === 304) {
|
|
164
|
+
logger.debug("304 Not Modified", { locale });
|
|
165
|
+
return { notModified: true };
|
|
166
|
+
}
|
|
156
167
|
if (!response.ok) {
|
|
157
168
|
const message = `Messages fetch failed for locale "${locale}" (${response.status})`;
|
|
158
169
|
logger.error(message);
|
|
159
170
|
throw new Error(`[better-i18n] ${message}`);
|
|
160
171
|
}
|
|
161
172
|
const data = (await response.json());
|
|
173
|
+
const etag = response.headers?.get?.("etag") ?? null;
|
|
162
174
|
logger.debug("fetched", { locale, keys: Object.keys(data).length });
|
|
163
|
-
return data;
|
|
175
|
+
return { notModified: false, messages: data, etag };
|
|
164
176
|
};
|
|
165
177
|
/**
|
|
166
178
|
* Get messages with full fallback chain:
|
|
@@ -179,13 +191,38 @@ const getMessagesWithFallback = async (config, locale, fetchFn) => {
|
|
|
179
191
|
const memoryCached = messagesCache.get(cacheKey);
|
|
180
192
|
if (memoryCached)
|
|
181
193
|
return memoryCached;
|
|
182
|
-
// 2. CDN fetch
|
|
194
|
+
// 2. CDN fetch (with ETag If-None-Match when available)
|
|
183
195
|
try {
|
|
184
|
-
const
|
|
185
|
-
|
|
186
|
-
//
|
|
187
|
-
|
|
188
|
-
|
|
196
|
+
const cachedETag = messagesETagCache.get(cacheKey);
|
|
197
|
+
const result = await fetchMessagesFromCdn(config, safeLng, fetchFn, cachedETag);
|
|
198
|
+
// 304 Not Modified — CDN confirmed content unchanged; refresh TTL with stored data
|
|
199
|
+
if (result.notModified) {
|
|
200
|
+
const stored = await readFromStorage(config.storage, storageKey);
|
|
201
|
+
if (stored) {
|
|
202
|
+
logger.debug(`304: refreshing TTL for "${safeLng}" from storage`);
|
|
203
|
+
messagesCache.set(cacheKey, stored, config.manifestCacheTtlMs);
|
|
204
|
+
return stored;
|
|
205
|
+
}
|
|
206
|
+
// No storage fallback — re-fetch without ETag to get fresh data
|
|
207
|
+
const freshResult = await fetchMessagesFromCdn(config, safeLng, fetchFn);
|
|
208
|
+
if (!freshResult.notModified) {
|
|
209
|
+
messagesCache.set(cacheKey, freshResult.messages, config.manifestCacheTtlMs);
|
|
210
|
+
if (freshResult.etag)
|
|
211
|
+
messagesETagCache.set(cacheKey, freshResult.etag, config.manifestCacheTtlMs);
|
|
212
|
+
writeToStorage(config.storage, storageKey, freshResult.messages);
|
|
213
|
+
return freshResult.messages;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
// 200 OK — new or changed content
|
|
217
|
+
if (!result.notModified) {
|
|
218
|
+
messagesCache.set(cacheKey, result.messages, config.manifestCacheTtlMs);
|
|
219
|
+
if (result.etag)
|
|
220
|
+
messagesETagCache.set(cacheKey, result.etag, config.manifestCacheTtlMs);
|
|
221
|
+
writeToStorage(config.storage, storageKey, result.messages);
|
|
222
|
+
return result.messages;
|
|
223
|
+
}
|
|
224
|
+
// Shouldn't reach here, but satisfy TypeScript
|
|
225
|
+
throw new Error("[better-i18n] Unexpected 304 without storage fallback");
|
|
189
226
|
}
|
|
190
227
|
catch (cdnError) {
|
|
191
228
|
logger.warn(`CDN fetch failed for locale "${safeLng}", trying fallback sources`, cdnError);
|
package/dist/cdn.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cdn.js","sourceRoot":"","sources":["../src/cdn.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACjE,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAUjD,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEpD,MAAM,cAAc,GAAG,cAAc,CAAC;AAEtC,0CAA0C;AAC1C,MAAM,aAAa,GAAG,IAAI,QAAQ,EAAoB,CAAC;AACvD,MAAM,aAAa,GAAG,IAAI,QAAQ,EAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"cdn.js","sourceRoot":"","sources":["../src/cdn.ts"],"names":[],"mappings":"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"}
|
package/dist/i18n/detection.d.ts
CHANGED
|
@@ -1,6 +1,49 @@
|
|
|
1
1
|
import type { LocaleDetectionOptions, LocaleDetectionResult } from "./types.js";
|
|
2
|
+
import type { LanguageOption } from "../types.js";
|
|
2
3
|
/**
|
|
3
|
-
*
|
|
4
|
+
* Build a country→locale map from CDN manifest languages.
|
|
5
|
+
*
|
|
6
|
+
* Uses each language's `countryCode` field as the primary source
|
|
7
|
+
* (set in the Better i18n dashboard). Falls back to `LANGUAGE_TO_COUNTRY`
|
|
8
|
+
* reverse lookup for languages without explicit country codes.
|
|
9
|
+
*
|
|
10
|
+
* Also includes multi-country overrides (e.g. AT→de, MX→es) so that
|
|
11
|
+
* visitors from countries sharing a language are correctly mapped.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```ts
|
|
15
|
+
* const languages = await i18n.getLanguages();
|
|
16
|
+
* const countryMap = buildCountryLocaleMap(languages);
|
|
17
|
+
* // { tr: "tr", de: "de", jp: "ja", cn: "zh-hans", at: "de", mx: "es", ... }
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
export declare function buildCountryLocaleMap(languages: LanguageOption[]): Record<string, string>;
|
|
21
|
+
/**
|
|
22
|
+
* Framework-agnostic locale detection with geo-IP support.
|
|
23
|
+
*
|
|
24
|
+
* Detection priority: path > cookie > geo (country) > Accept-Language header > default
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```ts
|
|
28
|
+
* // In your middleware/loader:
|
|
29
|
+
* const languages = await i18n.getLanguages();
|
|
30
|
+
* const countryMap = buildCountryLocaleMap(languages);
|
|
31
|
+
*
|
|
32
|
+
* const result = detectLocale({
|
|
33
|
+
* project: "acme/web",
|
|
34
|
+
* defaultLocale: "en",
|
|
35
|
+
* availableLocales: languages.map(l => l.code),
|
|
36
|
+
* pathLocale: getLocaleFromURL(pathname),
|
|
37
|
+
* cookieLocale: getCookie("locale"),
|
|
38
|
+
* countryCode: request.cf?.country, // Cloudflare
|
|
39
|
+
* // countryCode: request.geo?.country, // Vercel
|
|
40
|
+
* countryLocaleMap: countryMap,
|
|
41
|
+
* headerLocale: parseAcceptLanguage(request),
|
|
42
|
+
* });
|
|
43
|
+
*
|
|
44
|
+
* // result.locale = "tr"
|
|
45
|
+
* // result.detectedFrom = "geo"
|
|
46
|
+
* ```
|
|
4
47
|
*/
|
|
5
48
|
export declare function detectLocale(options: LocaleDetectionOptions): LocaleDetectionResult;
|
|
6
49
|
//# sourceMappingURL=detection.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"detection.d.ts","sourceRoot":"","sources":["../../src/i18n/detection.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"detection.d.ts","sourceRoot":"","sources":["../../src/i18n/detection.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAChF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAQlD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,qBAAqB,CACnC,SAAS,EAAE,cAAc,EAAE,GAC1B,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAwDxB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,YAAY,CAC1B,OAAO,EAAE,sBAAsB,GAC9B,qBAAqB,CAyCvB"}
|
package/dist/i18n/detection.js
CHANGED
|
@@ -1,16 +1,111 @@
|
|
|
1
1
|
import { normalizeLocale } from "../utils/locale.js";
|
|
2
|
+
import { LANGUAGE_TO_COUNTRY } from "../utils/locale-ui.js";
|
|
2
3
|
/** Case-insensitive locale lookup — returns the canonical (CDN) form if matched */
|
|
3
4
|
const findLocale = (code, available) => code ? available.find((a) => normalizeLocale(a) === normalizeLocale(code)) : undefined;
|
|
4
5
|
/**
|
|
5
|
-
*
|
|
6
|
+
* Build a country→locale map from CDN manifest languages.
|
|
7
|
+
*
|
|
8
|
+
* Uses each language's `countryCode` field as the primary source
|
|
9
|
+
* (set in the Better i18n dashboard). Falls back to `LANGUAGE_TO_COUNTRY`
|
|
10
|
+
* reverse lookup for languages without explicit country codes.
|
|
11
|
+
*
|
|
12
|
+
* Also includes multi-country overrides (e.g. AT→de, MX→es) so that
|
|
13
|
+
* visitors from countries sharing a language are correctly mapped.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```ts
|
|
17
|
+
* const languages = await i18n.getLanguages();
|
|
18
|
+
* const countryMap = buildCountryLocaleMap(languages);
|
|
19
|
+
* // { tr: "tr", de: "de", jp: "ja", cn: "zh-hans", at: "de", mx: "es", ... }
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export function buildCountryLocaleMap(languages) {
|
|
23
|
+
const map = {};
|
|
24
|
+
const availableCodes = new Set(languages.map((l) => l.code));
|
|
25
|
+
// Primary: manifest countryCode → locale code
|
|
26
|
+
for (const lang of languages) {
|
|
27
|
+
if (lang.countryCode) {
|
|
28
|
+
map[lang.countryCode.toLowerCase()] = lang.code;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
// Secondary: reverse LANGUAGE_TO_COUNTRY for languages with no countryCode
|
|
32
|
+
for (const lang of languages) {
|
|
33
|
+
if (!lang.countryCode) {
|
|
34
|
+
const country = LANGUAGE_TO_COUNTRY[lang.code]
|
|
35
|
+
|| LANGUAGE_TO_COUNTRY[lang.code.split("-")[0]];
|
|
36
|
+
if (country && !map[country]) {
|
|
37
|
+
map[country] = lang.code;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
// Multi-country overrides: countries whose primary language is available
|
|
42
|
+
// but they aren't the "home country" for that language
|
|
43
|
+
const MULTI_COUNTRY = {
|
|
44
|
+
// German-speaking
|
|
45
|
+
at: "de", ch: "de", li: "de",
|
|
46
|
+
// French-speaking
|
|
47
|
+
be: "fr", lu: "fr", mc: "fr",
|
|
48
|
+
// Spanish-speaking
|
|
49
|
+
mx: "es", ar: "es", co: "es", cl: "es", pe: "es",
|
|
50
|
+
ve: "es", ec: "es", gt: "es", cu: "es", do: "es",
|
|
51
|
+
hn: "es", sv: "es", ni: "es", cr: "es", pa: "es",
|
|
52
|
+
uy: "es", py: "es", bo: "es",
|
|
53
|
+
// Portuguese-speaking
|
|
54
|
+
br: "pt-br", ao: "pt", mz: "pt",
|
|
55
|
+
// Arabic-speaking
|
|
56
|
+
ae: "ar", eg: "ar", ma: "ar", dz: "ar", iq: "ar",
|
|
57
|
+
kw: "ar", qa: "ar", bh: "ar", om: "ar", jo: "ar", lb: "ar",
|
|
58
|
+
// Chinese-speaking
|
|
59
|
+
sg: "zh-hans", tw: "zh-hans", hk: "zh-hans", mo: "zh-hans",
|
|
60
|
+
// English-speaking (fallback)
|
|
61
|
+
us: "en", gb: "en", au: "en", nz: "en", ca: "en", ie: "en",
|
|
62
|
+
// Russian-speaking
|
|
63
|
+
by: "ru", kz: "ru", kg: "ru",
|
|
64
|
+
// Malay-speaking
|
|
65
|
+
bn: "ms",
|
|
66
|
+
};
|
|
67
|
+
for (const [country, locale] of Object.entries(MULTI_COUNTRY)) {
|
|
68
|
+
if (!map[country] && availableCodes.has(locale)) {
|
|
69
|
+
map[country] = locale;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return map;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Framework-agnostic locale detection with geo-IP support.
|
|
76
|
+
*
|
|
77
|
+
* Detection priority: path > cookie > geo (country) > Accept-Language header > default
|
|
78
|
+
*
|
|
79
|
+
* @example
|
|
80
|
+
* ```ts
|
|
81
|
+
* // In your middleware/loader:
|
|
82
|
+
* const languages = await i18n.getLanguages();
|
|
83
|
+
* const countryMap = buildCountryLocaleMap(languages);
|
|
84
|
+
*
|
|
85
|
+
* const result = detectLocale({
|
|
86
|
+
* project: "acme/web",
|
|
87
|
+
* defaultLocale: "en",
|
|
88
|
+
* availableLocales: languages.map(l => l.code),
|
|
89
|
+
* pathLocale: getLocaleFromURL(pathname),
|
|
90
|
+
* cookieLocale: getCookie("locale"),
|
|
91
|
+
* countryCode: request.cf?.country, // Cloudflare
|
|
92
|
+
* // countryCode: request.geo?.country, // Vercel
|
|
93
|
+
* countryLocaleMap: countryMap,
|
|
94
|
+
* headerLocale: parseAcceptLanguage(request),
|
|
95
|
+
* });
|
|
96
|
+
*
|
|
97
|
+
* // result.locale = "tr"
|
|
98
|
+
* // result.detectedFrom = "geo"
|
|
99
|
+
* ```
|
|
6
100
|
*/
|
|
7
101
|
export function detectLocale(options) {
|
|
8
|
-
const { pathLocale, cookieLocale, headerLocale, defaultLocale, availableLocales, } = options;
|
|
102
|
+
const { pathLocale, cookieLocale, headerLocale, countryCode, countryLocaleMap, defaultLocale, availableLocales, } = options;
|
|
9
103
|
let locale;
|
|
10
104
|
let detectedFrom;
|
|
11
|
-
// Priority: path > cookie > header > default
|
|
105
|
+
// Priority: path > cookie > geo > header > default
|
|
12
106
|
const pathMatch = findLocale(pathLocale, availableLocales);
|
|
13
107
|
const cookieMatch = findLocale(cookieLocale, availableLocales);
|
|
108
|
+
const geoMatch = resolveGeoLocale(countryCode, countryLocaleMap, availableLocales);
|
|
14
109
|
const headerMatch = findLocale(headerLocale, availableLocales);
|
|
15
110
|
if (pathMatch) {
|
|
16
111
|
locale = pathMatch;
|
|
@@ -20,6 +115,10 @@ export function detectLocale(options) {
|
|
|
20
115
|
locale = cookieMatch;
|
|
21
116
|
detectedFrom = "cookie";
|
|
22
117
|
}
|
|
118
|
+
else if (geoMatch) {
|
|
119
|
+
locale = geoMatch;
|
|
120
|
+
detectedFrom = "geo";
|
|
121
|
+
}
|
|
23
122
|
else if (headerMatch) {
|
|
24
123
|
locale = headerMatch;
|
|
25
124
|
detectedFrom = "header";
|
|
@@ -32,4 +131,89 @@ export function detectLocale(options) {
|
|
|
32
131
|
const shouldSetCookie = cookieLocale !== locale;
|
|
33
132
|
return { locale, detectedFrom, shouldSetCookie };
|
|
34
133
|
}
|
|
134
|
+
/**
|
|
135
|
+
* Built-in multi-country overrides for countries that share a language
|
|
136
|
+
* with another country already in LANGUAGE_TO_COUNTRY.
|
|
137
|
+
* This allows geo detection to work without a manifest-driven map.
|
|
138
|
+
*/
|
|
139
|
+
const BUILT_IN_COUNTRY_OVERRIDES = {
|
|
140
|
+
// German-speaking
|
|
141
|
+
at: "de", ch: "de", li: "de",
|
|
142
|
+
// French-speaking
|
|
143
|
+
be: "fr", lu: "fr", mc: "fr",
|
|
144
|
+
// Spanish-speaking
|
|
145
|
+
mx: "es", ar: "es", co: "es", cl: "es", pe: "es",
|
|
146
|
+
ve: "es", ec: "es", gt: "es", cu: "es", hn: "es",
|
|
147
|
+
sv: "es", ni: "es", cr: "es", pa: "es", uy: "es",
|
|
148
|
+
py: "es", bo: "es", do: "es",
|
|
149
|
+
// Portuguese-speaking
|
|
150
|
+
br: "pt", ao: "pt", mz: "pt",
|
|
151
|
+
// Arabic-speaking
|
|
152
|
+
ae: "ar", eg: "ar", ma: "ar", dz: "ar", iq: "ar",
|
|
153
|
+
kw: "ar", qa: "ar", bh: "ar", om: "ar", jo: "ar", lb: "ar",
|
|
154
|
+
// Chinese-speaking
|
|
155
|
+
sg: "zh", tw: "zh", hk: "zh", mo: "zh",
|
|
156
|
+
// Russian-speaking
|
|
157
|
+
by: "ru", kz: "ru", kg: "ru",
|
|
158
|
+
// Malay-speaking
|
|
159
|
+
bn: "ms",
|
|
160
|
+
// English-speaking
|
|
161
|
+
us: "en", au: "en", nz: "en", ca: "en", ie: "en",
|
|
162
|
+
};
|
|
163
|
+
/**
|
|
164
|
+
* Fuzzy locale match — finds a locale in available list even when the
|
|
165
|
+
* base language matches but the full code differs.
|
|
166
|
+
* e.g., lang="zh", available=["zh-hans"] → returns "zh-hans"
|
|
167
|
+
* e.g., lang="pt", available=["pt-br", "pt"] → returns "pt"
|
|
168
|
+
*/
|
|
169
|
+
function fuzzyFindLocale(lang, available) {
|
|
170
|
+
// Exact match first
|
|
171
|
+
const exact = findLocale(lang, available);
|
|
172
|
+
if (exact)
|
|
173
|
+
return exact;
|
|
174
|
+
// Base language match (zh → zh-hans, pt → pt-br)
|
|
175
|
+
const base = lang.split("-")[0].toLowerCase();
|
|
176
|
+
return available.find((a) => a.toLowerCase().startsWith(base + "-"))
|
|
177
|
+
?? available.find((a) => a.toLowerCase() === base);
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Resolve a country code to a locale.
|
|
181
|
+
*
|
|
182
|
+
* Resolution chain:
|
|
183
|
+
* 1. Explicit countryLocaleMap (manifest-driven, most accurate)
|
|
184
|
+
* 2. LANGUAGE_TO_COUNTRY reverse lookup (built-in)
|
|
185
|
+
* 3. BUILT_IN_COUNTRY_OVERRIDES (multi-country fallback)
|
|
186
|
+
*
|
|
187
|
+
* All lookups use fuzzy matching so zh→zh-hans, pt→pt-br work.
|
|
188
|
+
*/
|
|
189
|
+
function resolveGeoLocale(countryCode, countryLocaleMap, availableLocales) {
|
|
190
|
+
if (!countryCode)
|
|
191
|
+
return undefined;
|
|
192
|
+
const normalized = countryCode.toLowerCase();
|
|
193
|
+
// 1. Explicit map (manifest-driven)
|
|
194
|
+
if (countryLocaleMap) {
|
|
195
|
+
const mapped = countryLocaleMap[normalized];
|
|
196
|
+
if (mapped) {
|
|
197
|
+
const match = fuzzyFindLocale(mapped, availableLocales);
|
|
198
|
+
if (match)
|
|
199
|
+
return match;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
// 2. Reverse LANGUAGE_TO_COUNTRY (e.g., tr→"tr", ja→"jp")
|
|
203
|
+
for (const [lang, country] of Object.entries(LANGUAGE_TO_COUNTRY)) {
|
|
204
|
+
if (country === normalized) {
|
|
205
|
+
const match = fuzzyFindLocale(lang, availableLocales);
|
|
206
|
+
if (match)
|
|
207
|
+
return match;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
// 3. Multi-country overrides (e.g., AT→de, MX→es, BR→pt)
|
|
211
|
+
const override = BUILT_IN_COUNTRY_OVERRIDES[normalized];
|
|
212
|
+
if (override) {
|
|
213
|
+
const match = fuzzyFindLocale(override, availableLocales);
|
|
214
|
+
if (match)
|
|
215
|
+
return match;
|
|
216
|
+
}
|
|
217
|
+
return undefined;
|
|
218
|
+
}
|
|
35
219
|
//# sourceMappingURL=detection.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"detection.js","sourceRoot":"","sources":["../../src/i18n/detection.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"detection.js","sourceRoot":"","sources":["../../src/i18n/detection.ts"],"names":[],"mappings":"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"}
|
package/dist/i18n/types.d.ts
CHANGED
|
@@ -20,11 +20,30 @@ export interface LocaleDetectionOptions {
|
|
|
20
20
|
pathLocale?: string | null;
|
|
21
21
|
cookieLocale?: string | null;
|
|
22
22
|
headerLocale?: string | null;
|
|
23
|
+
/**
|
|
24
|
+
* ISO 3166-1 alpha-2 country code from geo-IP detection.
|
|
25
|
+
* Pass this from your edge platform:
|
|
26
|
+
* - Cloudflare Workers: `request.cf?.country`
|
|
27
|
+
* - Vercel Edge: `request.geo?.country`
|
|
28
|
+
* - Node.js behind CF: `request.headers.get("CF-IPCountry")`
|
|
29
|
+
*
|
|
30
|
+
* Used with `countryLocaleMap` to resolve country → locale.
|
|
31
|
+
* Priority: path > cookie > geo (country) > header > default
|
|
32
|
+
*/
|
|
33
|
+
countryCode?: string | null;
|
|
34
|
+
/**
|
|
35
|
+
* Country code → locale mapping. Built from CDN manifest's
|
|
36
|
+
* `languages[].countryCode` field via `buildCountryLocaleMap()`.
|
|
37
|
+
*
|
|
38
|
+
* If not provided but `countryCode` is set, falls back to
|
|
39
|
+
* `LANGUAGE_TO_COUNTRY` reverse lookup from core.
|
|
40
|
+
*/
|
|
41
|
+
countryLocaleMap?: Record<string, string>;
|
|
23
42
|
availableLocales: string[];
|
|
24
43
|
}
|
|
25
44
|
export interface LocaleDetectionResult {
|
|
26
45
|
locale: string;
|
|
27
|
-
detectedFrom: "path" | "cookie" | "header" | "default";
|
|
46
|
+
detectedFrom: "path" | "cookie" | "geo" | "header" | "default";
|
|
28
47
|
shouldSetCookie: boolean;
|
|
29
48
|
}
|
|
30
49
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/i18n/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/i18n/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,YAAY,GAAG,WAAW,GAAG,QAAQ,GAAG,OAAO,CAAC;AAE5D,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,SAAS,CAAC,EAAE;QACV,MAAM,CAAC,EAAE,OAAO,CAAC;QACjB,eAAe,CAAC,EAAE,OAAO,CAAC;QAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,YAAY,CAAC,EAAE,MAAM,CAAC;KACvB,CAAC;CACH;AAED,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,gBAAgB,EAAE,MAAM,EAAE,CAAC;CAC5B;AAED,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/i18n/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,YAAY,GAAG,WAAW,GAAG,QAAQ,GAAG,OAAO,CAAC;AAE5D,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,SAAS,CAAC,EAAE;QACV,MAAM,CAAC,EAAE,OAAO,CAAC;QACjB,eAAe,CAAC,EAAE,OAAO,CAAC;QAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,YAAY,CAAC,EAAE,MAAM,CAAC;KACvB,CAAC;CACH;AAED,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B;;;;;;;;;OASG;IACH,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B;;;;;;OAMG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC1C,gBAAgB,EAAE,MAAM,EAAE,CAAC;CAC5B;AAED,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,GAAG,QAAQ,GAAG,KAAK,GAAG,QAAQ,GAAG,SAAS,CAAC;IAC/D,eAAe,EAAE,OAAO,CAAC;CAC1B"}
|
package/dist/index.d.ts
CHANGED
|
@@ -3,8 +3,9 @@ export { createAutoStorage, createLocalStorage, createMemoryStorage } from "./st
|
|
|
3
3
|
export { normalizeConfig, parseProject, getProjectBaseUrl } from "./config.js";
|
|
4
4
|
export { extractLanguages } from "./manifest.js";
|
|
5
5
|
export { createLogger } from "./logger.js";
|
|
6
|
-
export { detectLocale } from "./i18n/detection.js";
|
|
6
|
+
export { detectLocale, buildCountryLocaleMap } from "./i18n/detection.js";
|
|
7
7
|
export { TtlCache, buildCacheKey } from "./cache.js";
|
|
8
|
+
export { LANGUAGE_TO_COUNTRY, getCountryCodeFromLocale, getFlagEmoji, getLanguageLabel, resolveFlag, type ResolvedFlag, } from "./utils/locale-ui.js";
|
|
8
9
|
export { normalizeLocale, extractLocale, getLocaleFromPath, hasLocalePrefix, removeLocalePrefix, addLocalePrefix, replaceLocaleInPath, createLocalePath, type LocaleConfig, } from "./utils/locale.js";
|
|
9
10
|
export type { I18nCoreConfig, NormalizedConfig, ParsedProject, ManifestResponse, ManifestLanguage, ManifestFile, LanguageOption, Messages, Locale, I18nCore, TranslationStorage, Logger, LogLevel, CacheEntry, } from "./types.js";
|
|
10
11
|
export type { I18nMiddlewareConfig, LocaleDetectionOptions, LocaleDetectionResult, LocalePrefix, } from "./i18n/types.js";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAGlF,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAGhG,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAG/E,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAGjD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAG3C,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAGlF,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAGhG,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAG/E,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAGjD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAG3C,OAAO,EAAE,YAAY,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAG1E,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAGrD,OAAO,EACL,mBAAmB,EACnB,wBAAwB,EACxB,YAAY,EACZ,gBAAgB,EAChB,WAAW,EACX,KAAK,YAAY,GAClB,MAAM,sBAAsB,CAAC;AAG9B,OAAO,EACL,eAAe,EACf,aAAa,EACb,iBAAiB,EACjB,eAAe,EACf,kBAAkB,EAClB,eAAe,EACf,mBAAmB,EACnB,gBAAgB,EAChB,KAAK,YAAY,GAClB,MAAM,mBAAmB,CAAC;AAG3B,YAAY,EAEV,cAAc,EACd,gBAAgB,EAChB,aAAa,EAGb,gBAAgB,EAChB,gBAAgB,EAChB,YAAY,EACZ,cAAc,EAGd,QAAQ,EACR,MAAM,EAGN,QAAQ,EAGR,kBAAkB,EAGlB,MAAM,EACN,QAAQ,EACR,UAAU,GACX,MAAM,YAAY,CAAC;AAEpB,YAAY,EACV,oBAAoB,EACpB,sBAAsB,EACtB,qBAAqB,EACrB,YAAY,GACb,MAAM,iBAAiB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -9,9 +9,11 @@ export { extractLanguages } from "./manifest.js";
|
|
|
9
9
|
// Logger
|
|
10
10
|
export { createLogger } from "./logger.js";
|
|
11
11
|
// Middleware logic
|
|
12
|
-
export { detectLocale } from "./i18n/detection.js";
|
|
12
|
+
export { detectLocale, buildCountryLocaleMap } from "./i18n/detection.js";
|
|
13
13
|
// Cache utilities
|
|
14
14
|
export { TtlCache, buildCacheKey } from "./cache.js";
|
|
15
|
+
// Locale UI utilities (flags, labels, country codes)
|
|
16
|
+
export { LANGUAGE_TO_COUNTRY, getCountryCodeFromLocale, getFlagEmoji, getLanguageLabel, resolveFlag, } from "./utils/locale-ui.js";
|
|
15
17
|
// Locale utilities
|
|
16
18
|
export { normalizeLocale, extractLocale, getLocaleFromPath, hasLocalePrefix, removeLocalePrefix, addLocalePrefix, replaceLocaleInPath, createLocalePath, } from "./utils/locale.js";
|
|
17
19
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,WAAW;AACX,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAElF,mBAAmB;AACnB,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAEhG,0BAA0B;AAC1B,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAE/E,qBAAqB;AACrB,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEjD,SAAS;AACT,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,mBAAmB;AACnB,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,WAAW;AACX,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAElF,mBAAmB;AACnB,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAEhG,0BAA0B;AAC1B,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAE/E,qBAAqB;AACrB,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEjD,SAAS;AACT,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,mBAAmB;AACnB,OAAO,EAAE,YAAY,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAE1E,kBAAkB;AAClB,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAErD,qDAAqD;AACrD,OAAO,EACL,mBAAmB,EACnB,wBAAwB,EACxB,YAAY,EACZ,gBAAgB,EAChB,WAAW,GAEZ,MAAM,sBAAsB,CAAC;AAE9B,mBAAmB;AACnB,OAAO,EACL,eAAe,EACf,aAAa,EACb,iBAAiB,EACjB,eAAe,EACf,kBAAkB,EAClB,eAAe,EACf,mBAAmB,EACnB,gBAAgB,GAEjB,MAAM,mBAAmB,CAAC"}
|
package/dist/manifest.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,cAAc,EAEd,gBAAgB,EACjB,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,cAAc,EAEd,gBAAgB,EACjB,MAAM,YAAY,CAAC;AAepB;;GAEG;AACH,eAAO,MAAM,gBAAgB,GAC3B,UAAU,gBAAgB,KACzB,cAAc,EAahB,CAAC"}
|
package/dist/manifest.js
CHANGED
|
@@ -6,6 +6,7 @@ const normalizeLanguage = (language) => ({
|
|
|
6
6
|
name: language.name,
|
|
7
7
|
nativeName: language.nativeName || language.name || language.code.toUpperCase(),
|
|
8
8
|
flagUrl: language.flagUrl ?? null,
|
|
9
|
+
countryCode: language.countryCode ?? null,
|
|
9
10
|
isDefault: language.isSource ?? false,
|
|
10
11
|
});
|
|
11
12
|
/**
|
package/dist/manifest.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manifest.js","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"AAMA;;GAEG;AACH,MAAM,iBAAiB,GAAG,CAAC,QAA0B,EAAkB,EAAE,CAAC,CAAC;IACzE,IAAI,EAAE,QAAQ,CAAC,IAAI;IACnB,IAAI,EAAE,QAAQ,CAAC,IAAI;IACnB,UAAU,EACR,QAAQ,CAAC,UAAU,IAAI,QAAQ,CAAC,IAAI,IAAI,QAAQ,CAAC,IAAI,CAAC,WAAW,EAAE;IACrE,OAAO,EAAE,QAAQ,CAAC,OAAO,IAAI,IAAI;IACjC,SAAS,EAAE,QAAQ,CAAC,QAAQ,IAAI,KAAK;CACtC,CAAC,CAAC;AAEH;;GAEG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAC9B,QAA0B,EACR,EAAE;IACpB,MAAM,SAAS,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC;QACjD,CAAC,CAAC,QAAQ,CAAC,SAAS;QACpB,CAAC,CAAC,EAAE,CAAC;IAEP,OAAO,SAAS;SACb,MAAM,CACL,CAAC,QAAQ,EAAgC,EAAE,CACzC,CAAC,CAAC,QAAQ;QACV,OAAO,QAAQ,CAAC,IAAI,KAAK,QAAQ;QACjC,QAAQ,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAC3B;SACA,GAAG,CAAC,iBAAiB,CAAC,CAAC;AAC5B,CAAC,CAAC"}
|
|
1
|
+
{"version":3,"file":"manifest.js","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"AAMA;;GAEG;AACH,MAAM,iBAAiB,GAAG,CAAC,QAA0B,EAAkB,EAAE,CAAC,CAAC;IACzE,IAAI,EAAE,QAAQ,CAAC,IAAI;IACnB,IAAI,EAAE,QAAQ,CAAC,IAAI;IACnB,UAAU,EACR,QAAQ,CAAC,UAAU,IAAI,QAAQ,CAAC,IAAI,IAAI,QAAQ,CAAC,IAAI,CAAC,WAAW,EAAE;IACrE,OAAO,EAAE,QAAQ,CAAC,OAAO,IAAI,IAAI;IACjC,WAAW,EAAE,QAAQ,CAAC,WAAW,IAAI,IAAI;IACzC,SAAS,EAAE,QAAQ,CAAC,QAAQ,IAAI,KAAK;CACtC,CAAC,CAAC;AAEH;;GAEG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAC9B,QAA0B,EACR,EAAE;IACpB,MAAM,SAAS,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC;QACjD,CAAC,CAAC,QAAQ,CAAC,SAAS;QACpB,CAAC,CAAC,EAAE,CAAC;IAEP,OAAO,SAAS;SACb,MAAM,CACL,CAAC,QAAQ,EAAgC,EAAE,CACzC,CAAC,CAAC,QAAQ;QACV,OAAO,QAAQ,CAAC,IAAI,KAAK,QAAQ;QACjC,QAAQ,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAC3B;SACA,GAAG,CAAC,iBAAiB,CAAC,CAAC;AAC5B,CAAC,CAAC"}
|
package/dist/types.d.ts
CHANGED
|
@@ -108,6 +108,8 @@ export interface ManifestLanguage {
|
|
|
108
108
|
name?: string;
|
|
109
109
|
nativeName?: string;
|
|
110
110
|
flagUrl?: string | null;
|
|
111
|
+
/** ISO 3166-1 alpha-2 country code (e.g. "tr", "jp", "cn") */
|
|
112
|
+
countryCode?: string | null;
|
|
111
113
|
isSource?: boolean;
|
|
112
114
|
lastUpdated?: string | null;
|
|
113
115
|
keyCount?: number;
|
|
@@ -138,6 +140,8 @@ export interface LanguageOption {
|
|
|
138
140
|
name?: string;
|
|
139
141
|
nativeName?: string;
|
|
140
142
|
flagUrl?: string | null;
|
|
143
|
+
/** ISO 3166-1 alpha-2 country code (e.g. "tr", "jp", "cn") */
|
|
144
|
+
countryCode?: string | null;
|
|
141
145
|
/**
|
|
142
146
|
* Whether this is the default/source language
|
|
143
147
|
*/
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* UI utilities for locale display: flag resolution, country codes, and labels.
|
|
3
|
+
*
|
|
4
|
+
* Extracted from the platform's LanguageSwitcher for use across all OSS packages.
|
|
5
|
+
* Zero dependencies — works in any React environment.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Maps primary language codes to their most commonly associated country codes.
|
|
9
|
+
* Used as a fallback when no explicit `countryCode` or regional subtag is available.
|
|
10
|
+
*/
|
|
11
|
+
export declare const LANGUAGE_TO_COUNTRY: Record<string, string>;
|
|
12
|
+
/**
|
|
13
|
+
* Derives a two-letter country code from a locale string.
|
|
14
|
+
*
|
|
15
|
+
* Resolution order:
|
|
16
|
+
* 1. Regional subtag (e.g., "pt-BR" → "br")
|
|
17
|
+
* 2. LANGUAGE_TO_COUNTRY map (e.g., "ja" → "jp")
|
|
18
|
+
* 3. null if no mapping exists
|
|
19
|
+
*/
|
|
20
|
+
export declare function getCountryCodeFromLocale(locale: string): string | null;
|
|
21
|
+
/**
|
|
22
|
+
* Converts a two-letter country code to its flag emoji using regional indicator symbols.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* getFlagEmoji("us") // "🇺🇸"
|
|
26
|
+
* getFlagEmoji("tr") // "🇹🇷"
|
|
27
|
+
* getFlagEmoji(null) // null
|
|
28
|
+
*/
|
|
29
|
+
export declare function getFlagEmoji(countryCode?: string | null): string | null;
|
|
30
|
+
/** Minimal language shape for UI utilities — compatible with `LanguageOption`. */
|
|
31
|
+
interface LanguageLike {
|
|
32
|
+
code: string;
|
|
33
|
+
name?: string;
|
|
34
|
+
nativeName?: string;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Returns the best display label for a language.
|
|
38
|
+
* Priority: nativeName → name → uppercased code.
|
|
39
|
+
*/
|
|
40
|
+
export declare function getLanguageLabel(language: LanguageLike): string;
|
|
41
|
+
/** Resolved flag info for rendering. */
|
|
42
|
+
export type ResolvedFlag = {
|
|
43
|
+
type: "url";
|
|
44
|
+
url: string;
|
|
45
|
+
} | {
|
|
46
|
+
type: "emoji";
|
|
47
|
+
emoji: string;
|
|
48
|
+
} | {
|
|
49
|
+
type: "none";
|
|
50
|
+
};
|
|
51
|
+
/** Minimal shape needed for flag resolution. */
|
|
52
|
+
interface FlagResolvable {
|
|
53
|
+
code: string;
|
|
54
|
+
countryCode?: string | null;
|
|
55
|
+
flagUrl?: string | null;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Resolves the best available flag representation for a language.
|
|
59
|
+
*
|
|
60
|
+
* Resolution order:
|
|
61
|
+
* 1. `flagUrl` → image URL (custom flag from CDN manifest)
|
|
62
|
+
* 2. Emoji flag derived from country code or locale
|
|
63
|
+
* 3. `{ type: "none" }` — caller should render a globe icon
|
|
64
|
+
*/
|
|
65
|
+
export declare function resolveFlag(language: FlagResolvable): ResolvedFlag;
|
|
66
|
+
export {};
|
|
67
|
+
//# sourceMappingURL=locale-ui.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"locale-ui.d.ts","sourceRoot":"","sources":["../../src/utils/locale-ui.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;GAGG;AACH,eAAO,MAAM,mBAAmB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAuCtD,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CActE;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,CAQvE;AAED,kFAAkF;AAClF,UAAU,YAAY;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,YAAY,GAAG,MAAM,CAE/D;AAED,wCAAwC;AACxC,MAAM,MAAM,YAAY,GACpB;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAC5B;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAChC;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAErB,gDAAgD;AAChD,UAAU,cAAc;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,cAAc,GAAG,YAAY,CAclE"}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* UI utilities for locale display: flag resolution, country codes, and labels.
|
|
3
|
+
*
|
|
4
|
+
* Extracted from the platform's LanguageSwitcher for use across all OSS packages.
|
|
5
|
+
* Zero dependencies — works in any React environment.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Maps primary language codes to their most commonly associated country codes.
|
|
9
|
+
* Used as a fallback when no explicit `countryCode` or regional subtag is available.
|
|
10
|
+
*/
|
|
11
|
+
export const LANGUAGE_TO_COUNTRY = {
|
|
12
|
+
ar: "sa",
|
|
13
|
+
bg: "bg",
|
|
14
|
+
bn: "bd",
|
|
15
|
+
cs: "cz",
|
|
16
|
+
da: "dk",
|
|
17
|
+
de: "de",
|
|
18
|
+
el: "gr",
|
|
19
|
+
en: "gb",
|
|
20
|
+
es: "es",
|
|
21
|
+
et: "ee",
|
|
22
|
+
fi: "fi",
|
|
23
|
+
fr: "fr",
|
|
24
|
+
he: "il",
|
|
25
|
+
hi: "in",
|
|
26
|
+
hr: "hr",
|
|
27
|
+
hu: "hu",
|
|
28
|
+
id: "id",
|
|
29
|
+
it: "it",
|
|
30
|
+
ja: "jp",
|
|
31
|
+
ko: "kr",
|
|
32
|
+
lt: "lt",
|
|
33
|
+
lv: "lv",
|
|
34
|
+
ms: "my",
|
|
35
|
+
nl: "nl",
|
|
36
|
+
no: "no",
|
|
37
|
+
pl: "pl",
|
|
38
|
+
pt: "pt",
|
|
39
|
+
ro: "ro",
|
|
40
|
+
ru: "ru",
|
|
41
|
+
sk: "sk",
|
|
42
|
+
sl: "si",
|
|
43
|
+
sr: "rs",
|
|
44
|
+
sv: "se",
|
|
45
|
+
th: "th",
|
|
46
|
+
tr: "tr",
|
|
47
|
+
uk: "ua",
|
|
48
|
+
vi: "vn",
|
|
49
|
+
zh: "cn",
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* Derives a two-letter country code from a locale string.
|
|
53
|
+
*
|
|
54
|
+
* Resolution order:
|
|
55
|
+
* 1. Regional subtag (e.g., "pt-BR" → "br")
|
|
56
|
+
* 2. LANGUAGE_TO_COUNTRY map (e.g., "ja" → "jp")
|
|
57
|
+
* 3. null if no mapping exists
|
|
58
|
+
*/
|
|
59
|
+
export function getCountryCodeFromLocale(locale) {
|
|
60
|
+
const normalizedLocale = locale.trim().toLowerCase();
|
|
61
|
+
if (!normalizedLocale)
|
|
62
|
+
return null;
|
|
63
|
+
const [, regionOrScript] = normalizedLocale.split("-");
|
|
64
|
+
if (regionOrScript && /^[a-z]{2}$/i.test(regionOrScript)) {
|
|
65
|
+
return regionOrScript.toLowerCase();
|
|
66
|
+
}
|
|
67
|
+
return (LANGUAGE_TO_COUNTRY[normalizedLocale] ||
|
|
68
|
+
LANGUAGE_TO_COUNTRY[normalizedLocale.split("-")[0]] ||
|
|
69
|
+
null);
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Converts a two-letter country code to its flag emoji using regional indicator symbols.
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* getFlagEmoji("us") // "🇺🇸"
|
|
76
|
+
* getFlagEmoji("tr") // "🇹🇷"
|
|
77
|
+
* getFlagEmoji(null) // null
|
|
78
|
+
*/
|
|
79
|
+
export function getFlagEmoji(countryCode) {
|
|
80
|
+
if (!countryCode || !/^[a-z]{2}$/i.test(countryCode))
|
|
81
|
+
return null;
|
|
82
|
+
return countryCode
|
|
83
|
+
.toUpperCase()
|
|
84
|
+
.split("")
|
|
85
|
+
.map((char) => String.fromCodePoint(127397 + char.charCodeAt(0)))
|
|
86
|
+
.join("");
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Returns the best display label for a language.
|
|
90
|
+
* Priority: nativeName → name → uppercased code.
|
|
91
|
+
*/
|
|
92
|
+
export function getLanguageLabel(language) {
|
|
93
|
+
return language.nativeName || language.name || language.code.toUpperCase();
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Resolves the best available flag representation for a language.
|
|
97
|
+
*
|
|
98
|
+
* Resolution order:
|
|
99
|
+
* 1. `flagUrl` → image URL (custom flag from CDN manifest)
|
|
100
|
+
* 2. Emoji flag derived from country code or locale
|
|
101
|
+
* 3. `{ type: "none" }` — caller should render a globe icon
|
|
102
|
+
*/
|
|
103
|
+
export function resolveFlag(language) {
|
|
104
|
+
if (language.flagUrl) {
|
|
105
|
+
return { type: "url", url: language.flagUrl };
|
|
106
|
+
}
|
|
107
|
+
const countryCode = language.countryCode || getCountryCodeFromLocale(language.code);
|
|
108
|
+
const emoji = getFlagEmoji(countryCode);
|
|
109
|
+
if (emoji) {
|
|
110
|
+
return { type: "emoji", emoji };
|
|
111
|
+
}
|
|
112
|
+
return { type: "none" };
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=locale-ui.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"locale-ui.js","sourceRoot":"","sources":["../../src/utils/locale-ui.ts"],"names":[],"mappings":"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"}
|
package/dist/utils/locale.d.ts
CHANGED
|
@@ -20,10 +20,21 @@ export interface LocaleConfig {
|
|
|
20
20
|
*/
|
|
21
21
|
locales: string[];
|
|
22
22
|
/**
|
|
23
|
-
* Default locale code
|
|
23
|
+
* Default locale code
|
|
24
24
|
* @example 'en'
|
|
25
25
|
*/
|
|
26
26
|
defaultLocale: string;
|
|
27
|
+
/**
|
|
28
|
+
* URL prefix strategy for locale codes.
|
|
29
|
+
*
|
|
30
|
+
* - `"as-needed"` (default): Default locale has NO prefix (`/about`), others do (`/tr/about`).
|
|
31
|
+
* Follows next-intl / Paraglide JS convention.
|
|
32
|
+
* - `"always"`: ALL locales get a prefix, including the default (`/en/about`, `/tr/about`).
|
|
33
|
+
* Use with TanStack Router `$locale/` route segments.
|
|
34
|
+
*
|
|
35
|
+
* @default "as-needed"
|
|
36
|
+
*/
|
|
37
|
+
localePrefix?: "always" | "as-needed";
|
|
27
38
|
}
|
|
28
39
|
/**
|
|
29
40
|
* Extract locale from URL pathname
|
|
@@ -67,27 +78,35 @@ export declare function hasLocalePrefix(pathname: string, config: LocaleConfig):
|
|
|
67
78
|
*/
|
|
68
79
|
export declare function removeLocalePrefix(pathname: string, config: LocaleConfig): string;
|
|
69
80
|
/**
|
|
70
|
-
* Add locale prefix to pathname
|
|
81
|
+
* Add locale prefix to pathname
|
|
71
82
|
*
|
|
72
|
-
*
|
|
83
|
+
* Respects `localePrefix` config:
|
|
84
|
+
* - `"as-needed"` (default): default locale has no prefix
|
|
85
|
+
* - `"always"`: all locales get a prefix
|
|
73
86
|
*
|
|
74
87
|
* @example
|
|
88
|
+
* // as-needed (default)
|
|
75
89
|
* addLocalePrefix('/about', 'tr', config) // '/tr/about'
|
|
76
|
-
* addLocalePrefix('/about', 'en', config) // '/about' (en is default
|
|
77
|
-
*
|
|
90
|
+
* addLocalePrefix('/about', 'en', config) // '/about' (en is default)
|
|
91
|
+
*
|
|
92
|
+
* // always
|
|
93
|
+
* addLocalePrefix('/about', 'en', { ...config, localePrefix: 'always' }) // '/en/about'
|
|
78
94
|
*/
|
|
79
95
|
export declare function addLocalePrefix(pathname: string, locale: string, config: LocaleConfig): string;
|
|
80
96
|
/**
|
|
81
97
|
* Replace/add locale in pathname
|
|
82
98
|
*
|
|
83
|
-
*
|
|
84
|
-
*
|
|
99
|
+
* Respects `localePrefix` config:
|
|
100
|
+
* - `"as-needed"` (default): default locale has no prefix
|
|
101
|
+
* - `"always"`: all locales always get a prefix
|
|
85
102
|
*
|
|
86
103
|
* @example
|
|
87
|
-
*
|
|
104
|
+
* // as-needed (default)
|
|
88
105
|
* replaceLocaleInPath('/tr/about', 'en', config) // '/about' (en is default)
|
|
89
106
|
* replaceLocaleInPath('/tr/about', 'de', config) // '/de/about'
|
|
90
|
-
*
|
|
107
|
+
*
|
|
108
|
+
* // always
|
|
109
|
+
* replaceLocaleInPath('/tr/about', 'en', { ...config, localePrefix: 'always' }) // '/en/about'
|
|
91
110
|
*/
|
|
92
111
|
export declare function replaceLocaleInPath(pathname: string, newLocale: string, config: LocaleConfig): string;
|
|
93
112
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"locale.d.ts","sourceRoot":"","sources":["../../src/utils/locale.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,eAAO,MAAM,eAAe,GAAI,QAAQ,MAAM,KAAG,MACR,CAAC;AAE1C;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B;;;OAGG;IACH,OAAO,EAAE,MAAM,EAAE,CAAC;IAElB;;;OAGG;IACH,aAAa,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"locale.d.ts","sourceRoot":"","sources":["../../src/utils/locale.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,eAAO,MAAM,eAAe,GAAI,QAAQ,MAAM,KAAG,MACR,CAAC;AAE1C;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B;;;OAGG;IACH,OAAO,EAAE,MAAM,EAAE,CAAC;IAElB;;;OAGG;IACH,aAAa,EAAE,MAAM,CAAC;IAEtB;;;;;;;;;OASG;IACH,YAAY,CAAC,EAAE,QAAQ,GAAG,WAAW,CAAC;CACvC;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,YAAY,GACnB,MAAM,GAAG,IAAI,CASf;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,YAAY,GACnB,MAAM,CAER;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,YAAY,GACnB,OAAO,CAET;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,YAAY,GACnB,MAAM,CAMR;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,YAAY,GACnB,MAAM,CAUR;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,YAAY,GACnB,MAAM,CAWR;AAED;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,YAAY,IAC3C,MAAM,MAAM,EAAE,SAAS,MAAM,KAAG,MAAM,CAI/C"}
|
package/dist/utils/locale.js
CHANGED
|
@@ -69,18 +69,23 @@ export function removeLocalePrefix(pathname, config) {
|
|
|
69
69
|
return result || "/";
|
|
70
70
|
}
|
|
71
71
|
/**
|
|
72
|
-
* Add locale prefix to pathname
|
|
72
|
+
* Add locale prefix to pathname
|
|
73
73
|
*
|
|
74
|
-
*
|
|
74
|
+
* Respects `localePrefix` config:
|
|
75
|
+
* - `"as-needed"` (default): default locale has no prefix
|
|
76
|
+
* - `"always"`: all locales get a prefix
|
|
75
77
|
*
|
|
76
78
|
* @example
|
|
79
|
+
* // as-needed (default)
|
|
77
80
|
* addLocalePrefix('/about', 'tr', config) // '/tr/about'
|
|
78
|
-
* addLocalePrefix('/about', 'en', config) // '/about' (en is default
|
|
79
|
-
*
|
|
81
|
+
* addLocalePrefix('/about', 'en', config) // '/about' (en is default)
|
|
82
|
+
*
|
|
83
|
+
* // always
|
|
84
|
+
* addLocalePrefix('/about', 'en', { ...config, localePrefix: 'always' }) // '/en/about'
|
|
80
85
|
*/
|
|
81
86
|
export function addLocalePrefix(pathname, locale, config) {
|
|
82
|
-
// Don't add prefix for default locale
|
|
83
|
-
if (locale === config.defaultLocale) {
|
|
87
|
+
// Don't add prefix for default locale in "as-needed" mode
|
|
88
|
+
if (config.localePrefix !== "always" && locale === config.defaultLocale) {
|
|
84
89
|
return pathname;
|
|
85
90
|
}
|
|
86
91
|
if (pathname === "/" || pathname === "") {
|
|
@@ -91,20 +96,23 @@ export function addLocalePrefix(pathname, locale, config) {
|
|
|
91
96
|
/**
|
|
92
97
|
* Replace/add locale in pathname
|
|
93
98
|
*
|
|
94
|
-
*
|
|
95
|
-
*
|
|
99
|
+
* Respects `localePrefix` config:
|
|
100
|
+
* - `"as-needed"` (default): default locale has no prefix
|
|
101
|
+
* - `"always"`: all locales always get a prefix
|
|
96
102
|
*
|
|
97
103
|
* @example
|
|
98
|
-
*
|
|
104
|
+
* // as-needed (default)
|
|
99
105
|
* replaceLocaleInPath('/tr/about', 'en', config) // '/about' (en is default)
|
|
100
106
|
* replaceLocaleInPath('/tr/about', 'de', config) // '/de/about'
|
|
101
|
-
*
|
|
107
|
+
*
|
|
108
|
+
* // always
|
|
109
|
+
* replaceLocaleInPath('/tr/about', 'en', { ...config, localePrefix: 'always' }) // '/en/about'
|
|
102
110
|
*/
|
|
103
111
|
export function replaceLocaleInPath(pathname, newLocale, config) {
|
|
104
112
|
// Remove existing locale prefix if present
|
|
105
113
|
const cleanPath = removeLocalePrefix(pathname, config);
|
|
106
|
-
//
|
|
107
|
-
if (newLocale === config.defaultLocale) {
|
|
114
|
+
// In "as-needed" mode, don't add prefix for default locale
|
|
115
|
+
if (config.localePrefix !== "always" && newLocale === config.defaultLocale) {
|
|
108
116
|
return cleanPath;
|
|
109
117
|
}
|
|
110
118
|
// Add new locale prefix
|
package/dist/utils/locale.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"locale.js","sourceRoot":"","sources":["../../src/utils/locale.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,MAAc,EAAU,EAAE,CACxD,MAAM,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"locale.js","sourceRoot":"","sources":["../../src/utils/locale.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,MAAc,EAAU,EAAE,CACxD,MAAM,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;AA+B1C;;;;;;;;;;GAUG;AACH,MAAM,UAAU,aAAa,CAC3B,QAAgB,EAChB,MAAoB;IAEpB,MAAM,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IACrD,MAAM,YAAY,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IAEjC,IAAI,YAAY,IAAI,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC;QAC1D,OAAO,YAAY,CAAC;IACtB,CAAC;IAED,OAAO,IAAI,CAAC,CAAC,oCAAoC;AACnD,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,iBAAiB,CAC/B,QAAgB,EAChB,MAAoB;IAEpB,OAAO,aAAa,CAAC,QAAQ,EAAE,MAAM,CAAC,IAAI,MAAM,CAAC,aAAa,CAAC;AACjE,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,eAAe,CAC7B,QAAgB,EAChB,MAAoB;IAEpB,OAAO,aAAa,CAAC,QAAQ,EAAE,MAAM,CAAC,KAAK,IAAI,CAAC;AAClD,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,kBAAkB,CAChC,QAAgB,EAChB,MAAoB;IAEpB,MAAM,MAAM,GAAG,aAAa,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IAC/C,IAAI,CAAC,MAAM;QAAE,OAAO,QAAQ,CAAC;IAE7B,MAAM,MAAM,GAAG,QAAQ,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,KAAK,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;IAC/D,OAAO,MAAM,IAAI,GAAG,CAAC;AACvB,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,eAAe,CAC7B,QAAgB,EAChB,MAAc,EACd,MAAoB;IAEpB,0DAA0D;IAC1D,IAAI,MAAM,CAAC,YAAY,KAAK,QAAQ,IAAI,MAAM,KAAK,MAAM,CAAC,aAAa,EAAE,CAAC;QACxE,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,IAAI,QAAQ,KAAK,GAAG,IAAI,QAAQ,KAAK,EAAE,EAAE,CAAC;QACxC,OAAO,IAAI,MAAM,EAAE,CAAC;IACtB,CAAC;IACD,OAAO,IAAI,MAAM,GAAG,QAAQ,EAAE,CAAC;AACjC,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,mBAAmB,CACjC,QAAgB,EAChB,SAAiB,EACjB,MAAoB;IAEpB,2CAA2C;IAC3C,MAAM,SAAS,GAAG,kBAAkB,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IAEvD,2DAA2D;IAC3D,IAAI,MAAM,CAAC,YAAY,KAAK,QAAQ,IAAI,SAAS,KAAK,MAAM,CAAC,aAAa,EAAE,CAAC;QAC3E,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,wBAAwB;IACxB,OAAO,IAAI,SAAS,GAAG,SAAS,KAAK,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC;AAC9D,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAAoB;IACnD,OAAO,CAAC,IAAY,EAAE,MAAe,EAAU,EAAE;QAC/C,MAAM,YAAY,GAAG,MAAM,IAAI,MAAM,CAAC,aAAa,CAAC;QACpD,OAAO,eAAe,CAAC,IAAI,EAAE,YAAY,EAAE,MAAM,CAAC,CAAC;IACrD,CAAC,CAAC;AACJ,CAAC"}
|