DuMes.Component.I18N
6.0.1
dotnet add package DuMes.Component.I18N --version 6.0.1
NuGet\Install-Package DuMes.Component.I18N -Version 6.0.1
<PackageReference Include="DuMes.Component.I18N" Version="6.0.1" />
<PackageVersion Include="DuMes.Component.I18N" Version="6.0.1" />
<PackageReference Include="DuMes.Component.I18N" />
paket add DuMes.Component.I18N --version 6.0.1
#r "nuget: DuMes.Component.I18N, 6.0.1"
#:package DuMes.Component.I18N@6.0.1
#addin nuget:?package=DuMes.Component.I18N&version=6.0.1
#tool nuget:?package=DuMes.Component.I18N&version=6.0.1
DuMes.Component.I18N
多脉本地化组件:按固定目录约定加载 JSON 文案,通过泛型资源类型 + 点号键解析多语言文本,并支持浏览器 Accept-Language。
项目结构
DuMes.Component.I18N/
├── Abstractions/ # II18NService
├── Context/ # 当前请求语言(AsyncLocal)
├── Extensions/ # AddI18N / UseI18N / GetLanguage<T>
│ # I18NLibrarySegmentValidator(末段唯一性)
├── Middleware/ # Accept-Language 解析
├── Options/ # I18NOptions、I18NLanguageSettings
└── Services/ # I18NService、I18NAccessor(静态入口)
功能概览
| 能力 | 说明 |
|---|---|
| 资源约定 | Resources/I18N/{语言}/{类库末段}/{类型名}.json |
| 泛型定位 | "xxx".GetLanguage<T>(),由 T 所在程序集末段 + 类型名定位文件 |
| 嵌套键 | JSON 对象扁平化为 xxx.xxx(如 HttpStatus.BadRequest) |
| 语言解析 | 优先 Accept-Language,否则使用配置默认语言 |
| Swagger | 由 DuMes.Component.FastEndpoints 的 AddModules 注入下拉;选项来自 I18N:SupportedLanguages(须先 AddI18N) |
| 大小写 | 语言目录、类库目录、JSON 文件名均忽略大小写(zh-cn / zh-CN 均可) |
| 缺失回退 | 找不到键时回退为键本身,不抛错;写入 logs/language_warning.log |
| 启动清理 | AddI18N 时清空上次残留的 language_warning 日志 |
| 末段冲突 | 多个程序集末段相同且都提供对应 JSON 标记类型时直接抛错,禁止启动(不写日志) |
| 配置校验 | DefaultLanguage / SupportedLanguages 必须在磁盘有对应语言目录,否则禁止启动 |
资源目录约定
输出目录(AppContext.BaseDirectory)下:
Resources/I18N/
├── zh-CN/
│ ├── Identity/ ← DuMes.Module.Identity 的末段
│ │ └── SystemI18N.json ← GetLanguage<SystemI18N>()
│ └── FastEndpoints/ ← DuMes.Component.FastEndpoints 的末段
│ └── FastEndpointsI18N.json ← GetLanguage<FastEndpointsI18N>()
└── en/
├── Identity/
│ └── SystemI18N.json
└── FastEndpoints/
└── FastEndpointsI18N.json
路径公式:
Resources/I18N/{culture}/{程序集名最后一段}/{标记类型名}.json
示例:
| 标记类型 | 所在类库 | 解析路径 |
|---|---|---|
SystemI18N |
DuMes.Module.Identity |
Resources/I18N/zh-CN/Identity/SystemI18N.json |
FastEndpointsI18N |
DuMes.Component.FastEndpoints |
Resources/I18N/zh-CN/FastEndpoints/FastEndpointsI18N.json |
提供资源的项目需将文件复制到输出目录,例如:
<None Include="Resources\**\*.*">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
JSON 示例
{
"Test": {
"V1": "测试V1"
},
"TestV2": "测试V2",
// 支持注释与尾逗号
"Count": 3
}
对应键:Test.V1、TestV2、Count(数字/布尔/null 会转为字符串;数组不参与扁平化)。
接入
1. 引用
Host 或消费方 ProjectReference / NuGet 引用本组件。依赖 DuMes.Component.Serilog(缺失键警告落盘到 logs/language_warning.log)。
建议 Host 同时接入 Serilog 管道(builder.Host.UseComponentSerilog()),否则 WriteWarning 可能无法按预期写文件。
若使用模块宿主 Swagger 语言下拉,还需引用 DuMes.Component.FastEndpoints,并保证 AddI18N 在 AddModules 之前。
2. 配置 appsettings.json
I18N 节与 DefaultLanguage 为必填。SupportedLanguages:
- 用于 Swagger 下拉与运行时匹配
- 未配置或为空时自动回退为仅含
DefaultLanguage - 若列表不含默认语言,会自动插入到首位
- 每个语言必须存在
Resources/I18N/{culture}/目录,否则启动失败
{
"I18N": {
"DefaultLanguage": "zh-CN",
"SupportedLanguages": [ "zh-CN", "en" ]
}
}
3. Program.cs
using DuMes.Component.I18N.Extensions;
builder.Services.AddI18N(builder.Configuration); // 须在 AddModules 之前
builder.Services.AddModules(...);
var app = builder.Build();
app.UseI18N(); // 须在业务中间件 / Endpoint 之前
4. 定义资源标记类型
namespace DuMes.Module.Identity;
/// <summary>对应 Resources/I18N/{culture}/Identity/SystemI18N.json</summary>
public abstract class SystemI18N;
5. 使用
using DuMes.Component.I18N.Extensions;
var text = "Test.V1".GetLanguage<SystemI18N>();
必须传入泛型;由类型所在类库末段 + 类型名定位 JSON。
GetLanguage<T>():依赖静态入口,须已调用UseI18N- 注入
II18NService:仅需AddI18N即可
语言匹配规则
- 解析请求头
Accept-Language(按 q 值降序;*忽略) - 与配置的
SupportedLanguages及磁盘上额外的语言目录做忽略大小写匹配 - 匹配顺序:
- 精确匹配(
zh-CN→zh-CN) - 请求为裸主语言时(如
zh)→ 可匹配同主语言的区域变体(如zh-CN;多条时取列表第一个) - 请求带区域时(如
zh-TW)→ 不匹配兄弟方言(zh-CN);仅当存在纯主语言标签zh时才回退到zh
- 精确匹配(
- 未匹配则使用
I18N:DefaultLanguage - 取文案时:当前语言 → 默认语言 → 仍无则回退为键本身
(若当前语言标签因大小写等原因无法映射到磁盘目录,等同直接走默认语言)
非 HTTP 场景(无请求上下文)直接使用默认语言。
注意事项
- 路径固定:
Resources/I18N/{culture}/{类库末段}/{TypeName}.json。 - 类库末段唯一:若多个程序集末段名相同,且各自都定义了与
Resources/I18N/*/{末段}/*.json文件名对应的标记类型,则视为冲突;AddI18N与UseI18N均会校验,重复则直接抛错退出,不写日志。不按程序集业务名称前缀过滤。 - 类型名 = JSON 文件名:
GetLanguage<SystemI18N>()读取SystemI18N.json。 - 复制到输出:未设置
CopyToOutputDirectory时,配置语言目录缺失会导致启动失败;单个 JSON 文件缺失则回退为键并写language_warning。 - 先 Add 再 Use:未调用
UseI18N时GetLanguage会抛未初始化异常;注入II18NService不受此限。 - 中间件顺序:
UseI18N须在 Endpoint 之前;AddI18N须在AddModules之前(否则 Swagger 无语言下拉)。 - 缺失不抛错:找不到键时返回键本身,详情见
logs/language_warning.log。 - 键大小写敏感:
Test.V1≠test.v1。 - 数组不支持:JSON 数组不参与扁平化查找;注释、尾逗号、数字/布尔/null 可用。
- 资源缓存:成功读到的 JSON 会缓存至进程结束;文件不存在不缓存(开发期补文件后下次请求可加载,无需为 miss 重启)。JSON 内容变更仍需重启进程。
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- DuMes.Component.Serilog (>= 6.0.1)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.