|
| 1 | +# Multilanguage Support Design |
| 2 | + |
| 3 | +Date: 2026-04-04 |
| 4 | +Repo: `gdb-cli` |
| 5 | +Issue: `#1 [Feature] add multilanguage support` |
| 6 | + |
| 7 | +## Goal |
| 8 | + |
| 9 | +Add first-version multilanguage support for: |
| 10 | + |
| 11 | +- Runtime CLI help and user-facing messages |
| 12 | +- JSON response messages, hints, warnings, and suggestions generated by `gdb-cli` |
| 13 | +- Repository README files |
| 14 | + |
| 15 | +The first supported languages are: |
| 16 | + |
| 17 | +- `en` |
| 18 | +- `zh-CN` |
| 19 | +- `ru` |
| 20 | + |
| 21 | +## Non-Goals |
| 22 | + |
| 23 | +This first version does not include: |
| 24 | + |
| 25 | +- Full translation of raw GDB error text returned by GDB itself |
| 26 | +- Automatic translation workflows for README files |
| 27 | +- External localization tooling such as `gettext`, `.po`, or `.mo` |
| 28 | +- Translation of internal test comments or developer-only notes |
| 29 | + |
| 30 | +## Design Summary |
| 31 | + |
| 32 | +The implementation uses a lightweight runtime i18n layer plus static multi-file README documents. |
| 33 | + |
| 34 | +- Runtime strings are translated through a centralized Python i18n module. |
| 35 | +- English is the source and fallback language. |
| 36 | +- Locale resolution is deterministic and tolerant of alias formats such as `zh_CN` or `ru_RU`. |
| 37 | +- README localization is handled as separate files in the repository root, following the pattern used in `cmux`. |
| 38 | + |
| 39 | +This keeps runtime internationalization and documentation localization decoupled. That reduces implementation cost, avoids introducing a build-time translation pipeline, and matches the current size of the project. |
| 40 | + |
| 41 | +## Approach Comparison |
| 42 | + |
| 43 | +### Recommended: lightweight i18n module |
| 44 | + |
| 45 | +Use a small runtime translation layer that provides locale detection, key lookup, parameter interpolation, and English fallback. |
| 46 | + |
| 47 | +Why this is the recommended approach: |
| 48 | + |
| 49 | +- It fits the current CLI project size. |
| 50 | +- It keeps translation behavior centralized. |
| 51 | +- It avoids the operational overhead of `gettext`. |
| 52 | +- It is compatible with future expansion if more languages or more commands are added. |
| 53 | + |
| 54 | +### Alternative 1: `language.py` constants only |
| 55 | + |
| 56 | +This would be fast to start but would likely degrade into large unstructured dictionaries spread across modules. It also tends to push locale detection, interpolation, and fallback behavior out to call sites. |
| 57 | + |
| 58 | +### Alternative 2: `gettext` |
| 59 | + |
| 60 | +This would be more standard for large mature applications, but it is heavier than needed for the current repository. It also does not solve README localization by itself, so it adds complexity without enough payoff in this first iteration. |
| 61 | + |
| 62 | +## Architecture |
| 63 | + |
| 64 | +### Runtime i18n module |
| 65 | + |
| 66 | +Add a new module at `src/gdb_cli/i18n.py`. |
| 67 | + |
| 68 | +Responsibilities: |
| 69 | + |
| 70 | +- Resolve the active locale |
| 71 | +- Normalize locale identifiers |
| 72 | +- Expose a translation function such as `t(key, **params)` |
| 73 | +- Fall back to English when a translation is missing |
| 74 | +- Keep translation behavior independent from command logic |
| 75 | + |
| 76 | +Expected locale precedence: |
| 77 | + |
| 78 | +1. Explicit process override through environment variable `GDB_CLI_LANG` |
| 79 | +2. System locale detection |
| 80 | +3. Default to `en` |
| 81 | + |
| 82 | +Future CLI flags such as `--lang` are intentionally deferred. The first version should not expand the command surface unless needed. |
| 83 | + |
| 84 | +### Translation catalog layout |
| 85 | + |
| 86 | +Store message catalogs in a dedicated module, for example: |
| 87 | + |
| 88 | +- `src/gdb_cli/messages.py` |
| 89 | + |
| 90 | +or a locale package, for example: |
| 91 | + |
| 92 | +- `src/gdb_cli/locales/en.py` |
| 93 | +- `src/gdb_cli/locales/zh_cn.py` |
| 94 | +- `src/gdb_cli/locales/ru.py` |
| 95 | + |
| 96 | +The preferred implementation is a locale package because it scales better once message count grows. |
| 97 | + |
| 98 | +Each language file contains the same stable keys. Example key families: |
| 99 | + |
| 100 | +- `cli.group.help` |
| 101 | +- `cli.load.binary_help` |
| 102 | +- `cli.load.core_help` |
| 103 | +- `cli.error.session_not_found` |
| 104 | +- `errors.ptrace_denied.suggestion` |
| 105 | +- `env_check.gdb_below_minimum` |
| 106 | + |
| 107 | +Keys are stable identifiers; user-facing text lives only in catalogs. |
| 108 | + |
| 109 | +### README localization |
| 110 | + |
| 111 | +Add root-level README files: |
| 112 | + |
| 113 | +- `README.md` for English |
| 114 | +- `README.zh-CN.md` for Simplified Chinese |
| 115 | +- `README.ru.md` for Russian |
| 116 | + |
| 117 | +Each README includes a language switcher near the top. The current language is rendered as plain text; other languages are links. |
| 118 | + |
| 119 | +README files are maintained manually. They should preserve: |
| 120 | + |
| 121 | +- Equivalent installation instructions |
| 122 | +- Equivalent command examples |
| 123 | +- Equivalent feature descriptions |
| 124 | + |
| 125 | +Small phrasing differences are acceptable, but technical meaning must stay aligned. |
| 126 | + |
| 127 | +## Data Flow |
| 128 | + |
| 129 | +### Runtime translation flow |
| 130 | + |
| 131 | +1. Process starts and imports CLI modules. |
| 132 | +2. Runtime i18n resolves the locale using environment or system settings. |
| 133 | +3. CLI help text, user-facing messages, and error wrappers call `t(key, **params)`. |
| 134 | +4. The translator looks up the key in the active locale catalog. |
| 135 | +5. If the key is missing, it looks up the same key in the English catalog. |
| 136 | +6. If interpolation parameters are provided, they are formatted into the translated string. |
| 137 | +7. The resulting text is returned to the caller and emitted through Click or JSON output. |
| 138 | + |
| 139 | +### README selection flow |
| 140 | + |
| 141 | +There is no runtime logic. Users select the README by following links at the top of the root document. |
| 142 | + |
| 143 | +## Locale Normalization Rules |
| 144 | + |
| 145 | +The i18n layer must normalize common locale spellings into the supported set. |
| 146 | + |
| 147 | +Examples: |
| 148 | + |
| 149 | +- `en`, `en_US`, `en-US` -> `en` |
| 150 | +- `zh`, `zh_CN`, `zh-CN`, `zh_Hans_CN` -> `zh-CN` |
| 151 | +- `ru`, `ru_RU`, `ru-RU` -> `ru` |
| 152 | + |
| 153 | +If a locale cannot be mapped to a supported language, use `en`. |
| 154 | + |
| 155 | +This rule is required to keep behavior stable across shells, CI, and different operating systems. |
| 156 | + |
| 157 | +## Scope of Runtime Translation |
| 158 | + |
| 159 | +The first version should translate all user-facing strings produced directly by this project in the CLI layer and high-value supporting modules. |
| 160 | + |
| 161 | +Priority targets: |
| 162 | + |
| 163 | +- Click command group help text |
| 164 | +- Click option help text |
| 165 | +- Click command docstrings shown in help output |
| 166 | +- CLI-generated `message`, `error`, `details`, `hint`, `warning`, and `suggestion` fields |
| 167 | +- Environment check guidance and actionable suggestions |
| 168 | + |
| 169 | +Deferred targets: |
| 170 | + |
| 171 | +- Free-form GDB-originated message bodies |
| 172 | +- Arbitrary strings returned directly from GDB internals when there is no stable local wrapper |
| 173 | + |
| 174 | +For deferred targets, wrap the message in translated outer context where possible, but preserve the original dynamic payload. |
| 175 | + |
| 176 | +## Error Handling |
| 177 | + |
| 178 | +The i18n implementation must fail safely. |
| 179 | + |
| 180 | +- Missing translation key must not crash CLI execution. |
| 181 | +- Missing translation key falls back to English. |
| 182 | +- Missing interpolation parameter should surface as a development error in tests, not silently produce malformed user text. |
| 183 | +- Unsupported locale should resolve to English. |
| 184 | + |
| 185 | +This keeps internationalization from becoming a reliability risk. |
| 186 | + |
| 187 | +## Testing Strategy |
| 188 | + |
| 189 | +Add targeted tests for the i18n behavior and key CLI integration points. |
| 190 | + |
| 191 | +Required coverage: |
| 192 | + |
| 193 | +- Locale normalization for English, Chinese, and Russian aliases |
| 194 | +- Locale fallback to English for unsupported locales |
| 195 | +- Translation lookup for the three supported languages |
| 196 | +- English fallback when a key is missing in a non-English catalog |
| 197 | +- CLI help output under different locales |
| 198 | +- Representative error and suggestion text under different locales |
| 199 | + |
| 200 | +The goal is not exhaustive snapshot coverage for every command in the first pass. The goal is to verify the translation mechanism and enough representative commands to prevent regressions. |
| 201 | + |
| 202 | +## Migration Strategy |
| 203 | + |
| 204 | +The rollout should be incremental. |
| 205 | + |
| 206 | +1. Introduce the i18n module and translation catalogs. |
| 207 | +2. Convert central CLI entry points and shared error helpers. |
| 208 | +3. Convert `env_check.py` suggestions and warnings. |
| 209 | +4. Add Russian README and update language switchers in all README files. |
| 210 | +5. Add or update tests to lock behavior. |
| 211 | + |
| 212 | +This sequence keeps the integration safe and reviewable. |
| 213 | + |
| 214 | +## Risks And Mitigations |
| 215 | + |
| 216 | +### Risk: Click help strings are evaluated early |
| 217 | + |
| 218 | +Mitigation: |
| 219 | +Design the translation helper so help text can be resolved safely at import time, or define a small helper pattern that Click decorators can consume consistently. |
| 220 | + |
| 221 | +### Risk: Message catalogs drift across languages |
| 222 | + |
| 223 | +Mitigation: |
| 224 | +Add tests that compare key sets across `en`, `zh-CN`, and `ru`. |
| 225 | + |
| 226 | +### Risk: Partial translation creates mixed-language output |
| 227 | + |
| 228 | +Mitigation: |
| 229 | +Use English fallback consistently and prioritize shared wrappers first, especially CLI-level errors and suggestions. |
| 230 | + |
| 231 | +### Risk: README content diverges over time |
| 232 | + |
| 233 | +Mitigation: |
| 234 | +Keep the README structure aligned and treat English as the source document for future updates. |
| 235 | + |
| 236 | +## Open Decisions Resolved |
| 237 | + |
| 238 | +The following decisions are fixed for the first implementation: |
| 239 | + |
| 240 | +- Use a lightweight runtime i18n layer, not `gettext` |
| 241 | +- Support `en`, `zh-CN`, and `ru` |
| 242 | +- Localize runtime CLI text and JSON user-facing hints |
| 243 | +- Localize README files using multiple root-level Markdown files |
| 244 | +- Use English as the fallback language |
| 245 | + |
| 246 | +## Acceptance Criteria |
| 247 | + |
| 248 | +The feature is complete when all of the following are true: |
| 249 | + |
| 250 | +- The CLI resolves locale from environment or system locale |
| 251 | +- Unsupported locales fall back to English |
| 252 | +- Core CLI help and major user-facing messages appear in English, Simplified Chinese, and Russian |
| 253 | +- JSON suggestions and hints generated by local code are translated for the supported languages |
| 254 | +- Root README language switchers include English, Simplified Chinese, and Russian |
| 255 | +- `README.ru.md` exists and mirrors the current README structure at a practical first-version level |
| 256 | +- Tests cover locale normalization, fallback, and representative translated CLI outputs |
| 257 | + |
0 commit comments