c# 如何实现多语言 winform/wpf

WinForm多语言需设Localizable=true并用卫星程序集,WPF依赖Uid和MSBuild生成资源;两者均须重启窗体切换语言,共用资源时需注意访问方式、命名规范及键名同步。

WinForm 中用 Localizable 属性 + 卫星程序集实现多语言

WinForm 多语言本质是资源文件驱动,不是运行时动态改控件文本。关键在于把界面字符串抽成 .resx,再为每种语言生成对应卫星程序集。

  • FormUserControlLocalizable 属性必须设为 true(在设计器属性面板里改),否则 VS 不会生成 Form.zh-CN.resx 这类文件
  • 语言切换不是靠代码“重载”界面,而是靠线程当前 Thread.CurrentThread.CurrentUICulture定加载哪个 .resources 文件
  • 切语言前必须重启窗体:新建实例 → 设置 CurrentUICulture → 显示,否则已有窗体不会刷新文本
  • 资源文件里键名必须和设计器生成的完全一致,比如 button1.Text,手动改键名会导致该控件文本回退到默认值
Thread.CurrentThread.CurrentUICulture = new CultureInfo("zh-CN");
var form = new MainForm();
form.Show();

WPF 中用 Uid + msbuild 生成 .g.resources 实现多语言

WPF 没有内置 Localizable 开关,得靠 Uid 属性标记元素,再用 MSBuild 工具链生成本地化资源。流程比 WinForm 更底层、更易出错。

  • 每个需要翻译的控件必须显式加 Uid 属性(如 ),VS 设计器不自动加,漏一个就无法提取该控件文本
  • 项目文件需启用本地化:en-US,并确保 true
  • 翻译后的 .csproj 要引用对应 .resources 文件,路径必须是 zh-CN\YourApp.resources.dll,放错目录或命名不符会导致运行时报 MissingManifestResourceException
  • WPF 不支持运行时切换语言后重绘现有窗口,必须关闭旧窗体、重建新窗体,并确保新窗体构造前已设置 Thread.CurrentThread.CurrentUICulture

共用资源文件(.resx)在 WinForm/WPF 间复用的坑

想让 WinForm 和 WPF 共享同一套中文/英文资源?可以,但要注意资源访问方式差异导致的硬编码风险。

  • WinForm 自动生成的 Resources.Designer.cs 是静态类,调用如 Resources.String1;WPF 默认用 Properties.Resources.ResourceManager.GetString("String1"),两者底层都读 .resources,但命名空间和访问路径不同
  • 若手动把 WinForm 的 Resources.resx 拖进 WPF 项目,必须右键属性 → Custom Tool 改为 PublicResXFileCodeGenerator,否则生成的类是 internal,WPF XAML 绑定不到
  • WPF 的 Binding 无法直接绑到 Resources.String1(非依赖属性),得用 x:Static 或写转换器,例如:{x:Static properties:Resources.String1}
  • 资源键名含空格或点号(如 login.button.text)在 WPF 中会被编译器拒绝,WinForm 倒是允许,统一建议用驼峰(LoginButtonText

运行时切换语言失败的三个高频原因

多数人卡在“改了 Culture 却没变语言”,问题往往不在逻辑,而在执行时机或资源加载路径。

  • 没调用 Application.Current.Shutdown() 或关闭所有窗体就新建窗体 → 旧窗体仍持有原 ResourceManager 实例,新窗体才生效
  • 程序集未生成卫星程序集 → 检查输出目录是否有 zh-CN\YourApp.resources.dll,没有说明 resgenal.exe 步骤失败,或项目未设 zh-CN;ja-JP
  • 资源文件名大小写错误 → Windows 下 zh-cnzh-CN 被视为不同文化,但 .NET 运行时只认标准格式(zh-CN),用错就 fallback 到默认资源

真正麻烦的是资源键同步:WinForm 控件名改了,WPF 的 Uid 没同步,或者翻译人员改了 .resx 键但忘了通知开发更新 Uid —— 这类问题不会报错,只会静默显示英文。