Skip to content

feat: add multi-language support (i18n) using gotext#18

Merged
chenwei791129 merged 3 commits into
mainfrom
feature/i18n-support
Jan 29, 2026
Merged

feat: add multi-language support (i18n) using gotext#18
chenwei791129 merged 3 commits into
mainfrom
feature/i18n-support

Conversation

@chenwei791129

@chenwei791129 chenwei791129 commented Jan 29, 2026

Copy link
Copy Markdown
Owner

Summary

Implements internationalization (i18n) support as proposed in #13, using the gotext library which follows the GNU gettext standard.

Changes

New i18n Package (internal/i18n/)

  • i18n.go - Core translation functions with embedded locale files
  • lang_windows.go - Windows-specific language detection using GetUserDefaultUILanguage API
  • lang_other.go - Fallback language detection for non-Windows (via LANG env)

Locale Files (internal/i18n/locales/)

  • en_US/LC_MESSAGES/default.po - English (default)
  • zh_TW/LC_MESSAGES/default.po - Traditional Chinese

GUI Refactoring

  • app.go - Window title now uses i18n
  • mainwindow.go - All UI labels, buttons, and status messages use i18n
  • monitor.go - All log messages and process status strings use i18n

Features

  • Automatic system language detection on Windows
  • Embedded locale files (no external files needed)
  • Fallback to English if translation not found
  • Easy to add more languages by creating new .po files

Test Plan

  • Build on Windows and verify compilation
  • Test with Windows set to Traditional Chinese - UI should display in Chinese
  • Test with Windows set to English - UI should display in English
  • Verify all strings are properly translated

Closes #13


🤖 Generated with Claude Code

Implements internationalization support as proposed in #13:

- Add github.com/leonelquinteros/gotext dependency
- Create internal/i18n package with:
  - Language detection (Windows GetUserDefaultUILanguage API)
  - Embedded locale files using go:embed
  - Get() function for translating strings
- Add locale files for:
  - English (en_US) - default
  - Traditional Chinese (zh_TW)
- Refactor GUI strings in:
  - app.go - window title
  - mainwindow.go - labels, buttons, status messages
  - monitor.go - log messages, process status

The application now automatically detects the system language on
Windows and displays the UI in the appropriate language.

Closes #13
@chenwei791129 chenwei791129 added the enhancement New feature or request label Jan 29, 2026
@chenwei791129

Copy link
Copy Markdown
Owner Author

@github-copilot review

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR implements internationalization (i18n) support for the Multiablo application using the gotext library, as proposed in issue #13. The implementation adds automatic system language detection on Windows and embeds locale files for English and Traditional Chinese translations.

Changes:

  • Added new internal/i18n package with core translation functions, Windows-specific language detection, and embedded locale files
  • Refactored all GUI strings in app.go, mainwindow.go, and monitor.go to use i18n translation functions
  • Added gotext v1.7.2 as a new dependency

Reviewed changes

Copilot reviewed 9 out of 10 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
internal/i18n/i18n.go Core i18n package with translation lookup and locale management using embedded filesystem
internal/i18n/lang_windows.go Windows-specific language detection using GetUserDefaultUILanguage API
internal/i18n/lang_other.go Fallback language detection for non-Windows platforms via environment variables
internal/i18n/locales/en_US/LC_MESSAGES/default.po English translation file (default/source language)
internal/i18n/locales/zh_TW/LC_MESSAGES/default.po Traditional Chinese translation file
internal/gui/app.go Initialize i18n system and convert AppTitle to function returning translated string
internal/gui/mainwindow.go Convert all UI labels, buttons, and status messages to use i18n.Get()
internal/gui/monitor.go Convert all log messages and process status strings to use i18n.Get()
go.mod Add gotext v1.7.2 dependency
go.sum Update dependency checksums for gotext

Comment thread internal/i18n/lang_windows.go Outdated
Comment on lines +27 to +31
if subLangID == 0x01 { // Traditional Chinese
return LangZhTW
}
// Default to Traditional Chinese for any Chinese variant
return LangZhTW

Copilot AI Jan 29, 2026

Copy link

Choose a reason for hiding this comment

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

The default behavior on line 31 returns Traditional Chinese (zh_TW) for all Chinese language variants that are not explicitly handled. This is unusual since Simplified Chinese (zh_CN) is more widely used. Consider either:

  1. Adding explicit handling for Simplified Chinese (sublanguage ID 0x02) and falling back to English for unknown Chinese variants, or
  2. Documenting why Traditional Chinese is the preferred default for this specific application.
Suggested change
if subLangID == 0x01 { // Traditional Chinese
return LangZhTW
}
// Default to Traditional Chinese for any Chinese variant
return LangZhTW
switch subLangID {
case 0x01: // Traditional Chinese
return LangZhTW
case 0x02: // Simplified Chinese
return LangZhCN
default:
// Fall back to English for other/unknown Chinese variants
return LangEnUS
}

Copilot uses AI. Check for mistakes.
msgstr "監控已停止。"

msgid "Closed %d handle(s) for D2R.exe (PID: %d)"
msgstr "已為 D2R.exe (PID: %d) 關閉 %d 個 Handle"

Copilot AI Jan 29, 2026

Copy link

Choose a reason for hiding this comment

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

The format string arguments are in the wrong order in the Chinese translation. The English message is "Closed %d handle(s) for D2R.exe (PID: %d)" where the first %d is closedCount and the second %d is PID. However, the Chinese translation "已為 D2R.exe (PID: %d) 關閉 %d 個 Handle" has them reversed, which will cause the PID to be displayed as the count and vice versa.

The correct translation should maintain the same argument order as the original format string.

Suggested change
msgstr "已為 D2R.exe (PID: %d) 關閉 %d 個 Handle"
msgstr "已關閉 %d 個 D2R.exe Handle (PID: %d)"

Copilot uses AI. Check for mistakes.
Comment thread internal/i18n/lang_windows.go Outdated
Comment on lines +37 to +68
// getLocaleInfo retrieves locale information from Windows.
func getLocaleInfo(lcid uint32, lcType uint32) string {
kernel32 := syscall.NewLazyDLL("kernel32.dll")
getLocaleInfoW := kernel32.NewProc("GetLocaleInfoW")

// First call to get required buffer size
size, _, _ := getLocaleInfoW.Call(
uintptr(lcid),
uintptr(lcType),
0,
0,
)

if size == 0 {
return ""
}

// Allocate buffer and get the actual value
buf := make([]uint16, size)
ret, _, _ := getLocaleInfoW.Call(
uintptr(lcid),
uintptr(lcType),
uintptr(unsafe.Pointer(&buf[0])),
size,
)

if ret == 0 {
return ""
}

return strings.TrimRight(syscall.UTF16ToString(buf), "\x00")
}

Copilot AI Jan 29, 2026

Copy link

Choose a reason for hiding this comment

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

The getLocaleInfo function is defined but never used anywhere in the codebase. This unused code should be removed to improve maintainability, or if it's intended for future use, it should be documented as such.

Copilot uses AI. Check for mistakes.
Comment thread internal/i18n/lang_windows.go Outdated

// getLocaleInfo retrieves locale information from Windows.
func getLocaleInfo(lcid uint32, lcType uint32) string {
kernel32 := syscall.NewLazyDLL("kernel32.dll")

Copilot AI Jan 29, 2026

Copy link

Choose a reason for hiding this comment

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

The local variable kernel32 on line 39 shadows the package-level variable of the same name declared on line 12. While this code is in an unused function (getLocaleInfo), if the function were to be used, this shadowing could lead to confusion. Consider using a different variable name like k32 or removing the unused function entirely.

Suggested change
kernel32 := syscall.NewLazyDLL("kernel32.dll")

Copilot uses AI. Check for mistakes.
Comment thread internal/i18n/i18n.go
Comment on lines +26 to +31
var (
// currentLocale holds the active locale
currentLocale *gotext.Locale
// currentLang holds the current language code
currentLang string
)

Copilot AI Jan 29, 2026

Copy link

Choose a reason for hiding this comment

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

The package-level variables currentLocale and currentLang are accessed and modified without any synchronization mechanism. The Init function (called by SetLanguage) writes to these variables, while Get/GetN/GetCurrentLanguage functions read from them. Since the GUI monitoring runs in multiple goroutines that call i18n.Get(), and SetLanguage could potentially be called concurrently, this creates a race condition risk. Consider protecting these variables with a sync.RWMutex or making Init/SetLanguage thread-safe by documenting that they should only be called during initialization before any goroutines start.

Copilot uses AI. Check for mistakes.
Comment on lines +5 to +9
import (
"strings"
"syscall"
"unsafe"
)

Copilot AI Jan 29, 2026

Copy link

Choose a reason for hiding this comment

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

The imports "strings" and "unsafe" are only used in the unused getLocaleInfo function. If getLocaleInfo is removed (as suggested in the other comment), these imports should also be removed to avoid unnecessary dependencies.

Copilot uses AI. Check for mistakes.
- Fix format string argument order in zh_TW translation (bug fix)
- Remove unused getLocaleInfo function and related imports
- Change Simplified Chinese fallback to English (no zh_CN translation)
- Add thread safety documentation for Init() and package
@chenwei791129
chenwei791129 merged commit 602934c into main Jan 29, 2026
1 check passed
@chenwei791129
chenwei791129 deleted the feature/i18n-support branch January 29, 2026 13:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Proposal: Add multi-language support (i18n) using the gotext package

2 participants