> For AI agents: the complete documentation index is available at https://docs.halo.run/llms.txt, the full documentation bundle is available at https://docs.halo.run/llms-full.txt.

# 国际化

主题可以在根目录的 `i18n` 中提供国际化消息。建议始终提供 `default.properties` 作为兜底，再按需要添加语言和地区文件。

```tree title="i18n"
i18n
├── default.properties
├── en.properties
├── zh.properties
├── zh_CN.properties
└── zh_TW.properties
```

Halo 会依次合并 `default.properties`、语言文件和语言地区文件，后读取的更具体文件会覆盖前面的同名键。例如访问者的语言为 `zh-CN` 时，读取顺序为 `default.properties`、`zh.properties`、`zh_CN.properties`。

## 定义消息

```properties title="i18n/default.properties"
pagination.previous=Previous
pagination.next=Next
site.poweredBy=Powered by {0}
```

```properties title="i18n/zh_CN.properties"
pagination.previous=上一页
pagination.next=下一页
site.poweredBy=由 {0} 提供支持
```

消息键建议按页面或组件分组，保持各语言文件使用相同的键集合。

## 在模板中使用

使用 `#{...}` 读取消息，并将当前语言写入 HTML：

```html
<html th:lang="${#locale.toLanguageTag}">
  <body>
    <a th:text="#{pagination.previous}">Previous</a>
    <p th:text="#{site.poweredBy(${site.title})}">Powered by Halo</p>
  </body>
</html>
```

如果某条消息确实是可选项，可以使用 `#messages.msgOrNull` 提供显式兜底：

```html
<span th:text="${#messages.msgOrNull('notice.optional') ?: 'Notice'}"></span>
```

普通必需消息不应静默兜底。缺少键时，页面会显示类似 `??pagination.previous_zh_CN??` 的标记，便于在测试时发现遗漏。

## 页面级消息

如果某个模板需要覆盖全局消息，也可以在模板旁提供同名的 properties 文件：

```tree title="templates"
templates
├── index.html
├── index.properties
└── index_zh_CN.properties
```

页面级文件中的同名键优先于根目录 `i18n` 中的消息。多个页面共用的文案仍应放在 `i18n`，只把页面专属或需要覆盖的消息放在模板旁。

## 在 JavaScript 中使用

使用 Thymeleaf JavaScript 内联，让消息值按 JavaScript 字面量规则转义：

```html
<script th:inline="javascript">
  const messages = {
    previous: /*[[#{pagination.previous}]]*/ "Previous",
    next: /*[[#{pagination.next}]]*/ "Next",
  };
</script>
```

不要把消息直接拼接进带引号的 JavaScript 字符串，否则翻译中的引号、换行等字符可能破坏脚本。

## 切换和测试语言

Halo 依次从 `language` 查询参数、`language` Cookie、已登录用户的语言偏好和浏览器 `Accept-Language` 请求头解析当前语言。开发时可以直接访问以下地址检查指定语言：

```text
http://localhost:8090/?language=zh-CN
```

至少检查默认语言、每个已提供的地区文件，以及不存在对应地区文件时能否正确回退到语言文件或 `default.properties`。
