@plumbus/core 0.6.3 → 0.6.4
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/dist/.tsbuildinfo +1 -1
- package/dist/define/defineTranslation.d.ts +39 -3
- package/dist/define/defineTranslation.d.ts.map +1 -1
- package/dist/define/defineTranslation.js +3 -0
- package/dist/define/defineTranslation.js.map +1 -1
- package/instructions/translations.md +21 -2
- package/package.json +2 -2
|
@@ -1,13 +1,49 @@
|
|
|
1
1
|
import type { MessageCatalog, TranslationDefinition } from '../types/translation.js';
|
|
2
|
-
|
|
2
|
+
/** Union of message keys across every locale catalog in M */
|
|
3
|
+
type UnionKeys<M extends Record<string, MessageCatalog>> = {
|
|
4
|
+
[L in keyof M]: keyof M[L] & string;
|
|
5
|
+
}[keyof M];
|
|
6
|
+
/**
|
|
7
|
+
* Keys present in the global union but absent from locale L.
|
|
8
|
+
* `never` when L already has every key.
|
|
9
|
+
*/
|
|
10
|
+
type MissingKeysForLocale<M extends Record<string, MessageCatalog>, L extends keyof M> = Exclude<UnionKeys<M>, keyof M[L] & string>;
|
|
11
|
+
/**
|
|
12
|
+
* Force TS to expand mapped types in error messages (avoids dumping
|
|
13
|
+
* `Record<UnionKeys<{...}>, string>` into the diagnostic).
|
|
14
|
+
*/
|
|
15
|
+
type Prettify<T> = {
|
|
16
|
+
[K in keyof T]: T[K];
|
|
17
|
+
} & {};
|
|
18
|
+
/**
|
|
19
|
+
* Per-locale catalog: pass-through when complete; otherwise expect a
|
|
20
|
+
* concrete `{ key: string; ... }` for the full key union so TS reports
|
|
21
|
+
* native diagnostics on that locale attribute, e.g.:
|
|
22
|
+
* Property 'farewell' is missing ...
|
|
23
|
+
* Type '…' is missing the following properties from type '…': greeting1, greeting2
|
|
24
|
+
*/
|
|
25
|
+
type SameKeyMessages<M extends Record<string, MessageCatalog>> = {
|
|
26
|
+
[L in keyof M]: [MissingKeysForLocale<M, L>] extends [never] ? M[L] : Prettify<{
|
|
27
|
+
[K in UnionKeys<M>]: string;
|
|
28
|
+
}>;
|
|
29
|
+
};
|
|
30
|
+
interface DefineTranslationInput<M extends Record<string, MessageCatalog>> {
|
|
3
31
|
name: string;
|
|
4
32
|
defaultLocale: string;
|
|
5
33
|
locales: string[];
|
|
6
|
-
|
|
34
|
+
/**
|
|
35
|
+
* Infer M from the literal catalogs, then require every locale to cover
|
|
36
|
+
* UnionKeys. Incomplete locales get a prettified concrete object type so
|
|
37
|
+
* TS emits native "missing the following properties: …" diagnostics.
|
|
38
|
+
*/
|
|
39
|
+
messages: SameKeyMessages<M>;
|
|
7
40
|
}
|
|
8
41
|
/**
|
|
9
42
|
* Define a translation catalog — a named set of i18n message strings.
|
|
10
43
|
*
|
|
44
|
+
* Validates at typecheck (for literal / `as const` catalogs):
|
|
45
|
+
* - all locales must declare the exact same message keys
|
|
46
|
+
*
|
|
11
47
|
* Validates at import time:
|
|
12
48
|
* - name is required
|
|
13
49
|
* - defaultLocale must exist in locales
|
|
@@ -16,6 +52,6 @@ interface DefineTranslationInput {
|
|
|
16
52
|
*
|
|
17
53
|
* Returns a deeply frozen TranslationDefinition.
|
|
18
54
|
*/
|
|
19
|
-
export declare function defineTranslation(config: DefineTranslationInput): TranslationDefinition;
|
|
55
|
+
export declare function defineTranslation<const M extends Record<string, MessageCatalog>>(config: DefineTranslationInput<M>): TranslationDefinition;
|
|
20
56
|
export {};
|
|
21
57
|
//# sourceMappingURL=defineTranslation.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"defineTranslation.d.ts","sourceRoot":"","sources":["../../src/define/defineTranslation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAIrF,UAAU,sBAAsB;
|
|
1
|
+
{"version":3,"file":"defineTranslation.d.ts","sourceRoot":"","sources":["../../src/define/defineTranslation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAIrF,6DAA6D;AAC7D,KAAK,SAAS,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,IAAI;KACxD,CAAC,IAAI,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,MAAM;CACpC,CAAC,MAAM,CAAC,CAAC,CAAC;AAEX;;;GAGG;AACH,KAAK,oBAAoB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,EAAE,CAAC,SAAS,MAAM,CAAC,IAAI,OAAO,CAC9F,SAAS,CAAC,CAAC,CAAC,EACZ,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,MAAM,CACpB,CAAC;AAEF;;;GAGG;AACH,KAAK,QAAQ,CAAC,CAAC,IAAI;KAAG,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CAAE,GAAG,EAAE,CAAC;AAEjD;;;;;;GAMG;AACH,KAAK,eAAe,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,IAAI;KAC9D,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,GACxD,CAAC,CAAC,CAAC,CAAC,GACJ,QAAQ,CAAC;SAAG,CAAC,IAAI,SAAS,CAAC,CAAC,CAAC,GAAG,MAAM;KAAE,CAAC;CAC9C,CAAC;AAEF,UAAU,sBAAsB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC;IACvE,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB;;;;OAIG;IACH,QAAQ,EAAE,eAAe,CAAC,CAAC,CAAC,CAAC;CAC9B;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,EAC9E,MAAM,EAAE,sBAAsB,CAAC,CAAC,CAAC,GAChC,qBAAqB,CAsEvB"}
|
|
@@ -3,6 +3,9 @@ import { throwDefineValidationError } from './validation-error.js';
|
|
|
3
3
|
/**
|
|
4
4
|
* Define a translation catalog — a named set of i18n message strings.
|
|
5
5
|
*
|
|
6
|
+
* Validates at typecheck (for literal / `as const` catalogs):
|
|
7
|
+
* - all locales must declare the exact same message keys
|
|
8
|
+
*
|
|
6
9
|
* Validates at import time:
|
|
7
10
|
* - name is required
|
|
8
11
|
* - defaultLocale must exist in locales
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"defineTranslation.js","sourceRoot":"","sources":["../../src/define/defineTranslation.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AACrD,OAAO,EAAE,0BAA0B,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"defineTranslation.js","sourceRoot":"","sources":["../../src/define/defineTranslation.ts"],"names":[],"mappings":"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"}
|
|
@@ -30,7 +30,9 @@ export const commonTranslation = defineTranslation({
|
|
|
30
30
|
|
|
31
31
|
- Place translation files in `app/translations/<name>.translation.ts` (classic layout), **or** use the locale-folder layout below
|
|
32
32
|
- Each assembler exports one `defineTranslation()` result
|
|
33
|
-
- All locales **must** have the same key set — mismatched keys throw at import time
|
|
33
|
+
- All locales **must** have the same key set — mismatched keys fail at typecheck for literal catalogs and throw at import time otherwise
|
|
34
|
+
- Prefer literal / `as const` catalogs so `tsc` catches drift. A locale typed as `Record<string, string>` skips compile-time key checks and still relies on import-time validation
|
|
35
|
+
- When a non-default locale has an extra key, typecheck may error on the **default** locale (“missing key X”) while runtime errors on the **other** locale (“extra key X”) — both catch the same drift
|
|
34
36
|
- Messages use ICU MessageFormat: `{name}` for interpolation, `{count, plural, ...}` for plurals, `{gender, select, ...}` for select
|
|
35
37
|
- The `name` field is the namespace: keys resolve as `<namespace>.<key>` (e.g., `common.nav.overview`)
|
|
36
38
|
|
|
@@ -105,4 +107,21 @@ function Nav() {
|
|
|
105
107
|
|
|
106
108
|
## Translation Sync
|
|
107
109
|
|
|
108
|
-
`defineTranslation()`
|
|
110
|
+
`defineTranslation()` enforces key consistency at typecheck for literal / `as const` catalogs, and again at import time. If locale "he" is missing keys that "en" has, `tsc` fails for typed catalogs and the app throws immediately otherwise. This ensures tests and CI catch translation drift.
|
|
111
|
+
|
|
112
|
+
### Dynamic locales
|
|
113
|
+
|
|
114
|
+
```ts
|
|
115
|
+
const he: Record<string, string> = loadFromCms("he"); // no compile-time key parity
|
|
116
|
+
|
|
117
|
+
defineTranslation({
|
|
118
|
+
name: "common",
|
|
119
|
+
defaultLocale: "en",
|
|
120
|
+
locales: ["en", "he"],
|
|
121
|
+
messages: {
|
|
122
|
+
en: { greeting: "Hello", farewell: "Bye" },
|
|
123
|
+
he,
|
|
124
|
+
},
|
|
125
|
+
});
|
|
126
|
+
// Runtime still throws if `he` is missing/extra keys relative to `en`.
|
|
127
|
+
```
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@plumbus/core",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.4",
|
|
4
4
|
"description": "Plumbus framework core — types, SDK, runtime, CLI, test utilities",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -109,6 +109,6 @@
|
|
|
109
109
|
"lint": "biome lint ./src",
|
|
110
110
|
"format": "biome format --write ./src",
|
|
111
111
|
"format:check": "biome format ./src",
|
|
112
|
-
"typecheck": "tsc --noEmit"
|
|
112
|
+
"typecheck": "tsc --noEmit && node ./scripts/check-define-translation-types.mjs"
|
|
113
113
|
}
|
|
114
114
|
}
|