Add Japanese, Korean, and Arabic locales to match the README set,
replace the two-option zh/en toggle with a full language dropdown,
and add comprehensive i18n parity tests.
i18n core
- New ja/ko/ar.json (634 keys each, 100% parity with en.json).
- SUPPORTED_LANGUAGES registry + isRtl()/applyDocumentDirection()
helpers; navigator as secondary detector with Node.js 21+ guard;
nonExplicitSupportedLngs for regional variant matching.
- New i18next.d.ts for strict t() key type-checking at compile time.
Components
- LanguageSwitcher dropdown in Layout.tsx: position: fixed + JS-measured
coords (resists overflow/clipping/RTL direction), full ARIA, touchstart
+ Escape dismiss, i18n.languages array for regional code matching.
- WelcomeScreen: fix double-prefix bug — CATEGORIES/CAPABILITY keys now
carry full i18n paths with `as const`.
- AlphaZoo: 10 dynamic t() calls use `as any` + defaultValue fallback.
- APP_VERSION constant removed; version string sourced from t('app.version').
RTL & theme
- Logical properties throughout (border-e, ps/pe, border-s-2) +
rtl:flex-row-reverse on main layout.
- --popover CSS variable defined (light + dark); bg-popover was producing
no color before, making every popover transparent.
- [dir="rtl"] .rtl\:flip-x rule for mirroring directional icons.
Tests (i18n.test.ts — 231 total, all passing)
- Key parity: 5 locales × 2 directions (missing + extra) + sanity check.
- Interpolation variable parity across all locales.
- isRtl: base codes, regional variants (ar-EG/ar-SA), unknown codes.
- SUPPORTED_LANGUAGES registry integrity.
zh-CN.json
- Translation refinements ("A股回测"→"多市场回测", description alignment
with en.json); key ordering aligned to en.json structure.
Signed-off-by: digger yu <digger-yu@outlook.com>
31 lines
1.3 KiB
TypeScript
31 lines
1.3 KiB
TypeScript
import type { Config } from "tailwindcss";
|
|
|
|
export default {
|
|
darkMode: "class",
|
|
content: ["./index.html", "./src/**/*.{ts,tsx}"],
|
|
theme: {
|
|
extend: {
|
|
colors: {
|
|
border: "hsl(var(--border))",
|
|
background: "hsl(var(--background))",
|
|
foreground: "hsl(var(--foreground))",
|
|
muted: { DEFAULT: "hsl(var(--muted))", foreground: "hsl(var(--muted-foreground))" },
|
|
primary: { DEFAULT: "hsl(var(--primary))", foreground: "hsl(var(--primary-foreground))" },
|
|
destructive: { DEFAULT: "hsl(var(--destructive))", foreground: "hsl(var(--destructive-foreground))" },
|
|
card: { DEFAULT: "hsl(var(--card))", foreground: "hsl(var(--card-foreground))" },
|
|
popover: { DEFAULT: "hsl(var(--popover))", foreground: "hsl(var(--popover-foreground))" },
|
|
success: "hsl(var(--success))",
|
|
danger: "hsl(var(--danger))",
|
|
warning: "hsl(var(--warning))",
|
|
info: "hsl(var(--info))",
|
|
},
|
|
fontFamily: {
|
|
sans: ["Inter", "system-ui", "sans-serif"],
|
|
mono: ["JetBrains Mono", "ui-monospace", "monospace"],
|
|
},
|
|
borderRadius: { lg: "var(--radius)", md: "calc(var(--radius) - 2px)", sm: "calc(var(--radius) - 4px)" },
|
|
},
|
|
},
|
|
plugins: [require("@tailwindcss/typography")],
|
|
} satisfies Config;
|