customization:
distribution_code_name: Weasel
distribution_version: 0.16.3
generator: "Rime::SwitcherSettings"
modified_time: "Wed Dec 31 08:34:49 2025"
rime_version: 1.11.2
patch: "menu/page_size": 9
schema_list:
- {schema: rime_ice} "switcher/hotkeys":
- "Control+grave"
- "Control+F3"
key_binder:
bindings:
- { when: composing, accept: comma, send: Page_Up } #翻页
- { when: composing, accept: period, send: Page_Down } #翻页
rime_ice.dict.yaml
import_tables: - cn_dicts/8105 # 字表 # - cn_dicts/41448 # 大字表(按需启用)(启用时和 8105 同时启用并放在 8105 下面) - cn_dicts/base # 基础词库 - cn_dicts/ext # 扩展词库 - cn_dicts/tencent # 腾讯词向量(大词库,部署时间较长) - cn_dicts/others # 一些杂项 - cn_dicts/myqq #你的词库
把qq词库放在
Rime\cn_dicts下myqq.dict.yam
转换python程序
import re
input_file = "QQPinyin_2025_12_31.txt"output_file = "myqq.dict.yaml"def read_lines(path): for enc in ("utf-16", "utf-8", "gbk"): try: with open(path, encoding=enc) as f: return f.readlines() except UnicodeDecodeError: pass
raise RuntimeError("无法识别文件编码")
lines = read_lines(input_file)
entries = []for line in lines:
line = line.strip() if not line: continue
m = re.match(r"([a-z']+)\s+([\u4e00-\u9fa5]+)\s+(\d+)", line) if not m: continue
code, word, weight = m.groups()
pinyin = code.replace("'", " ")
entries.append(f"{word}\t{pinyin}\t{weight}")with open(output_file, "w", encoding="utf-8") as f:
f.write( "---\n"
"name: my_qq\n"
"version: \"1.0\"\n"
"sort: by_weight\n"
"...\n\n"
)
f.write("\n".join(entries))print(f"转换完成:{len(entries)} 条")
架构设计
语言解析优先级
Cookie(用户手动切换)
↓ (未设置)
User Settings(用户偏好)
↓ (未设置)
Tenant Settings(租户默认)
↓ (未设置)
Global Settings(系统默认)
↓ (未设置)
zh-CN(最终回退)
Settings 存储结构
// 全局默认语言Module: "Localization"Key: "DefaultLanguage"Value: "zh-CN"Scope: Global// 租户默认语言Module: "Localization"Key: "DefaultLanguage"Value: "en"Scope: Tenant
ScopeId: "{tenantId}"// 用户偏好语言Module: "Localization"Key: "PreferredLanguage"Value: "en"Scope: User
ScopeId: "{userId}"
🚀 快速开始
1. 配置已完成
本地化服务已在 ServiceDefaults 中自动注册,无需额外配置。
2. 后端使用
在 Controller 中使用本地化
using CodeSpirit.Localization.Resources;using Microsoft.Extensions.Localization;public class MyController : ApiControllerBase{ private readonly IStringLocalizer<SharedResources> _localizer;
public MyController(IStringLocalizer<SharedResources> localizer)
{
_localizer = localizer;
}
[HttpPost] public IActionResult Create()
{ return Ok(new ApiResponse
{
Status = 1,
Msg = _localizer["Common.Save"].Value
});
}
}
抛出本地化异常
// 使用资源键throw new BusinessException("Errors.InvalidStartTime");// 带参数throw new ValidationException("Errors.NotFound", resourceId);
3. DTO 验证特性多语言
using CodeSpirit.Localization.Resources;public class CreateQuestionDto{
[Display(Name = "Content", ResourceType = typeof(DisplayResources))]
[Required(ErrorMessageResourceType = typeof(ValidationResources),
ErrorMessageResourceName = "Required")]
[StringLength(2000,
ErrorMessageResourceType = typeof(ValidationResources),
ErrorMessageResourceName = "StringLengthMax")] public string Content { get; set; } = string.Empty;
}
DTO 字段的描述信息(Description)也支持多语言,通过
LocalizedDescriptionAttribute 实现。
各服务应创建自己的资源文件,保持服务独立性:
资源文件结构:
CodeSpirit.ExamApi/Resources/ ├── ExamDisplayResources.cs # 资源占位类(包含ResourceManager) ├── ExamDisplay.resx # 中文资源 └── ExamDisplay.en.resx # 英文资源
资源键命名规范:
Description.{EntityName}.{PropertyName}Description.Question.Options、
Description.Question.CorrectAnswerusing CodeSpirit.Core.Attributes;using CodeSpirit.ExamApi.Resources;public class CreateQuestionDto{
[LocalizedDescription( "根据题目内容生成合适的选项", // 回退文本(可选)
ResourceKey = "Description.Question.Options",
ResourceType = typeof(ExamDisplayResources)
)] public List<string> Options { get; set; }
}
使用方式:
现有的
DescriptionAttribute 仍然可以正常使用,系统会优先检查
LocalizedDescriptionAttribute,如果不存在则回退到
DescriptionAttribute。
CodeSpirit.Localization/Resources/ - 存放真正通用的、跨服务的资源ApiServices/{ServiceName}/Resources/ - 存放服务特有的业务资源最佳实践:
Description.{EntityName}.{PropertyName} 命名约定描述多语言的资源解析由 AMIS 表单生成时统一处理:
GetLocalizedDescription 方法在表单生成时解析资源// 获取翻译文本const message = CodeSpirit.i18n.t('Common.Save');// 带参数const message = CodeSpirit.i18n.t('Validation.Required', { 0: '用户名' });// 切换语言CodeSpirit.i18n.switchLanguage('en');
@using CodeSpirit.Localization.Resources@using Microsoft.Extensions.Localization@inject IStringLocalizer<SharedResources> Localizer<h1>@Localizer["Common.Save"]</h1>
系统已自动集成 Settings 组件,可以通过 Settings API 管理语言配置:
await _settingsService.SetUserSettingAsync( module: "Localization", key: "PreferredLanguage", value: "en", userId: currentUserId );
await _settingsService.SetTenantSettingAsync( module: "Localization", key: "DefaultLanguage", value: "en", tenantId: currentTenantId );
await _settingsService.SetGlobalSettingAsync( module: "Localization", key: "DefaultLanguage", value: "en");
用户可以在导航栏的语言切换器中选择语言,切换后会:
.AspNetCore.Culture)| 资源文件 | 用途 | 示例键 |
|---|---|---|
Shared.resx |
通用 UI 文本 |
Common.Save,
Common.Cancel |
Errors.resx |
错误消息 |
Errors.NotFound,
Errors.Unauthorized |
Validation.resx |
验证消息模板 |
Required,
StringLengthMax |
Display.resx |
字段显示名称 |
Content,
Type,
Difficulty |
每个资源文件都有对应的英文版本(如
Shared.en.resx)。
各服务应创建自己的资源文件,保持服务独立性:
命名规范:
{ServiceName}DisplayResources.cs{ServiceName}Display.resx、
{ServiceName}Display.en.resx示例:
CodeSpirit.ExamApi/Resources/ ├── ExamDisplayResources.cs # 资源占位类(包含ResourceManager) ├── ExamDisplay.resx # 中文资源 └── ExamDisplay.en.resx # 英文资源CodeSpirit.SurveyApi/Resources/ ├── SurveyDisplayResources.cs ├── SurveyDisplay.resx └── SurveyDisplay.en.resx
资源键命名约定:
Description.{EntityName}.{PropertyName}Description.Question.Options、
Description.Survey.Title用户在导航栏选择 "English"
JavaScript 调用
CodeSpirit.i18n.switchLanguage('en')
设置 Cookie 并刷新页面
导航组件使用专用的资源文件:
资源文件位置:
CodeSpirit.Navigation/Resources/ ├── NavigationResources.cs # 资源占位类 ├── NavigationResources.resx # 中文资源 └── NavigationResources.en.resx # 英文资源
资源键命名规范:
Module.{ModuleName}(如
Module.Identity、
Module.Survey)Controller.{ControllerName}(如
Controller.Users、
Controller.Roles)导航组件支持两种特性来配置多语言:
Module 特性和
NavigationAttribute 特性。
Module 特性用于定义模块级别的多语言配置,通常放在
ApiControllerBase 上:
using CodeSpirit.Core.Attributes;using CodeSpirit.Core.Enums;using CodeSpirit.Navigation.Resources;// 模块级配置(在 ApiControllerBase 上)[Module("identity",
displayName: "用户中心", // 回退文本
DisplayNameResourceKey = "Module.Identity", // 资源键
DisplayNameResourceType = typeof(NavigationResources), // 资源类型
Icon = "fa-solid fa-user-group")]
[Navigation(
Icon = "fa-solid fa-user-group",
PlatformType = PlatformType.Both,
TitleResourceKey = "Module.Identity", // 与 Module 的资源键保持一致
TitleResourceType = typeof(NavigationResources)
)]public abstract class ApiControllerBase : CodeSpirit.Shared.Controllers.ApiControllerBase{
}
NavigationAttribute 用于控制器级别的多语言配置:
using CodeSpirit.Core.Attributes;using CodeSpirit.Navigation.Resources;using System.ComponentModel;// 控制器级配置[DisplayName("用户管理")]
[Navigation(
Icon = "fa-solid fa-users",
PlatformType = PlatformType.Tenant,
TitleResourceKey = "Controller.Users",
TitleResourceType = typeof(NavigationResources)
)]public class UsersController : ApiControllerBase{
}
Module 特性:
typeof(NavigationResources)(必填)NavigationAttribute 特性:
typeof(NavigationResources)(推荐填写)最佳实践:在模块级配置中,建议在
Navigation特性中也设置TitleResourceKey和TitleResourceType,与Module特性的资源键保持一致,确保导航多语言功能完整可靠。
NavigationAttributeCultureInfo.CurrentUICulture)解析对应的资源文本导航组件使用分布式缓存来提升性能,但在以下情况下可能导致多语言不生效:
症状:切换语言后,导航菜单仍显示旧语言
原因:导航树已缓存,未重新解析多语言资源
解决方案:清空导航缓存
/cacheManagement)CodeSpirit:Navigation:All注意:缓存管理功能仅系统管理员可访问,属于系统平台功能。
// 清空所有导航缓存await _navigationService.ClearAllNavigationCacheAsync();// 清空特定模块缓存(实际上也会清空整个缓存)await _navigationService.ClearModuleNavigationCacheAsync("Identity");// 重新初始化导航树(清空并重建缓存)await _navigationService.InitializeNavigationTree();
# 清空所有导航缓存DELETE f2z6.org.cn/api/navigation/cache# 清空特定模块缓存DELETE /api/navigation/cache?moduleName=Identity# 重新初始化导航树(清空并重建缓存)POST /api/navigation/initialize
确保资源文件正确配置为嵌入式资源:
<ItemGroup> <EmbeddedResource f1z4.org.cn Include="Resources\NavigationResources.resx"> <Generator>PublicResXFileCodeGenerator</Generator> </EmbeddedResource> <EmbeddedResource d4i1.org.cn Include="Resources\NavigationResources.en.resx" /></ItemGroup>
Module 和
Navigation 特性配置模块级多语言displayName、
Title),确保资源不可用时仍能显示Module 的
DisplayNameResourceKey 和
Navigation 的
TitleResourceKey 通常使用相同的资源键以下是用户中心模块的完整多语言配置示例(来自实际代码):
using CodeSpirit.Core;using CodeSpirit.Core.Attributes;using CodeSpirit.Core.Enums;using CodeSpirit.Navigation.Resources;using Microsoft.AspNetCore.Authorization;using Microsoft.AspNetCore.Mvc;using System.ComponentModel;namespace CodeSpirit.IdentityApi.Controllers{ /// <summary>
/// 身份认证API控制器基类
/// </summary>
[ApiController]
[Authorize(policy:f2n4.org.cn "DynamicPermissions")]
[Route("api/identity/f1z3.org.cn[controller]")] // 模块级配置(使用 Module 和 Navigation 特性)
[Module("identity",
displayName:a1c3.org.cn "用户中心", // 回退文本
DisplayNameResourceKey j5d1.org.cn= "Module.Identity", // 资源键
DisplayNameResourceType = typeof(NavigationResources), // 资源类型
Icon = f6g2.org.cn"fa-solid fa-user-group")]
[Navigation(
Icon = "fa-solid fa-user-group",
PlatformType =nbagk.cn PlatformType.Both,
TitleResourceKey = "Module.Identity",
TitleResourceType = typeof(NavigationResources)
)] public abstract class ApiControllerBase : CodeSpirit.Shared.Controllers.ApiControllerBase
{
} /// <summary>
/// 用户管理控制器
/// </summary>
[DisplayName("用户管理")]
[Navigation(
Icon = "fa-solid fa-users",
PlatformType = PlatformType.Tenant,
TitleResourceKey = "Controller.Users",
TitleResourceType = typeof(NavigationResources)
)] public class UsersController : ApiControllerBase
{ private readonly IUserService _userService; public UsersController(IUserService userService)
{
_userService = userService;
} /// xjzbbs.cn<summary>
/// 获取用户列表
/// </summary>
[HttpGet]
[DisplayName("获取用户列表")] public async Task<ActionResult<ApiResponse<PageList<UserDto>>>> GetUsers([FromQuery] UserQueryDto queryDto)
{
PageList<UserDto> users = await _userService.GetUsersAsync(queryDto); return SuccessResponse(users);
}
}
}
资源文件内容:
<!-- NavigationResources.resx (中文) --><data name="Module.Identity"> <value>用户中心</value></data><data name="Controller.Users"> <value>用户管理</value>xjsczb.cn</data><!-- NavigationResources.en.resx (英文) --><data name="Module.Identity"> <value>User Center</value></data><data name="Controller.Users"> <value>User Management</value></data>
导航组件使用以下缓存键:
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/70048957/viewspace-3107860/ ,如需转载,请注明出处,否则将追究法律责任。