github.com/graemephi/kahugo@v0.62.3-0.20211121071557-d78c0423784d/langs/i18n/translationProvider.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 "encoding/json" 18 "strings" 19 20 "github.com/gohugoio/hugo/common/paths" 21 22 "github.com/gohugoio/hugo/common/herrors" 23 "golang.org/x/text/language" 24 yaml "gopkg.in/yaml.v2" 25 26 "github.com/gohugoio/go-i18n/v2/i18n" 27 "github.com/gohugoio/hugo/helpers" 28 toml "github.com/pelletier/go-toml/v2" 29 30 "github.com/gohugoio/hugo/deps" 31 "github.com/gohugoio/hugo/hugofs" 32 "github.com/gohugoio/hugo/source" 33 _errors "github.com/pkg/errors" 34 ) 35 36 // TranslationProvider provides translation handling, i.e. loading 37 // of bundles etc. 38 type TranslationProvider struct { 39 t Translator 40 } 41 42 // NewTranslationProvider creates a new translation provider. 43 func NewTranslationProvider() *TranslationProvider { 44 return &TranslationProvider{} 45 } 46 47 // Update updates the i18n func in the provided Deps. 48 func (tp *TranslationProvider) Update(d *deps.Deps) error { 49 spec := source.NewSourceSpec(d.PathSpec, nil, nil) 50 51 bundle := i18n.NewBundle(language.English) 52 bundle.RegisterUnmarshalFunc("toml", toml.Unmarshal) 53 bundle.RegisterUnmarshalFunc("yaml", yaml.Unmarshal) 54 bundle.RegisterUnmarshalFunc("yml", yaml.Unmarshal) 55 bundle.RegisterUnmarshalFunc("json", json.Unmarshal) 56 57 // The source dirs are ordered so the most important comes first. Since this is a 58 // last key win situation, we have to reverse the iteration order. 59 dirs := d.BaseFs.I18n.Dirs 60 for i := len(dirs) - 1; i >= 0; i-- { 61 dir := dirs[i] 62 src := spec.NewFilesystemFromFileMetaInfo(dir) 63 files, err := src.Files() 64 if err != nil { 65 return err 66 } 67 for _, file := range files { 68 if err := addTranslationFile(bundle, file); err != nil { 69 return err 70 } 71 } 72 } 73 74 tp.t = NewTranslator(bundle, d.Cfg, d.Log) 75 76 d.Translate = tp.t.Func(d.Language.Lang) 77 78 return nil 79 } 80 81 const artificialLangTagPrefix = "art-x-" 82 83 func addTranslationFile(bundle *i18n.Bundle, r source.File) error { 84 f, err := r.FileInfo().Meta().Open() 85 if err != nil { 86 return _errors.Wrapf(err, "failed to open translations file %q:", r.LogicalName()) 87 } 88 89 b := helpers.ReaderToBytes(f) 90 f.Close() 91 92 name := r.LogicalName() 93 lang := paths.Filename(name) 94 tag := language.Make(lang) 95 if tag == language.Und { 96 name = artificialLangTagPrefix + name 97 } 98 99 _, err = bundle.ParseMessageFileBytes(b, name) 100 if err != nil { 101 if strings.Contains(err.Error(), "no plural rule") { 102 // https://github.com/gohugoio/hugo/issues/7798 103 name = artificialLangTagPrefix + name 104 _, err = bundle.ParseMessageFileBytes(b, name) 105 if err == nil { 106 return nil 107 } 108 } 109 return errWithFileContext(_errors.Wrapf(err, "failed to load translations"), r) 110 } 111 112 return nil 113 } 114 115 // Clone sets the language func for the new language. 116 func (tp *TranslationProvider) Clone(d *deps.Deps) error { 117 d.Translate = tp.t.Func(d.Language.Lang) 118 119 return nil 120 } 121 122 func errWithFileContext(inerr error, r source.File) error { 123 fim, ok := r.FileInfo().(hugofs.FileMetaInfo) 124 if !ok { 125 return inerr 126 } 127 128 meta := fim.Meta() 129 realFilename := meta.Filename 130 f, err := meta.Open() 131 if err != nil { 132 return inerr 133 } 134 defer f.Close() 135 136 err, _ = herrors.WithFileContext( 137 inerr, 138 realFilename, 139 f, 140 herrors.SimpleLineMatcher) 141 142 return err 143 }