@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
package/CHANGELOG.md
CHANGED
|
@@ -1,57 +1,168 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
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
|
-
|
|
1
|
+
# @chipmobilesdk/rn-i18n
|
|
2
|
+
|
|
3
|
+
## 0.2.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- One diagnostic stream: install a sink with `installSdkSink` from
|
|
8
|
+
`@chipmobilesdk/rn-core` and it receives what every package observes (events,
|
|
9
|
+
failures, warnings) as `SdkDiagnostic`s, redacted. Listeners are notified through
|
|
10
|
+
rn-core, so a listener that throws no longer stops the others nor fails the call that
|
|
11
|
+
notified, and its error is reported rather than swallowed. ([#17](https://github.com/operationd8979/chip-mobile-sdk/pull/17))
|
|
12
|
+
|
|
13
|
+
- rn-ads: a banner's auto-refresh is a new cycle, so its `loaded` and `impression`
|
|
14
|
+
events are no longer deduplicated away; the dedupe memory is bounded. A throwing
|
|
15
|
+
status, consent or placement listener is reported as an `internal_error` event.
|
|
16
|
+
- rn-i18n: new `onDiagnostic` config receives every diagnostic (`I18nDiagnostic`,
|
|
17
|
+
with a stable `code`); without it, warnings go to `console.warn` in development
|
|
18
|
+
builds only. The warn-once memory is bounded.
|
|
19
|
+
- rn-chart: now depends on rn-core for its diagnostics.
|
|
20
|
+
- rn-payment: status, entitlement and pending listeners report a throw to the logger
|
|
21
|
+
instead of swallowing it.
|
|
22
|
+
|
|
23
|
+
- The package's errors extend `SdkError` from the new `@chipmobilesdk/rn-core`
|
|
24
|
+
dependency: `isSdkError` recognises them alongside every other package's, and each
|
|
25
|
+
carries `pkg`, `code` and `retryable`. Names and codes are unchanged. ([#17](https://github.com/operationd8979/chip-mobile-sdk/pull/17))
|
|
26
|
+
|
|
27
|
+
- rn-ai and rn-camera: `retryable` is the new name of `recoverable`, which stays as a
|
|
28
|
+
deprecated alias.
|
|
29
|
+
- rn-auth: `retryable` is true for `network-unavailable`. `redact` also removes URLs,
|
|
30
|
+
e-mail addresses and UUIDs.
|
|
31
|
+
- rn-ads: `redact` also removes JWTs and e-mail addresses, and reduces an `AdsError`
|
|
32
|
+
to its code.
|
|
33
|
+
- rn-ai: an error message quoted from the gateway is pattern-redacted.
|
|
34
|
+
- rn-camera: `redact` also removes JWTs, e-mail addresses and UUIDs.
|
|
35
|
+
- rn-theme: `ThemeConfigError` has `code: 'invalid_config'` and `ThemeContrastError`
|
|
36
|
+
`code: 'contrast'` (new `ThemeErrorCode` type).
|
|
37
|
+
- rn-i18n: `I18nConfigError` has `code: 'invalid_config'` and `UnitConversionError`
|
|
38
|
+
`code: 'unit_conversion'` (new `I18nErrorCode` type).
|
|
39
|
+
|
|
40
|
+
- Hooks read through `useSyncExternalStore` (rn-core's `useExternalStore`) and
|
|
41
|
+
re-render only when what they return changes. ([#17](https://github.com/operationd8979/chip-mobile-sdk/pull/17))
|
|
42
|
+
|
|
43
|
+
- rn-auth: `useProfile` and `useAccessTier` no longer re-render for a status change,
|
|
44
|
+
and the provider's context no longer changes on every transition. New
|
|
45
|
+
`useAuthSelector`. `auth.getState()` returns the same frozen object until the state
|
|
46
|
+
changes, instead of a copy per call.
|
|
47
|
+
- rn-payment: `useEntitlement` re-renders only when its own entitlement changes; the
|
|
48
|
+
engine keeps unchanged entitlement objects across syncs and does not notify for a
|
|
49
|
+
sync that changed nothing.
|
|
50
|
+
- rn-ads: `usePlacementState` and `useAdsStatus` read tear-free; `useAdsEvents` keeps
|
|
51
|
+
one subscription when given an inline listener.
|
|
52
|
+
- rn-i18n: `useTranslation` returns the same `t` until the locale changes, and
|
|
53
|
+
`useLocale`'s `setLocale` is stable.
|
|
54
|
+
- rn-ai: new `useAiBehaviorState`, with `client.subscribe` and a stable
|
|
55
|
+
`client.getBehaviorState()`.
|
|
56
|
+
|
|
57
|
+
- Every package's own copy is an rn-core message catalog that an app can translate. ([#17](https://github.com/operationd8979/chip-mobile-sdk/pull/17))
|
|
58
|
+
|
|
59
|
+
- rn-i18n: new `runtimeEntriesFromCatalog(catalog)` registers any SDK catalog in one
|
|
60
|
+
line, converting `{name}` variables to `{{name}}`.
|
|
61
|
+
- rn-ai: new `messageKeyForError(error)` gives the copy for every error code, and
|
|
62
|
+
`aiMessageSet`. The input placeholder default is neutral ("Type a message…"), and
|
|
63
|
+
two keys were added for errors that had none (`ai.error.signIn`, `ai.error.generic`).
|
|
64
|
+
- rn-auth: new `authMessages`, the catalog split into user and developer copy.
|
|
65
|
+
- rn-payment: new `paymentMessages`.
|
|
66
|
+
- rn-chart: summaries, announcements, adjustable-action labels, built-in state text
|
|
67
|
+
and legend hints come from `chartStrings`; pass `strings` to translate them. The
|
|
68
|
+
`accessibility.summaryFormatter` prop, declared before, now replaces the summary.
|
|
69
|
+
|
|
70
|
+
- Formatters come from rn-core's cache instead of being built per call. ([#17](https://github.com/operationd8979/chip-mobile-sdk/pull/17))
|
|
71
|
+
|
|
72
|
+
- rn-notification: resolving a time zone builds one `Intl.DateTimeFormat` per zone
|
|
73
|
+
instead of one per occurrence; expanding 32 series of 32 occurrences went from
|
|
74
|
+
about 230 ms to under 30 ms on Node. Zone validity is memoized.
|
|
75
|
+
- rn-i18n: number, currency and date formatters are cached. A bad option (an unknown
|
|
76
|
+
currency such as `usd1`) goes through the invalid-format policy instead of
|
|
77
|
+
throwing out of a render, and a locale's `defaultCurrency` must be a three-letter
|
|
78
|
+
ISO 4217 code at startup.
|
|
79
|
+
|
|
80
|
+
- One app-lifecycle source, and a startup that needs no extra frame. ([#17](https://github.com/operationd8979/chip-mobile-sdk/pull/17))
|
|
81
|
+
|
|
82
|
+
- rn-core: `appLifecycle()`, a shared, reference-counted `AppState` subscription that
|
|
83
|
+
reports changes only (`active`, `inactive`, `background`), with `onForeground` for a
|
|
84
|
+
return from the background and `createManualLifecycle` in `./testing`.
|
|
85
|
+
- rn-camera, rn-ads and rn-notification hear the lifecycle through it instead of
|
|
86
|
+
subscribing to `AppState` each, so an app holds one native listener. The camera
|
|
87
|
+
controller's core layer no longer imports `react-native`.
|
|
88
|
+
- rn-payment: `syncOnForeground(engine)` and `<PaymentProvider syncOnForeground>` call
|
|
89
|
+
`handleForeground()` on each return from the background. Off by default; calling
|
|
90
|
+
`handleForeground()` yourself works as before.
|
|
91
|
+
- rn-i18n: `i18n.initSync()` resolves the locale before the first render when the
|
|
92
|
+
storage adapter has the new optional `getItemSync`, and returns false otherwise.
|
|
93
|
+
`localeStorageFromKeyValue(port)` builds such an adapter from rn-core's
|
|
94
|
+
`KeyValuePort` (MMKV).
|
|
95
|
+
|
|
96
|
+
### Patch Changes
|
|
97
|
+
|
|
98
|
+
- Updated dependencies ([#17](https://github.com/operationd8979/chip-mobile-sdk/pull/17), [#17](https://github.com/operationd8979/chip-mobile-sdk/pull/17), [#17](https://github.com/operationd8979/chip-mobile-sdk/pull/17)):
|
|
99
|
+
- @chipmobilesdk/rn-core@0.1.0
|
|
100
|
+
|
|
101
|
+
## 0.1.3
|
|
102
|
+
|
|
103
|
+
### Patch Changes
|
|
104
|
+
|
|
105
|
+
- Packaging only; no code change. The package no longer declares `engines.node`: a
|
|
106
|
+
React Native package does not run on Node, so the field only produced install
|
|
107
|
+
warnings in apps on another Node version. rn-i18n's command-line tooling does run
|
|
108
|
+
on Node; its README's compatibility table states the version it needs. ([#14](https://github.com/operationd8979/chip-mobile-sdk/pull/14))
|
|
109
|
+
|
|
110
|
+
## 0.1.2 — 2026-11-01
|
|
111
|
+
|
|
112
|
+
### Fixed
|
|
113
|
+
|
|
114
|
+
- **A throwing locale listener no longer breaks a locale switch.** Listeners
|
|
115
|
+
were notified without isolation, so one that threw skipped every listener
|
|
116
|
+
after it (React subscribers included) and made `setLocale` reject after the
|
|
117
|
+
switch but before the choice was persisted: the app showed one locale and
|
|
118
|
+
stored another. Each listener is now isolated and reported with
|
|
119
|
+
`console.warn`, and a listener unsubscribed by an earlier one during the
|
|
120
|
+
same change is no longer called. No code change is required.
|
|
121
|
+
|
|
122
|
+
## 0.1.1 — 2026-08-01
|
|
123
|
+
|
|
124
|
+
### Changed
|
|
125
|
+
|
|
126
|
+
- The package now ships its agent skill (`skills/`), which consuming apps
|
|
127
|
+
copy in with `scripts/sync-sdk-skills.mjs`. No code change.
|
|
128
|
+
|
|
129
|
+
## 0.1.0 — 2026-06-13
|
|
130
|
+
|
|
131
|
+
Initial release of the reusable mobile i18n and locale library.
|
|
132
|
+
|
|
133
|
+
### Added
|
|
134
|
+
|
|
135
|
+
- `createI18n(config)` with eager configuration validation: duplicate locales,
|
|
136
|
+
unknown/duplicate/cyclic fallback chains, missing fallback resources, and
|
|
137
|
+
missing storage adapter are rejected before any localized content is served.
|
|
138
|
+
- Translation lookup with namespaced nested keys, ordered fallback-chain
|
|
139
|
+
resolution, `{{name}}` interpolation, package-owned pluralization, and a
|
|
140
|
+
deterministic missing-key policy (one console warning per failed lookup path).
|
|
141
|
+
- Runtime locale switching without restart, persisted through an app-injected
|
|
142
|
+
`LocaleStorageAdapter`, with recovery from unsupported persisted values.
|
|
143
|
+
- Device-locale initialization via an injectable provider (default backed by
|
|
144
|
+
Hermes `Intl`), with exact-match and single-language-match selection.
|
|
145
|
+
- Locale-aware formatting: `formatNumber`, `formatDate`, `formatCurrency` (via
|
|
146
|
+
Hermes `Intl`), and package-owned `formatUnit`/`convertUnit` across length,
|
|
147
|
+
mass, volume, and temperature dimensions.
|
|
148
|
+
- Declared runtime-only translation entries that resolve through the same
|
|
149
|
+
pipeline and are protected during synchronization.
|
|
150
|
+
- React bindings: `I18nProvider`, `useTranslation`, `useLocale`.
|
|
151
|
+
- Node-only extraction/synchronization CLI (`@chipmobilesdk/rn-i18n/tooling`):
|
|
152
|
+
regex-pattern source scanning, locale JSON create/add/preserve/remove,
|
|
153
|
+
ambiguous-usage and conflict reporting, malformed-file isolation, typed key
|
|
154
|
+
contract generation, and deterministic output.
|
|
155
|
+
|
|
156
|
+
### Adoption notes
|
|
157
|
+
|
|
158
|
+
- App-owned translations live in the consuming app (commonly
|
|
159
|
+
`src/i18n/locales/<locale>.json`), never inside this package.
|
|
160
|
+
- Host frameworks (`react`, `react-native`) are peer dependencies; this package
|
|
161
|
+
has zero runtime dependencies.
|
|
162
|
+
- No native modules, permissions, network calls, analytics, or tracking are
|
|
163
|
+
introduced; the locale preference stays on-device via the injected adapter.
|
|
164
|
+
|
|
165
|
+
### Compatibility
|
|
166
|
+
|
|
167
|
+
React `19.x`, React Native `0.85+` (Hermes), TypeScript `5.8+`, Node `>=22.11.0`
|
|
168
|
+
for tooling. Android and iOS, with no native code.
|