Skip to content

Commit e8f33d6

Browse files
authored
Merge pull request #50 from cryptopoly/feature/language-locale
Feature/language locale
2 parents 3a5125d + 7ab4280 commit e8f33d6

261 files changed

Lines changed: 39679 additions & 1921 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ abstraction.
223223
- VRAM-fit hints on every Discover variant card so you see at a glance what'll actually run on your machine.
224224

225225
**Phase 3.x — substrate transparency**
226-
- KV strategy chip in composer: per-turn cache override (native / chaosengine / rotorquant / turboquant / triattention) without touching launch settings.
226+
- KV strategy chip in composer: per-turn cache override (native / turboquant / triattention) without touching launch settings.
227227
- DDTree accepted-token overlay: substrate truth view of which speculative draft tokens were accepted.
228228
- Logprobs viz (advanced-mode gated): per-message confidence summary, MLX logprobs streaming passthrough.
229229
- Substrate routing inspector: per-turn badge above the metrics row showing which engine + binary served the response.

CLAUDE.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,16 @@ Check for updates to external repos we build from or depend on:
9898
- [ ] Manifest includes `llamaServerTurbo` field
9999
- [ ] `src-tauri/src/lib.rs` sets `CHAOSENGINE_LLAMA_SERVER_TURBO` env var
100100

101+
### 6. Localization (i18n)
102+
- [ ] `npm run i18n:validate` passes — every locale parity check + ICU syntax compile + orphan key scan
103+
- [ ] No hardcoded user-facing strings introduced in this release (extraction script `npm run i18n:extract` reports zero new keys with empty `en` values)
104+
- [ ] All 10 shipping locales (`en`, `zh-CN`, `zh-TW`, `ja`, `de`, `ru`, `ko`, `fr`, `es`, `pt-BR`) reach ≥95 % coverage; missing keys auto-fall back to `en` at runtime
105+
- [ ] `backend_service/locales/*/LC_MESSAGES/messages.mo` compiled via `pybabel compile`
106+
- [ ] `src-tauri/locales/*.ftl` regenerated for any new menu / tray strings
107+
- [ ] Pseudo-locale `en-XA` smoke-tested for layout clipping on Setup + Diagnostics tabs (widest text surface)
108+
- [ ] CJK font fallback stack present in `styles.css` (Apple Silicon + Windows + Linux paths)
109+
- [ ] Per-feature translation workflow followed: new en-only strings ship with `null` placeholders in other locales (runtime falls back to `en`); follow-up PR fills translations (see FU-042+ tracker rows for cadence)
110+
101111
---
102112

103113
## Follow-Ups Tracker
@@ -147,6 +157,11 @@ no longer relevant.
147157
| ~~FU-038~~ | ~~Diagnostics cleanup: `_free_bytes` import, MallocStackLogging spam, Qwen3.6-27B alias~~ | **Shipped 2026-05-10.** | Three bugs surfaced by the live ``/api/diagnostics/snapshot`` payload from a Coder-Next + Tools repro. (1) ``backend_service/routes/diagnostics.py`` imported ``_free_bytes`` from ``backend_service.routes.setup``, but the setup package's ``__init__.py`` did not re-export it from ``gpu_bundle.py`` — the snapshot's ``extras`` section reported ``ImportError: cannot import name '_free_bytes'``. Added the re-export. (2) macOS hardened-runtime spawned every Python subprocess with three lines of ``MallocStackLogging: can't turn off malloc stack logging because it was not enabled.`` spam (we ship ``bundle.macOS.hardenedRuntime: true``). Hundreds per minute under the metrics poll, drowning out real INFO/ERROR lines. Fixed at source by ``command.env_remove("MallocStackLogging" / "MallocStackLoggingNoCompact" / "MallocScribble")`` in ``src-tauri/src/backend.rs`` so new builds don't produce the spam. Also added a regex filter (``_LOG_NOISE_PATTERNS`` + ``_filter_log_noise``) in ``diagnostics.py`` so the ``/api/diagnostics/log-tail`` and snapshot endpoints strip the spam from logs produced by older builds too — existing installs see a clean diagnostic surface without rebuilding. Filter reads 4× the requested line window so 200 useful lines survive even when the raw log is 50% spam. (3) Qwen3-Coder-Next was rebranded ``Qwen3.6-27B`` upstream; lmstudio-community MLX conversion's HF metadata reports ``mlx-community/Qwen3.6-27B-4bit`` as the canonical repo. ``model_resolution.resolve_dflash_target_ref`` prefers canonical, so ``DRAFT_MODEL_MAP`` missed and the runtimeNote said *DFLASH unavailable for 'mlx-community/Qwen3.6-27B-4bit': no compatible draft model is registered.* Aliased the three quant variants (4bit / bf16 / 8bit) back to ``Qwen/Qwen3-Coder-Next`` so the existing ``z-lab/Qwen3-Coder-Next-DFlash`` drafter resolves. New unit test pins the mapping. |
148158
| ~~FU-037~~ | ~~Per-tab ErrorBoundary + Tauri devtools in release builds~~ | **Shipped 2026-05-10.** | A tool-call in the Chat tab against `Qwen3-Coder-Next` blanked the entire packaged macOS app — webview reload returned the user to the Dashboard, and any subsequent Chat navigation crashed again. Root cause: the React tree had no error boundary, so a single uncaught render error in one tab tore down the whole `<main>` content frame. Release builds also did not ship the WebKit inspector, so the user could not pull a stack trace without rebuilding via `cargo tauri dev`. (1) New [src/components/ErrorBoundary.tsx](src/components/ErrorBoundary.tsx) — `getDerivedStateFromError` + `componentDidCatch` capture the error, render an inline fallback with the error message, JS stack, component stack, "Try again" reset, and "Copy details" clipboard button. Wrapped around `{content}` in [src/App.tsx](src/App.tsx) keyed by `activeTab` so switching tabs is its own recovery path. (2) `src-tauri/Cargo.toml` `tauri` dep gains the `devtools` Cargo feature so right-click → Inspect Element opens WebKit devtools in release builds. (3) CSS for `.error-boundary` lives next to the existing notice banners in [src/styles.css](src/styles.css) — same colour vocabulary. Unit tests in [src/components/__tests__/ErrorBoundary.test.ts](src/components/__tests__/ErrorBoundary.test.ts) pin the static-derive contract so the boundary cannot silently stop catching errors. Frontend errors land in the webview console; backend errors land in the Diagnostics tab + the in-memory `app.state.chaosengine` log buffer. |
149159
| ~~FU-034~~ | ~~Hide unrecoverable launch-modal options instead of greying them out~~ | **Shipped 2026-05-10.** | The launch settings panel ([src/components/RuntimeControls.tsx](src/components/RuntimeControls.tsx)) used to render every cache-strategy card and the DFlash speculative-decoding toggle for every model + engine combo, with disabled checkboxes + "N/A" badges when an option could not run. That taught users the wrong thing — a disabled card with no install button suggests something they could fix, when the only fix lived outside the app or did not exist at all. New rule: **hide options the user has no in-app path to recover.** (1) Cache-strategy cards now skip render when the strategy is engine-incompatible (e.g. TriAttention selected on the MLX engine — engine mismatch is fundamental, no install button helps) or when the strategy needs the turbo binary on a GGUF backend without `llama-server-turbo` present (only fix is `scripts/build-llama-turbo.sh` outside the app). (2) The DFlash toggle hides entirely when the selected model has no draft in [`DRAFT_MODEL_MAP`](dflash/__init__.py) or the engine is GGUF (DFlash needs MLX/vLLM). The "DFlash package not installed but model would be supported" case stays visible — the install button gets the user to ready in one click. ``native`` always survives. Hardcoded `f825ffb` install hint string in the DFlash help panel was the same drift bug from FU-033 — fixed alongside (now `fada1eb`). The popover-side filter ([src/components/kvStrategyFilter.ts](src/components/kvStrategyFilter.ts)) already followed this rule, so the modal now matches. |
160+
| FU-042 | i18n Phase 0 — infra scaffold + IME composition fix | **In progress (started 2026-05-11).** | Foundation work for full-stack localization. Adds `react-i18next` + `i18next-icu` + `i18next-browser-languagedetector` (FE), `Babel` (Py), `rust-i18n` + `fluent-bundle` (Rs). Creates `src/locales/`, `backend_service/locales/`, `src-tauri/locales/` directory trees with namespaced JSON / `.po` / `.ftl` files. Wires `i18n/index.ts` provider in `src/main.tsx`, FastAPI `Accept-Language` middleware in `backend_service/i18n.py`, `rust-i18n!` macro in `src-tauri/src/i18n.rs`. Adds `locale` field to settings (TS + Py + Rs). Builds Settings → Language dropdown rendering endonyms. Builds first-launch banner that detects OS lang ≠ en and prompts user. Adds `<html lang="…">` sync + CJK font-fallback CSS stack. Writes `scripts/i18n-extract.mjs` / `i18n-validate.mjs` / `i18n-pseudo.mjs` (pseudo-locales `en-XA` + `en-XB` dev-only). Hooks `i18n-validate` into `pre-build-check.sh` + `.mjs`. Fixes IME `e.isComposing` guard on prompt textarea Enter-to-send (latent bug breaking JP/CN/KR IME users). Audits `src/utils/format.ts` to thread `locale` arg into `Intl.NumberFormat` / `Intl.DateTimeFormat` helpers. Per CLAUDE.md §6, en-only feature commits ship with `null` placeholders in other locales — runtime falls back to `en`. Adds `THIRD_PARTY_NOTICES.md` rows for all 5 new deps (MIT × 3, Apache-2.0 × 1, BSD-3 × 1). Coverage gate is warn-only v1 with dashboard panel in Diagnostics tab. Wraps with FU-043 Phase 1 translations. |
161+
| FU-043 | i18n Phase 1 — anchor locales (en + zh-CN + ja) | Follows FU-042 | First user-visible localization: ships English baseline + Simplified Chinese (Qwen / DeepSeek / GLM author origin) + Japanese (Sakana AI / ELYZA / heavy Apple-Silicon-tinkerer cohort). Highest-leverage trio given Hugging Face + r/LocalLLaMA demographics. AI-translated (Claude) against a pre-locked `GLOSSARY.md` per locale pinning tech terms (`KV cache`, `tokens/sec`, `quantization`, `inference`, `cache strategy`, etc.) so phrasing stays consistent across 200+ keys. Layout audit pass for CJK glyph density (CJK runs ~30 % narrower than en; verify no fixed-width buttons clip). Live QA matrix: 5 tabs × {happy path, error path, empty state} per locale = ~30 cells. |
162+
| FU-044 | i18n Phase 2 — EU tier (de + fr + es + ru) | Follows FU-043 | Adds German (DiscoLM / LeoLM origin, privacy-first crowd), French (Mistral / CroissantLLM homeland), Spanish (LatAm + Iberia, Salamandra / RigoChat), Russian (Saiga / Vikhr / IlyaGusev — strong r/LocalLLaMA presence). Wide-string layout pass critical for `de` (30–50 % wider than `en`, especially in Setup install descriptions). Slavic 4-form plural pass for `ru` via ICU MessageFormat (one / few / many / other — different rules than the en `plural`). Tauri window minimum width may need bump after `de` audit. |
163+
| FU-045 | i18n Phase 3 — completion tier (ko + pt-BR + zh-TW) | Follows FU-044 | Closes the top-10 locale set: Korean (Upstage Solar / LG EXAONE / Kakao crowd, heavy benchmark scene), Brazilian Portuguese (large maker base, separate from `pt-PT` — both vocab + diacritics differ), Traditional Chinese (Taiwan / Hong Kong; TAIDE / Breeze authors, distinct vocab + idiom from `zh-CN` so it's a separate locale not a variant). Opens contributor PR flow with `GLOSSARY.md` lock + README contributor docs. Diagnostics tab gets a coverage panel showing per-locale `%`. |
164+
| FU-046 | i18n Phase 4 — long tail + RTL prep | Opportunistic / community-driven | Stretch locales as community PRs land ≥80 % coverage: `pl` (Bielik / SpeakLeash), `it` (Camoscio / Minerva), `uk` (DragoMan), `tr` (Trendyol-LLM), `vi` (VinaLlama / PhoGPT), `nl` / `sv` / `cs` (smaller but loud cohorts). RTL infrastructure prep for future `ar` (Jais / Fanar) + `he`: convert remaining `margin-left` / `padding-right` to logical properties (`margin-inline-start` / `padding-inline-end`); add `dir="auto"` to root + per-locale override; rehearse bidi flow via pseudo-locale `en-XB`. Don't ship `ar` / `he` until logical-property migration verified end-to-end. |
150165

151166
---
152167

0 commit comments

Comments
 (0)