fix(i18n): add missing pin/unpin tab context menu keys

EditorGroupTabBar referenced contextMenu.pinTab/unpinTab (introduced in
5a3a6e2bb) but no locale declared them, so the tab context menu rendered
the raw key path in every language. Rename the unused fixTab/unfixTab
entries to pinTab/unpinTab in all nine locales and add a test asserting
every tab-menu key resolves to text in en (the fallback locale) and that
pin/unpin labels resolve in every locale.
This commit is contained in:
t8y2 committed 2026-09-04 15:41:20 +08:00
1 parent d2401896dd
commit 392b2bf5b1
10 files changed
+73 -18

No files matched your search

@@ -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.<key>")`.
// 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<string, unknown>]> = [
["en", en as Record<string, unknown>],
["es", es],
["it", it_],
["ja", ja],
["ko", ko],
["pt-BR", ptBR],
["tr", tr],
["zh-CN", zhCN],
["zh-TW", zhTW],
];
function contextMenuEntry(locale: Record<string, unknown>, key: string): unknown {
const contextMenu = locale["contextMenu"];
if (!contextMenu || typeof contextMenu !== "object") return undefined;
return (contextMenu as Record<string, unknown>)[key];
}
describe("tab context menu i18n keys", () => {
it.each(tabMenuKeys)("en resolves contextMenu.%s to text", (key) => {
const value = contextMenuEntry(en as Record<string, unknown>, 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");
}
});
});
+2 -2
View File
@@ -3038,8 +3038,8 @@ export default {
pin: "Pin", pin: "Pin",
reorderPinned: "Reorder pinned item", reorderPinned: "Reorder pinned item",
unpin: "Unpin", unpin: "Unpin",
fixTab: "Fix Tab", pinTab: "Pin Tab",
unfixTab: "Unfix Tab", unpinTab: "Unpin Tab",
refreshTab: "Refresh Data", refreshTab: "Refresh Data",
renameTab: "Rename Tab", renameTab: "Rename Tab",
duplicateTab: "Duplicate Tab", duplicateTab: "Duplicate Tab",
+2 -2
View File
@@ -2956,8 +2956,8 @@ export default withEnglishFallback({
pin: "Fijar", pin: "Fijar",
reorderPinned: "Reordenar elemento fijado", reorderPinned: "Reordenar elemento fijado",
unpin: "Desfijar", unpin: "Desfijar",
fixTab: "Fijar pestaña", pinTab: "Fijar pestaña",
unfixTab: "Desfijar pestaña", unpinTab: "Desfijar pestaña",
refreshTab: "Actualizar datos", refreshTab: "Actualizar datos",
renameTab: "Renombrar pestaña", renameTab: "Renombrar pestaña",
duplicateTab: "Duplicar pestaña", duplicateTab: "Duplicar pestaña",
+2 -2
View File
@@ -2954,8 +2954,8 @@ export default withEnglishFallback({
pin: "Fissa", pin: "Fissa",
reorderPinned: "Riordina elemento fissato", reorderPinned: "Riordina elemento fissato",
unpin: "Sblocca", unpin: "Sblocca",
fixTab: "Blocca scheda", pinTab: "Blocca scheda",
unfixTab: "Sblocca scheda", unpinTab: "Sblocca scheda",
refreshTab: "Aggiorna Dati", refreshTab: "Aggiorna Dati",
renameTab: "Rinomina Scheda", renameTab: "Rinomina Scheda",
duplicateTab: "Duplica Scheda", duplicateTab: "Duplica Scheda",
+2 -2
View File
@@ -2978,8 +2978,8 @@ export default withEnglishFallback({
pin: "ピン留め", pin: "ピン留め",
reorderPinned: "ピン留め項目を並べ替え", reorderPinned: "ピン留め項目を並べ替え",
unpin: "ピン留め解除", unpin: "ピン留め解除",
fixTab: "タブを固定", pinTab: "タブを固定",
unfixTab: "タブの固定を解除", unpinTab: "タブの固定を解除",
refreshTab: "データを更新", refreshTab: "データを更新",
renameTab: "タブ名を変更", renameTab: "タブ名を変更",
duplicateTab: "タブを複製", duplicateTab: "タブを複製",
+2 -2
View File
@@ -2848,8 +2848,8 @@ export default withEnglishFallback({
pin: "고정", pin: "고정",
reorderPinned: "고정 항목 재정렬", reorderPinned: "고정 항목 재정렬",
unpin: "고정 해제", unpin: "고정 해제",
fixTab: "탭 고정", pinTab: "탭 고정",
unfixTab: "탭 고정 해제", unpinTab: "탭 고정 해제",
refreshTab: "데이터 새로고침", refreshTab: "데이터 새로고침",
renameTab: "탭 이름 변경", renameTab: "탭 이름 변경",
duplicateTab: "탭 복제", duplicateTab: "탭 복제",
+2 -2
View File
@@ -2956,8 +2956,8 @@ export default withEnglishFallback({
pin: "Fixar", pin: "Fixar",
reorderPinned: "Reordenar item fixado", reorderPinned: "Reordenar item fixado",
unpin: "Desafixar", unpin: "Desafixar",
fixTab: "Fixar aba", pinTab: "Fixar aba",
unfixTab: "Desafixar aba", unpinTab: "Desafixar aba",
refreshTab: "Atualizar Dados", refreshTab: "Atualizar Dados",
renameTab: "Renomear Aba", renameTab: "Renomear Aba",
duplicateTab: "Duplicar Aba", duplicateTab: "Duplicar Aba",
+2 -2
View File
@@ -3039,8 +3039,8 @@ export default withEnglishFallback({
pin: "Sabitle", pin: "Sabitle",
reorderPinned: "Sabitlenmiş öğeyi yeniden sırala", reorderPinned: "Sabitlenmiş öğeyi yeniden sırala",
unpin: "Sabitlemeyi kaldır", unpin: "Sabitlemeyi kaldır",
fixTab: "Sekmeyi Sabitle", pinTab: "Sekmeyi Sabitle",
unfixTab: "Sekme Sabitlemesini Kaldır", unpinTab: "Sekme Sabitlemesini Kaldır",
refreshTab: "Verileri Yenile", refreshTab: "Verileri Yenile",
renameTab: "Sekmeyi Yeniden Adlandır", renameTab: "Sekmeyi Yeniden Adlandır",
duplicateTab: "Sekmeyi Çoğalt", duplicateTab: "Sekmeyi Çoğalt",
+2 -2
View File
@@ -2961,8 +2961,8 @@ export default withEnglishFallback({
pin: "置顶", pin: "置顶",
reorderPinned: "拖动调整置顶顺序", reorderPinned: "拖动调整置顶顺序",
unpin: "取消置顶", unpin: "取消置顶",
fixTab: "固定标签页", pinTab: "固定标签页",
unfixTab: "取消固定标签页", unpinTab: "取消固定标签页",
refreshTab: "刷新数据", refreshTab: "刷新数据",
renameTab: "重命名标签页", renameTab: "重命名标签页",
duplicateTab: "复制标签页", duplicateTab: "复制标签页",
+2 -2
View File
@@ -2953,8 +2953,8 @@ export default withEnglishFallback({
pin: "置頂", pin: "置頂",
reorderPinned: "拖曳調整置頂順序", reorderPinned: "拖曳調整置頂順序",
unpin: "取消置頂", unpin: "取消置頂",
fixTab: "固定分頁", pinTab: "固定分頁",
unfixTab: "取消固定分頁", unpinTab: "取消固定分頁",
refreshTab: "重新整理資料", refreshTab: "重新整理資料",
renameTab: "重新命名分頁", renameTab: "重新命名分頁",
duplicateTab: "複製分頁", duplicateTab: "複製分頁",