@courthive/i18n 0.1.1

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 ADDED
@@ -0,0 +1,73 @@
1
+ # @courthive/i18n
2
+
3
+ Translation locales for the CourtHive ecosystem. Source-of-truth bundle
4
+ served at runtime by `competition-factory-server` to TMX clients; see
5
+ [`Mentat/planning/I18N_DELIVERY.md`](../Mentat/planning/I18N_DELIVERY.md)
6
+ for the full delivery architecture.
7
+
8
+ ## Layout
9
+
10
+ ```text
11
+ src/
12
+ locale-labels.ts # Per-locale label + RTL flag
13
+ manifest.gen.ts # Build-time CLI: SHA256, keyCount, completeness
14
+ locales/
15
+ en.json # Source of truth for English (mirrored from TMX)
16
+ fr.json
17
+ es.json
18
+ pt-BR.json
19
+ de.json
20
+ ar.json
21
+ zh-CN.json
22
+ scripts/
23
+ compare-keys.cjs # CI gate: fails on key drift / duplicate keys
24
+ install-husky-hooks.cjs # Copies scripts/husky/* into .husky/ on prepare
25
+ husky/
26
+ pre-commit # Hook body (lint + check-types + compare-keys)
27
+ commit-msg # Hook body (commitlint)
28
+ ```
29
+
30
+ ## Build artifact (`dist/`)
31
+
32
+ `pnpm build` emits:
33
+
34
+ - `dist/locales/*.json` — copies of every source locale.
35
+ - `dist/locale-labels.js` + `.d.ts` — label/RTL metadata.
36
+ - `dist/manifest.json` — runtime manifest (SHA256 per locale, key count,
37
+ completeness, RTL flag) used by CFS to serve `GET /i18n/manifest`.
38
+ - `dist/index.js` + `.d.ts` — re-exports the manifest type and labels.
39
+
40
+ `completeness = 1 - (__TODO__ count / total keys)`. New keys land as
41
+ `__TODO__` placeholders in non-English locales; translators fill them
42
+ in and merge a follow-up PR that brings completeness back to 1.0.
43
+
44
+ ## Scripts
45
+
46
+ ```bash
47
+ pnpm build # tsc → dist/, then node dist/manifest.gen.js
48
+ pnpm check-types # tsc --noEmit
49
+ pnpm lint # eslint . --fix --max-warnings 0
50
+ pnpm format # prettier --write
51
+ pnpm test # node scripts/compare-keys.cjs (key parity gate)
52
+ ```
53
+
54
+ ## Compare-keys gate
55
+
56
+ `scripts/compare-keys.cjs` is the canonical key-parity script — promoted
57
+ from `TMX/src/i18n/compare-keys.cjs`. It exits with code 1 on:
58
+
59
+ - duplicate keys within a single locale
60
+ - any leaf key present in one locale but missing in another
61
+
62
+ CI runs it on every PR and push. Pre-commit (husky) runs it too.
63
+
64
+ ## Consumed by
65
+
66
+ | Repo | How |
67
+ | ---------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
68
+ | `competition-factory-server` | `pnpm` dep (`link:../courthive-i18n` in dev); on bootstrap copies `dist/locales/*` + `dist/manifest.json` to a writable `i18n/` directory and serves them via `GET /i18n/*` endpoints. |
69
+ | `TMX` (eventually) | Reads from CFS at runtime — never depends on `@courthive/i18n` directly. |
70
+
71
+ ## License
72
+
73
+ MIT
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Public entry point for `@courthive/i18n`.
3
+ *
4
+ * Consumers (CFS) typically read locale JSON via the published `dist/`
5
+ * artifact directly (file copy on bootstrap), but the runtime re-exports
6
+ * here are convenient for tooling/tests and for treating the package as
7
+ * a library when desired.
8
+ */
9
+ export { localeLabels, type LocaleLabel } from './locale-labels.js';
10
+ export type { Manifest, ManifestLocaleEntry } from './manifest.gen.js';
package/dist/index.js ADDED
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Public entry point for `@courthive/i18n`.
3
+ *
4
+ * Consumers (CFS) typically read locale JSON via the published `dist/`
5
+ * artifact directly (file copy on bootstrap), but the runtime re-exports
6
+ * here are convenient for tooling/tests and for treating the package as
7
+ * a library when desired.
8
+ */
9
+ export { localeLabels } from './locale-labels.js';
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Human-readable labels and metadata for each locale carried by
3
+ * `@courthive/i18n`. Used by:
4
+ *
5
+ * - `src/manifest.gen.ts` to enrich the runtime manifest.
6
+ * - Consumers (TMX, CFS) that need a label without round-tripping
7
+ * through the manifest fetch.
8
+ *
9
+ * Adding a new locale: drop `<code>.json` into `src/locales/`, add a
10
+ * matching entry here, and re-run `pnpm build`. The compare-keys CI
11
+ * gate will fail loud if the new locale is missing keys.
12
+ */
13
+ export interface LocaleLabel {
14
+ /** English label, e.g. 'Czech'. */
15
+ label: string;
16
+ /** Native label, e.g. 'Čeština'. */
17
+ nativeLabel: string;
18
+ /** Right-to-left rendering required. */
19
+ rtl: boolean;
20
+ }
21
+ export declare const localeLabels: Record<string, LocaleLabel>;
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Human-readable labels and metadata for each locale carried by
3
+ * `@courthive/i18n`. Used by:
4
+ *
5
+ * - `src/manifest.gen.ts` to enrich the runtime manifest.
6
+ * - Consumers (TMX, CFS) that need a label without round-tripping
7
+ * through the manifest fetch.
8
+ *
9
+ * Adding a new locale: drop `<code>.json` into `src/locales/`, add a
10
+ * matching entry here, and re-run `pnpm build`. The compare-keys CI
11
+ * gate will fail loud if the new locale is missing keys.
12
+ */
13
+ export const localeLabels = {
14
+ en: { label: 'English', nativeLabel: 'English', rtl: false },
15
+ fr: { label: 'French', nativeLabel: 'Français', rtl: false },
16
+ es: { label: 'Spanish', nativeLabel: 'Español', rtl: false },
17
+ 'pt-BR': { label: 'Portuguese (Brazil)', nativeLabel: 'Português (Brasil)', rtl: false },
18
+ de: { label: 'German', nativeLabel: 'Deutsch', rtl: false },
19
+ ar: { label: 'Arabic', nativeLabel: 'العربية', rtl: true },
20
+ cs: { label: 'Czech', nativeLabel: 'Čeština', rtl: false },
21
+ hr: { label: 'Croatian', nativeLabel: 'Hrvatski', rtl: false },
22
+ 'zh-CN': { label: 'Chinese (Simplified)', nativeLabel: '简体中文', rtl: false },
23
+ };