2026-09-20 15:53:28 +08:00
|
|
|
|
---
|
|
|
|
|
|
title: UI 本地化
|
2026-09-21 17:27:45 +08:00
|
|
|
|
description: 将应用翻译器桥接到 UI 组件,并加载当前语言的日历 locale。
|
2026-09-20 15:53:28 +08:00
|
|
|
|
order: 21
|
|
|
|
|
|
toc:
|
2026-09-21 17:27:45 +08:00
|
|
|
|
- id: two-layers
|
|
|
|
|
|
title: 两层职责
|
|
|
|
|
|
- id: catalogs
|
|
|
|
|
|
title: 合并词典
|
|
|
|
|
|
- id: bridge-provider
|
|
|
|
|
|
title: 桥接 Provider
|
|
|
|
|
|
- id: fallback
|
|
|
|
|
|
title: 回退行为
|
|
|
|
|
|
- id: direction
|
|
|
|
|
|
title: 文本方向
|
2026-09-20 15:53:28 +08:00
|
|
|
|
---
|
|
|
|
|
|
|
2026-09-21 17:27:45 +08:00
|
|
|
|
## 两层职责 {#two-layers}
|
2026-09-20 15:53:28 +08:00
|
|
|
|
|
2026-09-21 17:27:45 +08:00
|
|
|
|
`@workspace/i18n` 管理应用 locale、词典加载、格式化和切换;`@workspace/ui/components/i18n` 是轻量适配层,让 UI primitives 不绑定某个国际化框架。后者接收一个兼容的翻译函数、语言标签和 `react-day-picker` locale。
|
|
|
|
|
|
|
|
|
|
|
|
这种拆分允许 UI 包独立复用,也允许应用继续使用工作区的完整国际化运行时。
|
|
|
|
|
|
|
|
|
|
|
|
## 合并词典 {#catalogs}
|
|
|
|
|
|
|
|
|
|
|
|
在应用的 `i18n.config.json` 中加入 UI 词典来源:
|
2026-09-20 15:53:28 +08:00
|
|
|
|
|
|
|
|
|
|
```json
|
|
|
|
|
|
{
|
|
|
|
|
|
"catalogSources": ["@workspace/ui/locales/{locale}"]
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
2026-09-21 17:27:45 +08:00
|
|
|
|
根入口 `@workspace/ui/locales` 只导出 `uiCatalogLocales`、`uiMessageIds` 和类型,不会静态导入所有语言。当前仅支持 `en-US` 与 `zh-Hans`。
|
|
|
|
|
|
|
|
|
|
|
|
## 桥接 Provider {#bridge-provider}
|
|
|
|
|
|
|
|
|
|
|
|
从当前应用 Provider 中读取翻译器,再传给 UI Provider:
|
|
|
|
|
|
|
|
|
|
|
|
```tsx
|
|
|
|
|
|
import { useLocaleDefinition, useTranslate } from "@workspace/i18n"
|
|
|
|
|
|
import {
|
|
|
|
|
|
I18nProvider as UiI18nProvider,
|
|
|
|
|
|
type CalendarLocale,
|
|
|
|
|
|
} from "@workspace/ui/components/i18n"
|
|
|
|
|
|
import { calendarLocale as enUS } from "@workspace/ui/locales/en-US"
|
|
|
|
|
|
import { calendarLocale as zhHans } from "@workspace/ui/locales/zh-Hans"
|
2026-09-20 15:53:28 +08:00
|
|
|
|
|
2026-09-21 17:27:45 +08:00
|
|
|
|
const calendarLocales: Record<string, CalendarLocale> = {
|
|
|
|
|
|
"en-US": enUS,
|
|
|
|
|
|
"zh-Hans": zhHans,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export function AppUiI18nProvider({ children }: React.PropsWithChildren) {
|
|
|
|
|
|
const locale = useLocaleDefinition()
|
|
|
|
|
|
const t = useTranslate()
|
2026-09-20 15:53:28 +08:00
|
|
|
|
|
2026-09-21 17:27:45 +08:00
|
|
|
|
return (
|
|
|
|
|
|
<UiI18nProvider
|
|
|
|
|
|
calendarLocale={calendarLocales[locale.locale]}
|
|
|
|
|
|
locale={locale.languageTag ?? locale.locale}
|
|
|
|
|
|
t={t}
|
|
|
|
|
|
>
|
|
|
|
|
|
{children}
|
|
|
|
|
|
</UiI18nProvider>
|
|
|
|
|
|
)
|
|
|
|
|
|
}
|
2026-09-20 15:53:28 +08:00
|
|
|
|
```
|
|
|
|
|
|
|
2026-09-21 17:27:45 +08:00
|
|
|
|
`Calendar` 会优先使用组件自身的 `locale` prop,其次使用 Provider 的 `calendarLocale`;月份格式化与 `lang` 默认使用 Provider 的语言标签。
|
|
|
|
|
|
|
|
|
|
|
|
## 回退行为 {#fallback}
|
|
|
|
|
|
|
|
|
|
|
|
没有 Provider 时,UI 层使用 `en-US` 和消息描述符中的英文原文。因此独立测试和 Story 不会因为缺少 Provider 崩溃,但正式应用仍应桥接 Provider,保证 aria-label 与可见文本一致。
|
|
|
|
|
|
|
|
|
|
|
|
自定义组件可以使用 `uiMessages`、`useMessage`、`useTranslate`、`LocalizedText`、`useLocale` 和 `useCalendarLocale`。产品业务文案应定义在应用或领域 package 中,不要追加到 UI 词典。
|
2026-09-20 15:53:28 +08:00
|
|
|
|
|
2026-09-21 17:27:45 +08:00
|
|
|
|
## 文本方向 {#direction}
|
2026-09-20 15:53:28 +08:00
|
|
|
|
|
2026-09-21 17:27:45 +08:00
|
|
|
|
翻译语言与布局方向是两件事。切换 locale 时,应用应同步设置 `document.documentElement.lang` 与 `dir`,并在需要时使用 `DirectionProvider`。本地组件使用 `start`、`end`、`ps`、`pe` 等逻辑方向 utility,`components.json` 也开启了 `rtl`。
|