diff --git a/apps/desktop/src/i18n/__tests__/tabContextMenuKeys.spec.ts b/apps/desktop/src/i18n/__tests__/tabContextMenuKeys.spec.ts new file mode 100644 index 0000000000..7ef13ca94f --- /dev/null +++ b/apps/desktop/src/i18n/__tests__/tabContextMenuKeys.spec.ts @@ -0,0 +1,55 @@ +import { describe, expect, it } from "vitest"; +import en from "../locales/en"; +import es from "../locales/es"; +import it_ from "../locales/it"; +import ja from "../locales/ja"; +import ko from "../locales/ko"; +import ptBR from "../locales/pt-BR"; +import tr from "../locales/tr"; +import zhCN from "../locales/zh-CN"; +import zhTW from "../locales/zh-TW"; + +// EditorGroupTabBar renders its context menu via `t("contextMenu.")`. +// When a key is missing everywhere, vue-i18n echoes the key path itself and +// the menu shows raw text like "contextMenu.pinTab" (regression in 5a3a6e2bb: +// the component landed without locale entries; spec mocks supplied their own +// translations, so tests stayed green). en is the fallbackLocale, so a missing +// en key leaks the raw path in every language — guard the full tab-menu key +// set against the real en module, not a mock. +const tabMenuKeys = ["changeOrientation", "closeAllTabs", "closeLeftTabs", "closeOtherTabs", "closeRightTabs", "closeTab", "closeTabGroup", "compactTabTitle", "copyName", "editTabGroup", "fullTabTitle", "pinTab", "resetTabGroup", "splitDown", "splitRight", "unpinTab", "unsplit"] as const; + +// Non-English locales are `export default withEnglishFallback({...})`, so +// these imports are en-merged; the assertions below prove the key resolves to +// real text for every UI language, while the en test above is the one that +// actually catches a missing-from-everywhere key. +const locales: Array<[string, Record]> = [ + ["en", en as Record], + ["es", es], + ["it", it_], + ["ja", ja], + ["ko", ko], + ["pt-BR", ptBR], + ["tr", tr], + ["zh-CN", zhCN], + ["zh-TW", zhTW], +]; + +function contextMenuEntry(locale: Record, key: string): unknown { + const contextMenu = locale["contextMenu"]; + if (!contextMenu || typeof contextMenu !== "object") return undefined; + return (contextMenu as Record)[key]; +} + +describe("tab context menu i18n keys", () => { + it.each(tabMenuKeys)("en resolves contextMenu.%s to text", (key) => { + const value = contextMenuEntry(en as Record, key); + expect(value, `contextMenu.${key} missing from locales/en.ts`).toBeTypeOf("string"); + expect(value).not.toBe(""); + }); + + it.each(locales)("%s resolves pin/unpin tab menu labels", (_name, locale) => { + for (const key of ["pinTab", "unpinTab"] as const) { + expect(contextMenuEntry(locale, key), `${_name} contextMenu.${key}`).toBeTypeOf("string"); + } + }); +}); diff --git a/apps/desktop/src/i18n/locales/en.ts b/apps/desktop/src/i18n/locales/en.ts index fc29fdb56c..00a67c16c8 100644 --- a/apps/desktop/src/i18n/locales/en.ts +++ b/apps/desktop/src/i18n/locales/en.ts @@ -3038,8 +3038,8 @@ export default { pin: "Pin", reorderPinned: "Reorder pinned item", unpin: "Unpin", - fixTab: "Fix Tab", - unfixTab: "Unfix Tab", + pinTab: "Pin Tab", + unpinTab: "Unpin Tab", refreshTab: "Refresh Data", renameTab: "Rename Tab", duplicateTab: "Duplicate Tab", diff --git a/apps/desktop/src/i18n/locales/es.ts b/apps/desktop/src/i18n/locales/es.ts index bea7bcf32c..6963435269 100644 --- a/apps/desktop/src/i18n/locales/es.ts +++ b/apps/desktop/src/i18n/locales/es.ts @@ -2956,8 +2956,8 @@ export default withEnglishFallback({ pin: "Fijar", reorderPinned: "Reordenar elemento fijado", unpin: "Desfijar", - fixTab: "Fijar pestaña", - unfixTab: "Desfijar pestaña", + pinTab: "Fijar pestaña", + unpinTab: "Desfijar pestaña", refreshTab: "Actualizar datos", renameTab: "Renombrar pestaña", duplicateTab: "Duplicar pestaña", diff --git a/apps/desktop/src/i18n/locales/it.ts b/apps/desktop/src/i18n/locales/it.ts index eb0ab87d91..cbb64e8749 100644 --- a/apps/desktop/src/i18n/locales/it.ts +++ b/apps/desktop/src/i18n/locales/it.ts @@ -2954,8 +2954,8 @@ export default withEnglishFallback({ pin: "Fissa", reorderPinned: "Riordina elemento fissato", unpin: "Sblocca", - fixTab: "Blocca scheda", - unfixTab: "Sblocca scheda", + pinTab: "Blocca scheda", + unpinTab: "Sblocca scheda", refreshTab: "Aggiorna Dati", renameTab: "Rinomina Scheda", duplicateTab: "Duplica Scheda", diff --git a/apps/desktop/src/i18n/locales/ja.ts b/apps/desktop/src/i18n/locales/ja.ts index f7a9735892..83b0284236 100644 --- a/apps/desktop/src/i18n/locales/ja.ts +++ b/apps/desktop/src/i18n/locales/ja.ts @@ -2978,8 +2978,8 @@ export default withEnglishFallback({ pin: "ピン留め", reorderPinned: "ピン留め項目を並べ替え", unpin: "ピン留め解除", - fixTab: "タブを固定", - unfixTab: "タブの固定を解除", + pinTab: "タブを固定", + unpinTab: "タブの固定を解除", refreshTab: "データを更新", renameTab: "タブ名を変更", duplicateTab: "タブを複製", diff --git a/apps/desktop/src/i18n/locales/ko.ts b/apps/desktop/src/i18n/locales/ko.ts index 541fc99ca3..a9f8d56794 100644 --- a/apps/desktop/src/i18n/locales/ko.ts +++ b/apps/desktop/src/i18n/locales/ko.ts @@ -2848,8 +2848,8 @@ export default withEnglishFallback({ pin: "고정", reorderPinned: "고정 항목 재정렬", unpin: "고정 해제", - fixTab: "탭 고정", - unfixTab: "탭 고정 해제", + pinTab: "탭 고정", + unpinTab: "탭 고정 해제", refreshTab: "데이터 새로고침", renameTab: "탭 이름 변경", duplicateTab: "탭 복제", diff --git a/apps/desktop/src/i18n/locales/pt-BR.ts b/apps/desktop/src/i18n/locales/pt-BR.ts index b6850b5c02..8be0791bf2 100644 --- a/apps/desktop/src/i18n/locales/pt-BR.ts +++ b/apps/desktop/src/i18n/locales/pt-BR.ts @@ -2956,8 +2956,8 @@ export default withEnglishFallback({ pin: "Fixar", reorderPinned: "Reordenar item fixado", unpin: "Desafixar", - fixTab: "Fixar aba", - unfixTab: "Desafixar aba", + pinTab: "Fixar aba", + unpinTab: "Desafixar aba", refreshTab: "Atualizar Dados", renameTab: "Renomear Aba", duplicateTab: "Duplicar Aba", diff --git a/apps/desktop/src/i18n/locales/tr.ts b/apps/desktop/src/i18n/locales/tr.ts index e2c44027be..b8a95f6aef 100644 --- a/apps/desktop/src/i18n/locales/tr.ts +++ b/apps/desktop/src/i18n/locales/tr.ts @@ -3039,8 +3039,8 @@ export default withEnglishFallback({ pin: "Sabitle", reorderPinned: "Sabitlenmiş öğeyi yeniden sırala", unpin: "Sabitlemeyi kaldır", - fixTab: "Sekmeyi Sabitle", - unfixTab: "Sekme Sabitlemesini Kaldır", + pinTab: "Sekmeyi Sabitle", + unpinTab: "Sekme Sabitlemesini Kaldır", refreshTab: "Verileri Yenile", renameTab: "Sekmeyi Yeniden Adlandır", duplicateTab: "Sekmeyi Çoğalt", diff --git a/apps/desktop/src/i18n/locales/zh-CN.ts b/apps/desktop/src/i18n/locales/zh-CN.ts index 4744c1d50c..92d3d4d947 100644 --- a/apps/desktop/src/i18n/locales/zh-CN.ts +++ b/apps/desktop/src/i18n/locales/zh-CN.ts @@ -2961,8 +2961,8 @@ export default withEnglishFallback({ pin: "置顶", reorderPinned: "拖动调整置顶顺序", unpin: "取消置顶", - fixTab: "固定标签页", - unfixTab: "取消固定标签页", + pinTab: "固定标签页", + unpinTab: "取消固定标签页", refreshTab: "刷新数据", renameTab: "重命名标签页", duplicateTab: "复制标签页", diff --git a/apps/desktop/src/i18n/locales/zh-TW.ts b/apps/desktop/src/i18n/locales/zh-TW.ts index 65465aa169..037916cf00 100644 --- a/apps/desktop/src/i18n/locales/zh-TW.ts +++ b/apps/desktop/src/i18n/locales/zh-TW.ts @@ -2953,8 +2953,8 @@ export default withEnglishFallback({ pin: "置頂", reorderPinned: "拖曳調整置頂順序", unpin: "取消置頂", - fixTab: "固定分頁", - unfixTab: "取消固定分頁", + pinTab: "固定分頁", + unpinTab: "取消固定分頁", refreshTab: "重新整理資料", renameTab: "重新命名分頁", duplicateTab: "複製分頁",