feat(client): typed locale standard seat in the slot framework

Registrations declare a dictionary namespace (locale: NS) and the renderer
synthesizes a typed t prop for the entry's component from the installed
LocaleFace; the seat binding is re-derived per locale revision, so a language
switch hands out fresh t references and memoized consumers re-render through
ordinary shallow comparison. LocaleNamespaceMap is the declare-merge table
(namespace -> dictionary key union); TranslateNS<'ns'> is the
namespace-addressed translate type (namespace keys plus the shared common
vocabulary), carried by the t seat and by the locale service's typed bind.

LocaleService implements the face (lookup ns -> common -> zh -> key,
revision-carrying snapshots with subscriber isolation) and installs it
through the boot-once slots.installLocale seam, mirroring the renderer
install. The typed register(ns, {zh, en}) overload checks each dictionary
against the namespace's key union and requires every shipped locale, so a
missing or extra key and an unbalanced translation are compile errors.
Dictionary registration bumps the face revision without emitting
locale/change — the event now means exactly 'the active locale switched',
so registration-heavy boot cannot storm event listeners.
This commit is contained in:
imccyu
2026-07-30 01:04:56 +08:00
parent 1f242753ec
commit c317fbc489
44 changed files with 925 additions and 189 deletions

View File

@@ -1,2 +1,29 @@
/** en base dictionary for the common namespace (starter skeleton; texts land with their features). */
export const en: Record<string, string> = {}
import type { CommonKey } from './zh.ts'
/** en base dictionary for the common namespace, checked complete against the zh key set. */
export const en = {
'ok': 'OK',
'cancel': 'Cancel',
'close': 'Close',
'copy': 'Copy',
'copied': 'Copied',
'retry': 'Retry',
'loading': 'Loading…',
'load.failed': 'Failed to load',
'submit': 'Submit',
'submitting': 'Submitting…',
'next': 'Next',
'previous': 'Previous',
'skip': 'Skip',
'delete': 'Delete',
'edit': 'Edit',
'save': 'Save',
'search': 'Search',
'more': 'More',
'collapse': 'Collapse',
'expand': 'Expand',
'back': 'Back',
'unknown': 'Unknown',
'none': 'None',
'truncated': 'Truncated',
} satisfies Record<CommonKey, string>

View File

@@ -0,0 +1,8 @@
/**
* The common-namespace dictionary pair. zh is the source of truth for the
* key set (Chinese-first repo convention); en is checked complete against it
* — a missing or extra en key is a compile error.
*/
export { zh } from './zh.ts'
export { en } from './en.ts'
export type { CommonKey } from './zh.ts'

View File

@@ -0,0 +1,14 @@
/** `settings.locale` namespace dictionaries (the Language row's copy). */
/** Simplified Chinese dictionary (the key-set source of truth). */
export const zh = {
'language.title': '语言',
} satisfies Record<string, string>
/** The settings.locale namespace key union. */
export type SettingsLocaleKey = keyof typeof zh
/** English dictionary, checked complete against the zh key set. */
export const en = {
'language.title': 'Language',
} satisfies Record<SettingsLocaleKey, string>

View File

@@ -1,2 +1,30 @@
/** zh base dictionary for the common namespace (starter skeleton; texts land with their features). */
export const zh: Record<string, string> = {}
/** zh base dictionary for the common namespace: cross-feature standard words. */
export const zh = {
'ok': '确定',
'cancel': '取消',
'close': '关闭',
'copy': '复制',
'copied': '复制成功',
'retry': '重试',
'loading': '加载中…',
'load.failed': '加载失败',
'submit': '提交',
'submitting': '正在提交…',
'next': '下一步',
'previous': '上一步',
'skip': '跳过',
'delete': '删除',
'edit': '编辑',
'save': '保存',
'search': '搜索',
'more': '更多',
'collapse': '收起',
'expand': '展开',
'back': '返回',
'unknown': '未知',
'none': '无',
'truncated': '已截断',
} satisfies Record<string, string>
/** The common vocabulary key union (zh is the key-set source of truth). */
export type CommonKey = keyof typeof zh