feat: JSON-based i18n system with English + Turkish support#2
Merged
KilimcininKorOglu merged 1 commit intoMay 8, 2026
Merged
Conversation
Custom Zustand-powered i18n with zero external deps. Flat-key JSON catalogs, useTranslation() hook with interpolation + pluralization, localStorage persistence, and a LanguageSwitcher dropdown on the home page header + Settings modal. All 32 web UI component files migrated from hardcoded English strings to t() / tArray() / plural() calls. Turkish translations complete and verified in-browser.
ersinkoc
pushed a commit
to oxogdev/SelfClaude
that referenced
this pull request
May 8, 2026
The cumulative role-cost ledger (`metrics.json`) shows what was spent
but not what *happened*. Phase 2 adds an event log that captures the
shape of activity — turns by role, tool calls by kind, files touched,
phase-contract pass rates — and surfaces it in two places:
- Bottom toolbar: new "first-pass %" badge driven by Phase 1 contract
attempts. The Phase 1 determinism KPI is now visible per session.
- Pinned project cards: cumulative project rollup with raw counters
(turns / files / pass rate) primary, and an explicitly-labelled
"Estimate (Nx baseline)" chip secondary. Operator picks the
multiplier from the home-page header (off / 2x / 3x / 5x / 10x);
"off" hides the estimate panel entirely.
Per ROADMAP calibration badursun#2: raw numbers first, estimates clearly
second and clearly labelled. The dropdown's tooltip spells out that
the estimate is a comparison against a chosen baseline, not a
measurement — there's no way for it to be confused with a real value.
Storage: append-only JSONL at <cwd>/.selfclaude/session-metrics.jsonl,
separate from the existing cost ledger so neither schema migrates.
Rollups (per-session, per-project) are computed on read, not cached —
keeps the math honest and lets us iterate on the formula without
invalidating stored state.
Telemetry hooks: every dev / agent / sup tool call records a tool-call
event with tool name + agent + filePath (when present); applyMetrics
emits a turn event per CC result; createSession / destroySession
bracket with session-start / session-end. The Phase 1
phase-contract-attempt event already emitted from the orchestrator now
flows through the same pipe.
Endpoints:
- GET /api/sessions/:id/metrics — live session rollup
- GET /api/projects/metrics?cwd=… — cross-session project rollup
Tests: 13 unit tests covering append/read round-trip, malformed-line
tolerance, session filtering, turns by role, tool/agent/file dedup,
first-pass / ultimate / override accounting, duration computation
with and without an end ts, and project-level aggregation. 214 unit
tests total, all green.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a complete, lightweight internationalization (i18n) system to the web UI — no external dependencies. Ships with full English and Turkish translations covering every user-facing string in the interface.
What's included
lib/i18n.ts— Zustand-powered locale store withuseTranslation()hook, string interpolation ({var}), pluralization (_one/_othersuffix convention), andgetTranslation()for non-component contextslocales/en.json+locales/tr.json— ~400 flat-key translation entries each, covering all 32 component files +failure-modes.tscomponents/language-switcher.tsx— dropdown selector, integrated into both the home page header and the Settings modal (new "Language" tab)t()/tArray()/plural()callsDesign decisions
common.close,agentPane.desc.developer)keyof typeof engives compile-time key validation with zero codegen_one/_othersuffix convention{var}syntax, regex replaceuseI18nStore(Zustand)useSessionStorepattern; no Context Provider neededlocalStoragekeyselfclaude.localeen→ raw keyAdding a new language
locales/xx.json(copyen.jsonand translate)'xx'toSUPPORTEDarray andCATALOGSmap inlib/i18n.ts(2 lines)TypeScript safety
TranslationKey = keyof typeof en— compile-time validation of everyt()calltr.jsonwould cause a type error if enforced viaRecord<TranslationKey, string>assertion (currently relaxed for flexibility)Test plan
pnpm --filter @selfclaude/web typecheckpasses (zero i18n-related errors)selfclaude start --foreground)