mirror of
https://github.com/gohugoio/hugo.git
synced 2024-11-07 20:30:36 -05:00
tpl: Improve tests and docs for i18n
This commit is contained in:
parent
e7ff5c2d6a
commit
e7e2a1ca02
3 changed files with 99 additions and 68 deletions
|
@ -190,17 +190,16 @@ The rendering of the main navigation works as usual. `.Site.Menus` will just con
|
|||
|
||||
```
|
||||
|
||||
An empty string will be shown if the translation for the current language is missing and no default value is set.
|
||||
### Missing translations
|
||||
|
||||
While translating a Hugo website it can be handy to have a visual indicator as well. The `EnableMissingTranslationPlaceholders` config option allows you to replace the empty string with a placeholder like `[i18n] identifier`, where `identifier` is the id of the missing translation.
|
||||
If a string does not have a translation for the current language, Hugo will use the value from the default language. If no default value is set, an empty string will be shown.
|
||||
|
||||
While translating a Hugo site, it can be handy to have a visual indicator of missing translations. The `EnableMissingTranslationPlaceholders` config option will flag all untranslated strings with the placeholder `[i18n] identifier`, where `identifier` is the id of the missing translation.
|
||||
|
||||
**Remember: Hugo will generate your website with these placeholders. It might not be suited for production environments.**
|
||||
|
||||
|
||||
### Multilingual Themes support
|
||||
|
||||
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 `relLangURL` or `absLangURL` template funcs -- or prefixed with `{{.LanguagePrefix }}`.
|
||||
|
||||
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.
|
||||
|
||||
|
||||
|
|
|
@ -135,7 +135,7 @@ along with their current, default values:
|
|||
# Enable Emoji emoticons support for page content.
|
||||
# See www.emoji-cheat-sheet.com
|
||||
enableEmoji: false
|
||||
# Show a placeholder like "[i18n] foo" instead of an empty string if a translation is missing
|
||||
# Show a placeholder instead of the default value or an empty string if a translation is missing
|
||||
enableMissingTranslationPlaceholders: false
|
||||
footnoteAnchorPrefix: ""
|
||||
footnoteReturnLinkContents: ""
|
||||
|
|
|
@ -22,15 +22,94 @@ import (
|
|||
)
|
||||
|
||||
type test struct {
|
||||
file string
|
||||
content []byte
|
||||
data map[string][]byte
|
||||
args interface{}
|
||||
lang, id, expected, expected_flag string
|
||||
}
|
||||
|
||||
func doTestI18nTranslate(t *testing.T, data []test, lang, id string) string {
|
||||
var tests []test = []test{
|
||||
// All translations present
|
||||
{
|
||||
data: map[string][]byte{
|
||||
"en.yaml": []byte("- id: \"hello\"\n translation: \"Hello, World!\""),
|
||||
"es.yaml": []byte("- id: \"hello\"\n translation: \"¡Hola, Mundo!\""),
|
||||
},
|
||||
args: nil,
|
||||
lang: "es",
|
||||
id: "hello",
|
||||
expected: "¡Hola, Mundo!",
|
||||
expected_flag: "¡Hola, Mundo!",
|
||||
},
|
||||
// Translation missing in current language but present in default
|
||||
{
|
||||
data: map[string][]byte{
|
||||
"en.yaml": []byte("- id: \"hello\"\n translation: \"Hello, World!\""),
|
||||
"es.yaml": []byte("- id: \"goodbye\"\n translation: \"¡Adiós, Mundo!\""),
|
||||
},
|
||||
args: nil,
|
||||
lang: "es",
|
||||
id: "hello",
|
||||
expected: "Hello, World!",
|
||||
expected_flag: "[i18n] hello",
|
||||
},
|
||||
// Translation missing in default language but present in current
|
||||
{
|
||||
data: map[string][]byte{
|
||||
"en.yaml": []byte("- id: \"goodybe\"\n translation: \"Goodbye, World!\""),
|
||||
"es.yaml": []byte("- id: \"hello\"\n translation: \"¡Hola, Mundo!\""),
|
||||
},
|
||||
args: nil,
|
||||
lang: "es",
|
||||
id: "hello",
|
||||
expected: "¡Hola, Mundo!",
|
||||
expected_flag: "¡Hola, Mundo!",
|
||||
},
|
||||
// Translation missing in both default and current language
|
||||
{
|
||||
data: map[string][]byte{
|
||||
"en.yaml": []byte("- id: \"goodbye\"\n translation: \"Goodbye, World!\""),
|
||||
"es.yaml": []byte("- id: \"goodbye\"\n translation: \"¡Adiós, Mundo!\""),
|
||||
},
|
||||
args: nil,
|
||||
lang: "es",
|
||||
id: "hello",
|
||||
expected: "",
|
||||
expected_flag: "[i18n] hello",
|
||||
},
|
||||
// Default translation file missing or empty
|
||||
{
|
||||
data: map[string][]byte{
|
||||
"en.yaml": []byte(""),
|
||||
},
|
||||
args: nil,
|
||||
lang: "es",
|
||||
id: "hello",
|
||||
expected: "",
|
||||
expected_flag: "[i18n] hello",
|
||||
},
|
||||
// Context provided
|
||||
{
|
||||
data: map[string][]byte{
|
||||
"en.yaml": []byte("- id: \"wordCount\"\n translation: \"Hello, {{.WordCount}} people!\""),
|
||||
"es.yaml": []byte("- id: \"wordCount\"\n translation: \"¡Hola, {{.WordCount}} gente!\""),
|
||||
},
|
||||
args: struct {
|
||||
WordCount int
|
||||
}{
|
||||
50,
|
||||
},
|
||||
lang: "es",
|
||||
id: "wordCount",
|
||||
expected: "¡Hola, 50 gente!",
|
||||
expected_flag: "¡Hola, 50 gente!",
|
||||
},
|
||||
}
|
||||
|
||||
func doTestI18nTranslate(t *testing.T, data map[string][]byte, lang, id string, args interface{}) string {
|
||||
i18nBundle := bundle.New()
|
||||
|
||||
for _, r := range data {
|
||||
err := i18nBundle.ParseTranslationFileBytes(r.file, r.content)
|
||||
for file, content := range data {
|
||||
err := i18nBundle.ParseTranslationFileBytes(file, content)
|
||||
if err != nil {
|
||||
t.Errorf("Error parsing translation file: %s", err)
|
||||
}
|
||||
|
@ -39,7 +118,7 @@ func doTestI18nTranslate(t *testing.T, data []test, lang, id string) string {
|
|||
SetI18nTfuncs(i18nBundle)
|
||||
SetTranslateLang(lang)
|
||||
|
||||
translated, err := I18nTranslate(id, nil)
|
||||
translated, err := I18nTranslate(id, args)
|
||||
if err != nil {
|
||||
t.Errorf("Error translating '%s': %s", id, err)
|
||||
}
|
||||
|
@ -47,7 +126,6 @@ func doTestI18nTranslate(t *testing.T, data []test, lang, id string) string {
|
|||
}
|
||||
|
||||
func TestI18nTranslate(t *testing.T) {
|
||||
var data []test
|
||||
var actual, expected string
|
||||
|
||||
viper.SetDefault("DefaultContentLanguage", "en")
|
||||
|
@ -56,60 +134,14 @@ func TestI18nTranslate(t *testing.T) {
|
|||
for _, enablePlaceholders := range []bool{false, true} {
|
||||
viper.Set("EnableMissingTranslationPlaceholders", enablePlaceholders)
|
||||
|
||||
// All translations present
|
||||
data = []test{
|
||||
{"en.yaml", []byte("- id: \"hello\"\n translation: \"Hello, World!\"")},
|
||||
{"es.yaml", []byte("- id: \"hello\"\n translation: \"¡Hola, Mundo!\"")},
|
||||
}
|
||||
expected = "¡Hola, Mundo!"
|
||||
actual = doTestI18nTranslate(t, data, "es", "hello")
|
||||
assert.Equal(t, expected, actual)
|
||||
|
||||
// Translation missing in current language but present in default
|
||||
data = []test{
|
||||
{"en.yaml", []byte("- id: \"hello\"\n translation: \"Hello, World!\"")},
|
||||
{"es.yaml", []byte("- id: \"goodbye\"\n translation: \"¡Adiós, Mundo!\"")},
|
||||
}
|
||||
for _, test := range tests {
|
||||
if enablePlaceholders {
|
||||
expected = "[i18n] hello"
|
||||
expected = test.expected_flag
|
||||
} else {
|
||||
expected = "Hello, World!"
|
||||
}
|
||||
actual = doTestI18nTranslate(t, data, "es", "hello")
|
||||
assert.Equal(t, expected, actual)
|
||||
|
||||
// Translation missing in default language but present in current
|
||||
data = []test{
|
||||
{"en.yaml", []byte("- id: \"goodbye\"\n translation: \"Goodbye, World!\"")},
|
||||
{"es.yaml", []byte("- id: \"hello\"\n translation: \"¡Hola, Mundo!\"")},
|
||||
}
|
||||
expected = "¡Hola, Mundo!"
|
||||
actual = doTestI18nTranslate(t, data, "es", "hello")
|
||||
assert.Equal(t, expected, actual)
|
||||
|
||||
// Translation missing in both default and current language
|
||||
data = []test{
|
||||
{"en.yaml", []byte("- id: \"goodbye\"\n translation: \"Goodbye, World!\"")},
|
||||
{"es.yaml", []byte("- id: \"goodbye\"\n translation: \"¡Adiós, Mundo!\"")},
|
||||
}
|
||||
if enablePlaceholders {
|
||||
expected = "[i18n] hello"
|
||||
} else {
|
||||
expected = ""
|
||||
}
|
||||
actual = doTestI18nTranslate(t, data, "es", "hello")
|
||||
assert.Equal(t, expected, actual)
|
||||
|
||||
// Default translation file missing or empty
|
||||
data = []test{
|
||||
{"en.yaml", []byte("")},
|
||||
}
|
||||
actual = doTestI18nTranslate(t, data, "es", "hello")
|
||||
if enablePlaceholders {
|
||||
expected = "[i18n] hello"
|
||||
} else {
|
||||
expected = ""
|
||||
expected = test.expected
|
||||
}
|
||||
actual = doTestI18nTranslate(t, test.data, test.lang, test.id, test.args)
|
||||
assert.Equal(t, expected, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue