fix: 注册 locale 字典,修掉设置行显示翻译键的问题

设置行之前显示的是 settings.title / settings.description 这样的原始键:
插件只调用了 locale.bind(NS) 却没有调用 locale.register(NS, { zh, en }),
而 locale 服务在命名空间没有字典时会把 key 原样返回。

- apply 里用 ctx.effect 注册本包的 zh / en 字典(注册会打点 locale 修订号,
  已渲染的条目自动换上文案,不需要刷新页面);
- 单语言注册形式作为兼容兜底;
- 自带字典兜底同时生效:拿不到框架的 t、或 locale 服务没保存注册时,
  仍然渲染中文/英文文案而不是原始键;快照语言改为读 snapshot.active(真实字段名);
- 验证从 40 项增加到 44 项,新增:字典已注册且中英键集合一致、
  设置行与弹窗渲染出的字符串都不是原始键、无框架 t 时的本地兜底、
  locale 服务不保存注册时仍有文案。
This commit is contained in:
pyh
2026-09-30 15:55:12 +08:00
parent 6b83a6ac19
commit 24d1ff3ffa
3 changed files with 42 additions and 7 deletions
+33 -4
View File
@@ -375,10 +375,35 @@ window.__ModuleLoader__.load({
return preview(interaction.displayReason?.text ?? interaction.reason?.text ?? '')
}
/**
* Register this package's dictionaries with the locale service.
*
* Without this the service has no entry for the namespace and every
* `locale.bind(NS)` lookup answers with the key itself, so the settings row
* shows `settings.title` instead of its copy. The typed form takes every
* shipped locale in one call, and the older single-locale form stays
* supported as a fallback. Registration bumps the locale revision, so
* already-rendered entries pick the copy up without a reload.
* @param locale - the locale service, or undefined when this profile has none.
* @returns a disposer for whichever registrations were installed.
*/
function registerDictionaries(locale) {
if (locale === undefined || typeof locale.register !== 'function') return () => {}
const dictionaries = { zh, en }
try {
return locale.register(NS, dictionaries)
} catch {
const disposers = Object.entries(dictionaries).map(([id, dict]) => locale.register(NS, id, dict))
return () => {
for (const dispose of disposers) dispose?.()
}
}
}
/**
* Build a translate function for one locale service: the service's own bound
* namespace first, then the current language's dictionary, then the key
* itself, so a missing seat degrades copy instead of rendering.
* namespace first, then this package's dictionaries, then the key itself, so
* a missing seat degrades copy instead of rendering.
* @param locale - the locale service, or undefined when this profile has none.
* @returns a translate function with `{ name }` interpolation.
*/
@@ -387,7 +412,10 @@ window.__ModuleLoader__.load({
if (locale !== undefined && typeof locale.bind === 'function') {
try {
const bound = locale.bind(NS)
if (typeof bound === 'function') return bound(key, params)
if (typeof bound === 'function') {
const translated = bound(key, params)
if (typeof translated === 'string' && translated !== key) return translated
}
} catch {
/* a locale service without this namespace still renders the fallback */
}
@@ -395,7 +423,7 @@ window.__ModuleLoader__.load({
let language = ''
try {
const snapshot = locale?.getSnapshot?.()
language = String(snapshot?.language ?? snapshot?.locale ?? snapshot?.id ?? '')
language = String(snapshot?.active ?? '')
} catch {
language = ''
}
@@ -951,6 +979,7 @@ window.__ModuleLoader__.load({
}
}
ctx.effect(() => registerDictionaries(locale), 'session-notify: dictionaries')
ctx.effect(() => installBridges(), 'session-notify: window focus')
ctx.effect(() => () => {
disposed = true