Skip to content

Commit fbbba02

Browse files
committed
docs: 添加本地化框架文档和使用示例
添加 README.Localization.md 和 USAGE_EXAMPLES.md 详细说明本地化框架功能 更新主 README.md 包含本地化框架介绍和使用示例
1 parent 9566498 commit fbbba02

3 files changed

Lines changed: 1138 additions & 0 deletions

File tree

Lines changed: 373 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,373 @@
1+
# GameFrameX.Foundation.Localization 本地化框架说明
2+
3+
## 概述
4+
5+
GameFrameX.Foundation.Localization 是 GameFrameX.Foundation 框架的本地化基础设施库,提供了轻量级、高性能的本地化解决方案。该框架采用懒加载机制,支持零配置使用,并具备优秀的线程安全特性。
6+
7+
## 主要特性
8+
9+
### 🚀 **零配置使用**
10+
- 无需任何初始化配置
11+
- 自动发现和加载本地化资源
12+
- 开箱即用的简单API
13+
14+
### **高性能设计**
15+
- 懒加载机制,首次使用时才加载资源
16+
- 多层缓存优化访问性能
17+
- 线程安全的并发访问支持
18+
19+
### 🌍 **多语言支持**
20+
- 内置中文(简体)和英文支持
21+
- 可扩展的支持更多语言
22+
- 智能的语言回退机制
23+
24+
### 🔧 **高度可扩展**
25+
- 支持自定义资源提供者
26+
- 灵活的优先级管理
27+
- 模块化的组件设计
28+
29+
## 快速开始
30+
31+
### 基础用法
32+
33+
```csharp
34+
using GameFrameX.Foundation.Localization.Core;
35+
36+
// 获取本地化字符串
37+
var message = LocalizationService.GetString("Utility.Exceptions.TimestampOutOfRange");
38+
39+
// 带参数的格式化消息
40+
var formattedMessage = LocalizationService.GetString("Encryption.InvalidKeySize", 128, 256);
41+
42+
// 如果键不存在,返回键名本身
43+
var unknown = LocalizationService.GetString("Some.Unknown.Key"); // 返回: "Some.Unknown.Key"
44+
```
45+
46+
### 预加载资源(可选)
47+
48+
```csharp
49+
// 应用启动时预加载所有本地化资源
50+
LocalizationService.EnsureLoaded();
51+
52+
// 之后的使用将没有首次访问延迟
53+
var message = LocalizationService.GetString("ArgumentNull");
54+
```
55+
56+
## 架构设计
57+
58+
### 核心组件
59+
60+
```
61+
GameFrameX.Foundation.Localization
62+
├── Core/ # 核心接口和管理类
63+
│ ├── IResourceProvider.cs # 资源提供者接口
64+
│ ├── ResourceManager.cs # 资源管理器
65+
│ └── ResourceManagerStatistics.cs # 统计信息
66+
└── Providers/ # 具体实现
67+
├── DefaultResourceProvider.cs # 默认资源提供者
68+
└── AssemblyResourceProvider.cs # 程序集资源提供者
69+
```
70+
71+
### 资源解析优先级
72+
73+
1. **自定义提供者**(最高优先级)
74+
2. **程序集资源提供者**
75+
3. **默认提供者**(兜底)
76+
77+
### 资源文件组织
78+
79+
```
80+
{程序集名称}/Localization/Messages/Resources.{文化代码}.resx
81+
82+
示例:
83+
GameFrameX.Foundation.Localization/Localization/Messages/Resources.zh-CN.resx
84+
GameFrameX.Foundation.Utility/Localization/Messages/Resources.resx
85+
GameFrameX.Foundation.Encryption/Localization/Messages/Resources.zh-CN.resx
86+
```
87+
88+
## 详细使用指南
89+
90+
### 1. 在现有模块中集成本地化
91+
92+
#### 步骤1:定义本地化键
93+
94+
在您的模块中创建 `Localization/Keys.cs`
95+
96+
```csharp
97+
// GameFrameX.Foundation.YourModule/Localization/Keys.cs
98+
namespace GameFrameX.Foundation.YourModule.Localization;
99+
100+
public static class LocalizationKeys
101+
{
102+
public static class Exceptions
103+
{
104+
public const string InvalidArgument = "YourModule.Exceptions.InvalidArgument";
105+
public const string OperationFailed = "YourModule.Exceptions.OperationFailed";
106+
}
107+
108+
public static class Messages
109+
{
110+
public const string Success = "YourModule.Messages.Success";
111+
public const string Processing = "YourModule.Messages.Processing";
112+
}
113+
}
114+
```
115+
116+
#### 步骤2:创建资源文件
117+
118+
创建 `Localization/Messages/Resources.resx`(默认英文):
119+
120+
```xml
121+
<?xml version="1.0" encoding="utf-8"?>
122+
<root>
123+
<data name="YourModule.Exceptions.InvalidArgument" xml:space="preserve">
124+
<value>Invalid argument provided for {0}</value>
125+
</data>
126+
<data name="YourModule.Exceptions.OperationFailed" xml:space="preserve">
127+
<value>Operation failed: {0}</value>
128+
</data>
129+
<data name="YourModule.Messages.Success" xml:space="preserve">
130+
<value>Operation completed successfully</value>
131+
</data>
132+
<data name="YourModule.Messages.Processing" xml:space="preserve">
133+
<value>Processing {0} items...</value>
134+
</data>
135+
</root>
136+
```
137+
138+
创建 `Localization/Messages/Resources.zh-CN.resx`(中文):
139+
140+
```xml
141+
<?xml version="1.0" encoding="utf-8"?>
142+
<root>
143+
<data name="YourModule.Exceptions.InvalidArgument" xml:space="preserve">
144+
<value>为 {0} 提供的参数无效</value>
145+
</data>
146+
<data name="YourModule.Exceptions.OperationFailed" xml:space="preserve">
147+
<value>操作失败:{0}</value>
148+
</data>
149+
<data name="YourModule.Messages.Success" xml:space="preserve">
150+
<value>操作成功完成</value>
151+
</data>
152+
<data name="YourModule.Messages.Processing" xml:space="preserve">
153+
<value>正在处理 {0} 个项目...</value>
154+
</data>
155+
</root>
156+
```
157+
158+
#### 步骤3:更新项目文件
159+
160+
确保项目文件包含资源文件:
161+
162+
```xml
163+
<PropertyGroup>
164+
<EnableDefaultEmbeddedResourceItems>false</EnableDefaultEmbeddedResourceItems>
165+
</PropertyGroup>
166+
167+
<ItemGroup>
168+
<EmbeddedResource Include="Localization\Messages\*.resx" />
169+
</ItemGroup>
170+
```
171+
172+
#### 步骤4:在代码中使用
173+
174+
```csharp
175+
using GameFrameX.Foundation.Localization.Core;
176+
using GameFrameX.Foundation.YourModule.Localization;
177+
178+
public class YourService
179+
{
180+
public void ProcessData(string input)
181+
{
182+
if (string.IsNullOrEmpty(input))
183+
{
184+
throw new ArgumentException(
185+
LocalizationService.GetString(LocalizationKeys.Exceptions.InvalidArgument, nameof(input)));
186+
}
187+
188+
// 使用带参数的本地化消息
189+
var processingMessage = LocalizationService.GetString(
190+
LocalizationKeys.Messages.Processing, 100);
191+
192+
Console.WriteLine(processingMessage);
193+
194+
// 处理逻辑...
195+
196+
var successMessage = LocalizationService.GetString(
197+
LocalizationKeys.Messages.Success);
198+
Console.WriteLine(successMessage);
199+
}
200+
}
201+
```
202+
203+
### 2. 自定义资源提供者
204+
205+
如果需要从数据库、API或其他自定义源加载本地化资源,可以实现自定义提供者:
206+
207+
```csharp
208+
public class DatabaseResourceProvider : IResourceProvider
209+
{
210+
private readonly IDbConnection _connection;
211+
212+
public DatabaseResourceProvider(IDbConnection connection)
213+
{
214+
_connection = connection;
215+
}
216+
217+
public string GetString(string key)
218+
{
219+
// 从数据库查询本地化字符串
220+
var sql = "SELECT localized_text FROM localization_strings WHERE key = @key AND culture = @culture";
221+
return _connection.ExecuteScalar<string>(sql, new { key, culture = CultureInfo.CurrentCulture.Name });
222+
}
223+
}
224+
225+
// 注册自定义提供者
226+
var dbProvider = new DatabaseResourceProvider(yourDbConnection);
227+
LocalizationService.RegisterProvider(dbProvider);
228+
```
229+
230+
### 3. 监控和统计
231+
232+
```csharp
233+
// 获取本地化系统统计信息
234+
var stats = LocalizationService.GetStatistics();
235+
Console.WriteLine($"提供者已加载: {stats.ProvidersLoaded}");
236+
Console.WriteLine($"总提供者数量: {stats.TotalProviderCount}");
237+
Console.WriteLine($"程序集提供者数量: {stats.AssemblyProviderCount}");
238+
Console.WriteLine($"默认提供者存在: {stats.DefaultProviderExists}");
239+
240+
// 获取所有提供者信息
241+
var providers = LocalizationService.GetProviders();
242+
foreach (var provider in providers)
243+
{
244+
Console.WriteLine($"提供者类型: {provider.GetType().Name}");
245+
}
246+
```
247+
248+
## 最佳实践
249+
250+
### 1. 键命名规范
251+
252+
- **模式**`{模块名}.{类别}.{具体键名}`
253+
- **示例**
254+
- `Utility.Exceptions.TimestampOutOfRange`
255+
- `Encryption.InvalidKeySize`
256+
- `Authentication.UserNotFound`
257+
258+
### 2. 参数化消息
259+
260+
对于包含变量的消息,使用 `string.Format` 格式:
261+
262+
```csharp
263+
// 资源文件
264+
<data name="User.InvalidPassword" xml:space="preserve">
265+
<value>用户 '{0}' 的密码无效,长度应在 {1}-{2} 个字符之间</value>
266+
</data>
267+
268+
// 代码中使用
269+
var message = LocalizationService.GetString("User.InvalidPassword", username, minLength, maxLength);
270+
```
271+
272+
### 3. 异常处理
273+
274+
```csharp
275+
try
276+
{
277+
var localized = LocalizationService.GetString(key);
278+
}
279+
catch (Exception ex)
280+
{
281+
// 记录错误,但不中断程序执行
282+
_logger.LogWarning(ex, "获取本地化字符串失败: {Key}", key);
283+
284+
// 返回键名作为兜底
285+
return key;
286+
}
287+
```
288+
289+
### 4. 性能优化
290+
291+
```csharp
292+
// 应用启动时预加载(可选)
293+
LocalizationService.EnsureLoaded();
294+
295+
// 避免频繁获取统计信息,仅在需要时调用
296+
var stats = LocalizationService.GetStatistics();
297+
```
298+
299+
## 已集成的模块
300+
301+
目前以下模块已完成本地化集成:
302+
303+
| 模块 | 本地化键数量 | 状态 |
304+
|------|-------------|------|
305+
| GameFrameX.Foundation.Utility | 4 | ✅ 完成 |
306+
| GameFrameX.Foundation.Encryption | 20+ | ✅ 完成 |
307+
| GameFrameX.Foundation.Extensions | 7 | ✅ 完成 |
308+
| GameFrameX.Foundation.Hash | 2 | ✅ 完成 |
309+
310+
## 常见问题
311+
312+
### Q: 如何添加新语言支持?
313+
314+
A: 在相应模块的 `Localization/Messages/` 目录下创建 `Resources.{语言代码}.resx` 文件,例如:
315+
- `Resources.fr.resx`(法语)
316+
- `Resources.ja.resx`(日语)
317+
- `Resources.de.resx`(德语)
318+
319+
### Q: 资源文件没有生效怎么办?
320+
321+
A: 检查以下几点:
322+
1. 资源文件是否设置为"嵌入的资源"
323+
2. 文件命名是否正确(`Resources.{文化代码}.resx`
324+
3. 项目文件是否包含资源文件配置
325+
4. 重新编译项目
326+
327+
### Q: 如何调试本地化问题?
328+
329+
A: 使用统计信息和提供者列表进行调试:
330+
331+
```csharp
332+
var stats = LocalizationService.GetStatistics();
333+
var providers = LocalizationService.GetProviders();
334+
335+
Console.WriteLine("本地化系统状态:");
336+
Console.WriteLine($"提供者已加载: {stats.ProvidersLoaded}");
337+
Console.WriteLine($"总提供者数量: {stats.TotalProviderCount}");
338+
339+
foreach (var provider in providers)
340+
{
341+
Console.WriteLine($"提供者: {provider.GetType().Name}");
342+
}
343+
```
344+
345+
### Q: 自定义提供者的优先级如何?
346+
347+
A: 手动注册的提供者具有最高优先级,会覆盖程序集资源和默认资源。
348+
349+
## 版本信息
350+
351+
- **当前版本**: 1.0.1
352+
- **目标框架**: .NET 8.0
353+
- **许可证**: Apache-2.0
354+
- **包标识**: GameFrameX.Foundation.Localization
355+
356+
## 更多资源
357+
358+
- **项目主页**: https://github.com/GameFrameX/GameFrameX
359+
- **框架文档**: https://gameframex.doc.alianblank.com
360+
- **问题反馈**: https://github.com/GameFrameX/GameFrameX/issues
361+
362+
## 总结
363+
364+
GameFrameX.Foundation.Localization 提供了一个完整、高效的本地化解决方案,具备以下优势:
365+
366+
1. **简单易用**:零配置,开箱即用
367+
2. **高性能**:懒加载和多层缓存机制
368+
3. **可靠性强**:完善的错误处理和兜底机制
369+
4. **高度可扩展**:支持自定义资源提供者
370+
5. **无缝集成**:与现有 GameFrameX 模块完美配合
371+
6. **质量保证**:完整的测试覆盖和文档
372+
373+
通过采用这个本地化框架,可以轻松地为 GameFrameX.Foundation 生态系统中的所有模块提供一致、高效的本地化支持。

0 commit comments

Comments
 (0)