i18n: scaffold panel.* and ui.* locale catalogs, wire panelCatalogs into officerdev's barrel
This commit is contained in:
@@ -210,6 +210,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",
|
||||
@@ -271,6 +272,7 @@
|
||||
"version": "0.0.1",
|
||||
"dependencies": {
|
||||
"hooks": "workspace:*",
|
||||
"i18n": "workspace:*",
|
||||
"state": "workspace:*",
|
||||
"widgets": "workspace:*",
|
||||
},
|
||||
|
||||
@@ -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 };
|
||||
};
|
||||
@@ -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",
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"hooks": "workspace:*",
|
||||
"i18n": "workspace:*",
|
||||
"state": "workspace:*",
|
||||
"widgets": "workspace:*"
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
export * from './hooks';
|
||||
export * from './channels';
|
||||
// The panel apps' own i18n catalog — I18nBridge merges it into the app-wide map under `panel.*`.
|
||||
export { panelCatalogs } from './locales';
|
||||
// For the shell: a screen naming itself better than its route can — see usePageTitle's precedence.
|
||||
export { usePageTitleOverride, usePublishPageTitle } from './page-title';
|
||||
export type { PageTitleOverride } from './page-title';
|
||||
@@ -49,13 +51,11 @@ export type {
|
||||
CommandHqCostSummary,
|
||||
} from './apps/CommandHQ';
|
||||
|
||||
|
||||
// /calendar and /contacts select with a query param rather than a path segment, so what the screens need
|
||||
// from the app is the param name and the link builder.
|
||||
export { COLLECTION_PARAM, davCollectionPath } from './apps/Dav/shared';
|
||||
export type { DavCollection, CalendarEvent, DavContact } from './apps/Dav/shared';
|
||||
|
||||
|
||||
export {
|
||||
useFilesAPI,
|
||||
useTasks,
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
{}
|
||||
@@ -0,0 +1,8 @@
|
||||
import type { TranslationMap } from 'i18n';
|
||||
import enGB from './en-GB.json';
|
||||
import ptPT from './pt-PT.json';
|
||||
|
||||
/** Panel apps' own catalog, per locale — merged into the app-wide map by `I18nBridge` under `panel.*`. */
|
||||
export const panelCatalogs: 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
|
||||
// (no panel is converted in this phase) — the test still runs so it is load-bearing from day one.
|
||||
describe('officerdev (panel.*) 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 PanelTranslationKey = TranslationKeys<typeof en>;
|
||||
|
||||
// The `panel.` prefix is namespace wiring for the merged catalog (D6) — callers never spell it, they
|
||||
// pass the same bare key the JSON file uses.
|
||||
export const useTranslation = () => {
|
||||
const { t: baseT, locale } = useTranslationBase();
|
||||
const t = (key: PanelTranslationKey, params?: InterpolationParams) => baseT(`panel.${key}`, params);
|
||||
return { t, locale };
|
||||
};
|
||||
Reference in New Issue
Block a user