Phase A plumbing for #188. Adds a users.language column (migration
0022), UserRepo.GetLanguage/SetLanguage, and Session.Lang()/SetLang
accessors so future phases can resolve localized content per session
instead of falling back to the server-wide config.Language.
The preference is loaded from the DB on login and persisted via a new
!lang <en|jp|fr|es> chat command that shows the current language when
called without an argument, validates the code (case-insensitive), and
replies in the newly selected language so the switch is visible
immediately. An empty stored value falls back to config.Language.
sys_language.go exposes getLangStringsFor(code) as the new dispatch
primitive; getLangStrings(server) is now a thin wrapper so existing
callers keep working unchanged. isSupportedLang + supportedLangs keep
the !lang validator in sync with the dispatcher.
Localized quest/scenario content and per-session i18n lookups in
existing handlers are deliberately out of scope for phase A — this
commit ships only the plumbing so it can be reviewed and deployed
independently.
TestLangCompleteness uses reflection to walk the i18n struct and fail
on any empty string field, catching incomplete translations at CI time.
Running it immediately found three missing strings in lang_jp.go
(playtime, timer.enabled, timer.disabled), which are now filled in.
CHANGELOG updated with i18n refactor, FR/ES languages, and the new test.
The config package used `package _config` with a leading underscore,
which is unconventional in Go. Rename to `package config` (matching the
directory name) and use `cfg` as the standard import alias across all
93 importing files.
Port test files from v9.2.x-stable branch to increase channelserver
coverage from 13.8% to 25.6% (556 tests passing).
Adapted all files to main's struct definitions: config import alias,
Airou/CatDefinition rename, packet field mismatches, Raviente struct
differences, and maxPlayers defaults. Removed tests referencing
production code not yet on main (Player, FestivalColour, etc.).
Excluded handlers_register_test.go (Raviente completely redesigned).