i18n: scaffold panel.* and ui.* locale catalogs, wire panelCatalogs into officerdev's barrel

This commit is contained in:
2026-08-23 03:42:53 +00:00
parent dcd11a3b17
commit 6ac9187c52
14 changed files with 76 additions and 2 deletions
@@ -0,0 +1 @@
{}
@@ -0,0 +1,8 @@
import type { TranslationMap } from 'i18n';
import enGB from './en-GB.json';
import ptPT from './pt-PT.json';
/** Shared components' own catalog, per locale — merged into the app-wide map by `I18nBridge` under `ui.*`. */
export const uiCatalogs: TranslationMap = { 'en-GB': enGB, 'pt-PT': ptPT };
export { useTranslation } from './useTranslation';
@@ -0,0 +1,12 @@
import { describe, expect, test } from 'bun:test';
import { findMissingKeys } from 'i18n';
import en from './en-GB.json';
import ptPT from './pt-PT.json';
// D2: every shipped locale ships a COMPLETE catalog. Phase 0 scaffolds this catalog with no keys yet
// (ui.* strings land in phase 1) — the test still runs so it is load-bearing from day one.
describe('shared components (ui.*) locale catalogs', () => {
test('pt-PT has every key en-GB has', () => {
expect(findMissingKeys(en, { 'pt-PT': ptPT })).toEqual([]);
});
});
@@ -0,0 +1 @@
{}
@@ -0,0 +1,13 @@
import type { InterpolationParams, TranslationKeys } from 'i18n';
import { useTranslation as useTranslationBase } from 'i18n';
import type en from './en-GB.json';
type UiTranslationKey = TranslationKeys<typeof en>;
// The `ui.` prefix is namespace wiring for the merged catalog (D6) — callers never spell it, they
// pass the same bare key the JSON file uses. `ui.*` may not name a feature (see the naming convention).
export const useTranslation = () => {
const { t: baseT, locale } = useTranslationBase();
const t = (key: UiTranslationKey, params?: InterpolationParams) => baseT(`ui.${key}`, params);
return { t, locale };
};
+1
View File
@@ -45,6 +45,7 @@
"dotenv": "^16.4.7",
"embla-carousel-react": "^8.5.1",
"hooks": "*",
"i18n": "*",
"input-otp": "^1.4.1",
"lucide-react": "^0.468.0",
"next-themes": "^0.4.4",