字符串的翻译
Hugo使用go-i18n来支持字符串翻译。查看项目的源代码库以找到能帮助你管理翻译工作流程的工具。
翻译内容被收集自themes/<THEME>/i18n/文件夹(内置在主题中),以及位于项目根目录下的i18n/中的翻译内容。在i18n中,翻译将会被合并,并优先于主题文件夹中的内容。语言文件应根据RFC 5646的规定进行命名,例如en-US.toml,fr.toml等。
还支持使用RFC 5646 § 2.2.7中定义的带有私有使用子标记的人造语言。您可以省略art-x-前缀以简洁起见。例如:
art-x-hugolang
hugolang
私有使用子标记必须不超过8个字母数字字符。
查询基本翻译
在模板中使用i18n函数如下所示:
{{ i18n "home" }}
该函数将搜索"home"的id:
home:
  other: 主页
[home]
  other = '主页'
{
   "home": {
      "other": "主页"
   }
}
结果将会是
主页
查询带有变量的灵活翻译
通常,您希望在翻译字符串中使用页面变量。为此,在调用i18n时通过传递.上下文:
{{ i18n "wordCount" . }}
该函数将会将.上下文传递给"wordCount"的id:
wordCount:
  other: 本文章有{{ .WordCount }}个单词。
[wordCount]
  other = '本文章有{{ .WordCount }}个单词。'
{
   "wordCount": {
      "other": "本文章有{{ .WordCount }}个单词。"
   }
}
假设上下文中的.WordCount的值为101。结果将会是:
本文章有101个单词。
查询单数/复数翻译
为了在翻译时启用复数形式,可以将带有一个数值.Count属性的映射传递给i18n函数。下面的示例使用了内置的.ReadingTime变量,该变量具有.Count属性。
{{ i18n "readingTime" .ReadingTime }}
该函数将从.ReadingTime中读取.Count并确定该数字是单数(one)还是复数(other)。然后,它将传递给i18n/en-US.toml文件中的readingTime id:
readingTime:
  one: 阅读需要一分钟
  other: 阅读需要{{ .Count }}分钟
[readingTime]
  one = '阅读需要一分钟'
  other = '阅读需要{{ .Count }}分钟'
{
   "readingTime": {
      "one": "阅读需要一分钟",
      "other": "阅读需要{{ .Count }}分钟"
   }
}
假设上下文中的.ReadingTime.Count的值是525600。结果将会是:
阅读需要525600分钟
如果上下文中的.ReadingTime.Count的值是1。结果将会是:
阅读需要一分钟
如果您需要传递自定义数据:((dict "Count" numeric_value_only)是最小要求)
{{ i18n "readingTime" (dict "Count" 25 "FirstArgument" true "SecondArgument" false "Etc" "so on, so far") }}
本地化
以下本地化示例假定您网站的主要语言是英语,并提供了法语和德语的翻译。
defaultContentLanguage: en
languages:
  de:
    contentDir: content/de
    languageName: Deutsch
    weight: 3
  en:
    contentDir: content/en
    languageName: English
    weight: 1
  fr:
    contentDir: content/fr
    languageName: Français
    weight: 2
defaultContentLanguage = 'en'
[languages]
  [languages.de]
    contentDir = 'content/de'
    languageName = 'Deutsch'
    weight = 3
  [languages.en]
    contentDir = 'content/en'
    languageName = 'English'
    weight = 1
  [languages.fr]
    contentDir = 'content/fr'
    languageName = 'Français'
    weight = 2
{
   "defaultContentLanguage": "en",
   "languages": {
      "de": {
         "contentDir": "content/de",
         "languageName": "Deutsch",
         "weight": 3
      },
      "en": {
         "contentDir": "content/en",
         "languageName": "English",
         "weight": 1
      },
      "fr": {
         "contentDir": "content/fr",
         "languageName": "Français",
         "weight": 2
      }
   }
}
日期
在具有以下前置信息的情况下:
date: 2021-11-03T12:34:56+01:00
date = 2021-11-03T12:34:56+01:00
{
   "date": "2021-11-03T12:34:56+01:00"
}
以及以下模板代码:
{{ .Date | time.Format ":date_full" }}
渲染的页面显示为:
| 语言 | 数值 | 
|---|---|
| English | Wednesday, November 3, 2021 | 
| Français | mercredi 3 novembre 2021 | 
| Deutsch | Mittwoch, 3. November 2021 | 
有关详细信息,请参阅time.Format。
货币
使用以下模板代码:
{{ 512.5032 | lang.FormatCurrency 2 "USD" }}
渲染的页面显示为:
| 语言 | 数值 | 
|---|---|
| English | $512.50 | 
| Français | 512,50 $US | 
| Deutsch | 512,50 $ | 
有关详细信息,请参阅lang.FormatCurrency和lang.FormatAccounting。
数字
使用以下模板代码:
{{ 512.5032 | lang.FormatNumber 2 }}
渲染的页面显示为:
| 语言 | 数值 | 
|---|---|
| English | 512.50 | 
| Français | 512,50 | 
| Deutsch | 512,50 | 
有关详细信息,请参阅lang.FormatNumber和lang.FormatNumberCustom。
百分比
使用以下模板代码:
{{ 512.5032 | lang.FormatPercent 2 }}
渲染的页面显示为:
| 语言 | 数值 | 
|---|---|
| English | 512.50% | 
| Français | 512,50 % | 
| Deutsch | 512,50 % | 
有关详细信息,请参阅lang.FormatPercent。
菜单
菜单项的本地化取决于您如何定义它们:
- 当您使用页面菜单自动定义菜单项时,您必须使用翻译表来本地化每个菜单项。
- 当您在前置信息中定义菜单项时,它们已根据前置信息本地化。如果前置信息的值不足够,使用翻译表来本地化每个菜单项。
- 当您在站点配置中定义菜单项时,您必须在每个语言键下创建特定于语言的菜单项。如果菜单项的名称不足够,使用翻译表来本地化每个菜单项。
创建特定于语言的菜单项
方法1-使用单个配置文件
对于只有少量菜单项的简单菜单,可以使用单个配置文件。例如:
languages:
  de:
    languageCode: de-DE
    languageName: Deutsch
    menu:
      main:
      - name: Produkte
        pageRef: /products
        weight: 10
      - name: Leistungen
        pageRef: /services
        weight: 20
    weight: 1
  en:
    languageCode: en-US
    languageName: English
    menu:
      main:
      - name: Products
        pageRef: /products
        weight: 10
      - name: Services
        pageRef: /services
        weight: 20
    weight: 2
[languages]
  [languages.de]
    languageCode = 'de-DE'
    languageName = 'Deutsch'
    weight = 1
    [languages.de.menu]
[[languages.de.menu.main]]
        name = 'Produkte'
        pageRef = '/products'
        weight = 10
[[languages.de.menu.main]]
        name = 'Leistungen'
        pageRef = '/services'
        weight = 20
  [languages.en]
    languageCode = 'en-US'
    languageName = 'English'
    weight = 2
    [languages.en.menu]
[[languages.en.menu.main]]
        name = 'Products'
        pageRef = '/products'
        weight = 10
[[languages.en.menu.main]]
        name = 'Services'
        pageRef = '/services'
        weight = 20
{
   "languages": {
      "de": {
         "languageCode": "de-DE",
         "languageName": "Deutsch",
         "menu": {
            "main": [
               {
                  "name": "Produkte",
                  "pageRef": "/products",
                  "weight": 10
               },
               {
                  "name": "Leistungen",
                  "pageRef": "/services",
                  "weight": 20
               }
            ]
         },
         "weight": 1
      },
      "en": {
         "languageCode": "en-US",
         "languageName": "English",
         "menu": {
            "main": [
               {
                  "name": "Products",
                  "pageRef": "/products",
                  "weight": 10
               },
               {
                  "name": "Services",
                  "pageRef": "/services",
                  "weight": 20
               }
            ]
         },
         "weight": 2
      }
   }
}
方法2-使用配置目录
对于更复杂的菜单结构,请创建一个配置目录并将菜单项拆分为多个文件,每个语言一个文件。例如:
config/
└── _default/
    ├── menus/
    │  ├── menu.de.toml
    │  └── menu.en.toml
    └── hugo.toml
使用翻译表
当渲染菜单项的文本时,示例菜单模板执行以下操作:
{{ or (T .Identifier) .Name | safeHTML }}
它使用当前语言查询翻译表中的菜单项的identifier,并返回翻译后的字符串。如果翻译表不存在,或者在翻译表中identifier键不存在,则会回退到name。
identifier的定义取决于您如何定义菜单项:
- 如果您使用页面菜单自动定义菜单项,则identifier是页面的.Section。
- 如果您使用站点配置或前置信息定义菜单项,请将identifier属性设置为所需的值。
例如,如果您在站点配置中定义菜单项:
menu:
  main:
  - identifier: products
    name: Products
    pageRef: /products
    weight: 10
  - identifier: services
    name: Services
    pageRef: /services
    weight: 20
[menu]
[[menu.main]]
    identifier = 'products'
    name = 'Products'
    pageRef = '/products'
    weight = 10
[[menu.main]]
    identifier = 'services'
    name = 'Services'
    pageRef = '/services'
    weight = 20
{
   "menu": {
      "main": [
         {
            "identifier": "products",
            "name": "Products",
            "pageRef": "/products",
            "weight": 10
         },
         {
            "identifier": "services",
            "name": "Services",
            "pageRef": "/services",
            "weight": 20
         }
      ]
   }
}
则在翻译表中创建相应的条目:
products: Produkte
services: Leistungen
products = 'Produkte'
services = 'Leistungen'
{
   "products": "Produkte",
   "services": "Leistungen"
}
缺失的翻译
如果当前语言没有某个字符串的翻译,Hugo将使用默认语言的值。如果没有设置默认值,则显示为空字符串。
在翻译Hugo网站时,有一个视觉指示缺失翻译的工具可能很方便。enableMissingTranslationPlaceholders配置选项将用占位符[i18n] identifier标记所有未翻译的字符串,其中identifier是缺失的翻译的id。
要追踪缺失的翻译字符串,请使用--printI18nWarnings标志运行Hugo:
hugo --printI18nWarnings | grep i18n
i18n|MISSING_TRANSLATION|en|wordCount
多语言主题支持
要支持主题的多语言模式,需要考虑模板中的URL。如果有多个语言,URL必须满足以下条件:
- 来自内置的.Permalink或.RelPermalink
- 通过relLangURL或absLangURL模板函数构建,或者以{{ .LanguagePrefix }}为前缀
如果定义了多个语言,LanguagePrefix变量将等于/en(或您的CurrentLanguage值)。如果未启用,它将为空字符串(因此对于单语言的Hugo网站没有影响)。
使用hugo new content生成多语言内容 
如果您将带翻译的内容组织在同一个目录中:
hugo new content post/test.en.md
hugo new content post/test.de.md
如果您将带翻译的内容组织在不同的目录中:
hugo new content content/en/post/test.md
hugo new content content/de/post/test.md