应调用getuserdefaultuilanguage获取windows系统ui语言标识符(如0x0804),再用getlocaleinfoex(locale_name_user_default)转为"zh-cn"等iso格式;unix系须调用setlocale(lc_messages, "")解析返回字符串,而非依赖lang环境变量或lc_ctype。

Windows上用GetUserDefaultUILanguage获取系统UI语言代码
Windows的系统语言设置(即UI显示语言)不等于区域格式,也不等同于当前线程locale。直接读GetLocaleInfo或setlocale可能返回区域设置而非UI语言。真正反映“系统显示语言”的是UI语言标识符(LANGID),应调用GetUserDefaultUILanguage。
这个函数返回的是Windows语言标识符(如0x0804表示简体中文,0x0409表示英文(美国)),不是字符串。需要配合GetLocaleInfoEx或查表转换成语言名(如"zh-CN")。
- 必须包含
<windows.h></windows.h>和<winnls.h></winnls.h> - 返回值为
LANGID类型,可用PRIMARYLANGID()和SUBLANGID()宏拆解 - 若需ISO格式字符串(如
"zh-CN"),推荐用GetLocaleInfoEx传入LOCALE_NAME_USER_DEFAULT,比手动查表更可靠 - 注意:该函数返回的是用户登录时默认的UI语言,不是当前线程locale,也不受
SetThreadLocale影响
Linux/macOS用setlocale + 环境变量推导语言环境
类Unix系统没有统一的“系统UI语言”概念,而是依赖环境变量(主要是LANG)和setlocale(LC_ALL, "")的实际生效结果。不能只看LANG变量——它可能被临时覆盖,而setlocale会按LC_*变量优先级链(LC_ALL > LC_MESSAGES > LANG)实际解析。
正确做法是先调用setlocale(LC_MESSAGES, "")(或LC_ALL),再用nl_langinfo(CODESET)和nl_langinfo(LANGNAME)提取信息;但LANGNAME非POSIX标准,macOS不支持,所以更稳妥的是解析setlocale返回值字符串。
-
setlocale(LC_MESSAGES, "")返回形如"zh_CN.UTF-8"或"en_US.UTF-8"的字符串,需手动分割下划线和点 - 不要直接信任
getenv("LANG")——它可能为空、格式非法,或被子进程修改 - macOS上
nl_langinfo对LANGNAME返回空,必须依赖setlocale返回值解析 - Linux下
LC_MESSAGES可能单独设为不同值(比如界面用中文、错误提示用英文),应以LC_MESSAGES为准
跨平台封装建议:避免硬编码语言映射表
别自己写switch(langid) { case 0x0804: return "zh-CN"; ... }——Windows语言ID有数百个,且新版本会增加;Unix locale名也存在变体(zh_CN.utf8、zh_CN.UTF-8、zh-Hans-CN等)。应交给系统API做标准化转换。
- Windows:用
GetLocaleInfoEx传LOCALE_NAME_USER_DEFAULT,直接得"zh-CN"这类BCL格式字符串 - Linux/macOS:用
setlocale(LC_MESSAGES, "")后,调用uselocale+nl_langinfo辅助,但最终仍建议用std::string解析返回值并规范化(如转小写、统一连字符) - C++20起可考虑
std::format配合std::locale构造,但std::locale("")在各平台行为不一致,慎用 - 如果只需判断是否为中文/英文等大类,建议用子串匹配(如
find("zh") != string::npos),而非全等比较
常见错误:混淆LC_CTYPE和LC_MESSAGES用途
很多代码用setlocale(LC_CTYPE, "")读取语言,这是错的。LC_CTYPE只控制字符分类(如大小写、宽窄字符),不决定界面语言;真正的UI/提示文本语言由LC_MESSAGES决定。glibc和musl都遵循此规则,macOS也一致。
- 调用
setlocale(LC_CTYPE, "")可能返回"C"(尤其在容器或minimal环境),但LC_MESSAGES仍是"zh_CN.UTF-8" - Qt、GTK等框架内部都优先读
LC_MESSAGES,你的程序也应保持一致 - 测试时务必在终端中显式设置:
LANG=zh_CN.UTF-8 LC_MESSAGES=fr_FR.UTF-8 ./myapp,验证是否真读到fr_FR - Windows无
LC_*机制,所以此问题仅存在于Unix系,但容易被跨平台开发者忽略
LC_CTYPE当语言标识、以及在Windows上用GetLocaleInfo查当前线程locale而非UI语言。三者混用会导致多语言切换失效或fallback异常。C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











