多言語対応モード
Hugo は、複数の言語を並べて表示する Web サイトの作成をサポートしています。
利用可能な言語は、サイト設定の languages
セクションで定義する必要があります。
Hugo の多言語対応 パート1: コンテンツの翻訳 も参照してください。
言語を設定する
これは多言語プロジェクトのサイト設定の例です。languages
オブジェクトで定義されていないキーは、サイト設定のルートにあるグローバル値にフォールバックされます。
defaultContentLanguage
- (
string
) RFC 5646 で定義されているプロジェクトのデフォルトの言語タグです。小文字でなければならず、定義されている言語キーのいずれかにマッチする必要があります。デフォルトはen
です。 たとえば、以下になります。
en
en-gb
pt-br
defaultContentLanguageInSubdir
- (
bool
)true
の場合、デフォルトの言語サイトをdefaultContentLanguage
にマッチするサブディレクトリにレンダリングします。デフォルトはfalse
です。 contentDir
- (
string
) この言語のコンテンツ ディレクトリです。 ファイル名で翻訳する 場合は省略します。 disabled
- (
bool
)true
の場合、Hugo はこの言語のコンテンツをレンダリングしません。 デフォルトはfalse
です。 languageCode
- (
string
) RFC 5646 で定義されている言語タグです。この値には大文字や小文字、ハイフンやアンダースコアを含めることができ、ローカライズや URL には影響しません。Hugo はこの値を 組み込み RSS テンプレート のlanguage
要素と 組み込みエイリアス テンプレート のhtml
要素のlang
属性に使用します。たとえば、以下になります。
en
en-GB
pt-BR
languageDirection
- (
string
) 言語の方向です。左から右 (ltr
) または右から左 (rtl
) のどちらかになります。この値はグローバルなdir
HTML 属性を持つテンプレートで使用してください。 languageName
- (
string
) 言語名です。通常、言語スイッチャーをレンダリングするときに使用されます。 title
- (
string
) 言語のタイトルです。 設定すると、この言語のサイトタイトルが上書きされます。 weight
- (
int
) 言語の重みです。 0 以外の値に設定すると、これがこの言語の主な並べ替え基準になります。
Hugo 0.112.0 での変更点
Hugo v0.112.0
では、すべての設定オプションを統合し、言語とそのパラメータをメイン設定にマージする方法を改善しました。
しかし、これを Hugo サイトでテストしているときに、いくつかのエラー報告を受け取り、非推奨の警告を優先して、以下のように変更の一部を元に戻しました。
site.Language.Params
は非推奨です。直接、site.Params
を使用してください。- トップレベルの言語設定へのカスタム パラメータの追加は非推奨です。これらをすべて
[params]
の下に追加します。以下の例のcolor
を参照してください。
title = "My blog"
languageCode = "en-us"
[languages]
[languages.sv]
title = "Min blogg"
languageCode = "sv"
[languages.en.params]
color = "blue"
上記の例では、params
以下の color
以外のすべての設定は、Hugo のサイトとその言語に関する定義済みの設定オプションにマップされており、以下のような文書化されたアクセサを介してアクセスする必要があります。
{{ site.Title }}
{{ site.LanguageCode }}
{{ site.Params.color }}
言語を無効にする
サイト設定の languages
オブジェクト内の言語を無効にするには、以下のようにします。
サイト設定のルートで1つまたは複数の言語を無効にするには、以下のようにします。
環境変数を使用して 1 つ以上の言語を無効にするには、以下のようにします。
HUGO_DISABLELANGUAGES="es fr" hugo
デフォルトのコンテンツ言語を無効にすることはできないことに注意してください。
多言語対応マルチホストの設定
Hugo 0.31 以降、マルチホスト構成で複数の言語をサポートしています。 詳細については、「この Issue」 を参照してください。
つまり、language
ごとに baseURL
を設定できるようになったということです。
例:
上記により、2 つのサイトが独自のルートを持つ public
に生成されます。
public
├── en
└── fr
すべてのURL(つまり .Permalink
など)は、このルートから生成されます。つまり、上記の英語のホームページの .Permalink
は https://example.com/
に設定されることになります。
hugo server
を実行すると、複数の HTTP サーバが起動されます。通常、コンソールには以下のような表示が出力されます。
Web Server is available at 127.0.0.1:1313 (bind address 127.0.0.1)
Web Server is available at 127.0.0.1:1314 (bind address 127.0.0.1)
Press Ctrl+C to stop
サーバー間のライブリロードと --navigateToChanged
は期待通りに動作しています。
コンテンツを翻訳する
コンテンツの翻訳を管理するには、2 つの方法があります。 どちらも、各ページに言語が割り当てられ、対応する翻訳にリンクされていることを確認します。
ファイル名による翻訳
以下の例で考えてみます。
/content/about.en.md
/content/about.fr.md
最初のファイルには英語が割り当てられ、2 番目のファイルにリンクされています。 2 番目のファイルにはフランス語が割り当てられ、最初のファイルにリンクされています。
それぞれの言語は、ファイル名のサフィックス として付加される言語コードに従って 割り当てられます。
同じ パスとベース ファイル名 を 持つことで、コンテンツの断片は翻訳されたページとして一緒に リンク されます。
コンテンツディレクトリによる翻訳
このシステムでは、各言語ごとに異なるコンテンツディレクトリを使用します。各言語のコンテンツディレクトリは contentDir
パラメータで設定します。
contentDir
の値には、任意の有効なパス (絶対パス参照も含む) を指定することができます。唯一の制限は、コンテンツディレクトリは重複できないことです。
上記の設定と合わせて、以下の例を考えてみます。
/content/english/about.md
/content/french/about.md
最初のファイルには英語が割り当てられ、2 番目のファイルにリンクされています。 2 番目のファイルにはフランス語が割り当てられ、最初のファイルにリンクされています。
それらの言語は、配置されている コンテンツディレクトリに従って 割り当てられます。
同じ パスとベース名 (言語コンテンツ ディレクトリからの相対パス) を持つことで、コンテンツの断片は翻訳されたページとして一緒に リンク されます。
デフォルトのリンクを回避する
フロントマターに設定された translationKey
を共有するすべてのページは、ベース名や場所に関係なく、翻訳されたページとしてリンクされます。
以下の例で考えてみます。
/content/about-us.en.md
/content/om.nn.md
/content/presentation/a-propos.fr.md
3 つのページで translationKey
フロントマター パラメータを about
に設定することで、翻訳されたページとして リンクされます。
パーマリンクのローカライズ
パスとファイル名はリンクの処理に使用されるため、翻訳されたすべてのページは (言語サブディレクトリを除いて) 同じ URL を共有します。
URL をローカライズするには、以下のようにします。
たとえば、フランス語の翻訳は、独自のローカライズされたスラグを持つことができます。
レンダリング時に、Hugo は /about/
と /fr/a-propos/
の翻訳リンクを維持したまま、両方をビルドします。
ページバンドル
ファイルの重複を避けるため、各ページバンドルは、コンテンツファイル (Markdown ファイル、HTML ファイルなど) を除き、リンク先の翻訳ページバンドルのリソースを継承します。
したがって、テンプレート内から、ページはリンクされたすべてのページのバンドルからファイルにアクセスできるようになります。
リンクされたバンドル全体で、2つ以上のファイルが同じベースネームを共有している場合、1 つのファイルだけが含まれ、以下のように選択されます。
- 現在の言語バンドルのファイル (存在する場合)。
- バンドル間で、言語
Weight
の順番で最初に見つかったファイル。
image.jpg
、image.fr.jpg
) とディレクトリ (english/about/header.jpg
、french/about/header.jpg
) によって、コンテンツファイルと同じ言語割り当てロジックに従います。
翻訳されたコンテンツを参照する
翻訳コンテンツへのリンク集を作成する場合は、以下のようなテンプレートを使用します。
{{ if .IsTranslated }}
<h4>{{ i18n "translations" }}</h4>
<ul>
{{ range .Translations }}
<li>
<a href="{{ .Permalink }}">{{ .Lang }}: {{ .Title }}{{ if .IsPage }} ({{ i18n "wordCount" . }}){{ end }}</a>
</li>
{{ end }}
</ul>
{{ end }}
上記は partial
(つまり、layouts/partials/
内) に配置でき、単一のコンテンツページ
または ホームページ
のいずれのテンプレートにも含めることができます。 指定されたページに翻訳がない場合、何も出力されません。
上記では、次のセクションで説明する i18n
関数
も使用します。
利用可能なすべての言語を一覧表示する
Page
の .AllTranslations
を使用して、ページ自体を含むすべての翻訳を一覧表示できます。 ホームページでは、言語ナビゲーターを構築するために使用できます。
<ul>
{{ range $.Site.Home.AllTranslations }}
<li><a href="{{ .Permalink }}">{{ .Language.LanguageName }}</a></li>
{{ end }}
</ul>
文字列の翻訳
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
変数を使用して柔軟な翻訳をクエリする
多くの場合、翻訳文字列でページ変数を使用したいと思うでしょう。 そのためには、i18n
を呼び出すときに、以下のように .
コンテキストを渡します。
{{ i18n "wordCount" . }}
この関数は .
コンテキストを "wordCount"
id に渡します。
コンテキストの .WordCount
の値が 101 であると仮定します。結果は以下のようになります。
This article has 101 words.
単数形/複数形の翻訳をクエリする
その他、単数/複数の要件を満たすには、 .Count
という数値プロパティを持つ辞書 (マップ) を i18n
関数に渡す必要があります。 以下の例では、組み込みの .Count
プロパティを持つ .ReadingTime
変数を使用しています。
{{ i18n "readingTime" .ReadingTime }}
この関数は .ReadingTime
から .Count
を読み込み、その数が単数 (one
) か複数 (other
) かを判断します。その後、i18n/en-US.toml
ファイルにある readingTime
の id を渡します。
コンテキストの .ReadingTime.Count
の値が 525600 であると仮定すると、結果は以下のようになります。
525600 minutes to read
コンテキストの .ReadingTime.Count
の値が 1 の場合、結果は以下のようになります。
One minute to read
カスタムデータを渡す必要がある場合: ((dict "Count" numeric_value_only)
が最低限必要)
{{ i18n "readingTime" (dict "Count" 25 "FirstArgument" true "SecondArgument" false "Etc" "so on, so far") }}
ローカライズ
以下のローカライズの例では、サイトの主要言語を英語とし、フランス語とドイツ語への翻訳を想定しています。
日付
以下のフロントマター
および、以下のテンプレート コード
{{ .Date | time.Format ":date_full" }}
で、以下のレンダリングされたページが表示されます。
Language | Value |
---|---|
English | Wednesday, November 3, 2021 |
Français | mercredi 3 novembre 2021 |
Deutsch | Mittwoch, 3. November 2021 |
詳細については、time.Format を参照してください。
通貨
以下のテンプレート コード
{{ 512.5032 | lang.FormatCurrency 2 "USD" }}
で、以下のレンダリングされたページが表示されます。
Language | Value |
---|---|
English | $512.50 |
Français | 512,50 $US |
Deutsch | 512,50 $ |
詳細については、lang.FormatCurrency と lang.FormatAccounting を参照してください。
数値
以下のテンプレート コード
{{ 512.5032 | lang.FormatNumber 2 }}
で、以下のレンダリングされたページが表示されます。
Language | Value |
---|---|
English | 512.50 |
Français | 512,50 |
Deutsch | 512,50 |
詳細については、lang.FormatNumber と lang.FormatNumberCustom を参照してください。
パーセント
以下のテンプレート コード
{{ 512.5032 | lang.FormatPercent 2 }} ---> 512.50%
で、以下のレンダリングされたページが表示されます。
Language | Value |
---|---|
English | 512.50% |
Français | 512,50 % |
Deutsch | 512,50 % |
詳細については、lang.FormatPercent を参照してください。
メニュー
メニューエントリのローカライズは、以下のように、それをどのように定義するかによって決まります。
- セクションページ メニューを使用してメニューエントリを 自動的に 定義する場合は、翻訳テーブルを使用して各エントリをローカライズする必要があります。
- メニューエントリを フロントマターで 定義した場合、それらはすでにフロントマターそのものに基づいてローカライズされています。フロントマターの値が不十分な場合は、翻訳テーブルを使って各エントリをローカライズしてください。
- メニューエントリを サイト設定で 定義するとき、(a) 翻訳テーブルを使うか、(b) 各言語キーの下に言語固有のメニューエントリを作成できます。
翻訳テーブルを使用する
メニューの各エントリに表示されるテキストをレンダリングするとき、メニュー テンプレートの例 は以下のことを行います。
{{ or (T .Identifier) .Name | safeHTML }}
メニューエントリの identifier
を使って現在の言語の翻訳テーブルに問い合わせ、翻訳された文字列を返します。
翻訳テーブルが存在しない場合、または identifier
キーが翻訳テーブルに存在しない場合、name
にフォールバックします。
identifier
は、メニューエントリをどのように定義するかによって、以下のように異なります。
- セクションページ メニューを使用してメニューエントリを 自動的に
定義する場合、
identifier
はページの.Section
になります。 - サイト設定で
または フロントマターで
メニューエントリを定義する場合は、
identifier
プロパティを目的の値に設定します。
たとえば、サイト設定でメニューエントリを定義すると、以下のようになります。
以下のように、翻訳テーブルに対応するエントリを作成します。
言語固有のメニューエントリを作成する
たとえば、以下のようにします。
2 つの言語を使用したシンプルなメニューの場合、これらのメニューエントリの作成と管理は簡単です。 より大きなメニューの場合、または 3 つ以上の言語を使用する場合は、上記のような翻訳テーブルを使用することをお勧めします。
不足している翻訳
文字列に現在の言語の翻訳がない場合、Hugo はデフォルト言語の値を使用します。 デフォルト値が設定されていない場合、空文字列が表示されます。
Hugo の Web サイトを翻訳しているとき、翻訳の欠落箇所を視覚的に確認できると便利です。設定オプションの enableMissingTranslationPlaceholders
は、すべての未翻訳の文字列に [i18n] identifier
というプレースホルダーを付けてフラグを立てます (ここで identifier
は未翻訳部分の ID です。
他の言語からのコンテンツのマージ (つまり、コンテンツの翻訳がない場合) については、lang.Merge を参照してください。
不足している翻訳文字列を追跡するには、以下のように、Hugo を --printI18nWarnings
フラグ付きで実行してください。
hugo --printI18nWarnings | grep i18n
i18n|MISSING_TRANSLATION|en|wordCount
多言語テーマへの対応
テーマで多言語モードをサポートするためには、テンプレート内の URL について、いくつかの配慮が必要です。複数の言語が存在する場合、URL は以下の条件を満たす必要があります。
- 組み込みの
.Permalink
または.RelPermalink
から来ること relLangURL
テンプレート関数 またはabsLangURL
テンプレート関数 で構築されること または{{ .LanguagePrefix }}
をプレフィックスとして持つこと
複数の言語が定義されている場合、LanguagePrefix
変数は /en
(または、どのような値でも CurrentLanguage
) と等しくなります。 有効にしない場合、空文字列になります (したがって、単一言語の Hugo Web サイトには無害です)。
hugo new
で多言語コンテンツを生成する
翻訳を含むコンテンツを同じディレクトリに整理する場合は、以下のコマンドを実行します。
hugo new post/test.en.md
hugo new post/test.de.md
翻訳を含むコンテンツを異なるディレクトリに整理する場合は、以下のコマンドを実行します。
hugo new content/en/post/test.md
hugo new content/de/post/test.md