当前位置: 首页 > news >正文

CodeSpirit 多语言国际化使用指南(Beta)

概述

CodeSpirit 框架现已支持完整的前后端多语言国际化功能,提供中英文双语支持,基于 .NET 资源文件和 AMIS locale,通过 Settings 组件实现全局、租户、用户三级语言配置。

版本: v1.0.0
支持语言: 简体中文(zh-CN)、英文(en)
更新日期: 2025年12月28日

  • Github:xin-lai/CodeSpirit
  • Gitee:magicodes/CodeSpirit

🎯 核心特性

  • 双语支持:中文(默认)+ 英文
  • 全栈覆盖:后端 API + 前端 UI
  • 多级配置:系统默认 → 租户默认 → 用户偏好
  • 类型安全:使用 .resx 资源文件,编译时强类型访问
  • 动态切换:用户可实时切换语言,无需重新登录
  • AMIS 兼容:集成 AMIS 的 locale 机制
  • DataAnnotations 支持:验证特性自动本地化
  • DTO描述多语言:支持字段描述信息的多语言
  • 零侵入:无需修改业务表结构,基于 Settings 组件

🏗️ 架构设计

语言解析优先级

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; }

验证错误示例

中文环境:题目内容不能为空
英文环境:Content is required

4. DTO 描述信息多语言

DTO 字段的描述信息(Description)也支持多语言,通过LocalizedDescriptionAttribute实现。

4.1 创建服务资源文件

各服务应创建自己的资源文件,保持服务独立性:

资源文件结构

CodeSpirit.ExamApi/Resources/ ├── ExamDisplayResources.cs # 资源占位类(包含ResourceManager) ├── ExamDisplay.resx # 中文资源 └── ExamDisplay.en.resx # 英文资源

资源键命名规范

  • DTO字段描述:Description.{EntityName}.{PropertyName}
  • 示例:Description.Question.OptionsDescription.Question.CorrectAnswer
4.2 在DTO中使用
using CodeSpirit.Core.Attributes; using CodeSpirit.ExamApi.Resources; public class CreateQuestionDto { [LocalizedDescription( "根据题目内容生成合适的选项", // 回退文本(可选) ResourceKey = "Description.Question.Options", ResourceType = typeof(ExamDisplayResources) )] public List<string> Options { get; set; } }

使用方式

  • 方式1:仅使用资源键(推荐)
  • 方式2:带回退文本(更安全,资源不可用时显示回退文本)
  • 方式3:使用共享资源(仅适用于通用描述)
4.3 向后兼容

现有的DescriptionAttribute仍然可以正常使用,系统会优先检查LocalizedDescriptionAttribute,如果不存在则回退到DescriptionAttribute

4.4 资源文件组织原则
  • 共享资源CodeSpirit.Localization/Resources/- 存放真正通用的、跨服务的资源
  • 服务资源ApiServices/{ServiceName}/Resources/- 存放服务特有的业务资源

最佳实践

  • 各服务管理自己的资源文件,避免在共享资源中放置服务特定内容
  • 遵循Description.{EntityName}.{PropertyName}命名约定
  • 建议提供回退文本,确保资源不可用时仍能显示
4.5 技术实现

描述多语言的资源解析由 AMIS 表单生成时统一处理:

  • CultureResolver:从 HttpContext Features、Cookie 等多个来源获取当前语言
  • 统一解析GetLocalizedDescription方法在表单生成时解析资源
  • 回退机制:英文环境下确保正确加载英文资源,避免回退到中文
  • 缓存优化:在同一请求中复用已解析的文化信息

5. 前端使用

JavaScript
// 获取翻译文本 const message = CodeSpirit.i18n.t('Common.Save'); // 带参数 const message = CodeSpirit.i18n.t('Validation.Required', { 0: '用户名' }); // 切换语言 CodeSpirit.i18n.switchLanguage('en');
Razor 页面
@using CodeSpirit.Localization.Resources @using Microsoft.Extensions.Localization @inject IStringLocalizer<SharedResources> Localizer <h1>@Localizer["Common.Save"]</h1>

🎛️ 语言配置管理

通过 API 设置语言

系统已自动集成 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" );

通过 UI 切换语言

用户可以在导航栏的语言切换器中选择语言,切换后会:

  1. 设置 Cookie(.AspNetCore.Culture
  2. 刷新页面
  3. 所有界面文本、错误消息自动切换为对应语言

📚 资源文件说明

共享资源(Localization组件)

资源文件用途示例键
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)。

服务特定资源(各API服务)

各服务应创建自己的资源文件,保持服务独立性:

命名规范

  • 占位类:{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

资源键命名约定

  • DTO字段描述:Description.{EntityName}.{PropertyName}
  • 示例:Description.Question.OptionsDescription.Survey.Title

🔧 常见场景

场景 1:用户切换语言

  1. 用户在导航栏选择 "English"

  2. JavaScript 调用CodeSpirit.i18n.switchLanguage('en')

  3. 设置 Cookie 并刷新页面

  4. 所有内容显示为英文

场景 2:租户设置默认语言

  1. 租户管理员在设置中选择默认语言为英文
  2. 系统通过 Settings API 保存配置
  3. 该租户下的所有用户默认使用英文
  4. 用户仍可以设置自己的语言偏好

场景 3:API 返回本地化错误

// 中文环境 throw new BusinessException("Errors.NotFound"); // API 返回: { "status": 0, "msg": "未找到资源" } // 英文环境 throw new BusinessException("Errors.NotFound"); // API 返回: { "status": 0, "msg": "Resource not found" }
http://www.cnnetsun.cn/news/1415832.html

相关文章:

  • 告别PDF提取烦恼!MinerU镜像5分钟实战:表格公式一键转Markdown
  • 从Kettle PDI到Spark/Flink:一个数据工程师的实战工具箱选择与避坑指南
  • Web开发核心技术解析:从CSS到Servlet的实战问答集锦
  • Qwen3-Reranker-8B模型解析:架构设计与训练方法
  • Nunchaku-flux-1-dev与Mathtype公式渲染:学术论文插图自动化生成
  • AI智能文档扫描仪使用技巧:提高边缘检测成功率的方法
  • 个人知识管理神器!WeKnora本地部署教程,保护隐私零泄露
  • OpenClaw多模态实践:GLM-4.7-Flash处理图片与文本混合输入
  • ILI9488 TFT驱动深度解析:RGB888转换与SPI性能优化
  • 开源CV大模型落地实践:cv_resnet101_face-detection_cvpr22papermogface在边缘设备部署可行性分析
  • Win10 系统下 WSL 的灵活部署:从 Microsoft Store 到离线包的全路径解析
  • 【ComfyUI】Qwen-Image-Edit-F2P效果展示:多风格人像生成作品集与参数解析
  • 1.6 面对攻击的网络 | 计算机网络的安全防线
  • 《计算机网络:自顶向下方法》第 1 章 核心知识梳理 + 原版习题解析
  • 为什么你的卫星C代码在轨待机功耗超标2.8倍?——TI C674x + STM32WL双平台功耗对比白皮书首发
  • 电子工程师必备硬件与软件工具全解析
  • 突破功能限制:MobaXterm-keygen许可证生成工具完整解决方案
  • 亲测有效!Nanbeige 4.1-3B极简WebUI,让AI对话变得时尚又好玩
  • 保姆级教程:手把手教你给MKS Robin Nano V3.0刷RRF固件,从刷机到调平一次搞定
  • Python+OpenCV外接USB摄像头报错?三步搞定设备ID识别难题
  • LIN自动寻址:从“菊花链”到“一键配置”的工程实践
  • 计算机组成原理视角:分析Ostrakon-VL-8B模型推理的GPU计算与存储瓶颈
  • 地震数据处理实战:如何用Python实现F-K滤波去噪(附完整代码)
  • 单ADC引脚实现电容触摸:纯软件嵌入式触控方案
  • SAP资产会计避坑指南:为什么AFAB执行首期折旧会提示‘上年已结算‘错误
  • 嵌入式传感器抽象库AD_Sensors设计与实践
  • OpenClaw自动化测试框架:ollama-QwQ-32B驱动的端到端验证
  • 实时手机检测-通用效果对比:DAMO-YOLO vs YOLOv5s在手机类AP提升分析
  • Postgresql管理-锁管理与分析
  • Nano-Banana算法解析:深入理解其独特的图像生成架构