summaryrefslogtreecommitdiffstats
path: root/langs/i18n/translationProvider.go
diff options
context:
space:
mode:
Diffstat (limited to 'langs/i18n/translationProvider.go')
-rw-r--r--langs/i18n/translationProvider.go135
1 files changed, 135 insertions, 0 deletions
diff --git a/langs/i18n/translationProvider.go b/langs/i18n/translationProvider.go
new file mode 100644
index 000000000..4ce9b59fe
--- /dev/null
+++ b/langs/i18n/translationProvider.go
@@ -0,0 +1,135 @@
+// Copyright 2017 The Hugo Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package i18n
+
+import (
+ "errors"
+
+ "github.com/gohugoio/hugo/common/herrors"
+
+ "github.com/gohugoio/hugo/deps"
+ "github.com/gohugoio/hugo/helpers"
+ "github.com/gohugoio/hugo/hugofs"
+ "github.com/gohugoio/hugo/source"
+ "github.com/nicksnyder/go-i18n/i18n/bundle"
+ "github.com/nicksnyder/go-i18n/i18n/language"
+ _errors "github.com/pkg/errors"
+)
+
+// TranslationProvider provides translation handling, i.e. loading
+// of bundles etc.
+type TranslationProvider struct {
+ t Translator
+}
+
+// NewTranslationProvider creates a new translation provider.
+func NewTranslationProvider() *TranslationProvider {
+ return &TranslationProvider{}
+}
+
+// Update updates the i18n func in the provided Deps.
+func (tp *TranslationProvider) Update(d *deps.Deps) error {
+ spec := source.NewSourceSpec(d.PathSpec, nil)
+
+ i18nBundle := bundle.New()
+
+ en := language.GetPluralSpec("en")
+ if en == nil {
+ return errors.New("the English language has vanished like an old oak table")
+ }
+ var newLangs []string
+
+ // The source dirs are ordered so the most important comes first. Since this is a
+ // last key win situation, we have to reverse the iteration order.
+ dirs := d.BaseFs.I18n.Dirs
+ for i := len(dirs) - 1; i >= 0; i-- {
+ dir := dirs[i]
+ src := spec.NewFilesystemFromFileMetaInfo(dir)
+
+ files, err := src.Files()
+ if err != nil {
+ return err
+ }
+
+ for _, r := range files {
+ currentSpec := language.GetPluralSpec(r.BaseFileName())
+ if currentSpec == nil {
+ // This may is a language code not supported by go-i18n, it may be
+ // Klingon or ... not even a fake language. Make sure it works.
+ newLangs = append(newLangs, r.BaseFileName())
+ }
+ }
+
+ if len(newLangs) > 0 {
+ language.RegisterPluralSpec(newLangs, en)
+ }
+
+ for _, file := range files {
+ if err := addTranslationFile(i18nBundle, file); err != nil {
+ return err
+ }
+ }
+ }
+
+ tp.t = NewTranslator(i18nBundle, d.Cfg, d.Log)
+
+ d.Translate = tp.t.Func(d.Language.Lang)
+
+ return nil
+
+}
+
+func addTranslationFile(bundle *bundle.Bundle, r source.File) error {
+ f, err := r.FileInfo().Meta().Open()
+ if err != nil {
+ return _errors.Wrapf(err, "failed to open translations file %q:", r.LogicalName())
+ }
+ err = bundle.ParseTranslationFileBytes(r.LogicalName(), helpers.ReaderToBytes(f))
+ f.Close()
+ if err != nil {
+ return errWithFileContext(_errors.Wrapf(err, "failed to load translations"), r)
+ }
+ return nil
+}
+
+// Clone sets the language func for the new language.
+func (tp *TranslationProvider) Clone(d *deps.Deps) error {
+ d.Translate = tp.t.Func(d.Language.Lang)
+
+ return nil
+}
+
+func errWithFileContext(inerr error, r source.File) error {
+ fim, ok := r.FileInfo().(hugofs.FileMetaInfo)
+ if !ok {
+ return inerr
+ }
+
+ meta := fim.Meta()
+ realFilename := meta.Filename()
+ f, err := meta.Open()
+ if err != nil {
+ return inerr
+ }
+ defer f.Close()
+
+ err, _ = herrors.WithFileContext(
+ inerr,
+ realFilename,
+ f,
+ herrors.SimpleLineMatcher)
+
+ return err
+
+}