---
url: /guide/i18n.md
---
# 国际化

日期与时间组件（`DatePicker`、`DateInput`、`TimePicker`、`TimeInput`）的文案、数字日期顺序与默认时钟格式
来自组件库的国际化模块。语言是**模块级单例**，和 `useTheme()` 一样：切换后所有组件立即重新渲染。

月份、星期名与日期格式化全部交给浏览器的 `Intl`，组件库只维护少量界面文案，因此自定义语言不用手抄月名表。

## 内置语言

| 代码      | 日期顺序     | 时钟格式  |
| --------- | ------------ | --------- |
| `en`      | `MM/DD/YYYY` | 12 小时制 |
| `zh-Hans` | `YYYY/MM/DD` | 24 小时制 |
| `zh-Hant` | `YYYY/MM/DD` | 24 小时制 |
| `ja`      | `YYYY/MM/DD` | 24 小时制 |

默认语言是 `en`。组件库不会自动读取浏览器语言，也不会持久化选择——这两件事由应用决定，
例如在挂载前根据 `matchLocale` 设置，并把结果存进 `localStorage`。

文档站是中文站点，因此在 `docs/.vitepress/theme/index.ts` 里调用 `setLocale("zh-Hans")`，演示中的月份、
日期顺序与操作按钮都按简体中文显示。

## 切换语言

```ts
import { setLocale, useI18n } from "@sharpdotnut/dotsharp";

setLocale("ja"); // true；未注册的代码会被忽略并给出警告

const { locale, t } = useI18n();
console.log(locale.value); // "ja"
console.log(t("cancel")); // "キャンセル"
```

`useI18n()` 返回：

| 成员             | 类型                                             | 说明                         |
| ---------------- | ------------------------------------------------ | ---------------------------- |
| `locale`         | `Readonly<Ref<string>>`                          | 当前语言代码                 |
| `intlLocale`     | `ComputedRef<string>`                            | 交给 `Intl` 的合法标签       |
| `order`          | `ComputedRef<"mdy" \| "dmy" \| "ymd">`           | 数字日期顺序                 |
| `firstDayOfWeek` | `ComputedRef<1…7>`                               | 一周首日，1 = 周一，7 = 周日 |
| `timeFormat`     | `ComputedRef<"12h" \| "24h">`                    | 默认时钟格式                 |
| `setLocale`      | `(code: string) => boolean`                      | 切换语言                     |
| `registerLocale` | `(code, messages, options?) => void`             | 注册或覆盖语言               |
| `t`              | `(key: keyof LocaleMessages) => string`          | 当前语言的文案               |
| `matchLocale`    | `(supported, requested?) => string \| undefined` | 从候选里挑最合适的语言       |

`setLocale`、`registerLocale`、`matchLocale` 也从包入口直接导出。

## 获取当前语言

`matchLocale` 用 `Intl` 规范化并补全语言标签（`zh-TW` 补全为 `zh-Hant-TW`），再按
完整匹配 → 同语言同书写系统 → 同语言同地区 → 同语言唯一候选 的顺序选出结果：

```ts
import { matchLocale } from "@sharpdotnut/dotsharp";

const supported = ["en", "zh-Hans", "zh-Hant", "ja"];

matchLocale(supported, ["zh-TW"]); // "zh-Hant"
matchLocale(supported, ["zh-CN"]); // "zh-Hans"
matchLocale(supported, ["ja-JP"]); // "ja"
matchLocale(supported, ["fr-FR"]); // undefined
```

省略第二个参数时读取 `navigator.languages`（服务端没有 `navigator`，返回 `undefined`）：

```ts
const locale = matchLocale(supported) ?? "en";
setLocale(locale);
```

## 加载自定义语言

`registerLocale` 只覆盖提供的字段，其余回退到英文；`order` 与 `firstDayOfWeek` 是可选的语言级设置。
语言代码应当是合法的 BCP 47 标签，月份与星期名由它决定：

```ts
import { registerLocale, setLocale } from "@sharpdotnut/dotsharp";

registerLocale(
  "fr",
  {
    date: "Date",
    enterDate: "Saisir une date",
    selectDate: "Choisir une date",
    invalidDate: "Date invalide",
    cancel: "Annuler",
    ok: "Valider",
    previousMonth: "Mois précédent",
    nextMonth: "Mois suivant",
    time: "Heure",
    selectTime: "Choisir une heure",
    invalidTime: "Heure invalide",
    hour: "Heure",
    minute: "Minute",
    second: "Seconde",
    am: "AM",
    pm: "PM",
    clock: "Ouvrir l'horloge",
    chooseMonth: "Choisir le mois",
    chooseYear: "Choisir l'année",
    calendar: "Ouvrir le calendrier",
  },
  { order: "dmy", firstDayOfWeek: 1, timeFormat: "24h" },
);

setLocale("fr");
```

也可以覆盖内置语言的部分字段：

```ts
registerLocale("ja", { ok: "決定" });
```

`firstDayOfWeek` 省略时从 `Intl.Locale` 的区域周信息读取，读不到则回退到周日；
`timeFormat` 省略时也按该语言的区域小时制推断（`h11` / `h12` 为 12 小时制，其余为 24 小时制）。

## 服务端渲染

语言状态在模块作用域里，服务端与浏览器各有一份。为了让 SSR 输出与首次水合一致：

* 服务端与浏览器都用同一个初始语言（默认 `en`），或把语言放在应用的根上下文里统一设置；
* 依赖 `navigator` / `localStorage` 的自动检测放到 `onMounted`，不要让首次渲染读到浏览器状态；
* 文档站里所有触碰浏览器状态的示例都用 `mounted` ref 包一层。

## 新增文案

组件的界面文案集中在 `src/i18n/index.ts` 的 `LocaleMessages`；新增日期组件文案时先加英文键，
再补三种内置翻译，`t` 的键类型会自动覆盖到自定义语言。
