@chipmobilesdk/rn-i18n 0.1.1 → 0.1.2
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 +12 -0
- package/README.md +32 -32
- package/package.json +1 -1
- package/skills/sdk-rn-i18n/SKILL.md +62 -62
- package/src/locale/activeLocale.ts +11 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,18 @@
|
|
|
3
3
|
All notable changes to `@chipmobilesdk/rn-i18n` are documented here. This project
|
|
4
4
|
follows [Semantic Versioning](https://semver.org/).
|
|
5
5
|
|
|
6
|
+
## 0.1.2 — 2026-11-01
|
|
7
|
+
|
|
8
|
+
### Fixed
|
|
9
|
+
|
|
10
|
+
- **A throwing locale listener no longer breaks a locale switch.** Listeners
|
|
11
|
+
were notified without isolation, so one that threw skipped every listener
|
|
12
|
+
after it (React subscribers included) and made `setLocale` reject after the
|
|
13
|
+
switch but before the choice was persisted: the app showed one locale and
|
|
14
|
+
stored another. Each listener is now isolated and reported with
|
|
15
|
+
`console.warn`, and a listener unsubscribed by an earlier one during the
|
|
16
|
+
same change is no longer called. No code change is required.
|
|
17
|
+
|
|
6
18
|
## 0.1.0 — 2026-06-13
|
|
7
19
|
|
|
8
20
|
Initial release of the reusable mobile i18n and locale library.
|
package/README.md
CHANGED
|
@@ -4,30 +4,30 @@ Reusable localization for ChipMobileSdk-family React Native apps: per-locale
|
|
|
4
4
|
configuration, app-owned namespaced translations, typed keys, interpolation,
|
|
5
5
|
pluralization, fallback chains, runtime locale switching with app-injected
|
|
6
6
|
persistence, device-locale detection, locale-aware number/date/currency/unit
|
|
7
|
-
formatting, and a Node CLI that extracts and synchronizes translation keys.
|
|
8
|
-
|
|
9
|
-
> **License:** `UNLICENSED`. Published publicly for use by the owner's
|
|
10
|
-
> applications; no open-source license is granted.
|
|
7
|
+
formatting, and a Node CLI that extracts and synchronizes translation keys.
|
|
8
|
+
|
|
9
|
+
> **License:** `UNLICENSED`. Published publicly for use by the owner's
|
|
10
|
+
> applications; no open-source license is granted.
|
|
11
11
|
|
|
12
12
|
- **Zero runtime dependencies.** Formatting uses the `Intl` APIs built into
|
|
13
13
|
Hermes; plural rules and unit conversion are package-owned.
|
|
14
|
-
- **No native code.** Storage and (optionally) device-locale detection are
|
|
15
|
-
injected by the consuming app.
|
|
16
|
-
- **Public package.** Published under the `@chipmobilesdk` npm organization.
|
|
17
|
-
- **Version**: `0.1.
|
|
18
|
-
- **Entrypoints**: `@chipmobilesdk/rn-i18n` and the Node-only
|
|
19
|
-
`@chipmobilesdk/rn-i18n/tooling`
|
|
14
|
+
- **No native code.** Storage and (optionally) device-locale detection are
|
|
15
|
+
injected by the consuming app.
|
|
16
|
+
- **Public package.** Published under the `@chipmobilesdk` npm organization.
|
|
17
|
+
- **Version**: `0.1.2`
|
|
18
|
+
- **Entrypoints**: `@chipmobilesdk/rn-i18n` and the Node-only
|
|
19
|
+
`@chipmobilesdk/rn-i18n/tooling`
|
|
20
20
|
|
|
21
21
|
## Installation
|
|
22
22
|
|
|
23
|
-
This package ships TypeScript sources and is consumed through the workspace or
|
|
24
|
-
the public npm registry:
|
|
25
|
-
|
|
26
|
-
```bash
|
|
27
|
-
npm install @chipmobilesdk/rn-i18n
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
Host frameworks are peer dependencies:
|
|
23
|
+
This package ships TypeScript sources and is consumed through the workspace or
|
|
24
|
+
the public npm registry:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npm install @chipmobilesdk/rn-i18n
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Host frameworks are peer dependencies:
|
|
31
31
|
|
|
32
32
|
```jsonc
|
|
33
33
|
// peerDependencies
|
|
@@ -104,12 +104,12 @@ t('cart.items', { count }, { count }); // plural variant by count
|
|
|
104
104
|
| Unit conversion | `i18n.convertUnit`, `convertUnit`, `getUnitSymbol`, `SUPPORTED_UNITS`, `UnitConversionError` |
|
|
105
105
|
| Runtime-only declarations | `i18n.registerRuntimeEntries` |
|
|
106
106
|
| Persistence key | `LOCALE_STORAGE_KEY` |
|
|
107
|
-
| React | `I18nProvider` |
|
|
108
|
-
|
|
109
|
-
Public contract types also include the configuration, locale, translation,
|
|
110
|
-
formatting, unit, provider/adapter, and hook result types exported by
|
|
111
|
-
`src/index.ts`. Do not deep-import package internals. Node-only extraction and
|
|
112
|
-
synchronization APIs must be imported from `@chipmobilesdk/rn-i18n/tooling`.
|
|
107
|
+
| React | `I18nProvider` |
|
|
108
|
+
|
|
109
|
+
Public contract types also include the configuration, locale, translation,
|
|
110
|
+
formatting, unit, provider/adapter, and hook result types exported by
|
|
111
|
+
`src/index.ts`. Do not deep-import package internals. Node-only extraction and
|
|
112
|
+
synchronization APIs must be imported from `@chipmobilesdk/rn-i18n/tooling`.
|
|
113
113
|
|
|
114
114
|
### Storage adapter (required for persistence)
|
|
115
115
|
|
|
@@ -148,9 +148,9 @@ App-owned JSON, organized by locale and namespace; nested dot-path keys,
|
|
|
148
148
|
}
|
|
149
149
|
```
|
|
150
150
|
|
|
151
|
-
Plural categories deliberately come from package-owned rules rather than
|
|
152
|
-
depending on `Intl.PluralRules`, which keeps behavior consistent across the
|
|
153
|
-
supported Hermes environments. Built-ins cover `en` (one/other), `vi`/`ja`
|
|
151
|
+
Plural categories deliberately come from package-owned rules rather than
|
|
152
|
+
depending on `Intl.PluralRules`, which keeps behavior consistent across the
|
|
153
|
+
supported Hermes environments. Built-ins cover `en` (one/other), `vi`/`ja`
|
|
154
154
|
(other-only), and a default `count === 1 -> one` rule; supply
|
|
155
155
|
`LocaleConfig.pluralRule` for richer languages.
|
|
156
156
|
|
|
@@ -209,10 +209,10 @@ locales; `report` only lists them.
|
|
|
209
209
|
npm test # package + demo suites
|
|
210
210
|
npm run typecheck:i18n # tsc -p packages/rn-i18n/tsconfig.json --noEmit
|
|
211
211
|
npm run pack:i18n # npm pack --workspace @chipmobilesdk/rn-i18n --dry-run
|
|
212
|
-
npm run i18n:sync # extraction + synchronization
|
|
213
|
-
```
|
|
214
|
-
|
|
215
|
-
The demo integration lives in `src/screens/I18nDemoScreen.tsx` and uses
|
|
216
|
-
`src/i18n/` for setup, translations, persistence, and generated keys.
|
|
212
|
+
npm run i18n:sync # extraction + synchronization
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
The demo integration lives in `src/screens/I18nDemoScreen.tsx` and uses
|
|
216
|
+
`src/i18n/` for setup, translations, persistence, and generated keys.
|
|
217
217
|
|
|
218
218
|
See [CHANGELOG.md](CHANGELOG.md) for release notes and adoption guidance.
|
package/package.json
CHANGED
|
@@ -1,62 +1,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
|
-
packageVersion: "0.1.0"
|
|
7
|
-
user-invocable: true
|
|
8
|
-
disable-model-invocation: false
|
|
9
|
-
---
|
|
10
|
-
|
|
11
|
-
# @chipmobilesdk/rn-i18n
|
|
12
|
-
|
|
13
|
-
Localization with device-locale detection, persisted locale choice, typed translation
|
|
14
|
-
access, unit/number formatting, and a CLI that extracts and synchronizes keys.
|
|
15
|
-
|
|
16
|
-
## Use this when
|
|
17
|
-
|
|
18
|
-
- Adding or changing any user-facing string
|
|
19
|
-
- Reading or switching the active locale
|
|
20
|
-
- Formatting numbers, dates or units for a locale
|
|
21
|
-
- Translation keys are missing, stale, or out of sync across locale files
|
|
22
|
-
|
|
23
|
-
## Never hardcode a user-facing string
|
|
24
|
-
|
|
25
|
-
Every string rendered to a user goes through `useTranslation`. A literal in a component
|
|
26
|
-
is a defect — it cannot be translated and will not appear in extraction output.
|
|
27
|
-
|
|
28
|
-
## Keys are generated, not hand-maintained
|
|
29
|
-
|
|
30
|
-
Do not hand-edit locale JSON to add a key. Run the extraction/sync CLI so every locale
|
|
31
|
-
file stays aligned. The monorepo exposes it as `npm run i18n:sync`. See
|
|
32
|
-
`## Extraction & synchronization CLI`.
|
|
33
|
-
|
|
34
|
-
## Public API (v0.1.
|
|
35
|
-
|
|
36
|
-
Runtime:
|
|
37
|
-
|
|
38
|
-
- `createI18n(...)` → `I18n`
|
|
39
|
-
- `I18nProvider` (+ `I18nProviderProps`)
|
|
40
|
-
- `useTranslation()` → `UseTranslationResult`
|
|
41
|
-
- `useLocale()` → `UseLocaleResult`
|
|
42
|
-
- `defaultDeviceLocaleProvider` — device locale detection
|
|
43
|
-
- `LOCALE_STORAGE_KEY` — where the chosen locale persists
|
|
44
|
-
- `I18nConfigError` — thrown on invalid configuration at startup
|
|
45
|
-
|
|
46
|
-
Types: `I18n`, `UnitFormatOptions`, `I18nProviderProps`, `UseLocaleResult`,
|
|
47
|
-
`UseTranslationResult`
|
|
48
|
-
|
|
49
|
-
`I18nConfigError` throws at startup by design — a misconfigured i18n setup should fail
|
|
50
|
-
loudly, not silently render keys.
|
|
51
|
-
|
|
52
|
-
## Where the detail lives
|
|
53
|
-
|
|
54
|
-
Read one section of `node_modules/@chipmobilesdk/rn-i18n/README.md`:
|
|
55
|
-
|
|
56
|
-
| Need | Section |
|
|
57
|
-
|---|---|
|
|
58
|
-
| First integration | `## Installation`, `## Quick start` |
|
|
59
|
-
| Full export list | `## Public API` |
|
|
60
|
-
| Locale file layout, plurals | `## Translations` |
|
|
61
|
-
| Adding/syncing keys | `## Extraction & synchronization CLI` |
|
|
62
|
-
| Version/peer constraints | `## Compatibility` |
|
|
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
|
+
packageVersion: "0.1.0"
|
|
7
|
+
user-invocable: true
|
|
8
|
+
disable-model-invocation: false
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# @chipmobilesdk/rn-i18n
|
|
12
|
+
|
|
13
|
+
Localization with device-locale detection, persisted locale choice, typed translation
|
|
14
|
+
access, unit/number formatting, and a CLI that extracts and synchronizes keys.
|
|
15
|
+
|
|
16
|
+
## Use this when
|
|
17
|
+
|
|
18
|
+
- Adding or changing any user-facing string
|
|
19
|
+
- Reading or switching the active locale
|
|
20
|
+
- Formatting numbers, dates or units for a locale
|
|
21
|
+
- Translation keys are missing, stale, or out of sync across locale files
|
|
22
|
+
|
|
23
|
+
## Never hardcode a user-facing string
|
|
24
|
+
|
|
25
|
+
Every string rendered to a user goes through `useTranslation`. A literal in a component
|
|
26
|
+
is a defect — it cannot be translated and will not appear in extraction output.
|
|
27
|
+
|
|
28
|
+
## Keys are generated, not hand-maintained
|
|
29
|
+
|
|
30
|
+
Do not hand-edit locale JSON to add a key. Run the extraction/sync CLI so every locale
|
|
31
|
+
file stays aligned. The monorepo exposes it as `npm run i18n:sync`. See
|
|
32
|
+
`## Extraction & synchronization CLI`.
|
|
33
|
+
|
|
34
|
+
## Public API (v0.1.2)
|
|
35
|
+
|
|
36
|
+
Runtime:
|
|
37
|
+
|
|
38
|
+
- `createI18n(...)` → `I18n`
|
|
39
|
+
- `I18nProvider` (+ `I18nProviderProps`)
|
|
40
|
+
- `useTranslation()` → `UseTranslationResult`
|
|
41
|
+
- `useLocale()` → `UseLocaleResult`
|
|
42
|
+
- `defaultDeviceLocaleProvider` — device locale detection
|
|
43
|
+
- `LOCALE_STORAGE_KEY` — where the chosen locale persists
|
|
44
|
+
- `I18nConfigError` — thrown on invalid configuration at startup
|
|
45
|
+
|
|
46
|
+
Types: `I18n`, `UnitFormatOptions`, `I18nProviderProps`, `UseLocaleResult`,
|
|
47
|
+
`UseTranslationResult`
|
|
48
|
+
|
|
49
|
+
`I18nConfigError` throws at startup by design — a misconfigured i18n setup should fail
|
|
50
|
+
loudly, not silently render keys.
|
|
51
|
+
|
|
52
|
+
## Where the detail lives
|
|
53
|
+
|
|
54
|
+
Read one section of `node_modules/@chipmobilesdk/rn-i18n/README.md`:
|
|
55
|
+
|
|
56
|
+
| Need | Section |
|
|
57
|
+
|---|---|
|
|
58
|
+
| First integration | `## Installation`, `## Quick start` |
|
|
59
|
+
| Full export list | `## Public API` |
|
|
60
|
+
| Locale file layout, plurals | `## Translations` |
|
|
61
|
+
| Adding/syncing keys | `## Extraction & synchronization CLI` |
|
|
62
|
+
| Version/peer constraints | `## Compatibility` |
|
|
@@ -20,8 +20,18 @@ export function createActiveLocaleStore(
|
|
|
20
20
|
set(next) {
|
|
21
21
|
preference = next;
|
|
22
22
|
version += 1;
|
|
23
|
+
// Snapshot, and isolate each listener (CORE-03). One that threw used to
|
|
24
|
+
// skip every listener after it — useSyncExternalStore subscribers
|
|
25
|
+
// included — and made setLocale reject after the switch but before the
|
|
26
|
+
// choice was persisted, so the app showed one locale and stored another.
|
|
23
27
|
for (const listener of [...listeners]) {
|
|
24
|
-
listener
|
|
28
|
+
// Unsubscribed by an earlier listener during this notification.
|
|
29
|
+
if (!listeners.has(listener)) continue;
|
|
30
|
+
try {
|
|
31
|
+
listener();
|
|
32
|
+
} catch (error) {
|
|
33
|
+
console.warn('[rn-i18n] A locale listener threw; the locale change still applied.', error);
|
|
34
|
+
}
|
|
25
35
|
}
|
|
26
36
|
},
|
|
27
37
|
subscribe(listener) {
|