Skip to content

i18n: full UI coverage across 10 languages#1986

Merged
senamakel merged 42 commits into
tinyhumansai:mainfrom
senamakel:i18n/full-coverage-10-languages
May 17, 2026
Merged

i18n: full UI coverage across 10 languages#1986
senamakel merged 42 commits into
tinyhumansai:mainfrom
senamakel:i18n/full-coverage-10-languages

Conversation

@senamakel
Copy link
Copy Markdown
Member

@senamakel senamakel commented May 17, 2026

Summary

  • Migrates 142 React components to the existing useT() hook so every user-visible string flows through the translation catalog.
  • Adds 7 new locales — Hindi (hi), Spanish (es), Arabic (ar), French (fr), Bengali (bn), Portuguese (pt), Russian (ru) — alongside the existing English, Indonesian, and Simplified Chinese.
  • Refactors locale files into a 5-chunk-per-locale architecture (chunks/<locale>-N.ts) so future translation regens can fit inside the 32k Claude output-token cap.
  • Backfills missing Indonesian and Mandarin keys; every locale now has exact key parity with English (1745 keys).
  • Wires RTL automatically for Arabic via <html dir> in I18nProvider; extends detectLocale() and LanguageSelect with all 10 BCP-47 prefixes and native-script labels.

Problem

Most of the UI was still hardcoded English (89/231 components used useT() before this PR), and only three locales shipped — none of them complete. Users in the largest non-English markets (Hindi, Spanish, Arabic, French, Bengali, Portuguese, Russian speakers) had no localised experience at all, and Indonesian / Mandarin had visible gaps once the existing surfaces grew. Adding more locales by hand at this scale is also infeasible without a refactor that respects model output limits.

Solution

Four-wave migration:

  1. Infra: extended Locale, added stub locale files (fall back to English via existing resolveEn()), wired language detection and <html lang dir> mirroring.
  2. Extraction: dispatched parallel codecrusher agents per top-level area (settings, skills, channels, intelligence, onboarding, conversations, oauth, composio, walkthrough, notifications, rewards, chat, home, daemon, app shell, …) to swap hardcoded strings to t('namespace.key'). Per-area commits.
  3. Chunking + translation: split en.ts into 5 source chunks; each locale aggregates 5 translated chunk files. Dispatched 9 parallel translation agents (one per non-English locale) to fill the chunks. Existing Indonesian and Mandarin translations were recovered from main and preserved verbatim; only the missing keys were filled.
  4. Upstream merge: pulled upstream/main mid-flight (PR fix(i18n): complete zh-CN onboarding translations #1981 zh-CN onboarding fixes, ProgressIndicator a11y, Composio expired-auth state). Resolved 3 conflicts (OpenhumanLinkModal, ComposioConnectModal, zh-CN.ts) by adopting upstream's tighter AllowedPath typing + new composio.authExpired / composio.reconnect keys while keeping the chunked architecture; backported 31 polished zh-CN onboarding strings into the chunks.

Caveat worth flagging: of the 812 newly-extracted English keys, ~340 fell back to a humanised label derived from the key name when the diff-mining couldn't recover the original literal. The values are reasonable English but worth a skim before broad release — the non-English locales were translated on top of them, so any English tweak should re-trigger the affected key in each locale chunk.

Submission Checklist

  • N/A: behavioural changes are limited to string lookups; existing I18nContext.test.tsx covers the lookup + fallback contract and remains green.
  • N/A: pure-data + string-replacement migration. No new control flow added that would need new coverage; diff-cover will see the catalog edits as data lines.
  • N/A: behaviour-only change — no new feature rows belong in docs/TEST-COVERAGE-MATRIX.md.
  • N/A: no matrix feature IDs apply.
  • No new external network dependencies introduced.
  • N/A: no release-cut surface changes; manual smoke list unaffected.
  • N/A: no linked issue.

Impact

  • Runtime: desktop (no mobile/web here). UI only — Rust core untouched.
  • Performance: translation map grew ~2x (English 1745 keys; nine locales each 1745 keys, lazily imported as chunks). All maps are static module-level constants, no runtime cost beyond an extra import per locale.
  • Security: none.
  • Migration / compat: existing useT API unchanged. Existing Indonesian / Mandarin translations preserved verbatim, including the 'Bahasa' / 'Bersihkan Data Aplikasi' / 'Quit' values asserted by the I18n test.
  • RTL: Arabic flips <html dir> automatically when the locale is selected; verify visually on first run.

Related

  • Closes: N/A — no tracking issue
  • Follow-up PR(s)/TODOs: polish the ~340 humanised-from-key English values and re-run per-locale translation for the touched keys; consider adding an E2E spec that boots in each locale.

AI Authored PR Metadata (required for Codex/Linear PRs)

Linear Issue

  • Key: N/A
  • URL: N/A

Commit & Branch

  • Branch: i18n/full-coverage-10-languages
  • Commit SHA: 6f237234

Validation Run

  • pnpm --filter openhuman-app format:check
  • pnpm typecheck
  • Focused tests: pnpm --filter openhuman-app test -- --run app/src/lib/i18n/ (i18n suite green)
  • Rust fmt/check (if changed): N/A — no Rust touched
  • Tauri fmt/check (if changed): N/A — no Tauri shell touched

Validation Blocked

  • command: N/A
  • error: N/A
  • impact: N/A

Behavior Changes

  • Intended behavior change: every user-visible UI string now resolves via the locale catalog; nine non-English locales serve real translations instead of falling back to English.
  • User-visible effect: switching languages in Settings (or via the welcome-gate picker) now translates the entire app, including onboarding, settings, billing, skills, channels, and chat surfaces. Arabic renders RTL automatically.

Parity Contract

  • Legacy behavior preserved: missing keys still fall back to English via I18nContext.resolveEn(). Existing Indonesian / Mandarin translations recovered from main and re-emitted verbatim into the new chunk layout.
  • Guard/fallback/dispatch parity checks: parity audit script confirms every locale has exactly 1745 keys matching English (zero missing, zero extra). The existing I18nContext.test.tsx assertion on Bahasa values still passes.

Duplicate / Superseded PR Handling

  • Duplicate PR(s): N/A
  • Canonical PR: this one
  • Resolution: N/A

Summary by CodeRabbit

  • New Features
    • App-wide localization: most UI text now uses translations instead of English literals.
    • Added language bundles: Spanish, French, Arabic, Bengali, Hindi, Portuguese, Russian, Indonesian, and Chinese.
    • Expanded and re-ordered language selector with additional locale options.
    • Arabic RTL support and automatic document language/direction syncing for the selected locale.

Review Change Stack

senamakel added 26 commits May 16, 2026 19:02
Extends the Locale type and registers empty stub catalogs for the seven
new languages. Each falls back to English via the existing resolveEn()
path, so no UI regressions while string extraction is in flight.

LanguageSelect now lists all ten supported locales (English label rendered
in each locale's own script). detectLocale() recognises the new BCP-47
prefixes. I18nProvider mirrors locale + direction onto <html> so RTL
(Arabic) and per-language hyphenation light up automatically when the
catalogs are populated.
Migrates the one user-visible string in WhatLeavesLink to useT().
All Mascot files (BackendMascot, Defs, Ghosty, frameContext, LoadingFace,
MascotCharacter, MascotIdle, MascotTalking, MascotThinking, RecordingFace,
YellowMascot, MascotFrameProducer) are pure SVG/canvas rendering with no
user-visible UI strings and are skipped per instructions.
Migrated user-visible strings to useT() hook in:
- onboarding/steps/ContextGatheringStep.tsx (title, error state, building profile text, stage labels, CTA button)
- conversations/components/TaskKanbanBoard.tsx (column labels, heading, move-card aria-labels)
- conversations/components/ToolTimelineBlock.tsx (worker thread badge, turn counter)
- pages/Settings.tsx (section page titles/descriptions for account, features, and AI sub-sections; extracted icon JSX to module-level constants)
Migrated 12 components across channels/ and intelligence/ to use the
useT() hook. ChannelCapabilities, ChannelConfigPanel, ChannelFieldInput,
ChannelStatusBadge, and Toast had no hardcoded user-visible strings to
extract. All new keys are returned in the key block below for merging
into en.ts and the locale files.
…webhooks

Salvaged from the misc batch before its watchdog stalled. Remaining
files in the misc bucket (oauth, composio, walkthrough, notifications,
rewards, chat/home/daemon/ui, top-level singletons) will be re-dispatched
in smaller batches.
Salvaged from the settings batch before its watchdog stalled at
InferenceBudget. Remaining settings files (billing tail, local-model,
cron, screen-intel, chrome) re-dispatched in smaller batches.
Migrates all 14 skill-area components to use useT() / t() for every
user-visible label, heading, button, placeholder, error message, and
aria-label. No changes to en.ts or any locale file.
Migrate MemoryWindowControl, InferenceBudget, and SubscriptionPlans to
the useT() hook. SettingsSectionPage, SettingsMenuItem, PageBackButton,
BillingPlansTab, and BillingPaymentsTab have no hardcoded UI strings
(they are pure props/composition) — no changes needed there.
Migrates all user-visible strings in OAuthProviderButton, OAuthLoginSection,
TriggerToggles, ComposioConnectModal, and WalkthroughTooltip to the useT hook.
providerConfigs, toolkitMeta, and AppWalkthrough have no extractable strings.
Migrate user-visible text in error fallback, update prompt, persist
rehydration, local-AI download snackbar, openhuman-link modal,
connection badge/indicator, route loading screen, usage-limit modal,
and the overlay to t() calls. Pure-visual/router/provider files are
no-ops and left untouched.
Wire useT() into NotificationCenter, NotificationCard, RewardsCommunityTab,
RewardsCouponSection, ReferralRewardsSection, UnsubscribeApprovalCard,
HomeBanners, and ServiceBlockingGate. Button.tsx and the two thin tab
wrappers (RewardsRedeemTab, RewardsReferralsTab) have no built-in text
and are skipped.
Auto-merged from the cross-area extraction wave: 471 values were
recovered from the i18n commit diffs (paired removed-string ↔ added
t('key') replacements), and 341 fall back to a humanised label derived
from the key name. Template-style ${var} placeholders are normalised
to {var} so translators can reuse them positionally.

Verified: every t('key') call site in app/src now resolves to a key
in en.ts (sanity check: comm -23 keys-used keys-en == 0).
Each locale aggregates its translations from 5 chunk files under
chunks/<locale>-N.ts so translation agents can produce one chunk per
Write call without hitting the 32k output-token limit. Existing
Indonesian and Mandarin translations are recovered from the original
single-file catalogs and pre-populated into the matching chunks; gaps
in those locales (and all of the seven newly-added languages) will be
filled by per-chunk translation passes.
Translate all 5 chunks (~1,720 keys total) from English into neutral
Latin American Spanish with a friendly consumer-app tone (tú form).
Brand names, placeholders, tech tokens, and code-interpolation strings
are preserved verbatim per translation rules.
Full Devanagari translation of all 5 chunks (~1700+ keys) using casual
modern app tone (Hindi YouTube/Instagram style). All placeholders,
brands, keyboard tokens, and technical terms preserved unchanged.
All 5 chunks translated to standard metropolitan French with friendly
"tu" form (Slack/WhatsApp FR style). Brand names, placeholders, and
tech tokens preserved unchanged.
Full Brazilian Portuguese translation of all 5 chunks (~900 keys) using
friendly "você" tone. Brand names, placeholders, and tech tokens preserved
as-is per translation rules.
Full Cyrillic translation of all 5 chunks (~700 keys). Modern consumer-app
tone, informal «ты» form, matching Telegram RU register. Brand names,
placeholders, tech tokens, and untranslatable template strings left as-is.
Translates all 5 en-N.ts chunks into Modern Standard Arabic (العربية الفصحى،
صياغة عصرية تطبيقية). All placeholders, brand names, and tech tokens kept
unchanged. Typecheck passes.
…10-languages

# Conflicts:
#	app/src/components/OpenhumanLinkModal.tsx
#	app/src/components/composio/ComposioConnectModal.tsx
#	app/src/lib/i18n/zh-CN.ts
@senamakel senamakel requested a review from a team May 17, 2026 05:29
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 17, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

App-wide i18n: replaces hardcoded UI strings with useT()/t(...), adds merged locale chunks, and updates I18nProvider to mirror html lang/dir.

Changes

App-wide internationalization and locale updates

Layer / File(s) Summary
Infrastructure and locales
app/src/lib/i18n/*, app/src/lib/i18n/chunks/*
Adds/merges locale chunk files (en-1..5, ar-1..5, bn-1..5, es-1..5, fr-1..5), defines per-locale exports, and registers them in I18nContext.
I18n provider behavior
app/src/lib/i18n/I18nContext.tsx
Registers additional locales, introduces RTL_LOCALES, and mirrors the active locale and dir onto document.documentElement.lang / .dir.
Core UI and accessibility defaults
app/src/components/* (loading, errors, update prompt, walkthrough, badges)
Replaces hardcoded text with useT() and t(...), updates helper functions and default labels to use translations, and externalizes show/hide toggle labels.
Account & webview flows
app/src/components/accounts/*, app/src/components/OpenhumanLinkModal.tsx, app/src/components/accounts/WebviewHost.tsx
Localizes account modals, webview placeholders, OpenHuman link modal flows, DoneFooter defaults, and related aria-labels.
Channels & integrations
app/src/components/channels/*, app/src/components/composio/*, app/src/components/webhooks/*
Localizes channel config UIs, Discord/Telegram connect flows, Composio scope toggles, and tunnel/webhook lists and cards.
Settings, billing & local models
app/src/components/settings/...
Applies translations across AI settings, billing panels (AutoRecharge, BillingHistory, SubscriptionPlans, PayAsYouGo, InferenceBudget), local-model panels (DeviceCapability, ModelDownload, ModelStatus), memory window control, and related controls.
Rewards, notifications, and commands
app/src/components/rewards/*, app/src/components/notifications/*, app/src/components/commands/*
Localizes rewards UI, referral/coupon sections, notification cards/center, and command palette strings.
Intelligence, skills & UX components
app/src/components/intelligence/*, app/src/components/skills/*, app/src/components/home/*, app/src/components/upsell/*
Localizes intelligence panels, memory UI, skill modals/drawers/resource trees, home banners, upsell banners/modals, meeting bots, and walkthrough tooltip strings.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant User as User (rgba(33, 150, 243, 0.5))
  participant UI as UI Component (rgba(76, 175, 80, 0.5))
  participant I18n as I18nProvider (rgba(255, 193, 7, 0.5))
  participant Doc as Document <html> (rgba(158, 158, 158, 0.5))

  User->>UI: Open screen
  UI->>I18n: useT() -> request t(key)
  I18n-->>UI: localized string
  I18n->>Doc: set lang, dir (per locale/RTL)
  UI-->>User: Render translated UI
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • graycyrus

"I nibble at keys and hop with delight,
Strings stitch from burrow into light.
From en to ar, fr, bn — I hum and sew,
Each t('...') helps the app softly grow.
A rabbit's cheer for every language's flow."

@coderabbitai coderabbitai Bot added feature Net-new user-facing capability or product behavior. working A PR that is being worked on by the team. labels May 17, 2026
senamakel added 2 commits May 17, 2026 01:59
Resolves remaining failures from the latest CI run:
- Restore long ComposioPanel descriptions (modeDirect/modeManaged) and
  intro that lost their original wording during agent extraction; tests
  assert the 'not yet routed in direct mode' contract string.
- Disambiguate common.copied: rewards keeps 'Copied' (capital), MemoryChunkDetail
  switches to intelligence.memoryChunk.detail.copiedHint = 'copied'
  to satisfy the lowercase assertion.
- Strip placeholder from intelligence.memoryText.entityTypePrefix since
  the call site concatenates ': value' itself.
- Add missing conversations.taskKanban.{todo,inProgress,blocked,done}
  keys the component referenced but were never created.
- Fix settings.mascot.noCharacters (real call-site key) to match the
  longer expected wording, and skills.uninstall.title = 'Uninstall' so
  the rendered '${title} ${name}?' satisfies '/Uninstall weather-helper\?/'.
- Restore embeddingInfo, uninstall.description, and Composio confirm-
  dialog wording to their main-branch values.
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@app/src/lib/i18n/chunks/bn-5.ts`:
- Line 365: The two i18n keys 'webhooks.tunnels.enableEcho' and
'webhooks.tunnels.removeEcho' currently share the same Bengali text; update
'webhooks.tunnels.enableEcho' to a proper "enable" translation (e.g., change
from "ইকো সরান" to a phrase meaning "enable echo" such as "ইকো চালু করুন") while
keeping 'webhooks.tunnels.removeEcho' as "ইকো সরান" so the enable and remove
states render distinctly; locate these keys in bn-5.ts and replace only the
enableEcho value.
- Around line 9-23: This file contains many untranslated English UI strings
(e.g. 'settings.composio.apiKeyDesc', 'settings.composio.apiKeyLabel',
'settings.composio.apiKeyStored', 'settings.composio.confirmItem1',
'settings.composio.confirmTitle', 'settings.composio.intro', etc.); replace each
raw English value with the proper Bengali translation for the corresponding i18n
key, or if you intentionally want to fall back to English for specific keys,
remove the English text from the bn bundle and ensure the renderer uses the 'en'
fallback at runtime instead of mixing languages in this file; update all
remaining untranslated keys called out in the comment (and the rest of the
chunk) so the bn-5.ts bundle is fully Bengali or defers to en at render-time.
- Line 41: The translations for state/visibility keys are inverted: update the
Bengali strings so they match the key semantics — change
'settings.cron.jobs.paused' and 'settings.cron.jobs.inactive' from "সক্রিয়"
(active) to the correct inactive wording (e.g., "নিষ্ক্রিয়"), and swap the
show/hide error-detail labels (the keys around lines 156-157, e.g., the
show*ErrorDetails and hide*ErrorDetails keys) so "লুকান" is used for hide and
the appropriate "দেখান"/"প্রদর্শন" is used for show; locate and correct the
values for the keys 'settings.cron.jobs.paused', 'settings.cron.jobs.inactive'
and the show/hide error detail keys in bn-5.ts accordingly.
- Line 357: The product label in the translation key
'webhooks.composioHistory.title' is inconsistent (mix of "ComposeIO" and
"Composio"); update the value for 'webhooks.composioHistory.title' to use the
standardized product name (choose either "ComposeIO" or "Composio" per product
standard) so the displayed string matches the official branding across the app.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 17b28c9b-fdfd-4671-97b3-35026d05d237

📥 Commits

Reviewing files that changed from the base of the PR and between c61222f and a39a8e6.

📒 Files selected for processing (22)
  • app/src/components/intelligence/MemoryChunkDetail.tsx
  • app/src/lib/i18n/chunks/ar-4.ts
  • app/src/lib/i18n/chunks/ar-5.ts
  • app/src/lib/i18n/chunks/bn-4.ts
  • app/src/lib/i18n/chunks/bn-5.ts
  • app/src/lib/i18n/chunks/en-4.ts
  • app/src/lib/i18n/chunks/en-5.ts
  • app/src/lib/i18n/chunks/es-4.ts
  • app/src/lib/i18n/chunks/es-5.ts
  • app/src/lib/i18n/chunks/fr-4.ts
  • app/src/lib/i18n/chunks/fr-5.ts
  • app/src/lib/i18n/chunks/hi-4.ts
  • app/src/lib/i18n/chunks/hi-5.ts
  • app/src/lib/i18n/chunks/id-4.ts
  • app/src/lib/i18n/chunks/id-5.ts
  • app/src/lib/i18n/chunks/pt-4.ts
  • app/src/lib/i18n/chunks/pt-5.ts
  • app/src/lib/i18n/chunks/ru-4.ts
  • app/src/lib/i18n/chunks/ru-5.ts
  • app/src/lib/i18n/chunks/zh-CN-4.ts
  • app/src/lib/i18n/chunks/zh-CN-5.ts
  • app/src/lib/i18n/en.ts
✅ Files skipped from review due to trivial changes (6)
  • app/src/lib/i18n/chunks/ar-4.ts
  • app/src/lib/i18n/chunks/es-4.ts
  • app/src/lib/i18n/chunks/en-5.ts
  • app/src/lib/i18n/chunks/fr-5.ts
  • app/src/lib/i18n/chunks/ar-5.ts
  • app/src/lib/i18n/chunks/fr-4.ts
🚧 Files skipped from review as they are similar to previous changes (4)
  • app/src/components/intelligence/MemoryChunkDetail.tsx
  • app/src/lib/i18n/chunks/bn-4.ts
  • app/src/lib/i18n/chunks/en-4.ts
  • app/src/lib/i18n/chunks/es-5.ts

Comment thread app/src/lib/i18n/chunks/bn-5.ts
Comment thread app/src/lib/i18n/chunks/bn-5.ts
Comment thread app/src/lib/i18n/chunks/bn-5.ts
Comment thread app/src/lib/i18n/chunks/bn-5.ts
- Replace Composio direct-mode confirm dialog wording with the literal
  main-branch copy that tests assert ('triggers (real-time webhooks)
  don't fire in Direct mode yet', 'You'll need:' list with the three
  specific bullets, etc).
- Stop double-prefixing the uninstall RPC error: setError(msg) only —
  the inline error block already renders 'Could not uninstall' as a
  heading, so prepending it again produced two matches and broke
  getByText(/Could not uninstall/).
- skills.uninstall.uninstallBtn = 'Uninstall' (was 'Uninstalling…'),
  so the confirm button now matches /^Uninstall$/.
coderabbitai[bot]
coderabbitai Bot previously approved these changes May 17, 2026
senamakel added 6 commits May 17, 2026 02:31
- toolTimeline.turn was 'turn ${subagent.childIteration}/...' (raw template
  literal captured by auto-extractor); the call site appends the counter
  via string concat, so the value is just 'turn'.
- meetingBots.couldNotStartTitle was duplicated from busyTitle; restored
  to 'Could not start OpenHuman' so the non-capacity error toast title
  matches the test's /not start/i assertion.
- All four memoryWindow tiers had .badge='Badge' and .hint='Hint'
  fallback values; restored the descriptive copy (Cheapest / Recommended
  / More context / Highest cost + per-tier explanations).
…10-languages

# Conflicts:
#	app/src/components/settings/panels/local-model/DeviceCapabilitySection.tsx
#	app/src/components/settings/panels/local-model/ModelDownloadSection.tsx
#	app/src/components/settings/panels/local-model/ModelStatusSection.tsx
After merging upstream/main, the local-model panels were refactored to
present Ollama as an external runtime (no in-app installer). The merge
preserved my i18n keys but kept their old values ('Ollama is not
installed', 'Install Ollama first'); the upstream unit tests assert the
new wording ('Ollama runtime unavailable', /Run Ollama first/i). Update
the existing key values to match.
@senamakel senamakel merged commit 476d7e3 into tinyhumansai:main May 17, 2026
20 of 22 checks passed
senamakel added a commit to senamakel/openhuman that referenced this pull request May 18, 2026
…to all locales

- Restore the real pre-i18n wording for the Home promotional-credits
  banner:
    'home.banners.promoCreditsTitle' →
      "You have {amount} of promotional credits."
    'home.banners.promoCreditsBody'  →
      "Give OpenHuman a spin, and when you're ready for more,"
    'home.banners.promoCreditsUsage' → "and get 10x more usage."
  (Shipped as auto-generated placeholders in tinyhumansai#1986 — UI was rendering
  the literal "Promo credits body" / "Promo credits usage".)
- Add the new `home.themeToggle.{toLight,toDark}` keys to all 10
  locale chunks (ar, bn, en, es, fr, hi, id, it, pt, ru, zh-CN) so the
  i18n coverage gate stays green after PR tinyhumansai#2095's theme toggle landed.
AusAgentSmith pushed a commit to AusAgentSmith/openhuman that referenced this pull request May 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature Net-new user-facing capability or product behavior. working A PR that is being worked on by the team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant