Skip to content

国际化支持

微应用模板内置了轻量级国际化(i18n)方案,支持多语言翻译、占位符替换、配置引用等。国际化功能已集成在 @sun-panel/micro-app SDK 中,组件基类(SunPanelWidgetElement / SunPanelPageElement)会在 onConnected 生命周期中自动初始化 i18n,开发者无需手动调用 initI18n

需要满足条件:

  • Sun-Panel 主版本升级到 v2.0.0-dev-14+
  • 微应用模板升级v1.1.0+
  • SDK模块 (@sun-panel/micro-app) 升级到 v1.0.18+
  • app.config.js 下配置参数 {appJsonVersion: '1.1'},1.1及以上

目录结构

your-app/
├── locales/                    # 国际化语言文件(唯一翻译源)
│   ├── zh-CN.js               # 中文语言包
│   └── en-US.js               # 英文语言包
├── config/
│   └── app.config.js          # 应用配置(声明语言文件列表)
└── ...

快速开始

1. 配置应用信息

config/app.config.js 中,使用 $t:KEY 引用翻译键,并在 locales 对象中声明语言文件映射:

js
export default {
  // 配置文件格式版本
  // 1.1: appInfo 使用 $t: 引用,翻译文件在 locales/ 目录
  appJsonVersion: '1.1',

  // 应用信息(使用 $t: 变量引用翻译)
  appInfo: {
    appName: '$t:APP_NAME',
    description: '$t:APP_DESCRIPTION',
    networkDescription: '$t:NETWORK_DESCRIPTION',
  },

  // 语言文件映射(格式:{ 语言代码: 文件名 })
  // 文件名相对于 locales/ 目录,支持多语言代码指向同一文件
  locales: {
    'zh-CN': 'zh-CN.json',
    'en-US': 'en-US.json',
    // 'zh-TW': 'zh-CN.json',  // 示例:繁体中文可指向简体中文文件
  },

  // 默认语言(当主应用语言在微应用中不存在时,回退到此语言)
  // 如果不设置,默认为 'en-US'
  defaultLocale: 'en-US',

  // ...其他配置
};

提示

config/* 中的值使用 $t:翻译键名 格式引用。构建时,系统会自动解析这些引用并替换为对应语言的翻译文本。

2. 创建语言包文件

locales/ 目录下创建对应的语言包文件。文件名必须与 locales 对象中的值一致(去掉 .json 后缀,使用 .js 源文件):

js
// locales/zh-CN.js
export default {
  APP_NAME: '你好世界',
  APP_DESCRIPTION: 'Sun-Panel 演示微应用',
  NETWORK_DESCRIPTION: '无需链接任何三方网站',
  WIDGET_HELLO_NAME: '你好世界小部件',
  WIDGET_HELLO_DESCRIPTION: '这是一个演示小部件',
  GREETING: '你好, {name}!',
  // ...更多翻译
};
js
// locales/en-US.js
export default {
  APP_NAME: 'Hello World',
  APP_DESCRIPTION: 'Sun-Panel Demo Micro App',
  NETWORK_DESCRIPTION: 'For demonstration purposes',
  WIDGET_HELLO_NAME: 'Hello World Widget',
  WIDGET_HELLO_DESCRIPTION: 'A demo widget',
  GREETING: 'Hello, {name}!',
  // ...更多翻译
};

3. 在组件中使用

继承组件基类后,i18n 会在 onConnected 生命周期中自动初始化,开发者可以直接通过 this.t() 使用翻译:

js
// 在 widgetConfig.js 中
import { SunPanelWidgetElement } from '@sun-panel/micro-app';

class MyWidget extends SunPanelWidgetElement {
  render() {
    const config = {
      name: this.t('WIDGET_HELLO_NAME'),
      description: this.t('WIDGET_HELLO_DESCRIPTION'),
    };
    return config;
  }
}

无需手动调用 initI18n

组件基类 SunPanelWidgetElement / SunPanelPageElement 会在 onConnected 生命周期中自动完成 i18n 初始化,无需手动导入和调用 initI18n。直接使用 this.t() 即可。

在微应用的组件中使用

this.t(key, args?) - 翻译函数(推荐)

组件基类提供的实例方法,根据当前语言环境翻译指定的键,支持命名占位符替换。

参数:

  • key (string) - 翻译键名
  • args (Record<string, any>) - 可选的命名占位符替换参数对象

返回值: 翻译后的字符串(未找到时返回键名本身)

示例:

js
// 组件内部使用
this.t('APP_NAME');                              // => '你好世界'
this.t('GREETING', { name: '张三' });            // => '你好, 张三!'
this.t('WELCOME_USER_ROLE', { name: '李四', role: '管理员' });  // => '欢迎 李四,您是 管理员'

t(key, args?) - 翻译函数(独立导出)

根据当前语言环境翻译指定的键,支持命名占位符替换。

参数:

  • key (string) - 翻译键名
  • args (Record<string, any>) - 可选的命名占位符替换参数对象

返回值: 翻译后的字符串(未找到时返回键名本身)

示例:

js
import { t } from '@sun-panel/micro-app';

// 基本翻译
t('APP_NAME');        // => '你好世界'
t('SETTINGS');        // => '设置'

// 带命名占位符的翻译
t('GREETING', { name: '张三' });                    // => '你好, 张三!'
t('WELCOME_USER_ROLE', { name: '李四', role: '管理员' });  // => '欢迎 李四,您是 管理员'

setLocale(locale) - 单独切换语言

此方案仅适用于,脱离主应用语言,单独手动动态切换当前语言环境,并重新初始化解析器。

参数:

  • locale (string) - 目标语言标识符,如 'en-US'

示例:

js
import { setLocale } from '@sun-panel/micro-app';

// 组件代码
class WidgetConfig extends SunPanelPageElement {
  // ...

  // 语言切换处理
  async handleLanguageChange(locale) {
    try {
      await setLocale(locale);
      this.requestUpdate(); // 更新页面,重要!!!
      console.log(`Language changed to: ${locale}`);
    } catch (error) {
      console.error('Failed to change language:', error);
    }
  }

  // ...
}

getLocale() - 获取当前语言

返回当前语言环境的标识符字符串。

返回值: string - 当前语言标识符

占位符

占位符使用 {name} 格式,name 为参数对象中的键名:

js
// locales/zh-CN.js
export default {
  GREETING: '你好, {name}!',
  WELCOME_USER_ROLE: '欢迎 {name},您是 {role}',
};

// locales/en-US.js
export default {
  GREETING: 'Hello, {name}!',
  WELCOME_USER_ROLE: 'Welcome {name}, you are {role}',
};
js
t('GREETING', { name: '张三' });                                      // => '你好, 张三!'
t('WELCOME_USER_ROLE', { name: '李四', role: '管理员' });              // => '欢迎 李四,您是 管理员'

如果占位符对应的参数缺失,占位符将原样保留(如 {name})。

语言回退机制

当翻译键在当前语言中未找到时,系统会按以下顺序回退查找:

  1. 完整语言代码 - 如 zh-CN
  2. 语言短码 - 去掉地区后缀,如 zh
  3. 默认语言 - 由 app.config.js 中的 defaultLocale 字段指定,默认为 'en-US'
js
// 假设当前语言为 zh-TW,但只有 zh-CN 和 en-US 的翻译
// 查找顺序:zh-TW → zh → en-US(假设 defaultLocale 为 'en-US')
t('SETTINGS');  // 如果 zh-TW 和 zh 都没有,会从 en-US 获取

回退链示例

当前语言 (locale)defaultLocale回退链说明
zh-CNen-US['zh-CN', 'zh', 'en-US']中文回退到英文
en-USen-US['en-US', 'en']英文自身回退,defaultLocale 不重复
zh-CNzh-CN['zh-CN', 'zh']defaultLocale 与当前语言相同时不重复

配置默认语言

config/app.config.js 中设置 defaultLocale 字段来指定默认回退语言:

js
export default {
  // ...其他配置
  
  // 语言文件映射
  locales: {
    'zh-CN': 'zh-CN.json',
    'en-US': 'en-US.json',
  },
  
  // 默认语言(当主应用语言在微应用中不存在时,回退到此语言)
  // 如果不设置,默认为 'en-US'
  defaultLocale: 'en-US',
  
  // ...其他配置
};

工作原理

defaultLocale 的传递路径:

  1. app.config.js 中声明 defaultLocale
  2. main.js 在初始化 SDK 时读取该值并传入:initSDK({ defaultLocale: appConfig.defaultLocale || 'en-US' })
  3. SDK 内部将其传递给 i18n 初始化:initI18n({ locale, defaultLocale })
  4. 翻译查找时,defaultLocale 作为回退链的最终兜底,在所有回退之后

此外,SDK 在异步加载翻译文件时,会同时加载当前语言和 defaultLocale 的翻译文件,确保回退翻译数据可用。

注意事项:

  • defaultLocale 的值必须是 locales 对象中已定义的语言代码之一
  • 建议设置为应用的主要支持语言(如中文应用可设为 'zh-CN'
  • 如果未设置,默认值为 'en-US'

如果所有回退语言中都没有该 key,则返回 key 本身(如 MISSING_KEY)。

构建流程

开发模式

开发模式下,locales/*.js 源文件通过 Vite 动态 import 直接加载:

locales/zh-CN.js → import() 动态加载 → i18n 实例

生产构建

构建时,locales-generator.jslocales/*.js 编译为 JSON 格式,输出到 dist/locales/ 目录:

locales/zh-CN.js → locales-generator.js → dist/locales/zh-CN.json
locales/en-US.js → locales-generator.js → dist/locales/en-US.json

生产模式下,i18n 通过 fetch{staticPath}/locales/*.json 加载翻译文件。

最佳实践

1. 键名规范

翻译键不强制要求使用某种命名方法,按照个人习惯即可,暂时不支持嵌套翻译对象,请尽量不要在键名中使用 .。下面示例中使用的是 大写蛇形命名法(UPPER_SNAKE_CASE):

js
export default {
  APP_NAME: '应用名称',
  WIDGET_HELLO_NAME: '小部件名称',
  SETTINGS_TITLE: '设置标题',
  WIDGET_CONFIG_BUTTON_SAVE: '保存小部件',
};

2. 文件命名

语言包文件名尽量要与 app.config.jslocales 对象的值对应:

语言源文件locales 声明
简体中文locales/zh-CN.js'zh-CN': 'zh-CN.json'
英语locales/en-US.js'en-US': 'en-US.json'
繁体中文locales/zh-TW.js'zh-TW': 'zh-TW.json'

3. 保持翻译同步

所有语言包文件应包含相同的键。新增翻译时,记得同步更新所有语言包文件。

4. 仅翻译文本

只翻译用户可见的文本内容,以下内容不要国际化:

  • 配置键名(如 showLogotextOption
  • CSS 类名
  • API 路径
  • 数据节点标识

注意事项

  1. 翻译源位置:所有翻译应统一放在 locales/ 目录下,不要在 src/ 目录下创建语言文件
  2. 不要直接修改构建产物dist/locales/ 是构建输出,修改会被覆盖
  3. 语言标识符格式:遵循 IETF BCP 47 标准(如 zh-CNen-US

Released under the MIT License.