inline-i18n-multi 0.5.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 CHANGED
@@ -63,6 +63,13 @@ See "Hello" in your app? Just search for "Hello" in your codebase. **Done.**
63
63
  - **Compact Number Formatting** - Short number display (`{count, number, compact}`)
64
64
  - **Rich Text Interpolation** - Embed React components in translations (`<link>text</link>`)
65
65
  - **Lazy Loading** - Async dictionary loading on demand (`loadAsync()`)
66
+ - **Custom Formatter Registry** - Register custom ICU-style formatters (`registerFormatter('phone', fn)`)
67
+ - **Interpolation Guards** - Handle missing variables gracefully (`missingVarHandler`)
68
+ - **Locale Detection** - Auto-detect user locale from navigator, cookie, URL, or header (`detectLocale()`)
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()`)
66
73
 
67
74
  ---
68
75
 
@@ -206,7 +213,10 @@ it({
206
213
  }, { price: 1234.56 }) // → "Price: 1,234.56"
207
214
  ```
208
215
 
209
- **Supported ICU styles:**
216
+ **Supported ICU types:**
217
+ - `plural`: `zero`, `one`, `two`, `few`, `many`, `other` (and exact matches like `=0`, `=1`)
218
+ - `select`: match on string values
219
+ - `selectordinal`: ordinal plural categories (`one`, `two`, `few`, `other`)
210
220
  - `number`: `decimal`, `percent`, `integer`, `currency`, `compact`, `compactLong`
211
221
  - `date`: `short`, `medium`, `long`, `full`
212
222
  - `time`: `short`, `medium`, `long`, `full`
@@ -370,6 +380,283 @@ function Dashboard() {
370
380
 
371
381
  ---
372
382
 
383
+ ## Custom Formatter Registry
384
+
385
+ Register custom ICU-style formatters for domain-specific formatting:
386
+
387
+ ```typescript
388
+ import { registerFormatter, clearFormatters, it, setLocale } from 'inline-i18n-multi'
389
+
390
+ setLocale('en')
391
+
392
+ // Register a phone number formatter
393
+ registerFormatter('phone', (value, locale, style?) => {
394
+ const s = String(value)
395
+ if (locale === 'ko') return `${s.slice(0, 3)}-${s.slice(3, 7)}-${s.slice(7)}`
396
+ return `(${s.slice(0, 3)}) ${s.slice(3, 6)}-${s.slice(6)}`
397
+ })
398
+
399
+ // Use in translations
400
+ it({
401
+ en: 'Call {num, phone}',
402
+ ko: '전화: {num, phone}'
403
+ }, { num: '2125551234' })
404
+ // → "Call (212) 555-1234"
405
+
406
+ // Register a formatter with style support
407
+ registerFormatter('mask', (value, locale, style?) => {
408
+ const s = String(value)
409
+ if (style === 'email') {
410
+ const [user, domain] = s.split('@')
411
+ return `${user[0]}***@${domain}`
412
+ }
413
+ return s.slice(0, 2) + '***' + s.slice(-2)
414
+ })
415
+
416
+ it({ en: 'Email: {email, mask, email}' }, { email: 'john@example.com' })
417
+ // → "Email: j***@example.com"
418
+
419
+ // Clear all custom formatters
420
+ clearFormatters()
421
+ ```
422
+
423
+ Reserved names (`plural`, `select`, `selectordinal`, `number`, `date`, `time`, `relativeTime`, `list`, `currency`) cannot be used as custom formatter names and will throw an error.
424
+
425
+ ---
426
+
427
+ ## Interpolation Guards
428
+
429
+ Handle missing interpolation variables gracefully with a custom handler:
430
+
431
+ ```typescript
432
+ import { configure, it, setLocale } from 'inline-i18n-multi'
433
+
434
+ setLocale('en')
435
+
436
+ // Configure a missing variable handler
437
+ configure({
438
+ missingVarHandler: (varName, locale) => {
439
+ console.warn(`Missing variable "${varName}" for locale "${locale}"`)
440
+ return `[${varName}]`
441
+ }
442
+ })
443
+
444
+ // When a variable is missing, the handler is called instead of leaving {varName}
445
+ it({ en: 'Hello, {name}!' })
446
+ // logs: Missing variable "name" for locale "en"
447
+ // → "Hello, [name]!"
448
+
449
+ // Works with ICU patterns too
450
+ it({ en: '{count, plural, one {# item} other {# items}}' })
451
+ // logs: Missing variable "count" for locale "en"
452
+ // → "{count}"
453
+
454
+ // Without a handler, missing variables are left as-is: {varName}
455
+ ```
456
+
457
+ ---
458
+
459
+ ## Locale Detection
460
+
461
+ Auto-detect the user's locale from multiple sources:
462
+
463
+ ```typescript
464
+ import { detectLocale, setLocale } from 'inline-i18n-multi'
465
+
466
+ // Basic detection from browser navigator
467
+ const locale = detectLocale({
468
+ supportedLocales: ['en', 'ko', 'ja'],
469
+ defaultLocale: 'en',
470
+ })
471
+ setLocale(locale)
472
+
473
+ // Multiple sources in priority order
474
+ const detected = detectLocale({
475
+ supportedLocales: ['en', 'ko', 'ja'],
476
+ defaultLocale: 'en',
477
+ sources: ['cookie', 'url', 'navigator'],
478
+ cookieName: 'NEXT_LOCALE', // default
479
+ })
480
+
481
+ // Server-side detection from Accept-Language header
482
+ const ssrLocale = detectLocale({
483
+ supportedLocales: ['en', 'ko', 'ja'],
484
+ defaultLocale: 'en',
485
+ sources: ['header'],
486
+ headerValue: 'ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7',
487
+ })
488
+ // → "ko"
489
+
490
+ // BCP 47 parent matching (en-US matches en)
491
+ const matched = detectLocale({
492
+ supportedLocales: ['en', 'ko'],
493
+ defaultLocale: 'en',
494
+ sources: ['navigator'],
495
+ })
496
+ // Browser reports "en-US" → matches "en"
497
+ ```
498
+
499
+ **Detection sources:**
500
+
501
+ | Source | Description |
502
+ |--------|-------------|
503
+ | `navigator` | Browser `navigator.languages` / `navigator.language` |
504
+ | `cookie` | Reads locale from `document.cookie` (configurable name) |
505
+ | `url` | First path segment (e.g., `/ko/about` matches `ko`) |
506
+ | `header` | Parses `Accept-Language` header value (for SSR) |
507
+
508
+ Sources are tried in order; the first match wins. If no source matches, `defaultLocale` is returned.
509
+
510
+ ---
511
+
512
+ ## Selectordinal
513
+
514
+ Ordinal plural formatting for ranking and ordering (e.g., 1st, 2nd, 3rd):
515
+
516
+ ```typescript
517
+ import { it, setLocale } from 'inline-i18n-multi'
518
+
519
+ setLocale('en')
520
+
521
+ // Ordinal suffixes
522
+ it({
523
+ en: '{rank, selectordinal, one {#st} two {#nd} few {#rd} other {#th}}'
524
+ }, { rank: 1 }) // → "1st"
525
+
526
+ it({
527
+ en: '{rank, selectordinal, one {#st} two {#nd} few {#rd} other {#th}}'
528
+ }, { rank: 2 }) // → "2nd"
529
+
530
+ it({
531
+ en: '{rank, selectordinal, one {#st} two {#nd} few {#rd} other {#th}}'
532
+ }, { rank: 3 }) // → "3rd"
533
+
534
+ it({
535
+ en: '{rank, selectordinal, one {#st} two {#nd} few {#rd} other {#th}}'
536
+ }, { rank: 4 }) // → "4th"
537
+
538
+ // Handles English irregulars correctly
539
+ it({
540
+ en: '{rank, selectordinal, one {#st} two {#nd} few {#rd} other {#th}}'
541
+ }, { rank: 11 }) // → "11th" (not "11st")
542
+
543
+ it({
544
+ en: '{rank, selectordinal, one {#st} two {#nd} few {#rd} other {#th}}'
545
+ }, { rank: 21 }) // → "21st"
546
+
547
+ // Combined with text
548
+ it({
549
+ en: 'You finished {rank, selectordinal, one {#st} two {#nd} few {#rd} other {#th}} place!'
550
+ }, { rank: 3 }) // → "You finished 3rd place!"
551
+ ```
552
+
553
+ Uses `Intl.PluralRules` with `{ type: 'ordinal' }` for locale-aware ordinal categories.
554
+
555
+ ---
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
+
373
660
  ## Configuration
374
661
 
375
662
  Configure global settings for fallback behavior and warnings:
@@ -455,12 +742,27 @@ Available helpers:
455
742
 
456
743
  | Function | Description |
457
744
  |----------|-------------|
458
- | `configure(options)` | Configure global settings (fallback, warnings, debug) |
745
+ | `configure(options)` | Configure global settings (fallback, warnings, debug, missingVarHandler, icuCacheSize, persistLocale) |
459
746
  | `getConfig()` | Get current configuration |
460
747
  | `resetConfig()` | Reset configuration to defaults |
461
748
  | `loadAsync(locale, namespace?)` | Asynchronously load dictionary using configured loader |
462
749
  | `isLoaded(locale, namespace?)` | Check if dictionary has been loaded |
463
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) |
753
+
754
+ ### Custom Formatters
755
+
756
+ | Function | Description |
757
+ |----------|-------------|
758
+ | `registerFormatter(name, formatter)` | Register a custom ICU-style formatter |
759
+ | `clearFormatters()` | Clear all custom formatters |
760
+
761
+ ### Locale Detection
762
+
763
+ | Function | Description |
764
+ |----------|-------------|
765
+ | `detectLocale(options)` | Auto-detect user's locale from multiple sources |
464
766
 
465
767
  ### React Hooks & Components
466
768
 
@@ -486,6 +788,18 @@ interface Config {
486
788
  onMissingTranslation?: WarningHandler
487
789
  debugMode?: boolean | DebugModeOptions
488
790
  loader?: (locale: Locale, namespace: string) => Promise<Record<string, unknown>>
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
489
803
  }
490
804
 
491
805
  interface DebugModeOptions {
@@ -505,6 +819,23 @@ interface TranslationWarning {
505
819
 
506
820
  type WarningHandler = (warning: TranslationWarning) => void
507
821
 
822
+ type CustomFormatter = (value: unknown, locale: string, style?: string) => string
823
+
824
+ type DetectSource = 'navigator' | 'cookie' | 'url' | 'header'
825
+
826
+ interface DetectLocaleOptions {
827
+ /** Locales your app supports */
828
+ supportedLocales: Locale[]
829
+ /** Fallback when no source matches */
830
+ defaultLocale: Locale
831
+ /** Detection sources in priority order (default: ['navigator']) */
832
+ sources?: DetectSource[]
833
+ /** Cookie name to read (default: 'NEXT_LOCALE') */
834
+ cookieName?: string
835
+ /** Accept-Language header value (for SSR) */
836
+ headerValue?: string
837
+ }
838
+
508
839
  interface RichTextSegment {
509
840
  type: 'text' | 'component'
510
841
  content: string
@@ -564,30 +895,6 @@ npm install inline-i18n-multi-next
564
895
 
565
896
  ---
566
897
 
567
- ## Build-Time Optimization
568
-
569
- ### Babel Plugin
570
-
571
- Transform `it()` calls at build time for better performance. Extracts translations for static analysis and enables dead code elimination for unused locales.
572
-
573
- ```bash
574
- npm install -D @inline-i18n-multi/babel-plugin
575
- ```
576
-
577
- [View Babel plugin →](https://www.npmjs.com/package/@inline-i18n-multi/babel-plugin)
578
-
579
- ### SWC Plugin
580
-
581
- SWC plugin for Next.js 13+ projects. Faster than Babel with the same optimization benefits. Configure in `next.config.js` under `experimental.swcPlugins`.
582
-
583
- ```bash
584
- npm install -D @inline-i18n-multi/swc-plugin
585
- ```
586
-
587
- [View SWC plugin →](https://www.npmjs.com/package/@inline-i18n-multi/swc-plugin)
588
-
589
- ---
590
-
591
898
  ## Developer Tools
592
899
 
593
900
  ### CLI
@@ -614,7 +921,6 @@ npm install -D @inline-i18n-multi/cli
614
921
  **Please read the [full documentation on GitHub](https://github.com/exiivy98/inline-i18n-multi)** for:
615
922
  - Complete API reference
616
923
  - Framework integrations (React, Next.js)
617
- - Build-time optimization
618
924
  - CLI tools
619
925
  - Best practices and examples
620
926
 
package/dist/index.d.mts CHANGED
@@ -63,6 +63,19 @@ interface Config {
63
63
  debugMode?: boolean | DebugModeOptions;
64
64
  /** Async loader function for lazy loading dictionaries */
65
65
  loader?: (locale: Locale, namespace: string) => Promise<Record<string, unknown>>;
66
+ /** Custom handler for missing interpolation variables (v0.6.0) */
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
+ };
66
79
  }
67
80
 
68
81
  /**
@@ -81,12 +94,16 @@ declare function it(translations: Translations, vars?: TranslationVars): string;
81
94
 
82
95
  declare function setLocale(locale: Locale): void;
83
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;
84
102
 
85
103
  /**
86
- * Runtime lookup function for plugin-transformed code.
87
- * This is called by code that has been processed by @inline-i18n-multi/babel-plugin
88
- * or @inline-i18n-multi/swc-plugin.
104
+ * Runtime lookup function for build-tool-transformed code.
89
105
  *
106
+ * @deprecated Will be removed in v1.0.0
90
107
  * @param _hash - Content hash (for caching/debugging, unused at runtime)
91
108
  * @param translations - Translation map with locale keys
92
109
  * @param vars - Variables for interpolation
@@ -211,7 +228,7 @@ declare function getDictionary(locale: Locale, namespace?: string): Dictionary |
211
228
  */
212
229
  declare function getLoadedNamespaces(): string[];
213
230
 
214
- type FullConfig = Required<Omit<Config, 'loader'>> & Pick<Config, 'loader'>;
231
+ type FullConfig = Required<Omit<Config, 'loader' | 'missingVarHandler' | 'persistLocale'>> & Pick<Config, 'loader' | 'missingVarHandler' | 'persistLocale'>;
215
232
  /**
216
233
  * Configure inline-i18n-multi settings
217
234
  *
@@ -232,6 +249,52 @@ declare function getConfig(): FullConfig;
232
249
  */
233
250
  declare function resetConfig(): void;
234
251
 
252
+ /**
253
+ * Clear the ICU message AST cache
254
+ */
255
+ declare function clearICUCache(): void;
256
+ type CustomFormatter = (value: unknown, locale: string, style?: string) => string;
257
+ /**
258
+ * Register a custom formatter
259
+ *
260
+ * @example
261
+ * registerFormatter('phone', (value, locale, style?) => {
262
+ * const s = String(value)
263
+ * return `(${s.slice(0,3)}) ${s.slice(3,6)}-${s.slice(6)}`
264
+ * })
265
+ */
266
+ declare function registerFormatter(name: string, formatter: CustomFormatter): void;
267
+ /**
268
+ * Clear all custom formatters
269
+ */
270
+ declare function clearFormatters(): void;
271
+
272
+ type DetectSource = 'navigator' | 'cookie' | 'url' | 'header';
273
+ interface DetectLocaleOptions {
274
+ /** Locales your app supports */
275
+ supportedLocales: Locale[];
276
+ /** Fallback when no source matches */
277
+ defaultLocale: Locale;
278
+ /** Detection sources in priority order (default: ['navigator']) */
279
+ sources?: DetectSource[];
280
+ /** Cookie name to read (default: 'NEXT_LOCALE') */
281
+ cookieName?: string;
282
+ /** Accept-Language header value (for SSR) */
283
+ headerValue?: string;
284
+ }
285
+ /**
286
+ * Auto-detect the user's locale from multiple sources
287
+ *
288
+ * @example
289
+ * const locale = detectLocale({
290
+ * supportedLocales: ['en', 'ko', 'ja'],
291
+ * defaultLocale: 'en',
292
+ * sources: ['cookie', 'navigator'],
293
+ * cookieName: 'NEXT_LOCALE',
294
+ * })
295
+ */
296
+ declare function detectLocale(options: DetectLocaleOptions): Locale;
297
+
235
298
  /**
236
299
  * Rich Text segment types
237
300
  */
@@ -260,4 +323,4 @@ interface RichTextSegment {
260
323
  */
261
324
  declare function parseRichText(template: string, componentNames: string[]): RichTextSegment[];
262
325
 
263
- export { type Config, type DebugModeOptions, type Dictionaries, type Dictionary, type Locale, type PluralRules, type RichTextSegment, type TranslationVars, type TranslationWarning, type Translations, type WarningHandler, __i18n_lookup, clearDictionaries, configure, 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, 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
@@ -63,6 +63,19 @@ interface Config {
63
63
  debugMode?: boolean | DebugModeOptions;
64
64
  /** Async loader function for lazy loading dictionaries */
65
65
  loader?: (locale: Locale, namespace: string) => Promise<Record<string, unknown>>;
66
+ /** Custom handler for missing interpolation variables (v0.6.0) */
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
+ };
66
79
  }
67
80
 
68
81
  /**
@@ -81,12 +94,16 @@ declare function it(translations: Translations, vars?: TranslationVars): string;
81
94
 
82
95
  declare function setLocale(locale: Locale): void;
83
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;
84
102
 
85
103
  /**
86
- * Runtime lookup function for plugin-transformed code.
87
- * This is called by code that has been processed by @inline-i18n-multi/babel-plugin
88
- * or @inline-i18n-multi/swc-plugin.
104
+ * Runtime lookup function for build-tool-transformed code.
89
105
  *
106
+ * @deprecated Will be removed in v1.0.0
90
107
  * @param _hash - Content hash (for caching/debugging, unused at runtime)
91
108
  * @param translations - Translation map with locale keys
92
109
  * @param vars - Variables for interpolation
@@ -211,7 +228,7 @@ declare function getDictionary(locale: Locale, namespace?: string): Dictionary |
211
228
  */
212
229
  declare function getLoadedNamespaces(): string[];
213
230
 
214
- type FullConfig = Required<Omit<Config, 'loader'>> & Pick<Config, 'loader'>;
231
+ type FullConfig = Required<Omit<Config, 'loader' | 'missingVarHandler' | 'persistLocale'>> & Pick<Config, 'loader' | 'missingVarHandler' | 'persistLocale'>;
215
232
  /**
216
233
  * Configure inline-i18n-multi settings
217
234
  *
@@ -232,6 +249,52 @@ declare function getConfig(): FullConfig;
232
249
  */
233
250
  declare function resetConfig(): void;
234
251
 
252
+ /**
253
+ * Clear the ICU message AST cache
254
+ */
255
+ declare function clearICUCache(): void;
256
+ type CustomFormatter = (value: unknown, locale: string, style?: string) => string;
257
+ /**
258
+ * Register a custom formatter
259
+ *
260
+ * @example
261
+ * registerFormatter('phone', (value, locale, style?) => {
262
+ * const s = String(value)
263
+ * return `(${s.slice(0,3)}) ${s.slice(3,6)}-${s.slice(6)}`
264
+ * })
265
+ */
266
+ declare function registerFormatter(name: string, formatter: CustomFormatter): void;
267
+ /**
268
+ * Clear all custom formatters
269
+ */
270
+ declare function clearFormatters(): void;
271
+
272
+ type DetectSource = 'navigator' | 'cookie' | 'url' | 'header';
273
+ interface DetectLocaleOptions {
274
+ /** Locales your app supports */
275
+ supportedLocales: Locale[];
276
+ /** Fallback when no source matches */
277
+ defaultLocale: Locale;
278
+ /** Detection sources in priority order (default: ['navigator']) */
279
+ sources?: DetectSource[];
280
+ /** Cookie name to read (default: 'NEXT_LOCALE') */
281
+ cookieName?: string;
282
+ /** Accept-Language header value (for SSR) */
283
+ headerValue?: string;
284
+ }
285
+ /**
286
+ * Auto-detect the user's locale from multiple sources
287
+ *
288
+ * @example
289
+ * const locale = detectLocale({
290
+ * supportedLocales: ['en', 'ko', 'ja'],
291
+ * defaultLocale: 'en',
292
+ * sources: ['cookie', 'navigator'],
293
+ * cookieName: 'NEXT_LOCALE',
294
+ * })
295
+ */
296
+ declare function detectLocale(options: DetectLocaleOptions): Locale;
297
+
235
298
  /**
236
299
  * Rich Text segment types
237
300
  */
@@ -260,4 +323,4 @@ interface RichTextSegment {
260
323
  */
261
324
  declare function parseRichText(template: string, componentNames: string[]): RichTextSegment[];
262
325
 
263
- export { type Config, type DebugModeOptions, type Dictionaries, type Dictionary, type Locale, type PluralRules, type RichTextSegment, type TranslationVars, type TranslationWarning, type Translations, type WarningHandler, __i18n_lookup, clearDictionaries, configure, 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, 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 };