@chipmobilesdk/rn-i18n 0.1.2 → 0.2.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/CHANGELOG.md +168 -57
- package/README.md +277 -218
- package/package.json +49 -49
- package/skills/sdk-rn-i18n/SKILL.md +65 -62
- package/src/config/catalog.ts +25 -0
- package/src/config/diagnostics.ts +68 -0
- package/src/config/errors.ts +28 -0
- package/src/config/types.ts +150 -152
- package/src/config/validateConfig.ts +161 -174
- package/src/format/currency.ts +34 -27
- package/src/format/date.ts +32 -26
- package/src/format/invalid.ts +22 -16
- package/src/format/number.ts +30 -25
- package/src/format/units.ts +139 -151
- package/src/i18n.ts +231 -222
- package/src/index.ts +58 -50
- package/src/locale/activeLocale.ts +42 -45
- package/src/locale/deviceLocale.ts +50 -54
- package/src/locale/keyValueStorage.ts +27 -0
- package/src/locale/persistence.ts +59 -37
- package/src/react/I18nProvider.tsx +31 -35
- package/src/react/hooks.ts +66 -61
- package/src/tooling/cli.ts +76 -78
- package/src/tooling/generateKeys.ts +62 -68
- package/src/tooling/index.ts +27 -32
- package/src/tooling/report.ts +109 -117
- package/src/tooling/runner.ts +111 -126
- package/src/tooling/scan.ts +193 -210
- package/src/tooling/sync.ts +193 -198
- package/src/tooling/types.ts +119 -119
- package/src/translation/interpolate.ts +23 -23
- package/src/translation/plurals.ts +62 -69
- package/src/translation/resolver.ts +161 -146
- package/src/translation/runtimeKeys.ts +27 -27
|
@@ -1,62 +1,65 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: sdk-rn-i18n
|
|
3
|
-
description: "Localization via @chipmobilesdk/rn-i18n: createI18n, useTranslation, useLocale, locale persistence, unit formatting, and the extraction/sync CLI. Use when adding translated strings, switching locale, formatting units, or syncing translation keys."
|
|
4
|
-
metadata:
|
|
5
|
-
package: "@chipmobilesdk/rn-i18n"
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
-
|
|
19
|
-
-
|
|
20
|
-
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
- `
|
|
39
|
-
- `
|
|
40
|
-
- `
|
|
41
|
-
- `
|
|
42
|
-
- `
|
|
43
|
-
- `
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
`
|
|
48
|
-
|
|
49
|
-
`
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
|
60
|
-
|
|
61
|
-
|
|
|
62
|
-
|
|
|
1
|
+
---
|
|
2
|
+
name: sdk-rn-i18n
|
|
3
|
+
description: "Localization via @chipmobilesdk/rn-i18n: createI18n, useTranslation, useLocale, locale persistence, unit formatting, and the extraction/sync CLI. Use when adding translated strings, switching locale, formatting units, or syncing translation keys."
|
|
4
|
+
metadata:
|
|
5
|
+
package: "@chipmobilesdk/rn-i18n"
|
|
6
|
+
user-invocable: true
|
|
7
|
+
disable-model-invocation: false
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# @chipmobilesdk/rn-i18n
|
|
11
|
+
|
|
12
|
+
Localization with device-locale detection, persisted locale choice, typed translation
|
|
13
|
+
access, unit/number formatting, and a CLI that extracts and synchronizes keys.
|
|
14
|
+
|
|
15
|
+
## Use this when
|
|
16
|
+
|
|
17
|
+
- Adding or changing any user-facing string
|
|
18
|
+
- Reading or switching the active locale
|
|
19
|
+
- Formatting numbers, dates or units for a locale
|
|
20
|
+
- Translation keys are missing, stale, or out of sync across locale files
|
|
21
|
+
|
|
22
|
+
## Never hardcode a user-facing string
|
|
23
|
+
|
|
24
|
+
Every string rendered to a user goes through `useTranslation`. A literal in a component
|
|
25
|
+
is a defect — it cannot be translated and will not appear in extraction output.
|
|
26
|
+
|
|
27
|
+
## Keys are generated, not hand-maintained
|
|
28
|
+
|
|
29
|
+
Do not hand-edit locale JSON to add a key. Run the extraction/sync CLI so every locale
|
|
30
|
+
file stays aligned. The monorepo exposes it as `npm run i18n:sync`. See
|
|
31
|
+
`## Extraction & synchronization CLI`.
|
|
32
|
+
|
|
33
|
+
## Public API
|
|
34
|
+
|
|
35
|
+
Runtime:
|
|
36
|
+
|
|
37
|
+
- `createI18n(...)` → `I18n`
|
|
38
|
+
- `I18nProvider` (+ `I18nProviderProps`)
|
|
39
|
+
- `useTranslation()` → `UseTranslationResult`
|
|
40
|
+
- `useLocale()` → `UseLocaleResult`
|
|
41
|
+
- `defaultDeviceLocaleProvider` — device locale detection
|
|
42
|
+
- `LOCALE_STORAGE_KEY` — where the chosen locale persists
|
|
43
|
+
- `i18n.initSync()` — resolve the locale before the first render when storage reads
|
|
44
|
+
synchronously; `localeStorageFromKeyValue(port)` makes such storage from an rn-core
|
|
45
|
+
key-value port (MMKV)
|
|
46
|
+
- `I18nConfigError` — thrown on invalid configuration at startup; an rn-core SDK error with an
|
|
47
|
+
`I18nErrorCode`
|
|
48
|
+
|
|
49
|
+
Types: `I18n`, `UnitFormatOptions`, `I18nProviderProps`, `UseLocaleResult`,
|
|
50
|
+
`UseTranslationResult`
|
|
51
|
+
|
|
52
|
+
`I18nConfigError` throws at startup by design — a misconfigured i18n setup should fail
|
|
53
|
+
loudly, not silently render keys.
|
|
54
|
+
|
|
55
|
+
## Where the detail lives
|
|
56
|
+
|
|
57
|
+
Read one section of `node_modules/@chipmobilesdk/rn-i18n/README.md`:
|
|
58
|
+
|
|
59
|
+
| Need | Section |
|
|
60
|
+
|---|---|
|
|
61
|
+
| First integration | `## Installation`, `## Quick start` |
|
|
62
|
+
| Full export list | `## Public API` |
|
|
63
|
+
| Locale file layout, plurals | `## Translations` |
|
|
64
|
+
| Adding/syncing keys | `## Extraction & synchronization CLI` |
|
|
65
|
+
| Version/peer constraints | `## Compatibility` |
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { RuntimeTranslationEntry } from './types';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Runtime entries for a package's message catalog (I18N-13), so an app registers
|
|
5
|
+
* an SDK's copy in one line and translates it like its own:
|
|
6
|
+
*
|
|
7
|
+
* ```ts
|
|
8
|
+
* createI18n({ ...config, runtimeEntries: runtimeEntriesFromCatalog(paymentMessages.user) });
|
|
9
|
+
* ```
|
|
10
|
+
*
|
|
11
|
+
* Catalogs mark variables `{name}`; rn-i18n's are `{{name}}`, so they are
|
|
12
|
+
* converted. `policy: 'add'` lets the sync CLI write missing keys into each locale
|
|
13
|
+
* file with the default text.
|
|
14
|
+
*/
|
|
15
|
+
export function runtimeEntriesFromCatalog(
|
|
16
|
+
catalog: Readonly<Record<string, string>>,
|
|
17
|
+
options: { readonly policy?: 'add' | 'report'; readonly description?: string } = {},
|
|
18
|
+
): RuntimeTranslationEntry[] {
|
|
19
|
+
return Object.entries(catalog).map(([key, text]) => ({
|
|
20
|
+
key,
|
|
21
|
+
defaultText: text.replace(/(?<!\{)\{(\w+)\}(?!\})/g, '{{$1}}'),
|
|
22
|
+
policy: options.policy ?? 'report',
|
|
23
|
+
...(options.description === undefined ? {} : { description: options.description }),
|
|
24
|
+
}));
|
|
25
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createDiagnosticChannel,
|
|
3
|
+
redactPatterns,
|
|
4
|
+
type DiagnosticSeverity,
|
|
5
|
+
} from '@chipmobilesdk/rn-core';
|
|
6
|
+
|
|
7
|
+
/** What rn-i18n reports. Stable: an app may branch on these. */
|
|
8
|
+
export type I18nDiagnosticCode =
|
|
9
|
+
| 'missing_translation'
|
|
10
|
+
| 'fallback_used'
|
|
11
|
+
| 'missing_variable'
|
|
12
|
+
| 'invalid_value'
|
|
13
|
+
| 'invalid_format'
|
|
14
|
+
| 'locale_unsupported'
|
|
15
|
+
| 'locale_read_failed'
|
|
16
|
+
| 'locale_write_failed'
|
|
17
|
+
| 'listener_threw';
|
|
18
|
+
|
|
19
|
+
export interface I18nDiagnostic {
|
|
20
|
+
readonly code: I18nDiagnosticCode;
|
|
21
|
+
/** For people: names the key, locale or variable involved. */
|
|
22
|
+
readonly message: string;
|
|
23
|
+
readonly key?: string;
|
|
24
|
+
readonly locale?: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export type I18nDiagnosticHandler = (diagnostic: I18nDiagnostic) => void;
|
|
28
|
+
|
|
29
|
+
const SEVERITY: Record<I18nDiagnosticCode, DiagnosticSeverity> = {
|
|
30
|
+
missing_translation: 'warn',
|
|
31
|
+
fallback_used: 'info',
|
|
32
|
+
missing_variable: 'warn',
|
|
33
|
+
invalid_value: 'warn',
|
|
34
|
+
invalid_format: 'warn',
|
|
35
|
+
locale_unsupported: 'warn',
|
|
36
|
+
locale_read_failed: 'warn',
|
|
37
|
+
locale_write_failed: 'warn',
|
|
38
|
+
listener_threw: 'error',
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const channel = createDiagnosticChannel<I18nDiagnosticCode>('rn-i18n');
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* One place every diagnostic goes through (I18N-11): the app's SDK sinks always
|
|
45
|
+
* (`installSdkSink` from rn-core), then `onDiagnostic` when the app gave one,
|
|
46
|
+
* otherwise `console.warn` in development builds and tests only.
|
|
47
|
+
*/
|
|
48
|
+
export function createReporter(onDiagnostic?: I18nDiagnosticHandler): I18nDiagnosticHandler {
|
|
49
|
+
return diagnostic => {
|
|
50
|
+
channel.emit(diagnostic.code, SEVERITY[diagnostic.code], {
|
|
51
|
+
...(diagnostic.key === undefined ? {} : { key: diagnostic.key }),
|
|
52
|
+
...(diagnostic.locale === undefined ? {} : { locale: diagnostic.locale }),
|
|
53
|
+
});
|
|
54
|
+
if (onDiagnostic) {
|
|
55
|
+
onDiagnostic(diagnostic);
|
|
56
|
+
} else if (typeof __DEV__ === 'undefined' || __DEV__) {
|
|
57
|
+
console.warn(`[rn-i18n] ${diagnostic.message}`);
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** For the few call sites that run before or outside an i18n instance. */
|
|
63
|
+
export const defaultReporter = createReporter();
|
|
64
|
+
|
|
65
|
+
/** Foreign error text, shaped before it reaches a message. */
|
|
66
|
+
export function describeError(error: unknown): string {
|
|
67
|
+
return redactPatterns(error instanceof Error ? error.message : String(error));
|
|
68
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { SdkError } from '@chipmobilesdk/rn-core';
|
|
2
|
+
|
|
3
|
+
/** The package's error codes. */
|
|
4
|
+
export type I18nErrorCode = 'invalid_config' | 'unit_conversion';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Configuration error listing every detected violation. An `SdkError`
|
|
8
|
+
* (`@chipmobilesdk/rn-core`) with `pkg: 'rn-i18n'`.
|
|
9
|
+
*/
|
|
10
|
+
export class I18nConfigError extends SdkError<I18nErrorCode> {
|
|
11
|
+
readonly issues: readonly string[];
|
|
12
|
+
|
|
13
|
+
constructor(issues: readonly string[]) {
|
|
14
|
+
super('rn-i18n', 'invalid_config', {
|
|
15
|
+
message: `Invalid i18n configuration:\n- ${issues.join('\n- ')}`,
|
|
16
|
+
});
|
|
17
|
+
this.name = 'I18nConfigError';
|
|
18
|
+
this.issues = issues;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** A unit conversion the package cannot perform, such as across dimensions. */
|
|
23
|
+
export class UnitConversionError extends SdkError<I18nErrorCode> {
|
|
24
|
+
constructor(message: string) {
|
|
25
|
+
super('rn-i18n', 'unit_conversion', { message });
|
|
26
|
+
this.name = 'UnitConversionError';
|
|
27
|
+
}
|
|
28
|
+
}
|
package/src/config/types.ts
CHANGED
|
@@ -1,152 +1,150 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Public configuration and contract types for @chipmobilesdk/rn-i18n.
|
|
3
|
-
*
|
|
4
|
-
* The package has
|
|
5
|
-
* built into Hermes (Intl.NumberFormat, Intl.DateTimeFormat), while plural
|
|
6
|
-
* rules and unit conversion are package-owned because Intl.PluralRules and
|
|
7
|
-
* Intl unit-style formatting are not reliably available in Hermes.
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
export type
|
|
13
|
-
|
|
14
|
-
export type
|
|
15
|
-
|
|
16
|
-
export type
|
|
17
|
-
|
|
18
|
-
export type
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
| '
|
|
22
|
-
| '
|
|
23
|
-
| '
|
|
24
|
-
| '
|
|
25
|
-
| '
|
|
26
|
-
| '
|
|
27
|
-
| '
|
|
28
|
-
| '
|
|
29
|
-
| '
|
|
30
|
-
| '
|
|
31
|
-
| '
|
|
32
|
-
| '
|
|
33
|
-
| '
|
|
34
|
-
| '
|
|
35
|
-
| '
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
*
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
export type
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
*
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
export type InvalidFormatPolicy =
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
/**
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
export
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
}
|
|
152
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Public configuration and contract types for @chipmobilesdk/rn-i18n.
|
|
3
|
+
*
|
|
4
|
+
* The package has one runtime dependency, rn-core; formatting uses the Intl APIs
|
|
5
|
+
* built into Hermes (Intl.NumberFormat, Intl.DateTimeFormat), while plural
|
|
6
|
+
* rules and unit conversion are package-owned because Intl.PluralRules and
|
|
7
|
+
* Intl unit-style formatting are not reliably available in Hermes.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { I18nDiagnosticHandler } from './diagnostics';
|
|
11
|
+
|
|
12
|
+
export type LocaleDirection = 'ltr' | 'rtl';
|
|
13
|
+
|
|
14
|
+
export type PluralCategory = 'zero' | 'one' | 'two' | 'few' | 'many' | 'other';
|
|
15
|
+
|
|
16
|
+
export type PluralRule = (count: number) => PluralCategory;
|
|
17
|
+
|
|
18
|
+
export type UnitDimension = 'length' | 'mass' | 'volume' | 'temperature';
|
|
19
|
+
|
|
20
|
+
export type UnitId =
|
|
21
|
+
| 'millimeter'
|
|
22
|
+
| 'centimeter'
|
|
23
|
+
| 'meter'
|
|
24
|
+
| 'kilometer'
|
|
25
|
+
| 'inch'
|
|
26
|
+
| 'foot'
|
|
27
|
+
| 'mile'
|
|
28
|
+
| 'gram'
|
|
29
|
+
| 'kilogram'
|
|
30
|
+
| 'ounce'
|
|
31
|
+
| 'pound'
|
|
32
|
+
| 'milliliter'
|
|
33
|
+
| 'liter'
|
|
34
|
+
| 'gallon'
|
|
35
|
+
| 'celsius'
|
|
36
|
+
| 'fahrenheit'
|
|
37
|
+
| 'kelvin';
|
|
38
|
+
|
|
39
|
+
export interface LocaleConfig {
|
|
40
|
+
/** BCP-47 language-region code, e.g. `vi-VN`, `en-US`, `ja-JP`. */
|
|
41
|
+
code: string;
|
|
42
|
+
displayName: string;
|
|
43
|
+
direction: LocaleDirection;
|
|
44
|
+
/**
|
|
45
|
+
* Ordered locale codes consulted when a key is missing from this locale.
|
|
46
|
+
* Every entry must be another supported locale; cycles, duplicates, and
|
|
47
|
+
* self-references are rejected during setup validation.
|
|
48
|
+
*/
|
|
49
|
+
fallbackChain: string[];
|
|
50
|
+
/** ISO-4217 currency code used when no explicit currency is requested. */
|
|
51
|
+
defaultCurrency: string;
|
|
52
|
+
defaultUnit: UnitId;
|
|
53
|
+
/**
|
|
54
|
+
* Default Intl.DateTimeFormat options for this locale. Restricted to the
|
|
55
|
+
* component options supported by Hermes on both Android and iOS.
|
|
56
|
+
*/
|
|
57
|
+
defaultDateFormat: Intl.DateTimeFormatOptions;
|
|
58
|
+
/** Default Intl.NumberFormat options for this locale. */
|
|
59
|
+
defaultNumberFormat: Intl.NumberFormatOptions;
|
|
60
|
+
/** Optional plural rule override; defaults to the built-in language rule. */
|
|
61
|
+
pluralRule?: PluralRule;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export type TranslationNode = string | { [key: string]: TranslationNode };
|
|
65
|
+
|
|
66
|
+
export type TranslationNamespace = { [key: string]: TranslationNode };
|
|
67
|
+
|
|
68
|
+
/** App-owned translation resources keyed by locale code. */
|
|
69
|
+
export type TranslationResources = { [localeCode: string]: TranslationNamespace };
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* A translation key intentionally resolved at runtime and therefore not
|
|
73
|
+
* discoverable by static source scanning. Declared entries are protected
|
|
74
|
+
* from removal during locale JSON synchronization.
|
|
75
|
+
*/
|
|
76
|
+
export interface RuntimeTranslationEntry {
|
|
77
|
+
key: string;
|
|
78
|
+
/** Template text used when no locale resource provides a value. */
|
|
79
|
+
defaultText: string;
|
|
80
|
+
/**
|
|
81
|
+
* Synchronization policy when the key is missing from a locale file:
|
|
82
|
+
* `add` writes the default text, `report` only lists it. Default: `report`.
|
|
83
|
+
*/
|
|
84
|
+
policy?: 'add' | 'report';
|
|
85
|
+
/** Owning feature note surfaced in the extraction report. */
|
|
86
|
+
description?: string;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export type MissingTranslationPolicy = { mode: 'key' } | { mode: 'placeholder'; text: string };
|
|
90
|
+
|
|
91
|
+
export type InvalidFormatPolicy = { mode: 'placeholder'; text: string } | { mode: 'error' };
|
|
92
|
+
|
|
93
|
+
/** App-injected persistence contract. The package never bundles a backend. */
|
|
94
|
+
export interface LocaleStorageAdapter {
|
|
95
|
+
getItem(key: string): Promise<string | null>;
|
|
96
|
+
setItem(key: string, value: string): Promise<void>;
|
|
97
|
+
removeItem(key: string): Promise<void>;
|
|
98
|
+
/**
|
|
99
|
+
* A synchronous read, for a store that has one (MMKV, rn-core's `KeyValuePort`).
|
|
100
|
+
* With it, `initSync()` resolves the locale before the first render, so the app
|
|
101
|
+
* never paints a frame in the wrong language (PERF-08).
|
|
102
|
+
*/
|
|
103
|
+
getItemSync?(key: string): string | null;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/** Returns the device locale, or undefined when detection is unavailable. */
|
|
107
|
+
export type DeviceLocaleProvider = () => string | undefined;
|
|
108
|
+
|
|
109
|
+
export interface I18nConfig {
|
|
110
|
+
locales: LocaleConfig[];
|
|
111
|
+
/** Recovery locale when persistence or device detection cannot decide. */
|
|
112
|
+
primaryLocale: string;
|
|
113
|
+
resources: TranslationResources;
|
|
114
|
+
runtimeEntries?: RuntimeTranslationEntry[];
|
|
115
|
+
/** Persist the selected locale across launches. Default: true. */
|
|
116
|
+
persistLocale?: boolean;
|
|
117
|
+
/** Required when `persistLocale` is not disabled. */
|
|
118
|
+
storage?: LocaleStorageAdapter;
|
|
119
|
+
/**
|
|
120
|
+
* Receives every diagnostic: missing translations and variables, fallbacks,
|
|
121
|
+
* invalid formats, persistence failures. Defaults to `console.warn` in
|
|
122
|
+
* development builds only. Diagnostics also reach rn-core's SDK sinks.
|
|
123
|
+
*/
|
|
124
|
+
onDiagnostic?: I18nDiagnosticHandler;
|
|
125
|
+
deviceLocale?: DeviceLocaleProvider;
|
|
126
|
+
/** Default: `{ mode: 'key' }`. */
|
|
127
|
+
missingTranslation?: MissingTranslationPolicy;
|
|
128
|
+
/** Default: `{ mode: 'placeholder', text: '—' }`. */
|
|
129
|
+
invalidFormat?: InvalidFormatPolicy;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export type LocaleSelectionSource =
|
|
133
|
+
'persisted' | 'device' | 'languageMatch' | 'primaryFallback' | 'runtimeSwitch';
|
|
134
|
+
|
|
135
|
+
export interface ActiveLocalePreference {
|
|
136
|
+
code: string;
|
|
137
|
+
source: LocaleSelectionSource;
|
|
138
|
+
/** True when an unsupported persisted locale was discarded. */
|
|
139
|
+
recovered: boolean;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export type TranslateVars = Record<string, string | number>;
|
|
143
|
+
|
|
144
|
+
export interface TranslateOptions {
|
|
145
|
+
/** Selects the plural variant and is exposed as the `count` variable. */
|
|
146
|
+
count?: number;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Kept importable from here for compatibility; the errors live in config/errors.ts (I18N-14).
|
|
150
|
+
export { I18nConfigError } from './errors';
|