在Hugo多语言博客中使用标签时,我发现了两个问题。
多语言显示——希望中文页面显示「测试」,英语页面显示「Testing」。
命名不一致——如果在每种语言的front matter中直接写标签名,很容易出现偏差。英语里「e-mail」「email」「Email」混用,中文里「数据库」「资料库」难以统一。靠人工维护,很难保持一致。
下面介绍一个能同时解决这两个问题的方案。
整理需求
先明确我想实现什么:
- 按读者的语言显示标签
- 在一个地方统一管理
- 添加新标签时,不遗漏任何语言版本
在front matter中直接写标签名,可以满足第一个需求,但后两个就难了。文章越多,不一致的风险越大。
方案:用data/tags.yaml集中管理
最终我选择了这样做。
front matter只写英语slug:
# front matter(所有语言通用)
tags:
- testing
翻译放在data/tags.yaml,所有语言写在一起:
testing:
zh: 测试
en: Testing
ja: テスト
模板根据当前语言获取对应的显示名。
因为front matter在所有语言中完全相同,自然就不会出现不一致。翻译集中在一个文件里,有没有遗漏一目了然。
为什么用data/tags.yaml而不是i18n文件夹?
Hugo有标准的i18n功能,按语言分成多个文件:i18n/ja.yaml、i18n/en.yaml等等。
两种方式都需要修改模板。用i18n功能确实更「Hugo风格」一些。
但我选择了data/tags.yaml。
原因是可见性。
用i18n文件夹的话,每次添加标签都要编辑多个文件。想确认某个标签在其他语言里怎么翻译的,要逐个文件去找。
用data/tags.yaml,所有标签×所有语言都在一个文件里。添加、确认,全在一个地方完成。
还有一个好处:方便给AI提供上下文。让AI帮忙添加标签时,只需要传这一个文件。
实现
data/tags.yaml
创建标签主数据:
# data/tags.yaml
testing:
ja: テスト
en: Testing
zh: 测试
rails:
ja: Rails
en: Rails
zh: Rails
有些标签各语言写法相同,有些不同。无论哪种,结构都一样。
翻译用的partial
创建layouts/partials/tag-name.html:
{{- $tagKey := .tagKey | lower -}}
{{- $tagData := index site.Data.tags $tagKey -}}
{{- if not $tagData -}}
{{- errorf "Unknown tag '%s' - add to data/tags.yaml" $tagKey -}}
{{- end -}}
{{- $translated := index $tagData site.Language.Lang -}}
{{- if not $translated -}}
{{- errorf "Missing translation for tag '%s' (lang: %s)" $tagKey site.Language.Lang -}}
{{- end -}}
{{- $translated -}}
关键是errorf。标签未定义或翻译缺失时,构建会失败。问题立刻就能发现。
覆盖主题模板
在主题目录下用grep找到处理标签的文件:
grep -r "tags" themes/your-theme/layouts/
把相关文件复制到项目的layouts/目录下,保持相同的目录结构。Hugo会优先使用项目级的文件,主题本身不用改动。
在复制的文件中找到显示标签名的地方,替换成这个partial调用:
{{ partial "tag-name.html" (dict "tagKey" .) }}
不同主题的结构不同,但做法是一样的。
总结
front matter统一用英语slug,翻译用data/tags.yaml集中管理。多语言显示和命名统一,两个问题一起解决。
加上构建时的错误检测,翻译遗漏也能及时发现。
标准的i18n文件夹方式也可以,但对于标签来说,我觉得单文件方案更清晰,和AI配合也更顺畅。