前言
关于.Net下的多语言方案已经有很多成熟的方案,例如:# Avalonia 国际化之路:Resx 资源文件的深度应用与探索,或者# Avalonia使用XML文件实现国际化,基本都围绕官方的Satellite Assembly方案来实现。实际上,我们可以使用非常原始的方式来实现多语言。
步骤
1. resources资源文件生成
创建如下文本文件(假设为rex.txt)
Greeting=Hello
将ResGen.exe从framework的工具目录(使用everything找下就可以看到)拷贝到当前目录,执行如下命令
PS D:workSpaceCode测试resx> .ResGen.exe .rex.txt Read in 1 resources from ".rex.txt" Writing resource file... Done.
就可以得到我们第一步的rex.resources。
说明:
ResGen.exe工具同样支持resx文件,具体使用与文件格式参考https://learn.microsoft.com/en-us/dotnet/framework/tools/resgen-exe-resource-file-generator 官方文档,事实上,这也是我们使用的IDE编辑时msbuild背后调用的工具。
2. Dll文件生成
有了resources资源文件,我们就可以通过链接器(al.exe,同样在framework的工具目录中)将resources资源文件链接成动态链接库。
PS D:workSpaceCode测试resx> .al.exe -target:lib -embed:.rex.resources -out:Res.dll Microsoft(R) Assembly Linker 版本 14.7.2053.0 Copyright (C) Microsoft Corporation. All rights reserved.
说明:
-target:lib代表产物为类库-embed:.rex.resources代表嵌入刚刚第一步的生成资源文件-out:Res.dll代表生成物名称- 使用ilspy打开就可以看到嵌入的资源文件。
- 注意我们这里并没有指定
-culture:zh-Hans参数,而官方文档说这个参数必须传(https://learn.microsoft.com/en-us/dotnet/core/extensions/create-satellite-assemblies) 是因为我们完全没使用.net的语言资源机制,也完全不用遵从其hub-and-spoke模型(指的是轮子的中心和车轮的辐条的关系模型,也就是主dll和卫星资源dll的位置关系模型) - 这里要对.Net下dll的结构有一定认识,大家可以参考前面链接中的图片。
- 也可以使用
-template:Example.dll来指定生成dll的元数据模版,不然生成的dll在ilspy中元数据表的TypeDef会显示<Module>这样未命名的记录。 - 我们这里用的是链接器,其实也能用编译器(.net core下就是这样),参考前面的链接。
3. 使用
创建控制台应用,代码如下:
using System; using System.Globalization; using System.Reflection; using System.Resources; using System.Threading; namespace ConsoleApp1 { internal class Program { static void Main(string[] args) { // 手动加载刚刚链接器生成的程序集 Assembly ass = Assembly.LoadFile(@"D:workSpaceCode测试resxRes.dll"); // 第一个参数"rex"即为我们嵌入的rex.resources的文件名,第二个参数为应用程序集 ResourceManager rm = new ResourceManager("rex", ass); var s = rm.GetString("Greeting"); Console.WriteLine(s); } } }
输出为:
Hello D:workSpaceCode测试resxConsoleApp1binDebugConsoleApp1.exe (进程 5184)已退出,代码为 0 (0x0)。 按任意键关闭此窗口. . .
就能拿到我们定义的语言资源啦。
说明:
- 由于我们这里是纯手工加载,
Thread.CurrentThread.CurrentCulture = new CultureInfo("en-us");这样是完全没影响的,同样, 链接器的cultrue参数也不影响,大家可以自行测试。
How to:
看完这个和文章中的参考资料,应该对大家理解.Net的多语言有很大帮助。接下来就是我的方案(也许是胡说)
如果想统一在一个文件中管理整个sln的语言资源(举例一下特殊需求),可以通过msbuild自定义Task的方式(大家可以类比下编辑的Grpc的proto文件自动生成代码的过程,实际上谷歌也是这么干的),(或者结合下T4模版?)直接生成所有语言的ResourceManager字典。封装方法返回对应语言的资源,有特殊需求的可以自行尝试,如果不行就当我是胡说。