diff --git a/shortcuts/common/runner.go b/shortcuts/common/runner.go index aa535af0..2fbe9141 100644 --- a/shortcuts/common/runner.go +++ b/shortcuts/common/runner.go @@ -73,11 +73,20 @@ func (ctx *RuntimeContext) IsBot() bool { // UserOpenId returns the current user's open_id from config. func (ctx *RuntimeContext) UserOpenId() string { return ctx.Config.UserOpenId } -// Lang returns the user's preference as a canonical locale, or "" if unset or -// unrecognized; callers choose their own fallback. +// Lang returns the user's preference as a canonical locale. +// Empty stays empty (unset). Any non-empty stored value that does not resolve +// via i18n.Parse (e.g. legacy ko_kr / fr_fr from before the catalog was +// shrunk to zh/en/ja) is silently coerced to LangZhCN — existing configs +// stay readable, just behave as zh. func (ctx *RuntimeContext) Lang() i18n.Lang { - lang, _ := i18n.Parse(string(ctx.Config.Lang)) - return lang + raw := string(ctx.Config.Lang) + if raw == "" { + return "" + } + if lang, ok := i18n.Parse(raw); ok { + return lang + } + return i18n.LangZhCN } // BotInfo holds bot identity metadata fetched lazily from /bot/v3/info. diff --git a/shortcuts/common/runner_lang_test.go b/shortcuts/common/runner_lang_test.go index 9efd0eb6..4cbe6ec8 100644 --- a/shortcuts/common/runner_lang_test.go +++ b/shortcuts/common/runner_lang_test.go @@ -20,7 +20,13 @@ func TestRuntimeContext_Lang(t *testing.T) { {"legacy short value normalizes", "ja", i18n.LangJaJP}, {"legacy short zh normalizes", "zh", i18n.LangZhCN}, {"unset stays empty", "", ""}, - {"unrecognized stays empty", "klingon", ""}, + // Flipped semantics: unrecognized non-empty values are now treated + // as legacy storage from the pre-2026-05-28 14-language catalog + // and silently coerced to LangZhCN, not left empty. + {"unrecognized garbage coerces to zh", "klingon", i18n.LangZhCN}, + {"legacy ko_kr coerces to zh", "ko_kr", i18n.LangZhCN}, + {"legacy fr_fr coerces to zh", "fr_fr", i18n.LangZhCN}, + {"legacy short ko coerces to zh", "ko", i18n.LangZhCN}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) {