github.com/SDLMoe/hugo@v0.47.1/i18n/i18n.go (about) 1 // Copyright 2017 The Hugo Authors. All rights reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // http://www.apache.org/licenses/LICENSE-2.0 7 // 8 // Unless required by applicable law or agreed to in writing, software 9 // distributed under the License is distributed on an "AS IS" BASIS, 10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package i18n 15 16 import ( 17 "github.com/gohugoio/hugo/config" 18 "github.com/gohugoio/hugo/helpers" 19 "github.com/nicksnyder/go-i18n/i18n/bundle" 20 jww "github.com/spf13/jwalterweatherman" 21 ) 22 23 var ( 24 i18nWarningLogger = helpers.NewDistinctFeedbackLogger() 25 ) 26 27 // Translator handles i18n translations. 28 type Translator struct { 29 translateFuncs map[string]bundle.TranslateFunc 30 cfg config.Provider 31 logger *jww.Notepad 32 } 33 34 // NewTranslator creates a new Translator for the given language bundle and configuration. 35 func NewTranslator(b *bundle.Bundle, cfg config.Provider, logger *jww.Notepad) Translator { 36 t := Translator{cfg: cfg, logger: logger, translateFuncs: make(map[string]bundle.TranslateFunc)} 37 t.initFuncs(b) 38 return t 39 } 40 41 // Func gets the translate func for the given language, or for the default 42 // configured language if not found. 43 func (t Translator) Func(lang string) bundle.TranslateFunc { 44 if f, ok := t.translateFuncs[lang]; ok { 45 return f 46 } 47 t.logger.WARN.Printf("Translation func for language %v not found, use default.", lang) 48 if f, ok := t.translateFuncs[t.cfg.GetString("defaultContentLanguage")]; ok { 49 return f 50 } 51 t.logger.WARN.Println("i18n not initialized, check that you have language file (in i18n) that matches the site language or the default language.") 52 return func(translationID string, args ...interface{}) string { 53 return "" 54 } 55 56 } 57 58 func (t Translator) initFuncs(bndl *bundle.Bundle) { 59 defaultContentLanguage := t.cfg.GetString("defaultContentLanguage") 60 61 defaultT, err := bndl.Tfunc(defaultContentLanguage) 62 if err != nil { 63 jww.WARN.Printf("No translation bundle found for default language %q", defaultContentLanguage) 64 } 65 66 enableMissingTranslationPlaceholders := t.cfg.GetBool("enableMissingTranslationPlaceholders") 67 for _, lang := range bndl.LanguageTags() { 68 currentLang := lang 69 70 t.translateFuncs[currentLang] = func(translationID string, args ...interface{}) string { 71 tFunc, err := bndl.Tfunc(currentLang) 72 if err != nil { 73 jww.WARN.Printf("could not load translations for language %q (%s), will use default content language.\n", lang, err) 74 } 75 76 translated := tFunc(translationID, args...) 77 if translated != translationID { 78 return translated 79 } 80 // If there is no translation for translationID, 81 // then Tfunc returns translationID itself. 82 // But if user set same translationID and translation, we should check 83 // if it really untranslated: 84 if isIDTranslated(currentLang, translationID, bndl) { 85 return translated 86 } 87 88 if t.cfg.GetBool("logI18nWarnings") { 89 i18nWarningLogger.Printf("i18n|MISSING_TRANSLATION|%s|%s", currentLang, translationID) 90 } 91 if enableMissingTranslationPlaceholders { 92 return "[i18n] " + translationID 93 } 94 if defaultT != nil { 95 translated := defaultT(translationID, args...) 96 if translated != translationID { 97 return translated 98 } 99 if isIDTranslated(defaultContentLanguage, translationID, bndl) { 100 return translated 101 } 102 } 103 return "" 104 } 105 } 106 } 107 108 // If bndl contains the translationID for specified currentLang, 109 // then the translationID is actually translated. 110 func isIDTranslated(lang, id string, b *bundle.Bundle) bool { 111 _, contains := b.Translations()[lang][id] 112 return contains 113 }