@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 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.0`
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,6 +1,6 @@
1
1
  {
2
2
  "name": "@chipmobilesdk/rn-i18n",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "private": false,
5
5
  "license": "UNLICENSED",
6
6
  "main": "src/index.ts",
@@ -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.0)
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) {