Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions docs/i18n.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@

Register is localized with [Lingui v5](https://lingui.dev). Supported locales: **English (en),
Spanish (es), Korean (ko), Simplified Chinese (zh)**, plus a dev-only **pseudo** locale for
finding unwrapped strings. English is the default; an explicit choice is persisted to
`localStorage['register.locale']`.
finding unwrapped strings. The first visit uses the first supported locale from the browser's language
preferences, falling back to English. An explicit choice is persisted to
`localStorage['register.locale']` and takes precedence on later visits.

## The one rule: reactive vs non-reactive

Expand Down Expand Up @@ -135,7 +136,7 @@ still in plain English is unwrapped. It's the primary tool for catching missed s

```js
// in the browser console, then reload
localStorage.setItem('register.locale', 'pseudo')
localStorage.setItem('register.locale', JSON.stringify('pseudo'))
```

Pseudo is only selectable in dev (`import.meta.env.DEV`); in production the value is validated
Expand Down
6 changes: 5 additions & 1 deletion docs/wiki/log.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
title: Log
updated: 2026-08-08
updated: 2026-08-19
type: log
---

Expand Down Expand Up @@ -129,3 +129,7 @@ Play-by-play lives in git (PRs #1053/#1054/#1055/#1063, SDK PR #27). Durable out
## 2026-08-08

- DTF Settings confirmation was globally gated by deploy-time schema validity, so unchanged on-chain values with display-rounding drift blocked unrelated governance changes even though those values were omitted from proposal calldata. The gate now scopes errors to changed settings while preserving no-change and changed-invalid guards; the E2E regression models an unchanged invalid distribution plus a valid mandate update.

## 2026-08-19

- Locale initialization now uses the first supported browser preference for visitors without a saved choice; a persisted explicit choice still wins. A clean Lingui extraction confirmed 2,543 active catalog messages with zero missing Spanish, Korean, or Simplified Chinese translations and removed obsolete catalog entries. This supersedes the earlier ~117-missing-message backlog entry. Live browser verification covered Spanish auto-selection plus a Korean selection surviving reload.
4 changes: 2 additions & 2 deletions docs/wiki/progress.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
title: Progress
updated: 2026-08-10
updated: 2026-08-19
type: ledger
---

Expand All @@ -10,6 +10,7 @@ Stage ledger. One row per stage; keep entries short. Verifier = exact fresh comm

| Stage | Status | Verifier | Review | Next |
|---|---|---|---|---|
| Browser locale default and translation audit | human-review-required (base a6f20e340) | RED: browser es→expected es, got en; Traditional Chinese cases initially mapped to zh · GREEN i18n 15/15 · lint · typecheck · unit 895/895 · build:no-seo · live browser: es-ES→Español, persisted ko survives reload · active catalogs es/ko/Simplified Chinese 2543, 0 missing | independent review found Traditional→Simplified matching risks (including Hant+region); both fixed with negative and positive BCP-47 coverage; shared locale provider/persistence default requires Engineer review | PR review/merge only after Engineer review; wiki-lint blocked by pre-existing stale design-system page |
| Preserve Index DTF section in cmd-k navigation | human-review-required (base ebcd6febe) | RED: proposal/rebalance both landed overview; GREEN 2/2 · gate typecheck/lint/880 unit · live Ctrl+K proposal→governance + rebalance→auctions | independent Intent + Engineering Risk PASS, no findings; shared route-selection behavior requires Engineer review | merge only after Engineer review; wiki-lint blocked by pre-existing stale design-system page |
| vote modal: address-length title overflowed the dialog | done (base 6854a370b) | lint · typecheck · test:run · e2e helper units · smoke 58 · new `vote-modal-long-title` spec desktop+mobile green · RED-verified (reverted the index-dtf modal fix → checkbox right edge 943 vs dialog 849.9) | product/correctness: self — copy + layout only, no tx path touched | — |
| Fix DTF settings confirm button | human-review-required (base 6854a370b) | RED: rounded seeded distribution blocked mandate confirm; GREEN: unit 878 incl. mapper 27/27 · focused E2E 5/5 · typecheck · lint | Dark HOLD on untested mapping → 27 exhaustive mapper tests → Dark PASS; Light PASS; CodeRabbit 2 Minor → resolved (test IDs + editable confirmed state) | PR #1084 open; Engineer review required before merge; wiki-lint blocked by pre-existing stale design-system page |
Expand Down Expand Up @@ -85,7 +86,6 @@ buried comment — so "fail-loud" never degrades into "avoid-the-boundary" (re-a
- Zapper prompt: a sub-$1k weighted cap floors to $0 and suppresses the capacity card (the quote-failure path owns it) — revisit with a $100 step if it ever occurs in practice.
- Zapper prompt: an enso quote resolving above 1% impact while minting is unavailable renders no card (deliberate fail-safe: enso resolving means minting works) — pending product ack.
- Async-mint: `maxOrderValueUsd` (`async-zap-context.tsx`) still feeds un-weighted per-asset caps to the SDK while the instant zapper now uses weighted caps — likely correct there (the SDK splits per leg, where per-asset caps apply directly), but confirm with an engineer.
- Locales: ~117 pre-existing missing msgstr in es/ko/zh surfaced by re-extract (unrelated to any stage) — needs a translation pass.
- Upstream dtf-chat launcher theming (props/CSS vars) into `@reserve-protocol/dtf-chat` (reserve-ai repo), then delete the `.rc-*` overrides in `src/app.css`.
- Homepage animation hooks (from old IMPROVEMENTS_PLAN): move scroll/ticker/transcript side effects into focused hooks with observer/timer cleanup; respect `prefers-reduced-motion`.
- Accessibility audit of animated homepage cards: keyboard states, focus order, labels for chart-only info.
Expand Down
33 changes: 32 additions & 1 deletion src/i18n.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,37 @@ export type SupportedLocale = 'en' | 'es' | 'ko' | 'zh' | 'pseudo'

export const DEFAULT_LOCALE: SupportedLocale = 'en'

const BROWSER_LOCALES: SupportedLocale[] = ['en', 'es', 'ko']

export function getBrowserLocale(): SupportedLocale {
if (typeof navigator === 'undefined') return DEFAULT_LOCALE

const languages = navigator.languages.length ? navigator.languages : [navigator.language]

for (const language of languages) {
const subtags = language.toLowerCase().split('-')
const locale = subtags[0] as SupportedLocale

if (locale === 'zh') {
if (subtags.includes('hant')) continue

if (
subtags.length === 1 ||
subtags.includes('hans') ||
subtags.includes('cn') ||
subtags.includes('sg')
) {
return 'zh'
}
continue
}

if (BROWSER_LOCALES.includes(locale)) return locale
}

return DEFAULT_LOCALE
}

// 'pseudo' is a dev-only debugging locale that mangles every wrapped string,
// making unwrapped (untranslated) text visually obvious.
export const SUPPORTED_LOCALES: SupportedLocale[] = import.meta.env.DEV
Expand Down Expand Up @@ -48,7 +79,7 @@ export async function dynamicActivate(locale: SupportedLocale) {

const storedLocaleAtom = atomWithStorage<SupportedLocale>(
'register.locale',
DEFAULT_LOCALE,
getBrowserLocale(),
undefined,
{ getOnInit: true }
)
Expand Down
Loading
Loading