diff options
Diffstat (limited to 'helpers')
-rw-r--r-- | helpers/language.go | 100 | ||||
-rw-r--r-- | helpers/url.go | 53 | ||||
-rw-r--r-- | helpers/url_test.go | 104 |
3 files changed, 219 insertions, 38 deletions
diff --git a/helpers/language.go b/helpers/language.go new file mode 100644 index 000000000..4ef5edbc4 --- /dev/null +++ b/helpers/language.go @@ -0,0 +1,100 @@ +// Copyright 2016-present 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 helpers + +import ( + "sort" + "strings" + "sync" + + "github.com/spf13/cast" + + "github.com/spf13/viper" +) + +type Language struct { + Lang string + Title string + Weight int + params map[string]interface{} + paramsInit sync.Once +} + +func NewLanguage(lang string) *Language { + return &Language{Lang: lang, params: make(map[string]interface{})} +} + +func NewDefaultLanguage() *Language { + defaultLang := viper.GetString("DefaultContentLanguage") + + if defaultLang == "" { + defaultLang = "en" + } + + return NewLanguage(defaultLang) +} + +type Languages []*Language + +func NewLanguages(l ...*Language) Languages { + languages := make(Languages, len(l)) + for i := 0; i < len(l); i++ { + languages[i] = l[i] + } + sort.Sort(languages) + return languages +} + +func (l Languages) Len() int { return len(l) } +func (l Languages) Less(i, j int) bool { return l[i].Weight < l[j].Weight } +func (l Languages) Swap(i, j int) { l[i], l[j] = l[j], l[i] } + +func (l *Language) Params() map[string]interface{} { + l.paramsInit.Do(func() { + // Merge with global config. + // TODO(bep) consider making this part of a constructor func. + + globalParams := viper.GetStringMap("Params") + for k, v := range globalParams { + if _, ok := l.params[k]; !ok { + l.params[k] = v + } + } + }) + return l.params +} + +func (l *Language) SetParam(k string, v interface{}) { + l.params[k] = v +} + +func (l *Language) GetString(key string) string { return cast.ToString(l.Get(key)) } +func (ml *Language) GetStringMap(key string) map[string]interface{} { + return cast.ToStringMap(ml.Get(key)) +} + +func (l *Language) GetStringMapString(key string) map[string]string { + return cast.ToStringMapString(l.Get(key)) +} + +func (l *Language) Get(key string) interface{} { + if l == nil { + panic("language not set") + } + key = strings.ToLower(key) + if v, ok := l.params[key]; ok { + return v + } + return viper.Get(key) +} diff --git a/helpers/url.go b/helpers/url.go index 085f9e9fa..f9a41dde3 100644 --- a/helpers/url.go +++ b/helpers/url.go @@ -147,18 +147,18 @@ func MakePermalink(host, plink string) *url.URL { } // AbsURL creates a absolute URL from the relative path given and the BaseURL set in config. -func AbsURL(path string) string { - url, err := url.Parse(path) +func AbsURL(in string, addLanguage bool) string { + url, err := url.Parse(in) if err != nil { - return path + return in } - if url.IsAbs() || strings.HasPrefix(path, "//") { - return path + if url.IsAbs() || strings.HasPrefix(in, "//") { + return in } baseURL := viper.GetString("BaseURL") - if strings.HasPrefix(path, "/") { + if strings.HasPrefix(in, "/") { p, err := url.Parse(baseURL) if err != nil { panic(err) @@ -166,7 +166,23 @@ func AbsURL(path string) string { p.Path = "" baseURL = p.String() } - return MakePermalink(baseURL, path).String() + + if addLanguage { + addSlash := in == "" || strings.HasSuffix(in, "/") + in = path.Join(getLanguagePrefix(), in) + + if addSlash { + in += "/" + } + } + return MakePermalink(baseURL, in).String() +} + +func getLanguagePrefix() string { + if !viper.GetBool("Multilingual") { + return "" + } + return viper.Get("CurrentContentLanguage").(*Language).Lang } // IsAbsURL determines whether the given path points to an absolute URL. @@ -182,23 +198,34 @@ func IsAbsURL(path string) bool { // RelURL creates a URL relative to the BaseURL root. // Note: The result URL will not include the context root if canonifyURLs is enabled. -func RelURL(path string) string { +func RelURL(in string, addLanguage bool) string { baseURL := viper.GetString("BaseURL") canonifyURLs := viper.GetBool("canonifyURLs") - if (!strings.HasPrefix(path, baseURL) && strings.HasPrefix(path, "http")) || strings.HasPrefix(path, "//") { - return path + if (!strings.HasPrefix(in, baseURL) && strings.HasPrefix(in, "http")) || strings.HasPrefix(in, "//") { + return in } - u := path + u := in - if strings.HasPrefix(path, baseURL) { + if strings.HasPrefix(in, baseURL) { u = strings.TrimPrefix(u, baseURL) } + if addLanguage { + hadSlash := strings.HasSuffix(u, "/") + + u = path.Join(getLanguagePrefix(), u) + + if hadSlash { + u += "/" + } + } + if !canonifyURLs { u = AddContextRoot(baseURL, u) } - if path == "" && !strings.HasSuffix(u, "/") && strings.HasSuffix(baseURL, "/") { + + if in == "" && !strings.HasSuffix(u, "/") && strings.HasSuffix(baseURL, "/") { u += "/" } diff --git a/helpers/url_test.go b/helpers/url_test.go index 9cca1cbb8..f6dd9f9da 100644 --- a/helpers/url_test.go +++ b/helpers/url_test.go @@ -14,11 +14,13 @@ package helpers import ( + "fmt" "strings" "testing" "github.com/spf13/viper" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestURLize(t *testing.T) { @@ -43,62 +45,114 @@ func TestURLize(t *testing.T) { } func TestAbsURL(t *testing.T) { - defer viper.Reset() + for _, addLanguage := range []bool{true, false} { + for _, m := range []bool{true, false} { + for _, l := range []string{"en", "fr"} { + doTestAbsURL(t, addLanguage, m, l) + } + } + } +} + +func doTestAbsURL(t *testing.T, addLanguage, multilingual bool, lang string) { + viper.Reset() + viper.Set("Multilingual", multilingual) + viper.Set("CurrentContentLanguage", NewLanguage(lang)) tests := []struct { input string baseURL string expected string }{ - {"/test/foo", "http://base/", "http://base/test/foo"}, - {"", "http://base/ace/", "http://base/ace/"}, - {"/test/2/foo/", "http://base", "http://base/test/2/foo/"}, + {"/test/foo", "http://base/", "http://base/MULTItest/foo"}, + {"", "http://base/ace/", "http://base/ace/MULTI"}, + {"/test/2/foo/", "http://base", "http://base/MULTItest/2/foo/"}, {"http://abs", "http://base/", "http://abs"}, {"schema://abs", "http://base/", "schema://abs"}, {"//schemaless", "http://base/", "//schemaless"}, - {"test/2/foo/", "http://base/path", "http://base/path/test/2/foo/"}, - {"/test/2/foo/", "http://base/path", "http://base/test/2/foo/"}, - {"http//foo", "http://base/path", "http://base/path/http/foo"}, + {"test/2/foo/", "http://base/path", "http://base/path/MULTItest/2/foo/"}, + {"/test/2/foo/", "http://base/path", "http://base/MULTItest/2/foo/"}, + {"http//foo", "http://base/path", "http://base/path/MULTIhttp/foo"}, } for _, test := range tests { - viper.Reset() viper.Set("BaseURL", test.baseURL) - output := AbsURL(test.input) - if output != test.expected { - t.Errorf("Expected %#v, got %#v\n", test.expected, output) + output := AbsURL(test.input, addLanguage) + expected := test.expected + if multilingual && addLanguage { + expected = strings.Replace(expected, "MULTI", lang+"/", 1) + } else { + expected = strings.Replace(expected, "MULTI", "", 1) + } + if output != expected { + t.Errorf("Expected %#v, got %#v\n", expected, output) } } } +func TestIsAbsURL(t *testing.T) { + for i, this := range []struct { + a string + b bool + }{ + {"http://gohugo.io", true}, + {"https://gohugo.io", true}, + {"//gohugo.io", true}, + {"http//gohugo.io", false}, + {"/content", false}, + {"content", false}, + } { + require.True(t, IsAbsURL(this.a) == this.b, fmt.Sprintf("Test %d", i)) + } +} + func TestRelURL(t *testing.T) { - defer viper.Reset() - //defer viper.Set("canonifyURLs", viper.GetBool("canonifyURLs")) + for _, addLanguage := range []bool{true, false} { + for _, m := range []bool{true, false} { + for _, l := range []string{"en", "fr"} { + doTestRelURL(t, addLanguage, m, l) + } + } + } +} + +func doTestRelURL(t *testing.T, addLanguage, multilingual bool, lang string) { + viper.Reset() + viper.Set("Multilingual", multilingual) + viper.Set("CurrentContentLanguage", NewLanguage(lang)) + tests := []struct { input string baseURL string canonify bool expected string }{ - {"/test/foo", "http://base/", false, "/test/foo"}, - {"test.css", "http://base/sub", false, "/sub/test.css"}, - {"test.css", "http://base/sub", true, "/test.css"}, - {"/test/", "http://base/", false, "/test/"}, - {"/test/", "http://base/sub/", false, "/sub/test/"}, - {"/test/", "http://base/sub/", true, "/test/"}, - {"", "http://base/ace/", false, "/ace/"}, - {"", "http://base/ace", false, "/ace"}, + {"/test/foo", "http://base/", false, "MULTI/test/foo"}, + {"test.css", "http://base/sub", false, "/subMULTI/test.css"}, + {"test.css", "http://base/sub", true, "MULTI/test.css"}, + {"/test/", "http://base/", false, "MULTI/test/"}, + {"/test/", "http://base/sub/", false, "/subMULTI/test/"}, + {"/test/", "http://base/sub/", true, "MULTI/test/"}, + {"", "http://base/ace/", false, "/aceMULTI/"}, + {"", "http://base/ace", false, "/aceMULTI"}, {"http://abs", "http://base/", false, "http://abs"}, {"//schemaless", "http://base/", false, "//schemaless"}, } for i, test := range tests { - viper.Reset() viper.Set("BaseURL", test.baseURL) viper.Set("canonifyURLs", test.canonify) - output := RelURL(test.input) - if output != test.expected { - t.Errorf("[%d][%t] Expected %#v, got %#v\n", i, test.canonify, test.expected, output) + output := RelURL(test.input, addLanguage) + + expected := test.expected + if multilingual && addLanguage { + expected = strings.Replace(expected, "MULTI", "/"+lang, 1) + } else { + expected = strings.Replace(expected, "MULTI", "", 1) + } + + if output != expected { + t.Errorf("[%d][%t] Expected %#v, got %#v\n", i, test.canonify, expected, output) } } } |