github.com/SDLMoe/hugo@v0.47.1/i18n/i18n_test.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  	"path/filepath"
    18  	"testing"
    19  
    20  	"github.com/gohugoio/hugo/tpl/tplimpl"
    21  
    22  	"github.com/gohugoio/hugo/langs"
    23  	"github.com/spf13/afero"
    24  
    25  	"github.com/gohugoio/hugo/deps"
    26  
    27  	"io/ioutil"
    28  	"os"
    29  
    30  	"log"
    31  
    32  	"github.com/gohugoio/hugo/config"
    33  	"github.com/gohugoio/hugo/hugofs"
    34  	jww "github.com/spf13/jwalterweatherman"
    35  	"github.com/spf13/viper"
    36  	"github.com/stretchr/testify/require"
    37  )
    38  
    39  var logger = jww.NewNotepad(jww.LevelError, jww.LevelError, os.Stdout, ioutil.Discard, "", log.Ldate|log.Ltime)
    40  
    41  type i18nTest struct {
    42  	data                             map[string][]byte
    43  	args                             interface{}
    44  	lang, id, expected, expectedFlag string
    45  }
    46  
    47  var i18nTests = []i18nTest{
    48  	// All translations present
    49  	{
    50  		data: map[string][]byte{
    51  			"en.toml": []byte("[hello]\nother = \"Hello, World!\""),
    52  			"es.toml": []byte("[hello]\nother = \"¡Hola, Mundo!\""),
    53  		},
    54  		args:         nil,
    55  		lang:         "es",
    56  		id:           "hello",
    57  		expected:     "¡Hola, Mundo!",
    58  		expectedFlag: "¡Hola, Mundo!",
    59  	},
    60  	// Translation missing in current language but present in default
    61  	{
    62  		data: map[string][]byte{
    63  			"en.toml": []byte("[hello]\nother = \"Hello, World!\""),
    64  			"es.toml": []byte("[goodbye]\nother = \"¡Adiós, Mundo!\""),
    65  		},
    66  		args:         nil,
    67  		lang:         "es",
    68  		id:           "hello",
    69  		expected:     "Hello, World!",
    70  		expectedFlag: "[i18n] hello",
    71  	},
    72  	// Translation missing in default language but present in current
    73  	{
    74  		data: map[string][]byte{
    75  			"en.toml": []byte("[goodbye]\nother = \"Goodbye, World!\""),
    76  			"es.toml": []byte("[hello]\nother = \"¡Hola, Mundo!\""),
    77  		},
    78  		args:         nil,
    79  		lang:         "es",
    80  		id:           "hello",
    81  		expected:     "¡Hola, Mundo!",
    82  		expectedFlag: "¡Hola, Mundo!",
    83  	},
    84  	// Translation missing in both default and current language
    85  	{
    86  		data: map[string][]byte{
    87  			"en.toml": []byte("[goodbye]\nother = \"Goodbye, World!\""),
    88  			"es.toml": []byte("[goodbye]\nother = \"¡Adiós, Mundo!\""),
    89  		},
    90  		args:         nil,
    91  		lang:         "es",
    92  		id:           "hello",
    93  		expected:     "",
    94  		expectedFlag: "[i18n] hello",
    95  	},
    96  	// Default translation file missing or empty
    97  	{
    98  		data: map[string][]byte{
    99  			"en.toml": []byte(""),
   100  		},
   101  		args:         nil,
   102  		lang:         "es",
   103  		id:           "hello",
   104  		expected:     "",
   105  		expectedFlag: "[i18n] hello",
   106  	},
   107  	// Context provided
   108  	{
   109  		data: map[string][]byte{
   110  			"en.toml": []byte("[wordCount]\nother = \"Hello, {{.WordCount}} people!\""),
   111  			"es.toml": []byte("[wordCount]\nother = \"¡Hola, {{.WordCount}} gente!\""),
   112  		},
   113  		args: struct {
   114  			WordCount int
   115  		}{
   116  			50,
   117  		},
   118  		lang:         "es",
   119  		id:           "wordCount",
   120  		expected:     "¡Hola, 50 gente!",
   121  		expectedFlag: "¡Hola, 50 gente!",
   122  	},
   123  	// Same id and translation in current language
   124  	// https://github.com/gohugoio/hugo/issues/2607
   125  	{
   126  		data: map[string][]byte{
   127  			"es.toml": []byte("[hello]\nother = \"hello\""),
   128  			"en.toml": []byte("[hello]\nother = \"hi\""),
   129  		},
   130  		args:         nil,
   131  		lang:         "es",
   132  		id:           "hello",
   133  		expected:     "hello",
   134  		expectedFlag: "hello",
   135  	},
   136  	// Translation missing in current language, but same id and translation in default
   137  	{
   138  		data: map[string][]byte{
   139  			"es.toml": []byte("[bye]\nother = \"bye\""),
   140  			"en.toml": []byte("[hello]\nother = \"hello\""),
   141  		},
   142  		args:         nil,
   143  		lang:         "es",
   144  		id:           "hello",
   145  		expected:     "hello",
   146  		expectedFlag: "[i18n] hello",
   147  	},
   148  	// Unknown language code should get its plural spec from en
   149  	{
   150  		data: map[string][]byte{
   151  			"en.toml": []byte(`[readingTime]
   152  one ="one minute read"
   153  other = "{{.Count}} minutes read"`),
   154  			"klingon.toml": []byte(`[readingTime]
   155  one =  "eitt minutt med lesing"
   156  other = "{{ .Count }} minuttar lesing"`),
   157  		},
   158  		args:         3,
   159  		lang:         "klingon",
   160  		id:           "readingTime",
   161  		expected:     "3 minuttar lesing",
   162  		expectedFlag: "3 minuttar lesing",
   163  	},
   164  }
   165  
   166  func doTestI18nTranslate(t *testing.T, test i18nTest, cfg config.Provider) string {
   167  	assert := require.New(t)
   168  	fs := hugofs.NewMem(cfg)
   169  	tp := NewTranslationProvider()
   170  
   171  	for file, content := range test.data {
   172  		err := afero.WriteFile(fs.Source, filepath.Join("i18n", file), []byte(content), 0755)
   173  		assert.NoError(err)
   174  	}
   175  
   176  	depsCfg := newDepsConfig(tp, cfg, fs)
   177  	d, err := deps.New(depsCfg)
   178  	assert.NoError(err)
   179  
   180  	assert.NoError(d.LoadResources())
   181  	f := tp.t.Func(test.lang)
   182  	return f(test.id, test.args)
   183  
   184  }
   185  
   186  func newDepsConfig(tp *TranslationProvider, cfg config.Provider, fs *hugofs.Fs) deps.DepsCfg {
   187  	l := langs.NewLanguage("en", cfg)
   188  	l.Set("i18nDir", "i18n")
   189  	return deps.DepsCfg{
   190  		Language:            l,
   191  		Cfg:                 cfg,
   192  		Fs:                  fs,
   193  		Logger:              logger,
   194  		TemplateProvider:    tplimpl.DefaultTemplateProvider,
   195  		TranslationProvider: tp,
   196  	}
   197  }
   198  
   199  func TestI18nTranslate(t *testing.T) {
   200  	var actual, expected string
   201  	v := viper.New()
   202  	v.SetDefault("defaultContentLanguage", "en")
   203  	v.Set("contentDir", "content")
   204  	v.Set("dataDir", "data")
   205  	v.Set("i18nDir", "i18n")
   206  	v.Set("layoutDir", "layouts")
   207  	v.Set("archetypeDir", "archetypes")
   208  	v.Set("assetDir", "assets")
   209  	v.Set("resourceDir", "resources")
   210  	v.Set("publishDir", "public")
   211  
   212  	// Test without and with placeholders
   213  	for _, enablePlaceholders := range []bool{false, true} {
   214  		v.Set("enableMissingTranslationPlaceholders", enablePlaceholders)
   215  
   216  		for _, test := range i18nTests {
   217  			if enablePlaceholders {
   218  				expected = test.expectedFlag
   219  			} else {
   220  				expected = test.expected
   221  			}
   222  			actual = doTestI18nTranslate(t, test, v)
   223  			require.Equal(t, expected, actual)
   224  		}
   225  	}
   226  }