Files
OmniRoute/tests/unit/gamification-display-contract.test.ts
nguyenha935 4012bac41d fix(i18n): preserve remaining Vietnamese localization (#7935)
* fix(i18n): preserve remaining Vietnamese localization

* chore(quality): rebaseline file-size cap for 9 dashboard components (i18n wiring)

Restoring the Vietnamese localization on 9 dashboard components (useTranslations
wiring + t()/tc() call-site swaps for previously hardcoded strings) grows each
file by a small, irreducible amount. Bumps the frozen file-size-baseline.json
caps to match, with a justification entry per the project's own ratchet policy.

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>

* fix(i18n): wire weekday localization + add missing qwen CLI description

Two gaps left by this PR's own new contract tests, caught while
reconciling the branch against the release tip:

- CostOverviewTab.tsx added formatWeekdayLabel() but never called it;
  the Weekly Usage Pattern chart still showed raw English day
  abbreviations regardless of locale. Now maps weeklyPattern rows
  through it before handing them to WeeklyPatternCard.
- cliTools.toolDescriptions was missing an entry for "qwen" (a
  baseUrlSupport:"full" tool) in both en.json and vi.json, failing
  the PR's own cli-catalog-display-contract.test.ts.

Covered by the PR's existing tests/unit/dashboard-localization-contract.test.ts
and tests/unit/cli-catalog-display-contract.test.ts (both now pass).

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>

* i18n(vi): backfill the 4 proxySubscription keys #7299 added to en.json

#7299 (proxy subscriptions) merged while this branch was rebasing, adding
settings.proxySubscriptionsTab and settings.proxySubscription.error.{LOCAL_CORE_ENDPOINT_INVALID,
NEEDS_CORE_NOT_CONFIGURED,NO_USABLE_NODES} to en.json. This PR's own
i18n-vi-completeness contract asserts full en↔vi key parity, so the merge of the
current release tip surfaced them as missing. Adds the Vietnamese translations,
keeping the SS/VMess/Trojan/VLESS/SOCKS5 technical terms verbatim.

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>

---------

Co-authored-by: nguyenha935 <208228297+nguyenha935@users.noreply.github.com>
Co-authored-by: Diego Rodrigues de Sa e Souza <diegosouza.pw@gmail.com>
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
Co-authored-by: nguyenha935 <nguyenha935@users.noreply.github.com>
2026-07-21 13:41:02 -03:00

52 lines
2.1 KiB
TypeScript

import assert from "node:assert/strict";
import { readFileSync } from "node:fs";
import test from "node:test";
import en from "../../src/i18n/messages/en.json" with { type: "json" };
import vi from "../../src/i18n/messages/vi.json" with { type: "json" };
import { BUILTIN_BADGES } from "../../src/lib/gamification/badges";
const profileSource = readFileSync("src/app/(dashboard)/dashboard/profile/page.tsx", "utf8");
const tokensSource = readFileSync("src/app/(dashboard)/dashboard/tokens/page.tsx", "utf8");
const topListSource = readFileSync(
"src/app/(dashboard)/dashboard/costs/components/TopListCard.tsx",
"utf8"
);
const englishBadges = en.gamification.badges as Record<string, Record<string, string>>;
const vietnameseBadges = vi.gamification.badges as Record<string, Record<string, string>>;
test("every built-in badge has complete English and Vietnamese display copy", () => {
for (const badge of BUILTIN_BADGES) {
for (const field of ["name", "description", "criteria"] as const) {
const englishValue = englishBadges[badge.id]?.[field];
const vietnameseValue = vietnameseBadges[badge.id]?.[field];
assert.ok(englishValue?.trim(), `en missing gamification.badges.${badge.id}.${field}`);
assert.ok(vietnameseValue?.trim(), `vi missing gamification.badges.${badge.id}.${field}`);
}
}
});
test("profile renders mapped icons and localized badge criteria", () => {
assert.match(profileSource, /function BadgeIcon/);
assert.match(profileSource, /translateBadge\(selectedBadge, "criteria"\)/);
assert.doesNotMatch(profileSource, /<p className="text-sm">\{selectedBadge\.criteria\}<\/p>/);
});
test("token page no longer contains known raw English controls", () => {
for (const rawText of [
"Send Tokens",
"Create Invite",
"Connect Server",
"No servers connected",
"Last sync:",
"Disconnect",
]) {
assert.equal(tokensSource.includes(`>${rawText}<`), false, `raw token copy: ${rawText}`);
}
});
test("cost list component receives its localized legacy-free label", () => {
assert.match(topListSource, /legacyFreeLabel: string;/);
assert.match(topListSource, /\{legacyFreeLabel\}/);
});