@hoardodile/i18n 0.1.4 → 0.1.6

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.
@@ -132,6 +132,7 @@
132
132
  "marketplace": "插件市场",
133
133
  "marketplaceUpdatesBadge": "插件有可用更新",
134
134
  "feedbackAbout": "反馈与关于",
135
+ "updateAvailableBadge": "有可用更新",
135
136
  "help": "帮助"
136
137
  },
137
138
  "syncDueBadge": "有同步提醒待处理",
@@ -317,13 +318,16 @@
317
318
  "latest": "已是最新版本。",
318
319
  "outdated": "发现新版本 {{version}}。",
319
320
  "viewRelease": "查看发布页",
321
+ "updateAvailable": "新版本 {{version}} 已可用。",
320
322
  "updateError": "检查更新失败,请稍后重试。",
321
323
  "downloading": "正在下载… {{percent}}%",
322
- "updateReady": "版本 {{version}} 已就绪,可以安装。",
323
- "updateReadyResources": "资源 v{{version}} 已就绪,可以应用。",
324
+ "updateReady": "版本 {{version}} 已就绪。",
325
+ "updateReadyResources": "版本 {{version}} 已就绪。",
326
+ "updateFullReason": "重新打开应用以完成更新。",
327
+ "updateResourcesReason": "此更新会自动完成,你可以继续使用应用。",
324
328
  "applyResources": "应用",
325
329
  "resourcesVersion": "资源 v{{version}}",
326
- "restartToUpdate": "重启",
330
+ "restartToUpdate": "重新打开应用",
327
331
  "portableHint": "便携版请从 GitHub 下载新的压缩包来更新。"
328
332
  },
329
333
  "connections": {
@@ -410,7 +414,7 @@
410
414
  },
411
415
  "autoUpdate": {
412
416
  "title": "自动更新",
413
- "description": "在后台下载 GitHub 发行版。重启前始终需要确认。"
417
+ "description": "在后台下载 GitHub 发行版。重新打开应用前会先征得你的确认。"
414
418
  },
415
419
  "closeAction": {
416
420
  "title": "关闭窗口时",
@@ -419,9 +423,9 @@
419
423
  "tray": "最小化到托盘",
420
424
  "quit": "退出应用"
421
425
  },
422
- "updateBanner": "版本 {{version}} 已就绪,可以安装。",
423
- "updateBannerResources": "资源 v{{version}} 已就绪,可以应用。",
424
- "updateBannerRestart": "重启",
426
+ "updateBanner": "版本 {{version}} 已就绪。",
427
+ "updateBannerResources": "版本 {{version}} 已就绪。",
428
+ "updateBannerRestart": "重新打开应用",
425
429
  "updateBannerApply": "应用",
426
430
  "updateApplying": "正在应用资源更新…",
427
431
  "updatePhaseStopping": "正在停止本地服务…",
@@ -550,6 +554,25 @@
550
554
  "uninstallConfirmDescription_other": "有 {{count}} 个资源正在使用该插件。卸载后这些资源将改用内置文件插件预览;重新安装该插件可自动恢复。此操作无法撤销。",
551
555
  "uninstallConfirmNoUsage": "没有资源正在使用该插件。卸载后如需恢复,重新安装即可。此操作无法撤销。",
552
556
  "uninstallSuccess": "已卸载 {{name}}",
557
+ "replaceContentAction": "替换内容插件…",
558
+ "replaceContentTitle": "替换内容插件",
559
+ "replaceContentDescription": "把某个内容插件处理的全部资源迁移到另一个内容插件。每个资源的内容插件会被重新分配,其派生元数据会被清空以便重新识别。",
560
+ "replaceContentFrom": "原插件",
561
+ "replaceContentTo": "目标插件",
562
+ "replaceContentToPlaceholder": "选择一个目标插件",
563
+ "replaceContentRebuild": "重建",
564
+ "replaceContentRebuildImmediate": "立即重建(后台)",
565
+ "replaceContentRebuildImmediateDescription": "立即在后台启动所有受影响资源的元数据重建。",
566
+ "replaceContentRebuildDefer": "查看时再重建",
567
+ "replaceContentRebuildDeferDescription": "现在清空元数据;每个资源在你打开它时再重建。",
568
+ "replaceContentConfirm": "替换",
569
+ "replaceContentPassed": "已替换",
570
+ "replaceContentFailed": "未通过检测",
571
+ "replaceContentNoContent": "这个内容插件没有拥有任何资源。",
572
+ "replaceContentSamePlugin": "源插件与目标插件必须不同。",
573
+ "replaceContentInvalidTarget": "目标内容插件不可用。",
574
+ "replaceContentEmptyFrom": "没有任何内容插件拥有可替换的资源。",
575
+ "replaceContentMissingLabel": "缺失",
553
576
  "resetAllPluginPrefSuccess": "所有插件设置已重置",
554
577
  "resetAllPluginPrefConfirmTitle": "重置全部插件设置?",
555
578
  "resetAllPluginPrefConfirmDescription": "这将删除所有插件的已保存设置。所有插件将在重启后使用默认值。此操作无法撤销。",
@@ -572,14 +595,14 @@
572
595
  },
573
596
  "marketplace": {
574
597
  "title": "插件市场",
575
- "description": "通过你个人注册单仓库收录的、以 GitHub Release 发布的插件。",
576
- "registryRepoLabel": "注册单仓库地址",
598
+ "description": "通过你个人注册表仓库收录的、以 GitHub Release 发布的插件。",
599
+ "registryRepoLabel": "注册表仓库地址",
577
600
  "registryPlaceholder": "https://github.com/me/hoardodile-plugins",
578
601
  "setupHint": "填写一个 GitHub 仓库地址,其根目录 registry.json 按行列出插件仓库地址。其余信息——名称、版本、权限、发布说明——都会自动从各仓库及其 Release 读取。",
579
602
  "save": "保存",
580
603
  "disable": "停用",
581
604
  "saved": "插件市场已使用 {{repo}}",
582
- "notConfiguredHint": "尚未配置注册单仓库——填入上方地址即可陈列以 GitHub Release 发布的插件。",
605
+ "notConfiguredHint": "尚未配置注册表仓库——填入上方地址即可陈列以 GitHub Release 发布的插件。",
583
606
  "loadFailed": "插件市场刷新失败:{{message}}",
584
607
  "refreshedAt": "上次刷新 {{time}}",
585
608
  "refresh": "刷新",
@@ -587,7 +610,7 @@
587
610
  "refreshConfirmDescription": "该操作会通过 GitHub API 重新查询每个插件的最新发布(未认证限额为每小时 60 次)。频繁刷新可能触发限流;限流期间将回退展示缓存的发布信息,直至配额恢复。",
588
611
  "refreshed": "插件市场已刷新",
589
612
  "refreshFailed": "插件市场刷新失败",
590
- "emptyHint": "注册单还没有收录任何插件。在 registry.json 中添加仓库地址后刷新即可。",
613
+ "emptyHint": "注册表还没有收录任何插件。在 registry.json 中添加仓库地址后刷新即可。",
591
614
  "install": "安装",
592
615
  "update": "更新",
593
616
  "updateTo": "更新到 v{{version}}",
@@ -608,26 +631,28 @@
608
631
  "pluginId": "插件 ID",
609
632
  "repository": "仓库",
610
633
  "latestRelease": "最新发布",
611
- "manifestVersion": "清单版本",
612
634
  "packageAsset": "安装包",
613
635
  "checksum": "SHA-256",
614
636
  "notInstalled": "未安装",
615
637
  "reportIssue": "报告问题",
616
638
  "reportSecurity": "报告安全漏洞",
617
639
  "requestFeature": "申请新功能",
618
- "intro": "介绍",
640
+ "readme": "说明",
619
641
  "languages": "语言",
620
- "noIntro": "该版本未随发布提供介绍",
642
+ "noReadme": "该版本未随发布提供说明",
621
643
  "noReleaseNotes": "该版本未提供发布说明",
622
644
  "errorRateLimitedShort": "最新发布信息暂时无法获取,稍后自动重试。",
645
+ "updateUnavailableRateLimited": "v{{version}} 已发布,但因 GitHub 限额暂时无法直接更新。",
623
646
  "configureRegistry": "配置注册表",
624
- "pageHint": "插件以 GitHub Release 发布,通过你持有的注册单仓库发现。在上方配置注册表——目录将直接从各插件仓库及其 Release 读取名称、版本、权限与发布说明。",
647
+ "pageHint": "插件以 GitHub Release 发布,通过你持有的注册表仓库发现。在上方配置注册表——目录将直接从各插件仓库及其 Release 读取名称、版本、权限与发布说明。",
625
648
  "registryDialogTitle": "插件市场注册表",
626
649
  "installedBadge": "已安装",
627
650
  "filterAll": "全部",
628
651
  "filterInstalled": "已安装",
629
652
  "filterUpdates": "可更新",
630
653
  "emptyFilterHint": "当前筛选下没有插件。",
654
+ "searchPlaceholder": "搜索插件",
655
+ "searchEmpty": "没有匹配的插件。",
631
656
  "requiresAppVersion": "需要 hoardodile ≥ v{{version}}",
632
657
  "incompatibleAppVersion": "该插件需要 hoardodile ≥ v{{require}},当前为 v{{current}}",
633
658
  "registryActive": "当前 registry:{{url}}"
@@ -2252,8 +2277,8 @@
2252
2277
  "changeLibrary": "更换存储文件夹…",
2253
2278
  "copyLanAddress": "复制局域网地址",
2254
2279
  "restartServer": "重启服务器",
2255
- "updateReady": "更新已就绪——重启以完成",
2256
- "updateReadyResources": "资源更新已就绪——打开以应用",
2280
+ "updateReady": "更新已就绪——重新打开应用",
2281
+ "updateReadyResources": "更新已就绪——打开以应用",
2257
2282
  "quit": "退出",
2258
2283
  "tooltipServerStopped": "hoardodile —— 服务器已停止",
2259
2284
  "tooltipUpdateReady": "hoardodile —— 更新已就绪",
@@ -2286,7 +2311,7 @@
2286
2311
  "startInTray": "启动到托盘",
2287
2312
  "startInTrayHint": "在托盘中选择打开之前不显示窗口。",
2288
2313
  "continue": "继续",
2289
- "missingBridge": "桌面桥接不可用。请重启应用。"
2314
+ "missingBridge": "应用无法启动,请重新打开应用。"
2290
2315
  }
2291
2316
  }
2292
2317
  }
@@ -15,6 +15,7 @@
15
15
  * documented conventions in `src/core.ts` and the catalog registries.
16
16
  */
17
17
  import { describe, expect, it } from "vitest"
18
+ import { SHELL_CATALOGS } from "./catalogs/shell.ts"
18
19
  import { UI_CATALOGS } from "./catalogs/ui.ts"
19
20
  import { WORKBENCH_CATALOGS } from "./catalogs/workbench.ts"
20
21
  import { CATALOGS } from "./catalogs.ts"
@@ -172,4 +173,44 @@ describe("i18n catalog parity", () => {
172
173
  checkCatalogLockstep(CATALOGS)
173
174
  checkCatalogLockstep(UI_CATALOGS)
174
175
  checkCatalogLockstep(WORKBENCH_CATALOGS)
176
+ checkCatalogLockstep(SHELL_CATALOGS)
177
+ })
178
+
179
+ describe("shell catalog subset", () => {
180
+ // The shell bundle must carry only the `desktopShell` + `closeConfirm`
181
+ // subset, and those strings must exactly match their source catalogs so
182
+ // the shell and the app/`ui` surfaces never drift.
183
+ it("desktopShell entries match the app catalog for every language", () => {
184
+ const PREFIX = "desktopShell."
185
+ for (const [language, catalog] of Object.entries(SHELL_CATALOGS)) {
186
+ const shell = flatten(catalog)
187
+ const source = flatten(
188
+ CATALOGS[language as keyof typeof CATALOGS]
189
+ .desktopShell as unknown as Record<string, unknown>,
190
+ )
191
+ const sourceByKey = new Map(source.map((r) => [r.key, r.value]))
192
+ for (const entry of shell) {
193
+ if (!entry.key.startsWith(PREFIX)) continue
194
+ const expected = sourceByKey.get(entry.key.slice(PREFIX.length))
195
+ expect(expected, `${language}: ${entry.key}`).toBe(entry.value)
196
+ }
197
+ }
198
+ })
199
+
200
+ it("closeConfirm entries match the ui catalog for every language", () => {
201
+ const PREFIX = "closeConfirm."
202
+ for (const [language, catalog] of Object.entries(SHELL_CATALOGS)) {
203
+ const shell = flatten(catalog)
204
+ const source = flatten(
205
+ UI_CATALOGS[language as keyof typeof UI_CATALOGS]
206
+ .closeConfirm as unknown as Record<string, unknown>,
207
+ )
208
+ const sourceByKey = new Map(source.map((r) => [r.key, r.value]))
209
+ for (const entry of shell) {
210
+ if (!entry.key.startsWith(PREFIX)) continue
211
+ const expected = sourceByKey.get(entry.key.slice(PREFIX.length))
212
+ expect(expected, `${language}: ${entry.key}`).toBe(entry.value)
213
+ }
214
+ }
215
+ })
175
216
  })
@@ -0,0 +1,53 @@
1
+ {
2
+ "desktopShell": {
3
+ "tray": {
4
+ "open": "Öffnen",
5
+ "changeLibrary": "Bibliothek wechseln…",
6
+ "copyLanAddress": "LAN-Adresse kopieren",
7
+ "restartServer": "Server neu starten",
8
+ "updateReady": "Update bereit — App erneut öffnen",
9
+ "updateReadyResources": "Update bereit — Öffnen zum Anwenden",
10
+ "quit": "Beenden",
11
+ "tooltipServerStopped": "hoardodile — Server gestoppt",
12
+ "tooltipUpdateReady": "hoardodile — Update bereit",
13
+ "copied": "LAN-Adresse in die Zwischenablage kopiert."
14
+ },
15
+ "errorPage": {
16
+ "rendererCrashed": "Das App-Fenster ist abgestürzt. Drücke „Erneut versuchen“, um es neu zu laden — deine Daten und der eingebettete Server sind sicher.",
17
+ "serverError": "Der Server konnte nicht erreicht werden. Er startet möglicherweise noch oder wurde gestoppt. Warte einen Moment und drücke Erneut versuchen, oder verwende Server neu starten aus dem Infobereich.",
18
+ "devServerError": "Der Entwicklungsserver läuft nicht. Starte `pnpm dev` in einem anderen Terminal und drücke dann Erneut versuchen."
19
+ },
20
+ "dialog": {
21
+ "lanPasswordRequired": "Lege zuerst ein Admin-Passwort fest, bevor du den lokalen Netzwerkzugriff aktivierst.",
22
+ "cancel": "Abbrechen",
23
+ "serverStoppedBody": "Der Server wurde gestoppt. Verwende Server neu starten aus dem Infobereich.",
24
+ "serverNotRunningMessage": "Der Server läuft nicht.",
25
+ "restartServer": "Server neu starten",
26
+ "serverFailedToStart": "Server konnte nicht gestartet werden:\n{{message}}"
27
+ },
28
+ "shell": {
29
+ "serverUnreachable": "Server nicht erreichbar",
30
+ "retry": "Erneut versuchen"
31
+ },
32
+ "wizard": {
33
+ "title": "Willkommen bei hoardodile",
34
+ "intro": "Wähle, wo dieser Computer das Archiv speichert. Du kannst den Ordner später in den Einstellungen oder im Infobereich ändern.",
35
+ "library": "Bibliotheksordner",
36
+ "browse": "Durchsuchen",
37
+ "autoStart": "Mit Windows starten",
38
+ "autoStartHint": "hoardodile öffnen, wenn du dich anmeldest.",
39
+ "startInTray": "Im Infobereich starten",
40
+ "startInTrayHint": "Kein Fenster, bis du im Infobereich „Öffnen“ wählst.",
41
+ "continue": "Weiter",
42
+ "missingBridge": "Die App konnte nicht gestartet werden. Öffne die App erneut."
43
+ }
44
+ },
45
+ "closeConfirm": {
46
+ "title": "hoardodile schließen?",
47
+ "description": "Die App läuft im Infobereich weiter, außer du beendest sie.",
48
+ "tray": "Im Infobereich ausblenden",
49
+ "quit": "App beenden",
50
+ "cancel": "Abbrechen",
51
+ "remember": "Meine Auswahl merken"
52
+ }
53
+ }
@@ -0,0 +1,53 @@
1
+ {
2
+ "desktopShell": {
3
+ "tray": {
4
+ "open": "Open",
5
+ "changeLibrary": "Change library…",
6
+ "copyLanAddress": "Copy LAN address",
7
+ "restartServer": "Restart server",
8
+ "updateReady": "Update ready — Reopen the app",
9
+ "updateReadyResources": "Update ready — Open to apply",
10
+ "quit": "Quit",
11
+ "tooltipServerStopped": "hoardodile — server stopped",
12
+ "tooltipUpdateReady": "hoardodile — update ready",
13
+ "copied": "LAN address copied to the clipboard."
14
+ },
15
+ "errorPage": {
16
+ "rendererCrashed": "The app window crashed. Press Retry to reload it — your data and the bundled server are safe.",
17
+ "serverError": "The server could not be reached. It may still be starting, or it may have stopped. Wait a moment and press Retry, or use Restart server from the tray.",
18
+ "devServerError": "The development server is not running. Start `pnpm dev` in another terminal, then press Retry."
19
+ },
20
+ "dialog": {
21
+ "lanPasswordRequired": "Set an admin password first before enabling local network access.",
22
+ "cancel": "Cancel",
23
+ "serverStoppedBody": "The server stopped. Use Restart server from the tray.",
24
+ "serverNotRunningMessage": "The server is not running.",
25
+ "restartServer": "Restart server",
26
+ "serverFailedToStart": "Server failed to start:\n{{message}}"
27
+ },
28
+ "shell": {
29
+ "serverUnreachable": "Server unreachable",
30
+ "retry": "Retry"
31
+ },
32
+ "wizard": {
33
+ "title": "Welcome to hoardodile",
34
+ "intro": "Choose where this computer keeps the archive. You can change the folder later from Settings or the tray.",
35
+ "library": "Library folder",
36
+ "browse": "Browse",
37
+ "autoStart": "Start with Windows",
38
+ "autoStartHint": "Open hoardodile when you sign in.",
39
+ "startInTray": "Start in tray",
40
+ "startInTrayHint": "No window until you choose Open from the tray.",
41
+ "continue": "Continue",
42
+ "missingBridge": "The app couldn't start. Reopen the app."
43
+ }
44
+ },
45
+ "closeConfirm": {
46
+ "title": "Close hoardodile?",
47
+ "description": "The app keeps running in the tray unless you quit it.",
48
+ "tray": "Hide to tray",
49
+ "quit": "Quit the app",
50
+ "cancel": "Cancel",
51
+ "remember": "Remember my choice"
52
+ }
53
+ }
@@ -0,0 +1,53 @@
1
+ {
2
+ "desktopShell": {
3
+ "tray": {
4
+ "open": "Abrir",
5
+ "changeLibrary": "Cambiar biblioteca…",
6
+ "copyLanAddress": "Copiar dirección LAN",
7
+ "restartServer": "Reiniciar servidor",
8
+ "updateReady": "Actualización lista — Volver a abrir la app",
9
+ "updateReadyResources": "Actualización lista — Abrir para aplicar",
10
+ "quit": "Salir",
11
+ "tooltipServerStopped": "hoardodile — servidor detenido",
12
+ "tooltipUpdateReady": "hoardodile — actualización lista",
13
+ "copied": "Dirección LAN copiada al portapapeles."
14
+ },
15
+ "errorPage": {
16
+ "rendererCrashed": "La ventana de la aplicación se ha bloqueado. Pulsa Reintentar para recargarla: tus datos y el servidor integrado están a salvo.",
17
+ "serverError": "No se pudo conectar con el servidor. Puede que aún esté iniciando, o que se haya detenido. Espera un momento y pulsa Reintentar, o usa Reiniciar servidor desde la bandeja.",
18
+ "devServerError": "El servidor de desarrollo no está en ejecución. Inicia `pnpm dev` en otra terminal y pulsa Reintentar."
19
+ },
20
+ "dialog": {
21
+ "lanPasswordRequired": "Configura antes una contraseña de administrador antes de activar el acceso desde la red local.",
22
+ "cancel": "Cancelar",
23
+ "serverStoppedBody": "El servidor se detuvo. Usa Reiniciar servidor desde la bandeja.",
24
+ "serverNotRunningMessage": "El servidor no está en ejecución.",
25
+ "restartServer": "Reiniciar servidor",
26
+ "serverFailedToStart": "No se pudo iniciar el servidor:\n{{message}}"
27
+ },
28
+ "shell": {
29
+ "serverUnreachable": "Servidor inaccesible",
30
+ "retry": "Reintentar"
31
+ },
32
+ "wizard": {
33
+ "title": "Te damos la bienvenida a hoardodile",
34
+ "intro": "Elige dónde guarda este equipo el archivo. Puedes cambiar la carpeta más tarde desde Ajustes o la bandeja.",
35
+ "library": "Carpeta de la biblioteca",
36
+ "browse": "Explorar",
37
+ "autoStart": "Iniciar con Windows",
38
+ "autoStartHint": "Abre hoardodile cuando inicies sesión.",
39
+ "startInTray": "Iniciar en la bandeja",
40
+ "startInTrayHint": "No se abre ninguna ventana hasta que elijas Abrir desde la bandeja.",
41
+ "continue": "Continuar",
42
+ "missingBridge": "No se pudo iniciar la app. Vuelve a abrir la app."
43
+ }
44
+ },
45
+ "closeConfirm": {
46
+ "title": "¿Cerrar hoardodile?",
47
+ "description": "La app sigue ejecutándose en la bandeja a menos que la cierres.",
48
+ "tray": "Ocultar en la bandeja",
49
+ "quit": "Salir de la app",
50
+ "cancel": "Cancelar",
51
+ "remember": "Recordar mi elección"
52
+ }
53
+ }
@@ -0,0 +1,53 @@
1
+ {
2
+ "desktopShell": {
3
+ "tray": {
4
+ "open": "開く",
5
+ "changeLibrary": "ライブラリを変更…",
6
+ "copyLanAddress": "LAN アドレスをコピー",
7
+ "restartServer": "サーバーを再起動",
8
+ "updateReady": "更新準備完了 — アプリを開き直す",
9
+ "updateReadyResources": "更新準備完了 — 開いて適用",
10
+ "quit": "終了",
11
+ "tooltipServerStopped": "hoardodile — サーバー停止",
12
+ "tooltipUpdateReady": "hoardodile — 更新準備完了",
13
+ "copied": "LAN アドレスをクリップボードにコピーしました。"
14
+ },
15
+ "errorPage": {
16
+ "rendererCrashed": "アプリウィンドウがクラッシュしました。「再試行」で再読み込みしてください — データと内蔵サーバーは安全です。",
17
+ "serverError": "サーバーに接続できませんでした。まだ起動中か、停止している可能性があります。少し待って「再試行」を押すか、トレイの「サーバーを再起動」を使用してください。",
18
+ "devServerError": "開発サーバーが動作していません。別のターミナルで `pnpm dev` を起動し、「再試行」を押してください。"
19
+ },
20
+ "dialog": {
21
+ "lanPasswordRequired": "ローカルネットワークアクセスを有効にする前に、まず管理者パスワードを設定してください。",
22
+ "cancel": "キャンセル",
23
+ "serverStoppedBody": "サーバーが停止しました。トレイの「サーバーを再起動」を使用してください。",
24
+ "serverNotRunningMessage": "サーバーは動作していません。",
25
+ "restartServer": "サーバーを再起動",
26
+ "serverFailedToStart": "サーバーの起動に失敗しました:\n{{message}}"
27
+ },
28
+ "shell": {
29
+ "serverUnreachable": "サーバーに接続できません",
30
+ "retry": "再試行"
31
+ },
32
+ "wizard": {
33
+ "title": "hoardodile へようこそ",
34
+ "intro": "このコンピューターでアーカイブを保存する場所を選択してください。フォルダーは後で「設定」またはトレイから変更できます。",
35
+ "library": "ライブラリフォルダー",
36
+ "browse": "参照",
37
+ "autoStart": "Windows で起動",
38
+ "autoStartHint": "サインイン時に hoardodile を起動します。",
39
+ "startInTray": "トレイで起動",
40
+ "startInTrayHint": "トレイから「開く」を選択するまでウィンドウは表示されません。",
41
+ "continue": "続ける",
42
+ "missingBridge": "アプリを起動できませんでした。アプリを開き直してください。"
43
+ }
44
+ },
45
+ "closeConfirm": {
46
+ "title": "hoardodile を閉じますか?",
47
+ "description": "終了しない限り、アプリはトレイで動作し続けます。",
48
+ "tray": "トレイに隠す",
49
+ "quit": "アプリを終了",
50
+ "cancel": "キャンセル",
51
+ "remember": "選択を記憶する"
52
+ }
53
+ }
@@ -0,0 +1,53 @@
1
+ {
2
+ "desktopShell": {
3
+ "tray": {
4
+ "open": "打开",
5
+ "changeLibrary": "更换存储文件夹…",
6
+ "copyLanAddress": "复制局域网地址",
7
+ "restartServer": "重启服务器",
8
+ "updateReady": "更新已就绪——重新打开应用",
9
+ "updateReadyResources": "更新已就绪——打开以应用",
10
+ "quit": "退出",
11
+ "tooltipServerStopped": "hoardodile —— 服务器已停止",
12
+ "tooltipUpdateReady": "hoardodile —— 更新已就绪",
13
+ "copied": "局域网地址已复制到剪贴板。"
14
+ },
15
+ "errorPage": {
16
+ "rendererCrashed": "应用窗口崩溃了。点击重试即可重新加载——数据和内置服务都是安全的。",
17
+ "serverError": "无法连接服务器。服务器可能仍在启动,或已停止。稍候片刻后点击重试,或在托盘中使用「重启服务器」。",
18
+ "devServerError": "开发服务器未运行。请在另一个终端运行 `pnpm dev`,然后点击重试。"
19
+ },
20
+ "dialog": {
21
+ "lanPasswordRequired": "请先设置管理员密码,再启用局域网访问。",
22
+ "cancel": "取消",
23
+ "serverStoppedBody": "服务器已停止。请在托盘中使用「重启服务器」。",
24
+ "serverNotRunningMessage": "服务器未运行。",
25
+ "restartServer": "重启服务器",
26
+ "serverFailedToStart": "服务器启动失败:\n{{message}}"
27
+ },
28
+ "shell": {
29
+ "serverUnreachable": "无法连接服务器",
30
+ "retry": "重试"
31
+ },
32
+ "wizard": {
33
+ "title": "欢迎使用 hoardodile",
34
+ "intro": "选择这台电脑存放归档的位置。之后可以在设置或托盘里更换文件夹。",
35
+ "library": "存储文件夹",
36
+ "browse": "浏览",
37
+ "autoStart": "开机启动",
38
+ "autoStartHint": "登录 Windows 时打开 hoardodile。",
39
+ "startInTray": "启动到托盘",
40
+ "startInTrayHint": "在托盘中选择打开之前不显示窗口。",
41
+ "continue": "继续",
42
+ "missingBridge": "应用无法启动,请重新打开应用。"
43
+ }
44
+ },
45
+ "closeConfirm": {
46
+ "title": "关闭 hoardodile?",
47
+ "description": "除非选择退出,应用会继续在托盘运行。",
48
+ "tray": "最小化到托盘",
49
+ "quit": "退出应用",
50
+ "cancel": "取消",
51
+ "remember": "记住我的选择"
52
+ }
53
+ }
@@ -0,0 +1,52 @@
1
+ /**
2
+ * @vitest-environment node
3
+ *
4
+ * The app-reopen update copy must stay simple and user-friendly: no
5
+ * "应用壳 / app shell" (a technical detail a regular user doesn't need) and
6
+ * no "重启 / restart" (users read that as reboot-the-computer — the action
7
+ * is "reopen the app"). Locks the requirement so it can't silently regress.
8
+ */
9
+
10
+ import { describe, expect, it } from "vitest"
11
+ import { CATALOGS } from "./catalogs.ts"
12
+
13
+ /** Every app-reopen update string, keyed by its path in a catalog. */
14
+ const UPDATE_KEYS: readonly (readonly string[])[] = [
15
+ ["me", "about", "updateReady"],
16
+ ["me", "about", "updateReadyResources"],
17
+ ["me", "about", "updateFullReason"],
18
+ ["me", "about", "updateResourcesReason"],
19
+ ["me", "about", "restartToUpdate"],
20
+ ["me", "desktop", "updateBanner"],
21
+ ["me", "desktop", "updateBannerResources"],
22
+ ["me", "desktop", "updateBannerRestart"],
23
+ ["me", "desktop", "autoUpdate", "description"],
24
+ ["desktopShell", "tray", "updateReady"],
25
+ ["desktopShell", "tray", "updateReadyResources"],
26
+ ["desktopShell", "wizard", "missingBridge"],
27
+ ]
28
+
29
+ function valueAt(obj: unknown, path: readonly string[]): string | undefined {
30
+ let current: unknown = obj
31
+ for (const key of path) {
32
+ if (typeof current !== "object" || current === null) return undefined
33
+ current = (current as Record<string, unknown>)[key]
34
+ }
35
+ return typeof current === "string" ? current : undefined
36
+ }
37
+
38
+ describe("update copy stays simple and user-friendly", () => {
39
+ const FORBIDDEN = [/restart/i, /重启/, /app\s+shell/i, /应用壳/i]
40
+
41
+ it("never uses 'restart/重启' or 'app shell/应用壳' in app-reopen copy", () => {
42
+ for (const [language, catalog] of Object.entries(CATALOGS)) {
43
+ for (const path of UPDATE_KEYS) {
44
+ const value = valueAt(catalog, path)
45
+ expect(value, `${language}: ${path.join(".")} is missing`).toBeDefined()
46
+ for (const re of FORBIDDEN) {
47
+ expect(value?.match(re), `${language}: ${path.join(".")}`).toBeNull()
48
+ }
49
+ }
50
+ }
51
+ })
52
+ })
@@ -25,6 +25,21 @@
25
25
  "fontFamily": "Schriftfamilie",
26
26
  "fontFamilyPlaceholder": "App-Standard (System-Schriftstapel)",
27
27
  "fontFamilyHint": "Leer lassen für den App-Standard-System-Schriftstapel.",
28
+ "sectionPluginState": "Plugin-Zustand",
29
+ "pluginStateHint": "Setzt die vom Plugin gespeicherten Einstellungen und den Cache für diese Sitzung zurück — Live-Änderungen bleiben schreibgeschützt.",
30
+ "columnSettings": "Einstellungen",
31
+ "columnCache": "Cache",
32
+ "resetPrefs": "Einstellungen zurücksetzen",
33
+ "clearCache": "Cache leeren",
34
+ "restoreState": "Aus der Bibliothek wiederherstellen",
35
+ "resetPrefsConfirmTitle": "Plugin-Einstellungen zurücksetzen?",
36
+ "resetPrefsConfirmDescription": "Das Plugin sieht leere Einstellungen, bis Sie sie wiederherstellen.",
37
+ "clearCacheConfirmTitle": "Plugin-Cache leeren?",
38
+ "clearCacheConfirmDescription": "Der Cache dieses Plugins für diese Ressource wird geleert, bis Sie ihn wiederherstellen.",
39
+ "reset": "Zurücksetzen",
40
+ "clear": "Leeren",
41
+ "prefsCleared": "geleert",
42
+ "cacheCleared": "geleert",
28
43
  "system": "System",
29
44
  "infoTitle": "Plugin-Info",
30
45
  "infoAria": "Plugin-Info",
@@ -25,6 +25,21 @@
25
25
  "fontFamily": "Font family",
26
26
  "fontFamilyPlaceholder": "App default (system stack)",
27
27
  "fontFamilyHint": "Leave empty for the app default system stack.",
28
+ "sectionPluginState": "Plugin state",
29
+ "pluginStateHint": "Reset the plugin's own stored settings and cache for this session — live edits stay read-only.",
30
+ "columnSettings": "Settings",
31
+ "columnCache": "Cache",
32
+ "resetPrefs": "Reset settings",
33
+ "clearCache": "Clear cache",
34
+ "restoreState": "Restore from library",
35
+ "resetPrefsConfirmTitle": "Reset plugin settings?",
36
+ "resetPrefsConfirmDescription": "The plugin will see empty settings until you restore them.",
37
+ "clearCacheConfirmTitle": "Clear plugin cache?",
38
+ "clearCacheConfirmDescription": "The plugin's cache for this resource will be emptied until you restore it.",
39
+ "reset": "Reset",
40
+ "clear": "Clear",
41
+ "prefsCleared": "cleared",
42
+ "cacheCleared": "cleared",
28
43
  "system": "System",
29
44
  "infoTitle": "Plugin info",
30
45
  "infoAria": "Plugin info",
@@ -25,6 +25,21 @@
25
25
  "fontFamily": "Familia tipográfica",
26
26
  "fontFamilyPlaceholder": "Predeterminado de la app (pila del sistema)",
27
27
  "fontFamilyHint": "Déjalo vacío para la pila del sistema predeterminada de la app.",
28
+ "sectionPluginState": "Estado del plugin",
29
+ "pluginStateHint": "Restablece los ajustes y la caché que guarda el plugin para esta sesión — los cambios en vivo siguen siendo de solo lectura.",
30
+ "columnSettings": "Ajustes",
31
+ "columnCache": "Caché",
32
+ "resetPrefs": "Restablecer ajustes",
33
+ "clearCache": "Vaciar caché",
34
+ "restoreState": "Restaurar desde la biblioteca",
35
+ "resetPrefsConfirmTitle": "¿Restablecer los ajustes del plugin?",
36
+ "resetPrefsConfirmDescription": "El plugin verá ajustes vacíos hasta que los restaures.",
37
+ "clearCacheConfirmTitle": "¿Vaciar la caché del plugin?",
38
+ "clearCacheConfirmDescription": "La caché del plugin para este recurso se vaciará hasta que la restaures.",
39
+ "reset": "Restablecer",
40
+ "clear": "Vaciar",
41
+ "prefsCleared": "vacío",
42
+ "cacheCleared": "vacío",
28
43
  "system": "Sistema",
29
44
  "infoTitle": "Información del plugin",
30
45
  "infoAria": "Información del plugin",
@@ -25,6 +25,21 @@
25
25
  "fontFamily": "フォントファミリー",
26
26
  "fontFamilyPlaceholder": "アプリ既定(システムフォント)",
27
27
  "fontFamilyHint": "空欄ならアプリ既定のシステムフォントを使用します。",
28
+ "sectionPluginState": "プラグイン状態",
29
+ "pluginStateHint": "このセッションでプラグイン自身の保存済み設定とキャッシュをリセットします——実編集は読み取り専用のままです。",
30
+ "columnSettings": "設定",
31
+ "columnCache": "キャッシュ",
32
+ "resetPrefs": "設定をリセット",
33
+ "clearCache": "キャッシュをクリア",
34
+ "restoreState": "ライブラリから復元",
35
+ "resetPrefsConfirmTitle": "プラグイン設定をリセットしますか?",
36
+ "resetPrefsConfirmDescription": "復元するまで、プラグインには空の設定が表示されます。",
37
+ "clearCacheConfirmTitle": "プラグインのキャッシュをクリアしますか?",
38
+ "clearCacheConfirmDescription": "復元するまで、このリソースのプラグインキャッシュは空になります。",
39
+ "reset": "リセット",
40
+ "clear": "クリア",
41
+ "prefsCleared": "クリア済み",
42
+ "cacheCleared": "クリア済み",
28
43
  "system": "システム",
29
44
  "infoTitle": "プラグイン情報",
30
45
  "infoAria": "プラグイン情報",
@@ -25,6 +25,21 @@
25
25
  "fontFamily": "字体系列",
26
26
  "fontFamilyPlaceholder": "应用默认(系统字体栈)",
27
27
  "fontFamilyHint": "留空则使用应用默认的系统字体栈。",
28
+ "sectionPluginState": "插件状态",
29
+ "pluginStateHint": "重置插件在本会话中存储的设置与缓存——实时编辑保持只读。",
30
+ "columnSettings": "设置",
31
+ "columnCache": "缓存",
32
+ "resetPrefs": "重置设置",
33
+ "clearCache": "清空缓存",
34
+ "restoreState": "从资料库恢复",
35
+ "resetPrefsConfirmTitle": "重置插件设置?",
36
+ "resetPrefsConfirmDescription": "插件将看到空的设置,直至您将其恢复。",
37
+ "clearCacheConfirmTitle": "清空插件缓存?",
38
+ "clearCacheConfirmDescription": "该资源对应的插件缓存将被清空,直至您将其恢复。",
39
+ "reset": "重置",
40
+ "clear": "清空",
41
+ "prefsCleared": "已清空",
42
+ "cacheCleared": "已清空",
28
43
  "system": "系统",
29
44
  "infoTitle": "插件信息",
30
45
  "infoAria": "插件信息",