Files
dbx/apps/desktop/src/i18n/__tests__/tabContextMenuKeys.spec.ts
T
t8y2 392b2bf5b1 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.
2026-09-04 15:41:20 +08:00

56 lines
2.4 KiB
TypeScript
Vendored

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");
}
});
});