inline-i18n-multi 0.6.0 → 0.7.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 +120 -1
- package/dist/index.d.mts +22 -2
- package/dist/index.d.ts +22 -2
- package/dist/index.js +105 -14
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +104 -15
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -67,6 +67,9 @@ See "Hello" in your app? Just search for "Hello" in your codebase. **Done.**
|
|
|
67
67
|
- **Interpolation Guards** - Handle missing variables gracefully (`missingVarHandler`)
|
|
68
68
|
- **Locale Detection** - Auto-detect user locale from navigator, cookie, URL, or header (`detectLocale()`)
|
|
69
69
|
- **Selectordinal** - Ordinal plural formatting (`{rank, selectordinal, one {#st} two {#nd} ...}`)
|
|
70
|
+
- **ICU Message Cache** - Memoize parsed ICU ASTs for performance (`icuCacheSize`, `clearICUCache()`)
|
|
71
|
+
- **Plural Shorthand** - Concise plural syntax (`{count, p, item|items}`)
|
|
72
|
+
- **Locale Persistence** - Auto-save/restore locale to cookie or localStorage (`persistLocale`, `restoreLocale()`)
|
|
70
73
|
|
|
71
74
|
---
|
|
72
75
|
|
|
@@ -551,6 +554,109 @@ Uses `Intl.PluralRules` with `{ type: 'ordinal' }` for locale-aware ordinal cate
|
|
|
551
554
|
|
|
552
555
|
---
|
|
553
556
|
|
|
557
|
+
## ICU Message Cache
|
|
558
|
+
|
|
559
|
+
Memoize parsed ICU ASTs to avoid re-parsing the same message patterns:
|
|
560
|
+
|
|
561
|
+
```typescript
|
|
562
|
+
import { configure, clearICUCache } from 'inline-i18n-multi'
|
|
563
|
+
|
|
564
|
+
// Enable caching (default: 500 entries)
|
|
565
|
+
configure({ icuCacheSize: 500 })
|
|
566
|
+
|
|
567
|
+
// Disable caching
|
|
568
|
+
configure({ icuCacheSize: 0 })
|
|
569
|
+
|
|
570
|
+
// Manually clear the cache
|
|
571
|
+
clearICUCache()
|
|
572
|
+
```
|
|
573
|
+
|
|
574
|
+
The cache uses FIFO (First-In, First-Out) eviction when the maximum size is reached. Repeated calls to `it()` or `t()` with the same ICU pattern will reuse the cached AST instead of re-parsing.
|
|
575
|
+
|
|
576
|
+
---
|
|
577
|
+
|
|
578
|
+
## Plural Shorthand
|
|
579
|
+
|
|
580
|
+
Concise syntax for common plural patterns using `p` as a short type name:
|
|
581
|
+
|
|
582
|
+
```typescript
|
|
583
|
+
import { it, setLocale } from 'inline-i18n-multi'
|
|
584
|
+
|
|
585
|
+
setLocale('en')
|
|
586
|
+
|
|
587
|
+
// 2-part: singular|plural (value is prepended automatically)
|
|
588
|
+
it({
|
|
589
|
+
en: '{count, p, item|items}',
|
|
590
|
+
ko: '{count, p, 개|개}'
|
|
591
|
+
}, { count: 1 }) // → "1 item"
|
|
592
|
+
|
|
593
|
+
it({
|
|
594
|
+
en: '{count, p, item|items}',
|
|
595
|
+
ko: '{count, p, 개|개}'
|
|
596
|
+
}, { count: 5 }) // → "5 items"
|
|
597
|
+
|
|
598
|
+
// 3-part: zero|singular|plural
|
|
599
|
+
it({
|
|
600
|
+
en: '{count, p, no items|item|items}',
|
|
601
|
+
ko: '{count, p, 항목 없음|개|개}'
|
|
602
|
+
}, { count: 0 }) // → "no items"
|
|
603
|
+
|
|
604
|
+
it({
|
|
605
|
+
en: '{count, p, no items|item|items}',
|
|
606
|
+
ko: '{count, p, 항목 없음|개|개}'
|
|
607
|
+
}, { count: 1 }) // → "1 item"
|
|
608
|
+
|
|
609
|
+
it({
|
|
610
|
+
en: '{count, p, no items|item|items}',
|
|
611
|
+
ko: '{count, p, 항목 없음|개|개}'
|
|
612
|
+
}, { count: 5 }) // → "5 items"
|
|
613
|
+
```
|
|
614
|
+
|
|
615
|
+
The shorthand is preprocessed into standard ICU `plural` syntax before parsing.
|
|
616
|
+
|
|
617
|
+
---
|
|
618
|
+
|
|
619
|
+
## Locale Persistence
|
|
620
|
+
|
|
621
|
+
Auto-save and restore the user's locale to `cookie` or `localStorage`:
|
|
622
|
+
|
|
623
|
+
```typescript
|
|
624
|
+
import { configure, setLocale, restoreLocale } from 'inline-i18n-multi'
|
|
625
|
+
|
|
626
|
+
// Configure persistence
|
|
627
|
+
configure({
|
|
628
|
+
persistLocale: {
|
|
629
|
+
storage: 'cookie', // 'cookie' | 'localStorage'
|
|
630
|
+
key: 'LOCALE', // storage key (default: 'LOCALE')
|
|
631
|
+
expires: 365 // cookie expiry in days (default: 365)
|
|
632
|
+
}
|
|
633
|
+
})
|
|
634
|
+
|
|
635
|
+
// Restore locale from storage (returns the saved locale or undefined)
|
|
636
|
+
const saved = restoreLocale()
|
|
637
|
+
if (saved) {
|
|
638
|
+
// locale was restored from storage
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
// setLocale() automatically saves to the configured storage
|
|
642
|
+
setLocale('ko') // also saves 'ko' to cookie or localStorage
|
|
643
|
+
```
|
|
644
|
+
|
|
645
|
+
```typescript
|
|
646
|
+
// localStorage example
|
|
647
|
+
configure({
|
|
648
|
+
persistLocale: {
|
|
649
|
+
storage: 'localStorage',
|
|
650
|
+
key: 'APP_LOCALE'
|
|
651
|
+
}
|
|
652
|
+
})
|
|
653
|
+
|
|
654
|
+
restoreLocale() // reads from localStorage
|
|
655
|
+
setLocale('ja') // saves 'ja' to localStorage
|
|
656
|
+
```
|
|
657
|
+
|
|
658
|
+
---
|
|
659
|
+
|
|
554
660
|
## Configuration
|
|
555
661
|
|
|
556
662
|
Configure global settings for fallback behavior and warnings:
|
|
@@ -636,12 +742,14 @@ Available helpers:
|
|
|
636
742
|
|
|
637
743
|
| Function | Description |
|
|
638
744
|
|----------|-------------|
|
|
639
|
-
| `configure(options)` | Configure global settings (fallback, warnings, debug, missingVarHandler) |
|
|
745
|
+
| `configure(options)` | Configure global settings (fallback, warnings, debug, missingVarHandler, icuCacheSize, persistLocale) |
|
|
640
746
|
| `getConfig()` | Get current configuration |
|
|
641
747
|
| `resetConfig()` | Reset configuration to defaults |
|
|
642
748
|
| `loadAsync(locale, namespace?)` | Asynchronously load dictionary using configured loader |
|
|
643
749
|
| `isLoaded(locale, namespace?)` | Check if dictionary has been loaded |
|
|
644
750
|
| `parseRichText(template, names)` | Parse rich text template into segments |
|
|
751
|
+
| `clearICUCache()` | Clear the ICU message AST cache |
|
|
752
|
+
| `restoreLocale()` | Restore locale from configured persistent storage (cookie or localStorage) |
|
|
645
753
|
|
|
646
754
|
### Custom Formatters
|
|
647
755
|
|
|
@@ -681,6 +789,17 @@ interface Config {
|
|
|
681
789
|
debugMode?: boolean | DebugModeOptions
|
|
682
790
|
loader?: (locale: Locale, namespace: string) => Promise<Record<string, unknown>>
|
|
683
791
|
missingVarHandler?: (varName: string, locale: string) => string
|
|
792
|
+
icuCacheSize?: number
|
|
793
|
+
persistLocale?: PersistLocaleOptions
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
interface PersistLocaleOptions {
|
|
797
|
+
/** Storage backend */
|
|
798
|
+
storage: 'cookie' | 'localStorage'
|
|
799
|
+
/** Storage key (default: 'LOCALE') */
|
|
800
|
+
key?: string
|
|
801
|
+
/** Cookie expiry in days (default: 365, cookie only) */
|
|
802
|
+
expires?: number
|
|
684
803
|
}
|
|
685
804
|
|
|
686
805
|
interface DebugModeOptions {
|
package/dist/index.d.mts
CHANGED
|
@@ -65,6 +65,17 @@ interface Config {
|
|
|
65
65
|
loader?: (locale: Locale, namespace: string) => Promise<Record<string, unknown>>;
|
|
66
66
|
/** Custom handler for missing interpolation variables (v0.6.0) */
|
|
67
67
|
missingVarHandler?: (varName: string, locale: string) => string;
|
|
68
|
+
/** Maximum number of parsed ICU ASTs to cache (default: 500, 0 to disable) (v0.7.0) */
|
|
69
|
+
icuCacheSize?: number;
|
|
70
|
+
/** Locale persistence configuration (v0.7.0) */
|
|
71
|
+
persistLocale?: {
|
|
72
|
+
/** Storage mechanism */
|
|
73
|
+
storage: 'cookie' | 'localStorage';
|
|
74
|
+
/** Storage key name (default: 'LOCALE') */
|
|
75
|
+
key?: string;
|
|
76
|
+
/** Cookie expiry in days (default: 365). Only applies to cookie storage. */
|
|
77
|
+
expires?: number;
|
|
78
|
+
};
|
|
68
79
|
}
|
|
69
80
|
|
|
70
81
|
/**
|
|
@@ -83,6 +94,11 @@ declare function it(translations: Translations, vars?: TranslationVars): string;
|
|
|
83
94
|
|
|
84
95
|
declare function setLocale(locale: Locale): void;
|
|
85
96
|
declare function getLocale(): Locale;
|
|
97
|
+
/**
|
|
98
|
+
* Restore locale from configured persistent storage.
|
|
99
|
+
* Returns the restored locale, or undefined if nothing was found.
|
|
100
|
+
*/
|
|
101
|
+
declare function restoreLocale(): Locale | undefined;
|
|
86
102
|
|
|
87
103
|
/**
|
|
88
104
|
* Runtime lookup function for build-tool-transformed code.
|
|
@@ -212,7 +228,7 @@ declare function getDictionary(locale: Locale, namespace?: string): Dictionary |
|
|
|
212
228
|
*/
|
|
213
229
|
declare function getLoadedNamespaces(): string[];
|
|
214
230
|
|
|
215
|
-
type FullConfig = Required<Omit<Config, 'loader' | 'missingVarHandler'>> & Pick<Config, 'loader' | 'missingVarHandler'>;
|
|
231
|
+
type FullConfig = Required<Omit<Config, 'loader' | 'missingVarHandler' | 'persistLocale'>> & Pick<Config, 'loader' | 'missingVarHandler' | 'persistLocale'>;
|
|
216
232
|
/**
|
|
217
233
|
* Configure inline-i18n-multi settings
|
|
218
234
|
*
|
|
@@ -233,6 +249,10 @@ declare function getConfig(): FullConfig;
|
|
|
233
249
|
*/
|
|
234
250
|
declare function resetConfig(): void;
|
|
235
251
|
|
|
252
|
+
/**
|
|
253
|
+
* Clear the ICU message AST cache
|
|
254
|
+
*/
|
|
255
|
+
declare function clearICUCache(): void;
|
|
236
256
|
type CustomFormatter = (value: unknown, locale: string, style?: string) => string;
|
|
237
257
|
/**
|
|
238
258
|
* Register a custom formatter
|
|
@@ -303,4 +323,4 @@ interface RichTextSegment {
|
|
|
303
323
|
*/
|
|
304
324
|
declare function parseRichText(template: string, componentNames: string[]): RichTextSegment[];
|
|
305
325
|
|
|
306
|
-
export { type Config, type CustomFormatter, type DebugModeOptions, type DetectLocaleOptions, type DetectSource, type Dictionaries, type Dictionary, type Locale, type PluralRules, type RichTextSegment, type TranslationVars, type TranslationWarning, type Translations, type WarningHandler, __i18n_lookup, clearDictionaries, clearFormatters, configure, detectLocale, en_de, en_es, en_fr, en_ja, en_zh, getConfig, getDictionary, getLoadedLocales, getLoadedNamespaces, getLocale, hasTranslation, isLoaded, it, it_de, it_es, it_fr, it_ja, it_zh, ja_es, ja_zh, loadAsync, loadDictionaries, loadDictionary, parseRichText, registerFormatter, resetConfig, setLocale, t, zh_es };
|
|
326
|
+
export { type Config, type CustomFormatter, type DebugModeOptions, type DetectLocaleOptions, type DetectSource, type Dictionaries, type Dictionary, type Locale, type PluralRules, type RichTextSegment, type TranslationVars, type TranslationWarning, type Translations, type WarningHandler, __i18n_lookup, clearDictionaries, clearFormatters, clearICUCache, configure, detectLocale, en_de, en_es, en_fr, en_ja, en_zh, getConfig, getDictionary, getLoadedLocales, getLoadedNamespaces, getLocale, hasTranslation, isLoaded, it, it_de, it_es, it_fr, it_ja, it_zh, ja_es, ja_zh, loadAsync, loadDictionaries, loadDictionary, parseRichText, registerFormatter, resetConfig, restoreLocale, setLocale, t, zh_es };
|
package/dist/index.d.ts
CHANGED
|
@@ -65,6 +65,17 @@ interface Config {
|
|
|
65
65
|
loader?: (locale: Locale, namespace: string) => Promise<Record<string, unknown>>;
|
|
66
66
|
/** Custom handler for missing interpolation variables (v0.6.0) */
|
|
67
67
|
missingVarHandler?: (varName: string, locale: string) => string;
|
|
68
|
+
/** Maximum number of parsed ICU ASTs to cache (default: 500, 0 to disable) (v0.7.0) */
|
|
69
|
+
icuCacheSize?: number;
|
|
70
|
+
/** Locale persistence configuration (v0.7.0) */
|
|
71
|
+
persistLocale?: {
|
|
72
|
+
/** Storage mechanism */
|
|
73
|
+
storage: 'cookie' | 'localStorage';
|
|
74
|
+
/** Storage key name (default: 'LOCALE') */
|
|
75
|
+
key?: string;
|
|
76
|
+
/** Cookie expiry in days (default: 365). Only applies to cookie storage. */
|
|
77
|
+
expires?: number;
|
|
78
|
+
};
|
|
68
79
|
}
|
|
69
80
|
|
|
70
81
|
/**
|
|
@@ -83,6 +94,11 @@ declare function it(translations: Translations, vars?: TranslationVars): string;
|
|
|
83
94
|
|
|
84
95
|
declare function setLocale(locale: Locale): void;
|
|
85
96
|
declare function getLocale(): Locale;
|
|
97
|
+
/**
|
|
98
|
+
* Restore locale from configured persistent storage.
|
|
99
|
+
* Returns the restored locale, or undefined if nothing was found.
|
|
100
|
+
*/
|
|
101
|
+
declare function restoreLocale(): Locale | undefined;
|
|
86
102
|
|
|
87
103
|
/**
|
|
88
104
|
* Runtime lookup function for build-tool-transformed code.
|
|
@@ -212,7 +228,7 @@ declare function getDictionary(locale: Locale, namespace?: string): Dictionary |
|
|
|
212
228
|
*/
|
|
213
229
|
declare function getLoadedNamespaces(): string[];
|
|
214
230
|
|
|
215
|
-
type FullConfig = Required<Omit<Config, 'loader' | 'missingVarHandler'>> & Pick<Config, 'loader' | 'missingVarHandler'>;
|
|
231
|
+
type FullConfig = Required<Omit<Config, 'loader' | 'missingVarHandler' | 'persistLocale'>> & Pick<Config, 'loader' | 'missingVarHandler' | 'persistLocale'>;
|
|
216
232
|
/**
|
|
217
233
|
* Configure inline-i18n-multi settings
|
|
218
234
|
*
|
|
@@ -233,6 +249,10 @@ declare function getConfig(): FullConfig;
|
|
|
233
249
|
*/
|
|
234
250
|
declare function resetConfig(): void;
|
|
235
251
|
|
|
252
|
+
/**
|
|
253
|
+
* Clear the ICU message AST cache
|
|
254
|
+
*/
|
|
255
|
+
declare function clearICUCache(): void;
|
|
236
256
|
type CustomFormatter = (value: unknown, locale: string, style?: string) => string;
|
|
237
257
|
/**
|
|
238
258
|
* Register a custom formatter
|
|
@@ -303,4 +323,4 @@ interface RichTextSegment {
|
|
|
303
323
|
*/
|
|
304
324
|
declare function parseRichText(template: string, componentNames: string[]): RichTextSegment[];
|
|
305
325
|
|
|
306
|
-
export { type Config, type CustomFormatter, type DebugModeOptions, type DetectLocaleOptions, type DetectSource, type Dictionaries, type Dictionary, type Locale, type PluralRules, type RichTextSegment, type TranslationVars, type TranslationWarning, type Translations, type WarningHandler, __i18n_lookup, clearDictionaries, clearFormatters, configure, detectLocale, en_de, en_es, en_fr, en_ja, en_zh, getConfig, getDictionary, getLoadedLocales, getLoadedNamespaces, getLocale, hasTranslation, isLoaded, it, it_de, it_es, it_fr, it_ja, it_zh, ja_es, ja_zh, loadAsync, loadDictionaries, loadDictionary, parseRichText, registerFormatter, resetConfig, setLocale, t, zh_es };
|
|
326
|
+
export { type Config, type CustomFormatter, type DebugModeOptions, type DetectLocaleOptions, type DetectSource, type Dictionaries, type Dictionary, type Locale, type PluralRules, type RichTextSegment, type TranslationVars, type TranslationWarning, type Translations, type WarningHandler, __i18n_lookup, clearDictionaries, clearFormatters, clearICUCache, configure, detectLocale, en_de, en_es, en_fr, en_ja, en_zh, getConfig, getDictionary, getLoadedLocales, getLoadedNamespaces, getLocale, hasTranslation, isLoaded, it, it_de, it_es, it_fr, it_ja, it_zh, ja_es, ja_zh, loadAsync, loadDictionaries, loadDictionary, parseRichText, registerFormatter, resetConfig, restoreLocale, setLocale, t, zh_es };
|
package/dist/index.js
CHANGED
|
@@ -2,15 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
var icuMessageformatParser = require('@formatjs/icu-messageformat-parser');
|
|
4
4
|
|
|
5
|
-
// src/context.ts
|
|
6
|
-
var currentLocale = "en";
|
|
7
|
-
function setLocale(locale) {
|
|
8
|
-
currentLocale = locale;
|
|
9
|
-
}
|
|
10
|
-
function getLocale() {
|
|
11
|
-
return currentLocale;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
5
|
// src/config.ts
|
|
15
6
|
function defaultWarningHandler(warning) {
|
|
16
7
|
const parts = [`[inline-i18n] Missing translation for locale "${warning.requestedLocale}"`];
|
|
@@ -42,7 +33,8 @@ var defaultConfig = {
|
|
|
42
33
|
warnOnMissing: isDevMode(),
|
|
43
34
|
onMissingTranslation: defaultWarningHandler,
|
|
44
35
|
debugMode: false,
|
|
45
|
-
loader: void 0
|
|
36
|
+
loader: void 0,
|
|
37
|
+
icuCacheSize: 500
|
|
46
38
|
};
|
|
47
39
|
var config = { ...defaultConfig };
|
|
48
40
|
function configure(options) {
|
|
@@ -110,6 +102,82 @@ function applyDebugFormat(output, debugInfo) {
|
|
|
110
102
|
}
|
|
111
103
|
return output;
|
|
112
104
|
}
|
|
105
|
+
|
|
106
|
+
// src/context.ts
|
|
107
|
+
var currentLocale = "en";
|
|
108
|
+
function setCookie(name, value, days) {
|
|
109
|
+
if (typeof document === "undefined") return;
|
|
110
|
+
const expires = new Date(Date.now() + days * 864e5).toUTCString();
|
|
111
|
+
document.cookie = `${name}=${value}; expires=${expires}; path=/; SameSite=Lax`;
|
|
112
|
+
}
|
|
113
|
+
function getCookie(name) {
|
|
114
|
+
if (typeof document === "undefined") return void 0;
|
|
115
|
+
const match = document.cookie.match(new RegExp(`(?:^|;\\s*)${name}=([^;]*)`));
|
|
116
|
+
return match?.[1];
|
|
117
|
+
}
|
|
118
|
+
function persistLocaleToStorage(locale) {
|
|
119
|
+
const cfg = getConfig();
|
|
120
|
+
if (!cfg.persistLocale) return;
|
|
121
|
+
const { storage, key = "LOCALE", expires = 365 } = cfg.persistLocale;
|
|
122
|
+
if (storage === "cookie") {
|
|
123
|
+
setCookie(key, locale, expires);
|
|
124
|
+
} else if (storage === "localStorage") {
|
|
125
|
+
if (typeof localStorage !== "undefined") {
|
|
126
|
+
try {
|
|
127
|
+
localStorage.setItem(key, locale);
|
|
128
|
+
} catch {
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
function setLocale(locale) {
|
|
134
|
+
currentLocale = locale;
|
|
135
|
+
persistLocaleToStorage(locale);
|
|
136
|
+
}
|
|
137
|
+
function getLocale() {
|
|
138
|
+
return currentLocale;
|
|
139
|
+
}
|
|
140
|
+
function restoreLocale() {
|
|
141
|
+
const cfg = getConfig();
|
|
142
|
+
if (!cfg.persistLocale) return void 0;
|
|
143
|
+
const { storage, key = "LOCALE" } = cfg.persistLocale;
|
|
144
|
+
let stored;
|
|
145
|
+
if (storage === "cookie") {
|
|
146
|
+
stored = getCookie(key);
|
|
147
|
+
} else if (storage === "localStorage") {
|
|
148
|
+
if (typeof localStorage !== "undefined") {
|
|
149
|
+
try {
|
|
150
|
+
stored = localStorage.getItem(key) ?? void 0;
|
|
151
|
+
} catch {
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
if (stored) {
|
|
156
|
+
currentLocale = stored;
|
|
157
|
+
return stored;
|
|
158
|
+
}
|
|
159
|
+
return void 0;
|
|
160
|
+
}
|
|
161
|
+
var icuCache = /* @__PURE__ */ new Map();
|
|
162
|
+
function clearICUCache() {
|
|
163
|
+
icuCache.clear();
|
|
164
|
+
}
|
|
165
|
+
function cachedParse(template) {
|
|
166
|
+
const cached = icuCache.get(template);
|
|
167
|
+
if (cached) return cached;
|
|
168
|
+
const ast = icuMessageformatParser.parse(template);
|
|
169
|
+
const cfg = getConfig();
|
|
170
|
+
if (cfg.icuCacheSize > 0) {
|
|
171
|
+
if (icuCache.size >= cfg.icuCacheSize) {
|
|
172
|
+
const firstKey = icuCache.keys().next().value;
|
|
173
|
+
if (firstKey !== void 0) {
|
|
174
|
+
icuCache.delete(firstKey);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
icuCache.set(template, ast);
|
|
178
|
+
}
|
|
179
|
+
return ast;
|
|
180
|
+
}
|
|
113
181
|
function handleMissingVar(varName, locale) {
|
|
114
182
|
const cfg = getConfig();
|
|
115
183
|
if (cfg.missingVarHandler) {
|
|
@@ -404,13 +472,34 @@ function formatListValue(variableName, type, style, vars, locale) {
|
|
|
404
472
|
return value.join(", ");
|
|
405
473
|
}
|
|
406
474
|
}
|
|
475
|
+
var PLURAL_SHORTHAND_PATTERN = /\{(\w+),\s*p,\s*([^}]+)\}/g;
|
|
476
|
+
function hasPluralShorthand(template) {
|
|
477
|
+
PLURAL_SHORTHAND_PATTERN.lastIndex = 0;
|
|
478
|
+
return PLURAL_SHORTHAND_PATTERN.test(template);
|
|
479
|
+
}
|
|
480
|
+
function preprocessPluralShorthand(template) {
|
|
481
|
+
PLURAL_SHORTHAND_PATTERN.lastIndex = 0;
|
|
482
|
+
return template.replace(PLURAL_SHORTHAND_PATTERN, (_, variable, args) => {
|
|
483
|
+
const parts = args.split("|").map((s) => s.trim());
|
|
484
|
+
if (parts.length === 2) {
|
|
485
|
+
const [singular, plural] = parts;
|
|
486
|
+
return `{${variable}, plural, one {# ${singular}} other {# ${plural}}}`;
|
|
487
|
+
}
|
|
488
|
+
if (parts.length === 3) {
|
|
489
|
+
const [zero, singular, plural] = parts;
|
|
490
|
+
return `{${variable}, plural, =0 {${zero}} one {# ${singular}} other {# ${plural}}}`;
|
|
491
|
+
}
|
|
492
|
+
return `{${variable}, p, ${args}}`;
|
|
493
|
+
});
|
|
494
|
+
}
|
|
407
495
|
function interpolateICU(template, vars, locale) {
|
|
408
|
-
const
|
|
496
|
+
const afterPluralShorthand = preprocessPluralShorthand(template);
|
|
497
|
+
const { processed: afterCustom, replacements: customReplacements } = preprocessCustomFormatters(afterPluralShorthand);
|
|
409
498
|
const { processed: afterCurrency, replacements: currencyReplacements } = preprocessCurrency(afterCustom);
|
|
410
499
|
const { processed: afterCompact, replacements: compactReplacements } = preprocessCompactNumber(afterCurrency);
|
|
411
500
|
const { processed: afterRelTime, replacements: relTimeReplacements } = preprocessRelativeTime(afterCompact);
|
|
412
501
|
const { processed: afterList, replacements: listReplacements } = preprocessList(afterRelTime);
|
|
413
|
-
const ast =
|
|
502
|
+
const ast = cachedParse(afterList);
|
|
414
503
|
let result = formatElements(ast, vars, locale, null);
|
|
415
504
|
for (const [placeholder, { variable, formatterName, style }] of customReplacements) {
|
|
416
505
|
const value = vars[variable];
|
|
@@ -507,7 +596,7 @@ function formatSelect(el, vars, locale) {
|
|
|
507
596
|
}
|
|
508
597
|
return handleMissingVar(el.value, locale);
|
|
509
598
|
}
|
|
510
|
-
var ICU_PATTERN = /\{[^}]+,\s*(plural|select|selectordinal|number|date|time|relativeTime|list|currency)\s*[,}]/;
|
|
599
|
+
var ICU_PATTERN = /\{[^}]+,\s*(plural|select|selectordinal|number|date|time|relativeTime|list|currency|p)\s*[,}]/;
|
|
511
600
|
function hasICUPattern(template) {
|
|
512
601
|
return ICU_PATTERN.test(template);
|
|
513
602
|
}
|
|
@@ -516,7 +605,7 @@ function hasICUPattern(template) {
|
|
|
516
605
|
var VARIABLE_PATTERN = /\{(\w+)\}/g;
|
|
517
606
|
function interpolate(template, vars, locale) {
|
|
518
607
|
const resolvedLocale = locale || "en";
|
|
519
|
-
if (hasICUPattern(template) || hasCustomFormatter(template)) {
|
|
608
|
+
if (hasICUPattern(template) || hasCustomFormatter(template) || hasPluralShorthand(template)) {
|
|
520
609
|
if (!vars) {
|
|
521
610
|
const cfg = getConfig();
|
|
522
611
|
if (cfg.missingVarHandler) {
|
|
@@ -1000,6 +1089,7 @@ function parseRichText(template, componentNames) {
|
|
|
1000
1089
|
exports.__i18n_lookup = __i18n_lookup;
|
|
1001
1090
|
exports.clearDictionaries = clearDictionaries;
|
|
1002
1091
|
exports.clearFormatters = clearFormatters;
|
|
1092
|
+
exports.clearICUCache = clearICUCache;
|
|
1003
1093
|
exports.configure = configure;
|
|
1004
1094
|
exports.detectLocale = detectLocale;
|
|
1005
1095
|
exports.en_de = en_de;
|
|
@@ -1028,6 +1118,7 @@ exports.loadDictionary = loadDictionary;
|
|
|
1028
1118
|
exports.parseRichText = parseRichText;
|
|
1029
1119
|
exports.registerFormatter = registerFormatter;
|
|
1030
1120
|
exports.resetConfig = resetConfig;
|
|
1121
|
+
exports.restoreLocale = restoreLocale;
|
|
1031
1122
|
exports.setLocale = setLocale;
|
|
1032
1123
|
exports.t = t;
|
|
1033
1124
|
exports.zh_es = zh_es;
|