From 5d63d1e2e7b3e0258a7cdffe1e917021917ebe87 Mon Sep 17 00:00:00 2001 From: luozhixiong Date: Fri, 29 May 2026 14:47:15 +0800 Subject: [PATCH] feat(shortcuts): silently coerce legacy lang values to zh on read MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After the 2026-05-28 catalog shrink to zh/en/ja, existing user configs may still hold ko_kr / fr_fr / etc. RuntimeContext.Lang() now coerces any non-empty unrecognized value to LangZhCN instead of returning empty. Storage on disk is untouched — config.json keeps the legacy value verbatim — so users can still see what was previously set via 'config show', but runtime behavior is uniformly zh. --- shortcuts/common/runner.go | 17 +++++++++++++---- shortcuts/common/runner_lang_test.go | 8 +++++++- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/shortcuts/common/runner.go b/shortcuts/common/runner.go index aa535af01..2fbe9141d 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 9efd0eb6b..4cbe6ec8c 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) {