diff options
author | Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com> | 2016-08-04 12:06:29 +0200 |
---|---|---|
committer | Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com> | 2016-09-06 18:32:17 +0300 |
commit | f0b91852ea5e5d3ec985286751f17e34bfc6c7bc (patch) | |
tree | 78f4df9fbb03b836638a138cf49dd18992fdd461 | |
parent | ed0985404db4630d1b9d3ad0b7e41fb186ae0112 (diff) |
Rework the multilingual docs
And in the same go adjusted some minor parts of the language API:
Add LanguagePrefix alias to Node and rename the Multilingual config section to Languages.
See #2309
-rw-r--r-- | commands/multilingual.go | 2 | ||||
-rw-r--r-- | docs/content/content/multilingual.md | 197 | ||||
-rw-r--r-- | hugolib/hugo_sites_test.go | 4 | ||||
-rw-r--r-- | hugolib/node.go | 4 | ||||
-rw-r--r-- | hugolib/site.go | 2 |
5 files changed, 46 insertions, 163 deletions
diff --git a/commands/multilingual.go b/commands/multilingual.go index 4d0f6e107..16f392acc 100644 --- a/commands/multilingual.go +++ b/commands/multilingual.go @@ -13,7 +13,7 @@ import ( func readMultilingualConfiguration() (*hugolib.HugoSites, error) { sites := make([]*hugolib.Site, 0) - multilingual := viper.GetStringMap("Multilingual") + multilingual := viper.GetStringMap("Languages") if len(multilingual) == 0 { // TODO(bep) multilingo langConfigsList = append(langConfigsList, hugolib.NewLanguage("en")) sites = append(sites, hugolib.NewSite(hugolib.NewLanguage("en"))) diff --git a/docs/content/content/multilingual.md b/docs/content/content/multilingual.md index 8edc6a600..bfcd6c08a 100644 --- a/docs/content/content/multilingual.md +++ b/docs/content/content/multilingual.md @@ -9,13 +9,12 @@ title: Multilingual Mode weight: 68 toc: true --- +Hugo supports multiple languages side-by-side (added in `Hugo 0.17`). Define the available languages in a `Languages` section in your top-level `config.yaml` (or equivalent). -Since version 0.17, Hugo supports a native Multilingual mode. In your -top-level `config.yaml` (or equivalent), you define the available -languages in a `Multilingual` section such as: +Example: ``` -Multilingual: +Languages: en: weight: 1 title: "My blog" @@ -23,7 +22,6 @@ Multilingual: linkedin: "english-link" fr: weight: 2 - title: "Mon blog" params: linkedin: "lien-francais" @@ -33,21 +31,16 @@ copyright: "Everything is mine" ``` Anything not defined in a `[lang]:` block will fall back to the global -value for that key (like `copyright` for the `en` lang in this -example). +value for that key (like `copyright` for the English (`en`) language in this example). With the config above, all content, sitemap, RSS feeds, paginations -and taxonomy pages will be rendered under `/en` in English, and under -`/fr` in French. - -Only those keys are read under `Multilingual`: `weight`, `title`, -`author`, `social`, `languageCode`, `copyright`, `disqusShortname`, -`params` (which can contain a map of several other keys). +and taxonomy pages will be rendered below `/en` in English, and below `/fr` in French. +Only the obvious non-global options can be overridden per language. Examples of global options are `BaseURL`, `BuildDrafts`, etc. ### Translating your content -Translated articles are picked up by the name of the content files. +Translated articles are identified by the name of the content file. Example of translated articles: @@ -59,180 +52,66 @@ You can also have: 1. `/content/about.md` 2. `/content/about.fr.md` -in which case the config variable `DefaultContentLanguage` will be -used to affect the default language `about.md`. This way, you can -slowly start to translate your current content without having to -rename everything. - -If left unspecified, the value for `DefaultContentLanguage` defaults -to `en`. - -By having the same _base file name_, the content pieces are linked -together as translated pieces. Only the content pieces in the language -defined by **.Site.CurrentLanguage** will be rendered in a run of -`hugo`. The translated content will be available in the -`.Page.Translations` so you can create links to the corresponding -translated pieces. +In which case the config variable `DefaultContentLanguage` will be used to affect the default language `about.md`. This way, you can +slowly start to translate your current content without having to rename everything. +If left unspecified, the value for `DefaultContentLanguage` defaults to `en`. -### Language switching links +By having the same _base file name_, the content pieces are linked together as translated pieces. -Here is a simple example if all your pages are translated: +### Link to translated content -``` -{{if .IsPage}} - {{ range $txLang := .Site.Languages }} - {{if isset $.Translations $txLang}} - <a href="{{ (index $.Translations $txLang).Permalink }}">{{ i18n ( printf "language_switcher_%s" $txLang ) }}</a> - {{end}} - {{end}} -{{end}} - -{{if .IsNode}} - {{ range $txLang := .Site.Languages }} - <a href="/{{$txLang}}">{{ i18n ( printf "language_switcher_%s" $txLang ) }}</a> - {{end}} -{{end}} -``` - -This is a more complete example. It handles missing translations and will support non-multilingual sites. Better for theme authors: +To create a list of links to translated content, use a template similar to this: ``` -{{if .Site.Multilingual}} - {{if .IsPage}} - {{ range $txLang := .Site.Languages }} - {{if isset $.Translations $txLang}} - <a href="{{ (index $.Translations $txLang).Permalink }}">{{ i18n ( printf "language_switcher_%s" $txLang ) }}</a> - {{else}} - <a href="/{{$txLang}}">{{ i18n ( printf "language_switcher_%s" $txLang ) }}</a> - {{end}} - {{end}} - {{end}} - - {{if .IsNode}} - {{ range $txLang := .Site.Languages }} - <a href="/{{$txLang}}">{{ i18n ( printf "language_switcher_%s" $txLang ) }}</a> - {{end}} - {{end}} -{{end}} +{{ $translations := .Translations }} +{{ if gt (len $translations) 0 }} +<h4>{{ i18n "translations" }}</h4> +<ul> + {{ range $translations }} + <li> + <a href="{{ .Permalink }}">{{ .Lang }}: {{ .Title }}</a> + </li> + {{ end}} +</ul> +{{ end }} ``` +The above can be put in a `partial` and included in any template, be it for a content page or the home page. It will not print anything if there are no translations for a given page, or if it is -- in the case of the home page, section listing etc. -- a site with only one language. -This makes use of the **.Site.Languages** variable to create links to -the other available languages. The order in which the languages are -listed is defined by the `weight` attribute in each language under -`Multilingual`. - -This will also require you to have some content in your `i18n/` files -(see below) that would look like: - -``` -- id: language_switcher_en - translation: "English" -- id: language_switcher_fr - translation: "Français" -``` - -and a copy of this in translations for each language. - -As you might notice, node pages link to the root of the other -available translations (`/en`), as those pages do not necessarily have -a translated counterpart. - -Taxonomies (tags, categories) are completely segregated between -translations and will have their own tag clouds and list views. - +The above also uses the `i8n` func, see [Translation of strings](#translation-of-strings). ### Translation of strings -Hugo uses [go-i18n](https://github.com/nicksnyder/go-i18n) to support -string translations. Follow the link to find tools to manage your -translation workflows. +Hugo uses [go-i18n](https://github.com/nicksnyder/go-i18n) to support string translations. Follow the link to find tools to manage your translation workflows. -Translations are collected from the `themes/[name]/i18n/` folder -(built into the theme), as well as translations present in `i18n/` at -the root of your project. In the `i18n`, the translations will be -merged and take precedence over what is in the theme folder. Files in -there follow RFC 5646 and should be named something like `en-US.yaml`, -`fr.yaml`, etc.. +Translations are collected from the `themes/[name]/i18n/` folder (built into the theme), as well as translations present in `i18n/` at the root of your project. In the `i18n`, the translations will be merged and take precedence over what is in the theme folder. Language files should be named according to RFC 5646 with names such as `en-US.yaml`, `fr.yaml`, etc. -From within your templates, use the `i18n` function as such: +From within your templates, use the `i18n` function like this: ``` {{ i18n "home" }} ``` - -to use a definition like this one in `i18n/en-US.yaml`: - +This uses a definition like this one in `i18n/en-US.yaml`: ``` - id: home translation: "Home" ``` - -### Multilingual Themes support - -To support Multilingual mode in your themes, you only need to make -sure URLs defined manually (those not using `.Permalink` or `.URL` -variables) in your templates are prefixed with `{{ -.Site.LanguagePrefix }}`. If `Multilingual` mode is enabled, the -`LanguagePrefix` variable will equal `"/en"` (or whatever your -`CurrentLanguage` is). If not enabled, it will be an empty string, so -it is harmless for non-multilingual sites. - - -### Multilingual index.html and 404.html - -To redirect your users to their closest language, drop an `index.html` -in `/static` of your site, with the following content (tailored to -your needs) to redirect based on their browser's language: +Often you will want to use to the page variables in the translations strings. To do that, pass on the "." context when calling `18n`: ``` -<html><head> -<meta http-equiv="refresh" content="1;url=/en" /><!-- just in case JS doesn't work --> -<script> -lang = window.navigator.language.substr(0, 2); -if (lang == "fr") { - window.location = "/fr"; -} else { - window.location = "/en"; -} - -/* or simply: -window.location = "/en"; -*/ -</script></head><body></body></html> +{{ i18n "wordCount" . }} ``` - -An even simpler version will always redirect your users to a given language: - +This uses a definition like this one in `i18n/en-US.yaml`: ``` -<html><head> -<meta http-equiv="refresh" content="0;url=/en" /> -</head><body></body></html> +- id: wordCount + translation: "This article has {{ .WordCount }} words." ``` -You can do something similar with your `404.html` page, as you don't -know the language of someone arriving at a non-existing page. You -could inspect the prefix of the navigator path in Javascript or use -the browser's language detection like above. - +### Multilingual Themes support -### Sitemaps +To support Multilingual mode in your themes, some considerations must be taken for the URLs in the templates. If there are more than one language, URLs must either come from the built-in `.Permalink` or `.URL`, be constructed with `relURL` or `absURL` -- or prefixed with `{{.LanguagePrefix }}`. -As sitemaps are generated once per language and live in -`[lang]/sitemap.xml`. Write this content in `static/sitemap.xml` to -link all your sitemaps together: +If there are more than one language defined, the`LanguagePrefix` variable will equal `"/en"` (or whatever your `CurrentLanguage` is). If not enabled, it will be an empty string, so it is harmless for single-language sites. -``` -<?xml version="1.0" encoding="UTF-8"?> -<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"> - <sitemap> - <loc>https://example.com/en/sitemap.xml</loc> - </sitemap> - <sitemap> - <loc>https://example.com/fr/sitemap.xml</loc> - </sitemap> -</sitemapindex> -``` -and explicitly list all the languages you want referenced. diff --git a/hugolib/hugo_sites_test.go b/hugolib/hugo_sites_test.go index b63792a3b..aa8575075 100644 --- a/hugolib/hugo_sites_test.go +++ b/hugolib/hugo_sites_test.go @@ -48,7 +48,7 @@ func testCommonResetState() { } -func _TestMultiSites(t *testing.T) { +func TestMultiSites(t *testing.T) { sites := createMultiTestSites(t) @@ -65,7 +65,7 @@ func _TestMultiSites(t *testing.T) { if len(enSite.Pages) != 3 { t.Fatal("Expected 3 english pages") } - assert.Len(t, enSite.Source.Files(), 6, "should have 6 source files") + assert.Len(t, enSite.Source.Files(), 11, "should have 11 source files") assert.Len(t, enSite.AllPages, 6, "should have 6 total pages (including translations)") doc1en := enSite.Pages[0] diff --git a/hugolib/node.go b/hugolib/node.go index 3983a5192..2d07e426b 100644 --- a/hugolib/node.go +++ b/hugolib/node.go @@ -201,6 +201,10 @@ func (n *Node) Lang() string { return n.lang } +func (n *Node) LanguagePrefix() string { + return n.Site.LanguagePrefix +} + // AllTranslations returns all translations, including the current Node. // Note that this and the one below is kind of a temporary hack before #2297 is solved. func (n *Node) AllTranslations() Nodes { diff --git a/hugolib/site.go b/hugolib/site.go index 03e697130..cce78f14d 100644 --- a/hugolib/site.go +++ b/hugolib/site.go @@ -866,7 +866,7 @@ func (s *Site) initializeSiteInfo() { CurrentLanguage: lang.Lang, LanguagePrefix: languagePrefix, Languages: languages, - GoogleAnalytics: viper.GetString("GoogleAnalytics"), + GoogleAnalytics: lang.GetString("GoogleAnalytics"), RSSLink: permalinkStr(viper.GetString("RSSUri")), BuildDrafts: viper.GetBool("BuildDrafts"), canonifyURLs: viper.GetBool("CanonifyURLs"), |