i18n: route the remaining 300 hardcoded strings through the table

Grid, offset-maker, liquidity-maker and maker-points wrote their trade log and
Telegram alerts as Chinese literals, so LANG=en changed the menu but not a
single runtime message. src/ now holds zero user-facing Chinese literals.

Reuses rather than duplicates: the four engines' subscription boilerplate maps
onto the existing log.subscribe.* / log.process.* keys, and the spot-maker
wording shared by offset-maker and liquidity-maker became one log.spotMaker.*
set instead of two.

Exchange gateways were treated differently on purpose: aster's exception and
console.error text is developer diagnostics, not UI, and its eight sibling
gateways already used English — so those were translated to English rather than
added to the table.

Adds tests/i18n-coverage.test.ts to hold the line: it fails on any new CJK
literal in src/, on a key missing either language, and on a duplicate key.
Several existing tests asserted the Chinese literals, which is what let the gap
persist; they now assert the resolved key and hold in either language.

214 new keys (300 -> 514). 275 pass; tsc and oxlint clean.
This commit is contained in:
discountry
2026-07-29 21:35:19 +08:00
parent b9331c516a
commit 22b9c5a39d
14 changed files with 964 additions and 273 deletions
@@ -1,4 +1,5 @@
import { afterEach, describe, expect, it, vi } from "vitest";
import { t } from "../src/i18n";
import type { ExchangeAdapter } from "../src/exchanges/adapter";
import type { AccountSnapshot, Depth, Kline, Order, Ticker } from "../src/exchanges/types";
import { MakerPointsEngine } from "../src/strategy/maker-points-engine";
@@ -103,7 +104,11 @@ describe("MakerPointsEngine Binance depth health defense", () => {
expect((engine as any).defenseMode).toBe(true);
const logs = ((engine as any).tradeLog.all() as Array<{ detail: string }>).map((entry) => entry.detail);
expect(logs.some((detail) => detail.includes("Binance簿记异常(orderbook_not_ready)"))).toBe(true);
expect(
logs.some((detail) =>
detail.includes(t("defense.reason.binanceBook", { reason: "orderbook_not_ready" }))
)
).toBe(true);
engine.stop();
});