基础
i18n
让脚本按设备语言显示对应的文案。
onescript/i18n 会按 system.locale.languages(设备的语言偏好)从你提供的文案中选出一种语言,并提供文案查找、插值、复数,以及日期和数字的格式化。
快速开始
在项目中为每种语言准备一个 JSON 文件:
src/
app.tsx
locales/
en.json
zh-Hans.jsonlocales/en.json:
{
"greeting": "Hello, {name}!",
"cart": {
"items": { "one": "{count} item", "other": "{count} items" }
}
}locales/zh-Hans.json:
{
"greeting": "你好,{name}!",
"cart": {
"items": { "other": "{count} 件商品" }
}
}src/app.tsx:
import { createI18n } from "onescript/i18n"
import en from "./locales/en.json"
import zhHans from "./locales/zh-Hans.json"
const i18n = createI18n({
fallback: "en",
messages: { en, "zh-Hans": zhHans },
})
// 设备语言为简体中文时:
i18n.locale // "zh-Hans"
i18n.t("greeting", { name: "Ada" }) // "你好,Ada!"
i18n.t("cart.items", { count: 3 }) // "3 件商品"
// 设备语言为英文时:
i18n.locale // "en"
i18n.t("cart.items", { count: 1 }) // "1 item"
i18n.t("cart.items", { count: 3 }) // "3 items"文案
- 文案是嵌套对象,用点分路径作为 key,例如
"cart.items"。key 按fallback语言的文案做类型检查,写错时编辑器会报错。 {name}会被替换为传入的值。数字会按文案语言格式化,例如英文中1234显示为1,234。缺少对应的值时会报错。- 带
other键的对象是复数文案,调用时需要传入count。分支按Intl.PluralRules选择(zero、one、two、few、many、other),对应的分支不存在时使用other。 - 其他语言可以缺少部分文案。缺少时使用
fallback语言的文案,并对每个 key 只提示一次警告。
语言匹配
createI18n 按顺序检查 system.locale.languages,使用第一个能匹配到的语言;都匹配不到时使用 fallback。
- 地区不同也能匹配:
en-GB匹配en,pt-BR匹配pt。 - 中文按书写文字匹配:
zh-CN匹配zh-Hans,zh-TW、zh-HK匹配zh-Hant。 - 书写文字不同不会匹配:只提供了
zh-Hans时,繁体中文用户会继续尝试下一个偏好语言,而不是看到简体文案。
假设提供了 en、zh-Hans、zh-Hant 三种文案,fallback 为 en:
system.locale.languages | i18n.locale |
|---|---|
["zh-CN"] | "zh-Hans" |
["zh-HK"] | "zh-Hant" |
["en-GB"] | "en" |
["ja-JP", "zh-TW"] | "zh-Hant"(没有日语,使用下一个偏好语言) |
["ja-JP"] | "en"(都匹配不到,使用 fallback) |
如果不想跟随设备语言,可以通过 locale 指定:
const i18n = createI18n({
fallback: "en",
locale: "zh-Hans",
messages: { en, "zh-Hans": zhHans },
})
i18n.locale // 始终为 "zh-Hans"日期与数字
i18n.date(value, options) 和 i18n.number(value, options) 使用与文案相同的语言格式化,options 与 Intl.DateTimeFormat、Intl.NumberFormat 的选项相同。
const date = new Date(2026, 9, 7)
// i18n.locale 为 "en" 时:
i18n.date(date, { dateStyle: "long" }) // "October 7, 2026"
i18n.number(1234.5) // "1,234.5"
i18n.number(9.5, { style: "currency", currency: "USD" }) // "$9.50"
i18n.number(0.25, { style: "percent" }) // "25%"
i18n.number(12500, { notation: "compact" }) // "13K"
// i18n.locale 为 "zh-Hans" 时:
i18n.date(date, { dateStyle: "long" }) // "2026年10月7日"
i18n.number(12500, { notation: "compact" }) // "1.3万"API
createI18n(options) 的参数:
| 参数 | 类型 | 说明 |
|---|---|---|
fallback | string | 文案最完整的语言。其他语言缺少文案时使用它,key 的类型也从它推导。 |
messages | Record<string, object> | 各语言的文案,key 为语言标签,例如 "en"、"zh-Hans"。 |
locale | string | 可选。指定使用的语言,不再跟随设备语言。 |
返回值:
| 成员 | 说明 |
|---|---|
locale | 匹配到的语言。 |
t(key, values?) | 返回文案,values 用于插值和复数。 |
date(value, options?) | 按 locale 格式化日期。 |
number(value, options?) | 按 locale 格式化数字。 |
另外导出了 matchLocale(requested, available, fallback),可以单独使用上面的匹配规则,例如 matchLocale(["zh-TW"], ["en", "zh-Hant"], "en") 返回 "zh-Hant"。
使用其他库
如果需要 ICU MessageFormat 等更完整的功能,可以安装 i18next 等库,并用 system.locale.languages 决定语言:
import i18next from "i18next"
import { system } from "onescript"
await i18next.init({
lng: system.locale.languages[0],
fallbackLng: "en",
resources: {
en: { translation: { greeting: "Hello, {{name}}!" } },
},
})How is this guide?
最后更新于