界面语言
界面语言
Vergil 的界面文案支持中文和英文切换。改一行配置,主题自己渲染的所有文字就会跟着变。
它管什么,不管什么
这一点先说清楚,避免误解。
会跟着切换的,是主题自带的界面文案:
- 导航与结构:上一篇 / 下一篇、目录、面包屑、分页、跳过导航
- 侧边栏:站点信息、最近更新、精选文章、相关文章、标签、热力图
- 交互组件:搜索框、主题切换(含 11 个配色方案的名字)、浮动音频播放器、站点助理
- 整页:404、工具箱、数据统计、简历、四季相册
- 指令渲染出的文字:倒计时的天时分秒、日历的上月下月、OKR 的状态、plan 看板的列名与空态
<html lang>属性和日期格式
不会跟着切换的,是属于你的东西:
- 你写的文章、文档、图文动态、相册说明
src/data/config/里你填的内容:站点标题、导航菜单的标签、hero 文案、订阅框文字
这是有意为之。主题不去猜你的内容该是什么语言,你用什么语言写,它就原样呈现。
配置
在 src/data/config/identity.ts 里:
export const siteInfo = { title: 'Vergil', locale: 'zh-CN', // 改成 'en' 即切换为英文界面 // ...};目前支持 'zh-CN' 和 'en' 两个值。填了不认识的值会自动退回 'zh-CN',站点不会因此构建失败。
astro.config.mjs 在启动时会读取一次字典,把文案传给内容指令插件。改完 locale 之后,pnpm dev 需要重启才能看到指令部分的变化,页面热更新不足以覆盖。
日期格式
日期不是硬编码的,会跟随 locale 走。同一篇文章的发布时间,在两种语言下分别是:
| locale | 显示 |
|---|---|
zh-CN | 2026年5月30日 |
en | May 30, 2026 |
文章卡片上的相对时间(今天 / 昨天 / 3 天前)同理。
加一种新语言
字典在 src/i18n/ 下,三个文件:
| 文件 | 作用 |
|---|---|
zh-CN.ts | 中文基准。所有 key 以它为准 |
en.ts | 英文。类型声明为 typeof zhCN |
index.ts | 读配置选字典,导出 locale 和 t |
加一种语言,比如日语:
第一步,复制 en.ts 为 ja.ts,把值翻译过去。类型声明保持不变:
import type zhCN from './zh-CN'; const ja: typeof zhCN = { // ...}; export default ja;这个类型声明很关键。少写一个 key、多写一个 key、或者把函数写成字符串,TypeScript 都会报错,不会等到页面上才发现某处是空白。
第二步,在 index.ts 的 dictionaries 里登记:
import ja from './ja'; const dictionaries = { 'zh-CN': zhCN, en, ja } as const;第三步,把 siteInfo.locale 改成 'ja'。
在自己写的组件里用
如果你新增了组件,里面的文案也想跟着切换:
---import { t } from '../../i18n';--- <span>{t.nav.prev}</span><h3>{t.sidebar.featured}</h3>带参数的 key 是函数,直接调用:
<p>{t.page.series.postsCount(12)}</p><!-- zh-CN: 共 12 篇文章 en: 12 posts -->t 在构建期就确定了,没有运行时开销,也有完整的类型提示——key 写错编辑器会直接标红。
客户端脚本里的文案
浏览器里运行的脚本拿不到 t,需要在渲染时把文案传进去。
内联脚本用 define:vars:
<script is:inline define:vars={{ i18n: { empty: t.common.empty } }}> if (!items.length) el.textContent = i18n.empty;</script>打包脚本(没有 is:inline,或者里面有 import)不能用 define:vars,改成把文案挂在 DOM 属性上再读:
<div id="feed" data-i18n-empty={t.common.empty}></div> <script> const el = document.getElementById('feed'); el.textContent = el.dataset.i18nEmpty;</script>