@owlmeans/i18n 0.1.18-rc.2 → 0.1.18-rc.20
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 +2 -2
- package/agent-meta/manifest.json +2 -2
- package/agent-meta/skills/i18n/SKILL.md +42 -3
- package/agent-meta/skills/localization/SKILL.md +39 -11
- package/build/advertise.d.ts +2 -0
- package/build/advertise.d.ts.map +1 -0
- package/build/advertise.js +12 -0
- package/build/advertise.js.map +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@ Multi-level translation resource registration for OwlMeans applications.
|
|
|
11
11
|
## Installation
|
|
12
12
|
|
|
13
13
|
```bash
|
|
14
|
-
bun add @owlmeans/i18n
|
|
14
|
+
bun add @owlmeans/i18n@^0.1.18-rc.19
|
|
15
15
|
```
|
|
16
16
|
|
|
17
17
|
## Usage
|
|
@@ -62,7 +62,7 @@ This package ships embedded agent skills under `agent-meta/`. After installing y
|
|
|
62
62
|
your project's skill store (`.agents/skills/`):
|
|
63
63
|
|
|
64
64
|
```sh
|
|
65
|
-
npx @owlmeans/agent-skills
|
|
65
|
+
npx @owlmeans/agent-skills@^0.1.18-rc.24
|
|
66
66
|
```
|
|
67
67
|
|
|
68
68
|
The embedded files are version-matched to this package release. Do not edit them
|
package/agent-meta/manifest.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 2,
|
|
3
3
|
"package": "@owlmeans/i18n",
|
|
4
|
-
"version": "0.1.18-rc.
|
|
5
|
-
"generatedAt": "2026-
|
|
4
|
+
"version": "0.1.18-rc.20",
|
|
5
|
+
"generatedAt": "2026-09-15T12:59:01.020Z",
|
|
6
6
|
"canonicalRepo": "https://github.com/owlmeans/common",
|
|
7
7
|
"entries": [
|
|
8
8
|
{
|
|
@@ -8,7 +8,7 @@ user-invocable: false
|
|
|
8
8
|
# @owlmeans/i18n
|
|
9
9
|
|
|
10
10
|
**Layer:** Core (no runtime deps)
|
|
11
|
-
**Install:** `"@owlmeans/i18n": "^0.1.18-rc.
|
|
11
|
+
**Install:** `"@owlmeans/i18n": "^0.1.18-rc.20"` in `dependencies`
|
|
12
12
|
|
|
13
13
|
## Purpose
|
|
14
14
|
|
|
@@ -21,11 +21,27 @@ Global registration store that packages write into at import time. React clients
|
|
|
21
21
|
| `addI18nLib(lng, resource, data, opts?)` | Register library-owned strings (ns defaults to `'lib'`) |
|
|
22
22
|
| `addI18nApp(lng, resource, data, opts?)` | Register app-owned strings (ns defaults to resource name) |
|
|
23
23
|
| `initI18nResource(lng, resource, ns?)` | Drain a registered bundle for a language (called by client-i18n) |
|
|
24
|
-
| `SUPPORTED_LNGS` | `['en','pl','ru','be','uk','es','de']` — the canonical language set |
|
|
24
|
+
| `SUPPORTED_LNGS` / `SupportedLng` | `['en','pl','ru','be','uk','es','de']` — the canonical language set, and its union type |
|
|
25
25
|
| `DEFAULT_LNG` | `'en'` |
|
|
26
26
|
| `LIB_NAMESPACE` | `'lib'` |
|
|
27
|
+
| `DEFAULT_NAMESPACE` | `'translation'` — i18next's own default namespace, used whenever a lookup names none and `I18nConfig.defaultNs` is unset |
|
|
27
28
|
| `I18nTier` | `Library \| App` — enum used internally |
|
|
28
29
|
| `I18nConfig` | `{ defaultLng?, defaultNs?, fallbackLng?, supportedLngs? }` |
|
|
30
|
+
| `I18nResourceOptions` | `{ ns?, priority? }` — the `opts` every `add*` takes |
|
|
31
|
+
| `MAX_PRIORITY` | `Number.MAX_SAFE_INTEGER` — the value substituted for an unset `priority`, which is what makes an unset one sort last |
|
|
32
|
+
|
|
33
|
+
`opts` also accepts a bare string, which is read as `ns`: `addI18nLib('en', 'wallet', walletEn, 'did')`.
|
|
34
|
+
|
|
35
|
+
## Subpath Exports
|
|
36
|
+
|
|
37
|
+
- `./utils` — the store itself: `_OwlMeansI18nStorage` (`{ data }`, keyed ns → resource → language),
|
|
38
|
+
`ensureStructure(lng, resource, ns?)` which creates and returns one slot, and `tierCost`, the
|
|
39
|
+
`I18nTier` → number map the sort is written against.
|
|
40
|
+
|
|
41
|
+
Reach for `./utils` only to work around the drain-once rule below: assigning
|
|
42
|
+
`_OwlMeansI18nStorage.data = {}` empties every slot including its `lngInitialized` marks, so a
|
|
43
|
+
suite can register and drain the same resource repeatedly. This package's own tests do exactly
|
|
44
|
+
that between cases. Application and library code registers through `addI18nLib` / `addI18nApp`.
|
|
29
45
|
|
|
30
46
|
## Tiers
|
|
31
47
|
|
|
@@ -34,7 +50,30 @@ Global registration store that packages write into at import time. React clients
|
|
|
34
50
|
| Library | `addI18nLib` | `'lib'` | Any `@owlmeans/*` package |
|
|
35
51
|
| App | `addI18nApp` | resource name | Project-specific app / shared project package |
|
|
36
52
|
|
|
37
|
-
App-tier strings deep-merge **over** Library-tier strings
|
|
53
|
+
App-tier strings deep-merge **over** Library-tier strings at resolution time — but only for the
|
|
54
|
+
same **(ns, resource, language)** slot, because that triple is the address the store is keyed on
|
|
55
|
+
and the only thing `initI18nResource` drains. The default namespaces differ (`'lib'` for
|
|
56
|
+
`addI18nLib`, the resource name for `addI18nApp`), so overriding a library bundle means saying so:
|
|
57
|
+
|
|
58
|
+
```typescript
|
|
59
|
+
import { addI18nApp, LIB_NAMESPACE } from '@owlmeans/i18n'
|
|
60
|
+
|
|
61
|
+
addI18nApp('en', 'errors', myErrors, { ns: LIB_NAMESPACE })
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Without `{ ns: LIB_NAMESPACE }` the app bundle lands in namespace `errors` while the library's sits
|
|
65
|
+
in `lib`. Nothing errors, nothing merges, and the library strings keep rendering.
|
|
66
|
+
|
|
67
|
+
Within one tier the order is `priority`, ascending, and every bundle is merged over the one before
|
|
68
|
+
it — so the **last** applied wins. A registration that states no `priority` sorts last and
|
|
69
|
+
therefore beats every one that states a number: `priority` lowers a bundle in the stack rather than
|
|
70
|
+
raising it. Leave it unset unless one library must lose to another.
|
|
71
|
+
|
|
72
|
+
**A bundle only reaches i18next if it was registered before the first draw for its language.**
|
|
73
|
+
`initI18nResource` marks the (ns, resource, language) slot drained and answers `null` for every
|
|
74
|
+
later call, so an `import '@owlmeans/<pkg>'` evaluated after a screen has rendered adds nothing a
|
|
75
|
+
component can read. Register at module load — a side-effect import at the top of the entry file,
|
|
76
|
+
which is what re-exporting `./i18n.js` from `src/index.ts` achieves.
|
|
38
77
|
|
|
39
78
|
## Per-package pattern
|
|
40
79
|
|
|
@@ -28,7 +28,7 @@ The **resource name** is a stable identifier for the registering package, e.g. `
|
|
|
28
28
|
|
|
29
29
|
## Compound prefix keys
|
|
30
30
|
|
|
31
|
-
A key like `t('title')` resolves to `namespace : resource.prefix.key`. The prefix is composed by joining segments with `.` via `composePrefix` (never by hand-concatenating strings
|
|
31
|
+
A key like `t('title')` resolves to `namespace : resource.prefix.key`. The prefix is composed by joining segments with `.` via `composePrefix` — exported from `@owlmeans/client-i18n` (and re-exported by `@owlmeans/web-panel` and `@owlmeans/mui-panel`), never by hand-concatenating strings.
|
|
32
32
|
|
|
33
33
|
Example chain:
|
|
34
34
|
```
|
|
@@ -44,31 +44,59 @@ t('title')
|
|
|
44
44
|
|
|
45
45
|
## Context-based prefix switching
|
|
46
46
|
|
|
47
|
-
Use `PanelContext` (from `@owlmeans/client-panel`) to inject `resource`, `ns
|
|
47
|
+
Use `PanelContext` (from `@owlmeans/client-panel`) to inject `resource`, `ns` or `prefix` into a
|
|
48
|
+
React sub-tree. Child components that call `usePanelI18n()` pick those three up, and a nested
|
|
49
|
+
`PanelContext` inherits the outer one field by field.
|
|
48
50
|
|
|
49
51
|
```tsx
|
|
50
|
-
//
|
|
51
|
-
<PanelContext resource="
|
|
52
|
-
<
|
|
52
|
+
// Read a library's own bundle from inside an app sub-tree
|
|
53
|
+
<PanelContext resource="payment" ns="lib" prefix="plan">
|
|
54
|
+
<Text name="label.monthly" /> {/* usePanelI18n() → lib:payment.plan.label.monthly */}
|
|
53
55
|
</PanelContext>
|
|
54
56
|
```
|
|
55
57
|
|
|
56
|
-
|
|
58
|
+
`suppress` is **not** one of them. `TPanelContext` accepts it because it spreads `I18nBaseProps`,
|
|
59
|
+
but `usePanelI18n` reads only `prefix`, `resource` and `ns`, so a `<PanelContext suppress>` changes
|
|
60
|
+
nothing for any child. Suppression is per component, from that component's own `i18n` prop — which
|
|
61
|
+
is what `Button` and `ActionCtrl` check before translating a label.
|
|
62
|
+
|
|
63
|
+
**Form fields sit in a different context.** `useFormI18n` reads the form context that `FormContext`
|
|
64
|
+
publishes from the enclosing `Form`'s own `i18n` and `name` props; it never touches `PanelContext`.
|
|
65
|
+
So wrapping a form or a field in `<PanelContext …>` changes nothing for any field — redirect a
|
|
66
|
+
field by naming the enclosing `Form` or by giving that `Form` an `i18n` prop.
|
|
67
|
+
|
|
68
|
+
Use the `i18n` prop on an individual component to override just one level. It is declared by the
|
|
69
|
+
components whose props extend `I18nProps` — `Block`, `Text`, `Link`, `Status`, `Button` and `Form`
|
|
70
|
+
in both panel families:
|
|
57
71
|
```tsx
|
|
58
|
-
<
|
|
72
|
+
<Status i18n={{ prefix: 'my-status' }} />
|
|
59
73
|
```
|
|
60
74
|
|
|
75
|
+
Not every component carrying copy has it, and the two that lack it read different contexts.
|
|
76
|
+
`TextInput` — props extend `FormFieldProps` (`name`, `def`) and add `label`, `placeholder`, `hint`,
|
|
77
|
+
`type` and `disableAutocomplete` — resolves `<name>.label`, `<name>.placeholder` and `<name>.hint`
|
|
78
|
+
through `useFormI18n` when the matching prop is `true`, and renders the prop's own string when it
|
|
79
|
+
is given one; redirect it through the enclosing `Form`. `ButtonSelector` — `SelectorProps` is `name`,
|
|
80
|
+
`current`, `options` and `onSelect` — renders one `Button` per option labelled `<name>.<option>`,
|
|
81
|
+
and `Button` resolves through `usePanelI18n` with the app `buttons` and `lib:client-panel.buttons`
|
|
82
|
+
fallbacks; a surrounding `PanelContext` is what redirects it.
|
|
83
|
+
|
|
61
84
|
## App-level override of library strings
|
|
62
85
|
|
|
63
|
-
App-tier registrations deep-merge over Library-tier for the same `(ns, resource)
|
|
86
|
+
App-tier registrations deep-merge over Library-tier for the same `(ns, resource)` — and the
|
|
87
|
+
namespace has to be said out loud, because `addI18nApp` defaults it to the **resource** name while
|
|
88
|
+
the library's bundle sits in `lib`:
|
|
64
89
|
```typescript
|
|
65
|
-
import '@owlmeans/error'
|
|
66
|
-
import { addI18nApp } from '@owlmeans/i18n'
|
|
90
|
+
import '@owlmeans/error' // Library tier: lib:errors.*
|
|
91
|
+
import { addI18nApp, LIB_NAMESPACE } from '@owlmeans/i18n'
|
|
67
92
|
import myErrors from './i18n/en.json'
|
|
68
93
|
|
|
69
|
-
addI18nApp('en', 'errors', myErrors)
|
|
94
|
+
addI18nApp('en', 'errors', myErrors, { ns: LIB_NAMESPACE }) // App tier wins for matching keys
|
|
70
95
|
```
|
|
71
96
|
|
|
97
|
+
Drop `{ ns: LIB_NAMESPACE }` and the app bundle lands in namespace `errors` while `useI18nLib('errors')`
|
|
98
|
+
reads `lib`. Nothing errors and the library strings keep rendering.
|
|
99
|
+
|
|
72
100
|
## Per-package checklist
|
|
73
101
|
|
|
74
102
|
When adding translatable strings to any package:
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"advertise.d.ts","sourceRoot":"","sources":["../src/advertise.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"advertise.js","sourceRoot":"","sources":["../src/advertise.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AAEtD,eAAe,CAAC;IACd,KAAK,EAAE;QACL,IAAI,EAAE;YACJ,UAAU,EAAE,IAAI;YAChB,SAAS,EAAE,IAAI;YACf,WAAW,EAAE,IAAI;YACjB,aAAa,EAAE,IAAI;SACpB;KACF;CACF,CAAC,CAAA"}
|