资源文件命名和目录结构必须严格匹配语言代码,如Strings.zh-CN.resx;切换语言需重置CurrentUICulture并重建UI,不能仅修改文化或调用ApplyResources;GetString()须显式传入culture参数并手动兜底null;推荐使用Microsoft.Extensions.Localization替代裸ResourceManager。

Resource文件命名和目录结构必须严格匹配语言代码
资源文件名决定运行时能否被自动加载,不是随便起个名就行。主资源文件(如 Strings.resx)放在项目根目录或指定资源目录下;对应语言的文件必须用 Strings.zh-CN.resx、Strings.en-US.resx 这种格式,且后缀中的区域代码要和 CultureInfo 实际使用的字符串完全一致(比如用 zh-Hans 就不能配 zh-CN,二者不等价)。Visual Studio 会根据当前线程的 Thread.CurrentThread.CurrentUICulture 去查找匹配的资源集,找不到就回退到默认资源。
- 确保所有语言资源文件的“生成操作”属性设为
Embedded Resource - 不要手动修改 .resources 文件或 .resx 的内部
name属性 —— 它们由设计器自动生成,改了会导致键名解析失败 - 如果用 .NET Core / .NET 5+,推荐把资源文件放在
Resources/子目录,并在.csproj中显式包含:<itemgroup><compile update="Resources\Strings.*.resx"><generator>PublicResXFileCodeGenerator</generator></compile></itemgroup>
切换语言时必须重置当前线程的 CurrentUICulture 并重新创建 UI 元素
只改 Thread.CurrentThread.CurrentUICulture = new CultureInfo("fr-FR") 是不够的——已创建的窗体、控件不会自动刷新文本。资源管理器(ResourceManager)在控件初始化时读取一次值,之后就缓存了。所以真正生效的关键是:销毁旧界面 + 用新文化重建。
- WinForms 场景下,通常需关闭当前窗体,再以新 culture 启动新实例:
Thread.CurrentThread.CurrentUICulture = new CultureInfo("ja-JP"); Application.Restart(); // 或手动 new MainForm().Show() - WPF 可用
FrameworkElement.Language配合动态绑定,但更稳妥的做法仍是重新加载页面或整个窗口 - 切忌在运行中直接调用
ComponentResourceManager.ApplyResources()对已有控件批量重设文本——它依赖设计器生成的资源键名,一旦控件名变更或资源键缺失,就会静默失败,且无法处理嵌套控件(如 ToolStripMenuItem 子项)
ResourceManager.GetString() 要传对参数,否则返回 null 而不是抛异常
手动读取资源时,ResourceManager.GetString(string name, CultureInfo culture) 的 culture 参数不能为 null(除非你明确想走默认资源),否则行为不可靠。尤其在多线程环境下,若没传 culture,它会读取当前线程的 CurrentUICulture,而这个值可能已被其他模块修改过。
- 安全写法是显式传入所需 culture:
var rm = Properties.Resources.ResourceManager; string text = rm.GetString("LoginButton", new CultureInfo("de-DE")); - 如果 key 不存在,
GetString()直接返回null,不会 fallback 到默认语言 —— 必须自己判断并兜底,比如:text ?? rm.GetString("LoginButton", CultureInfo.InvariantCulture) - 别依赖 IDE 的“资源编辑器预览语言”功能来验证翻译效果,它不模拟真实线程文化切换,容易误判
第三方库(如 i18n)能绕过 Resource 机制但会丢失设计器支持
有人用 Json 或 YAML 管理多语言键值对,配合反射或属性绑定实现切换。这类方案灵活,支持热更新、在线翻译平台对接,但代价明显:
- WinForms 设计器里拖出来的按钮,
Text属性不再关联资源,每次改界面都要手动同步字符串 - 无法利用 Visual Studio 内置的资源本地化工具链(如自动生成 satellite 程序集、发布时自动打包)
- 若未统一处理复数、性别、占位符(如
"{0} files deleted"),后期维护成本陡增
真要换方案,优先考虑 Microsoft.Extensions.Localization(.NET Core+),它兼容 Resource 文件底层,又提供 DI 和上下文感知能力,比裸写 ResourceManager 更可控。











