Skip to content

Add i18n internationalization support#4032

Open
guixiao2026 wants to merge 4 commits intoChrisTitusTech:mainfrom
guixiao2026:feature/i18n-support
Open

Add i18n internationalization support#4032
guixiao2026 wants to merge 4 commits intoChrisTitusTech:mainfrom
guixiao2026:feature/i18n-support

Conversation

@guixiao2026
Copy link

@guixiao2026 guixiao2026 commented Feb 11, 2026

Summary

Add a JSON-based internationalization (i18n) system to WinUtil, allowing the UI to be translated into any language by simply adding a locale JSON file.

What changed

File Change
Compile.ps1 Exclude locales/ from preprocessing; embed locale JSON with explicit UTF-8 reading; output compiled script with UTF-8 BOM to preserve non-ASCII characters
functions/private/Set-WinUtilLanguage.ps1 New file — three functions: Set-WinUtilLanguage (config overlay with English fallback), Set-WinUtilLanguageUI (XAML element updates), Get-WinUtilAvailableLanguages (locale discovery)
locales/en.json English reference template with UI string keys
locales/zh-TW.json Complete Traditional Chinese translation — UI strings, categories, tweak/feature descriptions, and application tooltips
scripts/main.ps1 Language button initialization, menu population, language switch handler with panel rebuild, handler re-binding, and checkbox state preservation
xaml/inputXML.xaml Language button (globe icon) and popup menu in the toolbar

How it works

  1. Locale files in locales/*.json are embedded during compilation
  2. A globe button in the toolbar opens a language picker
  3. On language switch, original English configs are saved (first call only), restored, then translated values are overlaid
  4. UI panels are rebuilt with translated content; click handlers and checkbox states are preserved
  5. Missing translation keys fall back to English automatically

How to add a new language

  1. Copy locales/en.json to locales/{locale-code}.json (e.g., ja.json)
  2. Fill in _metadata.name with the display name (e.g., "日本語")
  3. Translate the ui, categories, and description fields
  4. Run .\Compile.ps1 — the new language appears automatically in the menu

Design decisions

  • No runtime file I/O — all locales are embedded at compile time, matching WinUtil's single-file distribution model
  • Config overlay approach — original configs are deep-cloned and restored before each switch, ensuring clean state
  • Explicit UTF-8 handling[System.IO.File]::ReadAllText() with UTF-8 encoding avoids corruption on non-English Windows systems where default encoding may be ANSI/Big5
  • Minimal footprint — only 6 files changed, no new dependencies, zero impact when no language switch is performed

Test plan

  • Compile with .\Compile.ps1 and verify syntax validation passes
  • Launch winutil, switch to 繁體中文, verify all UI elements translate
  • Switch back to English, verify full restoration
  • Switch languages multiple times, verify no handler duplication (buttons don't fire multiple times)
  • Verify checkbox states are preserved across language switches
  • Verify Button-type controls (Ultimate Performance, Region, etc.) remain functional after switch
  • Verify package manager radio button preference persists after switch
  • Verify winutil.ps1 is not included in the commit

@ChrisTitusTech ChrisTitusTech added new feature New feature or request ui update UI/UX improvements labels Feb 11, 2026
@GabiNun
Copy link
Contributor

GabiNun commented Feb 18, 2026

This approach works well, but with each language we add to winutil via this PR, the winutil.ps1 file increases by about 100 KB. Adding 12 more languages would bring it close to 2 MB.

@ChrisTitusTech
@guixiao2026

@Kingproone
Copy link

This approach works well, but with each language we add to winutil via this PR, the winutil.ps1 file increases by about 100 KB. Adding 12 more languages would bring it close to 2 MB.

what if during build, every language gets its own .ps1 build, tagged with the built language?
with this the user could manually choose which language they would like to use (english being the default), for example:

irm "https://christitus.com/win-zh" | iex
irm "https://christitus.com/windev-zh" | iex

one step further: when running the stable branch, it could check for the current user locale, and download the corresponding ps1 file.

@GabiNun
Copy link
Contributor

GabiNun commented Feb 19, 2026

This approach works well, but with each language we add to winutil via this PR, the winutil.ps1 file increases by about 100 KB. Adding 12 more languages would bring it close to 2 MB.

what if during build, every language gets its own .ps1 build, tagged with the built language? with this the user could manually choose which language they would like to use (english being the default), for example:

irm "https://christitus.com/win-zh" | iex
irm "https://christitus.com/windev-zh" | iex

one step further: when running the stable branch, it could check for the current user locale, and download the corresponding ps1 file.

ye im pretty sure thats what chris wants

@guixiao2026
Copy link
Author

Let me think about it.

- Remove en.json (English strings already hardcoded as defaults)
- Strip app descriptions from zh-TW.json (~55KB -> ~13KB)
- Embed only manifest.json at compile time, not full locale files
- Add Get-WinUtilLocale with 3-tier resolution: memory/cache/download
- Add download icon for uncached languages in language menu
- Create locale cache directory on startup
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

new feature New feature or request ui update UI/UX improvements

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants