feat(i18n): multilingual setup wizard — first-run language picker + gettext (zh/ja/es/fr/de)#20736
Open
songchao0421 wants to merge 1 commit into
Open
feat(i18n): multilingual setup wizard — first-run language picker + gettext (zh/ja/es/fr/de)#20736songchao0421 wants to merge 1 commit into
songchao0421 wants to merge 1 commit into
Conversation
c2371da to
7ec19f8
Compare
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
Internationalisation for the interactive
hermes setupwizard using Python gettext.Background & Motivation
Hermes Agent is used by developers worldwide. The very first command a new user runs is almost always
hermes setup— an interactive wizard that configures the model provider, terminal backend, messaging gateway, tool chain, and agent settings. Until now, every prompt, explanation, and error message in that wizard was hard-coded in English. For non-English speakers, this meant they had to complete a series of fairly technical setup steps — API keys, model parameters, gateway configs — in a language they might not be comfortable with, before they had even got the agent running.This PR lowers that barrier by making the entire setup wizard speak the user's language.
What this PR adds
hermes setupis run on a fresh install. The chosen locale is persisted toconfig.yamlunderdisplay.language._()— all section headers, prompts, info messages, warnings, success messages, and tooltips insetup.pyare now translatable.Language coverage (initial batch)
Adding a new language is trivial: create
hermes_cli/i18n/<locale>/LC_MESSAGES/setup.po, translate themsgstrentries, add one line tolanguages.py— no Python code changes required.Why gettext?
We evaluated three common approaches:
gettext— Zero dependencies, thirty-year industry track record,.po/.mo/.potformat supported by every major translation platform, and_()markers live inline next to the strings they translate so developers cannot forget them.Runtime architecture
__init__.pykeeps a module-level_current_translationsobject.setup_i18n(locale)initialises it once at the top ofrun_setup_wizard. If the locale file is missing or corrupt,fallback=Truesilently yieldsNullTranslations, so the wizard never crashes — it simply falls back to English msgids.Language-picker flow
The result is saved immediately after the user picks a language. If they later press Ctrl+C during provider configuration, the language choice survives and will not be asked again on the next run.
String extraction workflow
All user-facing strings are wrapped with
_(). f-strings are converted tostr.formatso thatxgettextcan extract the msgid correctly:Running
./hermes_cli/i18n/update_translations.shregeneratessetup.pot, merges changes into every existing.po, and recompiles all.mofiles.Scope: setup wizard only
This is an intentional product decision, not a technical limitation:
setup.pycontains ~300 user-facing strings. Localising the entire CLI surface would produce an unreviewable diff.Future expansion to other CLI surfaces (e.g.
hermes configprompts) follows the exact same pattern: add a domain, wrap strings with_(), done.Backwards compatibility
config.yamlalready had adisplay.languagekey with a default of"en". This PR changes the default to""(empty string) so that the picker fires on first run. Existing users who already have"en"configured will not see the picker again; their setting is respected and simply loaded.Files changed
hermes_cli/setup.py_()wrappers on all user-facing strings;_select_and_init_language()entry pointhermes_cli/config.pydisplay.languagedefault changed to""to trigger picker on first runhermes_cli/i18n/__init__.pyhermes_cli/i18n/languages.pyhermes_cli/i18n/setup.pothermes_cli/i18n/update_translations.shhermes_cli/i18n/.gitattributes.mofileshermes_cli/i18n/*/LC_MESSAGES/setup.{po,mo}Future work
.pofiles by hand..mofiles in CI rather than committing binaries to git.$LANG/$LC_ALLto pre-select the default language.Closes #12375, #20155, #16546, #13625