Skip to content

feat(desktop): localize built-in personality labels in the settings picker - #65406

Open
hansai-art wants to merge 1 commit into
NousResearch:mainfrom
hansai-art:feat/personality-labels-i18n
Open

hansai-art wants to merge 1 commit into
NousResearch:mainfrom
hansai-art:feat/personality-labels-i18n

Conversation

@hansai-art

@hansai-art hansai-art commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

What does this PR do?

Fixes the Personality picker in Desktop Settings showing raw English ids (pirate, uwu, noir) in every locale, and brings the Traditional Chinese catalog back to parity with en.ts.

The personality ids are already stable i18n keys, so no backend change is needed: a new settings.config.personalityLabels map is added to the catalog and passed to the existing optionLabels prop, exactly mirroring the tts.elevenlabs.voice_id pattern already in config-settings.tsx. Config ids, /personality <name> args, and custom personalities are untouched; customs still render via prettyName.

This PR supersedes #65405 (feat/i18n-zh-hant-desktop). Both branches rewrote apps/desktop/src/i18n/zh-hant.ts from the same base, so they could never both merge. This one is the strict superset (catalog catch-up plus the personality feature), and it now folds in the 7 keys that were unique to #65405: keybinds.search, settings.nav.keybinds, settings.providers.localEndpoint.title, settings.providers.localEndpoint.description, onboarding.fireworksPitch, shell.statusbar.modelPinned, sidebar.row.ownedByProfile. #65405 can be closed in favour of this one.

Rebuilt on current main, additively. The branch is now a single commit on top of main, and zh-hant.ts was edited additively starting from main's version rather than replaced wholesale, so the keys main gained after these branches were cut are preserved: the settings.toolsets.terminalBackend.* block (11 keys), settings.config.builtinOnly, settings.nav.billing, settings.toolsets.needsSetup, settings.toolsets.needsSignIn, and the 5 fieldLabels.tts.xai.* additions. Verified mechanically — see "How to Test".

Related Issue

Fixes #64132

Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)
  • ✨ New feature (non-breaking change that adds functionality)
  • 🔒 Security fix
  • 📝 Documentation update
  • ✅ Tests (adding or improving test coverage)
  • ♻️ Refactor (no behavior change)
  • 🎯 New skill (bundled or hub)

Changes Made

  • apps/desktop/src/i18n/types.ts — add settings.config.personalityLabels: Record<string, string>.
  • apps/desktop/src/i18n/en.ts — English labels for the 14 built-in personalities (source of truth for fallbacks).
  • apps/desktop/src/i18n/zh.ts, apps/desktop/src/i18n/ja.ts — localized personality labels.
  • apps/desktop/src/i18n/zh-hant.ts — localized personality labels plus 313 catalog keys that zh-Hant was missing relative to en.ts: the keybinds panel, desktop plugins page, Hermes Cloud gateway flow, MCP catalog tab, model defaults/fallbacks, skills hub, maintenance/ops panel, starmap sharing, tab-bar and composer strings.
  • apps/desktop/src/app/settings/config-settings.tsx — pass t.settings.config.personalityLabels as optionLabels when key === 'display.personality'.
  • apps/desktop/src/app/settings/helpers.test.ts — two new tests (see below).

How to Test

  1. cd apps/desktop && npm run typecheck — passes (tsc -p . --noEmit and tsc -p tsconfig.electron.json --noEmit, 0 errors).
  2. cd apps/desktop && npx vitest run --project ui src/app/settings/helpers.test.ts — 32/32 pass, including the two new personalityLabels cases.
  3. cd apps/desktop && npx vitest run — 2043 passed / 2 failed / 2 skipped. The 2 failures are in src/app/settings/billing/index.test.tsx and reproduce identically on unmodified main (pre-existing, unrelated to this PR).
  4. Catalog parity, checked by flattening the leaf keys of the object literals (the fieldLabels/fieldDescriptions subtree is excluded from the set math because en.ts uses the imported FIELD_LABELS/FIELD_DESCRIPTIONS constants while zh-hant.ts uses defineFieldCopy({...}) — a structural asymmetry, not a gap):
    • en.ts: 2330 leaf keys (excluding that subtree).
    • zh-hant.ts on this branch: 2330 leaf keys (excluding that subtree) + 116 in the subtree.
    • en.ts minus zh-hant.ts = 0 missing.
    • zh-hant.ts minus en.ts = 0 extra (no junk keys).
    • main's zh-hant.ts minus this branch's = 0 (nothing regressed), including the subtree.
  5. In the app: Settings → Config → Personality. Labels are localized in zh, zh-hant, ja; English elsewhere; custom personality ids still show prettyName(id).

Checklist

Code

  • I've read the Contributing Guide
  • My commit messages follow Conventional Commits (fix(scope):, feat(scope):, etc.)
  • I searched for existing PRs to make sure this isn't a duplicate
  • My PR contains only changes related to this fix/feature (no unrelated commits)
  • I've run pytest tests/ -q and all tests pass — N/A, this change is JS/TS only; ran the desktop vitest suite instead (see "How to Test")
  • I've added tests for my changes (required for bug fixes, strongly encouraged for features)
  • I've tested on my platform: macOS 15 (Darwin 25.5)

Documentation & Housekeeping

  • I've updated relevant documentation (README, docs/, docstrings) — N/A
  • I've updated cli-config.yaml.example if I added/changed config keys — N/A (no new config keys; only UI display names for existing ids)
  • I've updated CONTRIBUTING.md or AGENTS.md if I changed architecture or workflows — N/A
  • I've considered cross-platform impact (Windows, macOS) per the compatibility guide — N/A, UI catalog plus one component prop, no platform-specific behavior
  • I've updated tool descriptions/schemas if I changed tool behavior — N/A

Notes for reviewers

  • New tests in helpers.test.ts: one asserts every BUILTIN_PERSONALITIES id has a label in every locale (guards the list and the map drifting apart); the other asserts zh / zh-hant / ja actually differ from English rather than silently falling through defineLocale().
  • Follow-up (separate PR if wanted): the same treatment for the CLI/gateway /personality list via a personality.names map in locales/*.yaml.
  • Heads-up on a possible textual conflict: fix(i18n): align desktop zh/zh-hant allowSession wording with CLI #64002 also edits apps/desktop/src/i18n/zh-hant.ts (the allowSession wording). It touches a different region of the file, but whichever lands second will need a trivial rebase.

@alt-glitch alt-glitch added type/feature New feature or request P3 Low — cosmetic, nice to have comp/desktop Electron desktop app (apps/desktop/*) labels Jul 16, 2026

@teknium1 teknium1 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks for the focused picker change. The current-main premise is valid: apps/desktop/src/app/settings/config-settings.tsx:134 falls back to prettyName, and current main does not supply personality option labels at :472. The PR’s optionLabels wiring at apps/desktop/src/app/settings/config-settings.tsx:472-477 correctly preserves custom-personality fallback behavior.

Problems

  • Japanese remains incomplete. apps/desktop/src/i18n/catalog.ts:7-12 registers ja, while apps/desktop/src/i18n/define-locale.ts:39-40 merges missing keys from English. This PR adds personalityLabels only to en.ts, zh.ts, and zh-hant.ts; ja.ts has no override. Japanese users would therefore still see English labels such as Pirate. The existing test only checks truthiness, so the English fallback passes it. This conflicts with the Desktop checklist in apps/desktop/AGENTS.md:197-198 to update all locales.

Suggested changes

  • Add the 14 Japanese labels in apps/desktop/src/i18n/ja.ts and assert at least one representative Japanese label differs from English.

Automated hermes-sweeper review.

invalidJson: 'Invalid config JSON',
// Display names for the built-in personalities (config IDs stay English).
// Custom personalities fall back to prettyName(id) in the picker.
personalityLabels: {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Please add a matching Japanese override in ja.ts. ja is registered in the catalog and defineLocale() fills absent keys from this English map, so without an override the Japanese picker still displays English labels; the current truthiness test will not catch that fallback.

@teknium1 teknium1 added the sweeper:blast-contained Sweeper blast radius: contained — one narrow path / opt-in / few users label Jul 16, 2026
@hansai-art

Copy link
Copy Markdown
Contributor Author

Addressed in b14a613 - added the 14 ja.ts labels and a representative-difference assertion so the fallback can't satisfy the test. Thanks for the review!

… catch-up

The Personality picker rendered raw English ids (`pirate`, `uwu`, `noir`)
in every locale (NousResearch#64132). The ids are already stable i18n keys, so no
backend change is needed:

- `i18n/types.ts` + `en.ts`: new `settings.config.personalityLabels` map
  covering all 14 built-ins.
- `zh.ts` / `ja.ts` / `zh-hant.ts`: localized display names. Locales that
  do not override fall back to English via `defineLocale()`.
- `config-settings.tsx`: pass the map as `optionLabels` for
  `display.personality`, mirroring the `tts.elevenlabs.voice_id` pattern.
- Config ids, `/personality <name>` args and custom personalities are
  untouched; customs still render via `prettyName`.

Also brings the zh-Hant catalog back to parity with `en.ts` (313 keys:
keybinds panel, desktop plugins, Hermes Cloud gateway, MCP catalog,
model defaults, skills hub, maintenance/ops, starmap sharing, tab and
composer strings). This supersedes NousResearch#65405 and folds in its 7 unique
keys. All keys `main` gained after these branches were cut
(`settings.toolsets.terminalBackend.*`, `settings.config.builtinOnly`,
`settings.nav.billing`, `settings.toolsets.needsSetup` /
`needsSignIn`, the fieldLabels/fieldDescriptions additions) are
preserved.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AG6LyYMvHC2o6HbVUozmVR
@Enough1122

Copy link
Copy Markdown
Contributor

我也开了 #71231 顶一个 minimal 备选(基于当前 main,+132/-1,只做 personality 本地化),跟本 PR 的核心改动几乎一样,但不携带 zh-hant 那 +336 行的额外语料。如果 maintainer 想先合人格本地化、其余语料下次单独走,#71231 应该更容易收口;如果更愿意保留本 PR 的完整语料,我也完全 OK,#71231 可直接关。

(纯属技术备选,没有任何想抢你贡献的意思 🙏)

@hansai-art

Copy link
Copy Markdown
Contributor Author

Thanks for flagging #71231 rather than just opening it quietly, and for the offer to close it. I'd rather you keep it open.

Two things make yours the better review path, independent of who wrote what:

  1. This PR is dirty against current main. i18n(desktop): localize built-in personality labels in the settings picker #71231 is cut from current base.
  2. This PR bundles two separately reviewable concerns: the personality-picker localization (#64132) and a ~336-line zh-Hant catalog top-up. i18n(desktop): localize built-in personality labels in the settings picker #71231 is the narrow one: +132/-1, one concern. AGENTS.md asks for exactly that ("keep the change to the narrow piece that was actually agreed; offer the rest as a focused follow-up").

So: I am not rebasing this one to compete with #71231. If a maintainer wants the personality fix, yours is the one to take.

One note on the catalog half, in case it is useful to whoever picks this up: it should not be carried by a wholesale rewrite of apps/desktop/src/i18n/zh-hant.ts. main has gained keys since either of our branches was cut, and replacing the file regresses them. It needs to be an additive edit against current main, which is a separate PR.

No concern at all about the overlap. Narrowing the surface is the right call.

@GottZ

GottZ commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

This was generated by AI during triage.

Summary

Three PRs are in this complex: #65406 and #71231 both address #64132 by supplying localized display labels through the existing optionLabels path while preserving stored IDs and custom-personality fallback; #65405 is the broader zh-Hant catalog work referenced by #65406 but does not change the personality picker. #65406 bundles both concerns, whereas #71231 isolates the picker fix.

Related pull requests

Duplicates

#65406 and #71231 duplicate the core personality-picker fix for #64132; #65406 additionally subsumes the separate catalog scope represented by closed #65405.

Suggested consolidation

Keep #71231 open with a salvage path as the focused vehicle: its visible diff retains the effective picker fix and addresses both objections from the contributor's keep_open review. Close #65406 as a duplicate of #71231 for the #64132 scope despite its recorded best-fix and keep_open verdicts, because its author explicitly declined to rebase it, endorsed #71231, and its diff bundles the independent zh-Hant catalog work; retain that catalog work only as a separate focused follow-up, while #65405 remains closed as superseded reference material.

Complex graph

flowchart LR
    classDef open fill:#dbeafe,stroke:#1d4ed8,color:#1e3a8a
    classDef merged fill:#dcfce7,stroke:#15803d,color:#14532d
    classDef closed fill:#e5e7eb,stroke:#6b7280,color:#1f2937
    classDef unverified fill:#f3f4f6,stroke:#9ca3af,color:#374151
    classDef best stroke-width:3px,stroke:#b45309
    classDef target stroke-width:3px,stroke:#4338ca
    I64132(["issue #64132 (open)"])
    subgraph Dup65406 ["PRs duplicating each other"]
        P65406["PR #65406 (open)"]
        P71231["PR #71231 (open)"]
    end
    P65406 -->|best fix| I64132
    class I64132 open
    class P65406 open
    class P71231 open
    class P65406 best
    class P71231 best
    class P65406 target
    click I64132 "https://github.com/NousResearch/hermes-agent/issues/64132"
    click P65406 "https://github.com/NousResearch/hermes-agent/pull/65406"
    click P71231 "https://github.com/NousResearch/hermes-agent/pull/71231"
Loading

Graph: solid arrow = fixes / best fix, dashed arrow = partial or unverified (see edge label); boxed group = PRs duplicating each other; amber border = best fix; indigo border = target; gray node = closed (state tag in the node label).

Cross-PR triage: Reviewed 3 pull requests and 1 issue in this complex. Each diff was read against this issue; Assessment working set: 49 kB of PR diffs, 15 kB of issue/PR text, 11 kB of discussion (16 comments), 4 verify verdicts. verdicts reflect diff content, not PR titles. Part of an automated triage batch.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/desktop Electron desktop app (apps/desktop/*) P3 Low — cosmetic, nice to have sweeper:blast-contained Sweeper blast radius: contained — one narrow path / opt-in / few users type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Desktop app "Personality" picker labels are all English — unreadable for Simplified Chinese users (and most non-English locales)

5 participants