前言
关于.Net下的多语言方案已经有很多成熟的方案,例如:# Avalonia 国际化之路:Resx 资源文件的深度应用与探索,或者# Avalonia使用XML文件实现国际化,基本都围绕官方的Satellite Assembly方案来实现。实际上,我们可以使用非常原始的方式来实现多语言。
步骤
1. resources资源文件生成
创建如下文本文件(假设为rex.txt)
Greeting=Hello
将ResGen.exe从framework的工具目录(使用everything找下就可以看到)拷贝到当前目录,执行如下命令
PS D:\workSpace\Code\测试\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:\workSpace\Code\测试\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:\workSpace\Code\测试\resx\Res.dll");// 第一个参数"rex"即为我们嵌入的rex.resources的文件名,第二个参数为应用程序集ResourceManager rm = new ResourceManager("rex", ass);var s = rm.GetString("Greeting");Console.WriteLine(s);}}
}
输出为:
HelloD:\workSpace\Code\测试\resx\ConsoleApp1\bin\Debug\ConsoleApp1.exe (进程 5184)已退出,代码为 0 (0x0)。
按任意键关闭此窗口. . .
就能拿到我们定义的语言资源啦。
说明:
- 由于我们这里是纯手工加载,
Thread.CurrentThread.CurrentCulture = new CultureInfo("en-us");
这样是完全没影响的,同样, 链接器的cultrue参数也不影响,大家可以自行测试。
How to:
看完这个和文章中的参考资料,应该对大家理解.Net的多语言有很大帮助。接下来就是我的方案(也许是胡说)
如果想统一在一个文件中管理整个sln的语言资源(举例一下特殊需求),可以通过msbuild自定义Task的方式(大家可以类比下编辑的Grpc的proto文件自动生成代码的过程,实际上谷歌也是这么干的),(或者结合下T4模版?)直接生成所有语言的ResourceManager字典。封装方法返回对应语言的资源,有特殊需求的可以自行尝试,如果不行就当我是胡说。