feat: 初始化 Halo 暗色模式插件
- Halo Plugin 后端(Java/Gradle),含 DarkModePlugin 主类和测试 - Vue 3 + TypeScript 前端 UI,包含主题切换组件和设置页面 - 暗色模式 CSS 变量和覆盖样式(布局/编辑器/表单/滚动条等) - 设计文档和调查文档 - Halo 插件/主题开发 Agent Skills Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,109 @@
|
||||
# Internationalization (i18n)
|
||||
|
||||
Halo themes support i18n via `.properties` files under an `i18n/` directory. Thymeleaf provides the `#messages` object for reading translations in templates.
|
||||
|
||||
---
|
||||
|
||||
## Directory Structure
|
||||
|
||||
```
|
||||
my-theme/
|
||||
├── i18n/
|
||||
│ ├── default.properties # Fallback / default language
|
||||
│ ├── zh_CN.properties # Simplified Chinese
|
||||
│ ├── zh_TW.properties # Traditional Chinese
|
||||
│ └── es.properties # Spanish
|
||||
├── templates/
|
||||
└── theme.yaml
|
||||
```
|
||||
|
||||
> Halo uses `default.properties` as the fallback when no locale-specific file matches the user's preference.
|
||||
|
||||
---
|
||||
|
||||
## Properties File Format
|
||||
|
||||
Simple key-value pairs:
|
||||
|
||||
```properties
|
||||
# default.properties
|
||||
page.author.title=Author: {0}
|
||||
common.previousPage=Previous
|
||||
common.nextPage=Next
|
||||
common.noPosts=No posts yet.
|
||||
```
|
||||
|
||||
```properties
|
||||
# zh_CN.properties
|
||||
page.author.title=作者:{0}
|
||||
common.previousPage=上一页
|
||||
common.nextPage=下一页
|
||||
common.noPosts=暂无文章。
|
||||
```
|
||||
|
||||
Placeholders `{0}`, `{1}` ... are filled by the arguments passed to the message function.
|
||||
|
||||
---
|
||||
|
||||
## Using i18n in Templates
|
||||
|
||||
### `#messages.msg(key)` — Get a message
|
||||
|
||||
```html
|
||||
<h1 th:text="${#messages.msg('page.author.title', author.spec.displayName)}"></h1>
|
||||
```
|
||||
|
||||
### `#messages.msgOrNull(key)` — Get a message or null if missing
|
||||
|
||||
```html
|
||||
<span th:text="${#messages.msgOrNull('custom.label') ?: 'Default Label'}"></span>
|
||||
```
|
||||
|
||||
### Thymeleaf shorthand `#{key}` — Standard expression
|
||||
|
||||
```html
|
||||
<!-- Equivalent to #messages.msg('common.previousPage') -->
|
||||
<a th:text="#{common.previousPage}">Previous</a>
|
||||
|
||||
<!-- With arguments -->
|
||||
<title th:text="|#{page.author.title(${author.spec.displayName})} - ${site.title}|"></title>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## `#locale` — Current Locale
|
||||
|
||||
Useful for rendering language-specific UI or setting `<html lang>`:
|
||||
|
||||
```html
|
||||
<html th:lang="${#locale.toLanguageTag()}">
|
||||
<!-- Language selector -->
|
||||
<select>
|
||||
<option value="en" th:selected="${#locale.toLanguageTag() == 'en'}">English</option>
|
||||
<option value="zh-CN" th:selected="${#locale.toLanguageTag() == 'zh-CN'}">简体中文</option>
|
||||
</select>
|
||||
</html>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Frontend i18n Pattern
|
||||
|
||||
Some themes also need translations in JavaScript. A common pattern is to inject the needed strings into a global object via inline script:
|
||||
|
||||
```html
|
||||
<script th:inline="javascript">
|
||||
window.i18nResources = {
|
||||
"common.previousPage": `[(#{common.previousPage})]`,
|
||||
"common.nextPage": `[(#{common.nextPage})]`,
|
||||
};
|
||||
</script>
|
||||
```
|
||||
|
||||
> Note: `[(#{key})]` is Thymeleaf's unescaped inlining syntax. It evaluates the expression and inserts the raw value into the script.
|
||||
|
||||
---
|
||||
|
||||
## Online Docs
|
||||
|
||||
https://raw.githubusercontent.com/halo-dev/docs/refs/heads/main/docs/developer-guide/theme/global-variables.md
|
||||
Reference in New Issue
Block a user