github.com/jmooring/hugo@v0.47.1/langs/language.go (about) 1 // Copyright 2018 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 langs 15 16 import ( 17 "sort" 18 "strings" 19 20 "github.com/gohugoio/hugo/common/maps" 21 "github.com/gohugoio/hugo/config" 22 "github.com/spf13/cast" 23 ) 24 25 // These are the settings that should only be looked up in the global Viper 26 // config and not per language. 27 // This list may not be complete, but contains only settings that we know 28 // will be looked up in both. 29 // This isn't perfect, but it is ultimately the user who shoots him/herself in 30 // the foot. 31 // See the pathSpec. 32 var globalOnlySettings = map[string]bool{ 33 strings.ToLower("defaultContentLanguageInSubdir"): true, 34 strings.ToLower("defaultContentLanguage"): true, 35 strings.ToLower("multilingual"): true, 36 strings.ToLower("assetDir"): true, 37 strings.ToLower("resourceDir"): true, 38 } 39 40 // Language manages specific-language configuration. 41 type Language struct { 42 Lang string 43 LanguageName string 44 Title string 45 Weight int 46 47 Disabled bool 48 49 // If set per language, this tells Hugo that all content files without any 50 // language indicator (e.g. my-page.en.md) is in this language. 51 // This is usually a path relative to the working dir, but it can be an 52 // absolute directory reference. It is what we get. 53 ContentDir string 54 55 Cfg config.Provider 56 57 // These are params declared in the [params] section of the language merged with the 58 // site's params, the most specific (language) wins on duplicate keys. 59 params map[string]interface{} 60 61 // These are config values, i.e. the settings declared outside of the [params] section of the language. 62 // This is the map Hugo looks in when looking for configuration values (baseURL etc.). 63 // Values in this map can also be fetched from the params map above. 64 settings map[string]interface{} 65 } 66 67 func (l *Language) String() string { 68 return l.Lang 69 } 70 71 // NewLanguage creates a new language. 72 func NewLanguage(lang string, cfg config.Provider) *Language { 73 // Note that language specific params will be overridden later. 74 // We should improve that, but we need to make a copy: 75 params := make(map[string]interface{}) 76 for k, v := range cfg.GetStringMap("params") { 77 params[k] = v 78 } 79 maps.ToLower(params) 80 81 defaultContentDir := cfg.GetString("contentDir") 82 if defaultContentDir == "" { 83 panic("contentDir not set") 84 } 85 86 l := &Language{Lang: lang, ContentDir: defaultContentDir, Cfg: cfg, params: params, settings: make(map[string]interface{})} 87 return l 88 } 89 90 // NewDefaultLanguage creates the default language for a config.Provider. 91 // If not otherwise specified the default is "en". 92 func NewDefaultLanguage(cfg config.Provider) *Language { 93 defaultLang := cfg.GetString("defaultContentLanguage") 94 95 if defaultLang == "" { 96 defaultLang = "en" 97 } 98 99 return NewLanguage(defaultLang, cfg) 100 } 101 102 // Languages is a sortable list of languages. 103 type Languages []*Language 104 105 // NewLanguages creates a sorted list of languages. 106 // NOTE: function is currently unused. 107 func NewLanguages(l ...*Language) Languages { 108 languages := make(Languages, len(l)) 109 for i := 0; i < len(l); i++ { 110 languages[i] = l[i] 111 } 112 sort.Sort(languages) 113 return languages 114 } 115 116 func (l Languages) Len() int { return len(l) } 117 func (l Languages) Less(i, j int) bool { return l[i].Weight < l[j].Weight } 118 func (l Languages) Swap(i, j int) { l[i], l[j] = l[j], l[i] } 119 120 // Params retunrs language-specific params merged with the global params. 121 func (l *Language) Params() map[string]interface{} { 122 return l.params 123 } 124 125 // IsMultihost returns whether there are more than one language and at least one of 126 // the languages has baseURL specificed on the language level. 127 func (l Languages) IsMultihost() bool { 128 if len(l) <= 1 { 129 return false 130 } 131 132 for _, lang := range l { 133 if lang.GetLocal("baseURL") != nil { 134 return true 135 } 136 } 137 return false 138 } 139 140 // SetParam sets a param with the given key and value. 141 // SetParam is case-insensitive. 142 func (l *Language) SetParam(k string, v interface{}) { 143 l.params[strings.ToLower(k)] = v 144 } 145 146 // GetBool returns the value associated with the key as a boolean. 147 func (l *Language) GetBool(key string) bool { return cast.ToBool(l.Get(key)) } 148 149 // GetString returns the value associated with the key as a string. 150 func (l *Language) GetString(key string) string { return cast.ToString(l.Get(key)) } 151 152 // GetInt returns the value associated with the key as an int. 153 func (l *Language) GetInt(key string) int { return cast.ToInt(l.Get(key)) } 154 155 // GetStringMap returns the value associated with the key as a map of interfaces. 156 func (l *Language) GetStringMap(key string) map[string]interface{} { 157 return cast.ToStringMap(l.Get(key)) 158 } 159 160 // GetStringMapString returns the value associated with the key as a map of strings. 161 func (l *Language) GetStringMapString(key string) map[string]string { 162 return cast.ToStringMapString(l.Get(key)) 163 } 164 165 // returns the value associated with the key as a slice of strings. 166 func (l *Language) GetStringSlice(key string) []string { 167 return cast.ToStringSlice(l.Get(key)) 168 } 169 170 // Get returns a value associated with the key relying on specified language. 171 // Get is case-insensitive for a key. 172 // 173 // Get returns an interface. For a specific value use one of the Get____ methods. 174 func (l *Language) Get(key string) interface{} { 175 local := l.GetLocal(key) 176 if local != nil { 177 return local 178 } 179 return l.Cfg.Get(key) 180 } 181 182 // GetLocal gets a configuration value set on language level. It will 183 // not fall back to any global value. 184 // It will return nil if a value with the given key cannot be found. 185 func (l *Language) GetLocal(key string) interface{} { 186 if l == nil { 187 panic("language not set") 188 } 189 key = strings.ToLower(key) 190 if !globalOnlySettings[key] { 191 if v, ok := l.settings[key]; ok { 192 return v 193 } 194 } 195 return nil 196 } 197 198 // Set sets the value for the key in the language's params. 199 func (l *Language) Set(key string, value interface{}) { 200 if l == nil { 201 panic("language not set") 202 } 203 key = strings.ToLower(key) 204 l.settings[key] = value 205 } 206 207 // IsSet checks whether the key is set in the language or the related config store. 208 func (l *Language) IsSet(key string) bool { 209 key = strings.ToLower(key) 210 211 key = strings.ToLower(key) 212 if !globalOnlySettings[key] { 213 if _, ok := l.settings[key]; ok { 214 return true 215 } 216 } 217 return l.Cfg.IsSet(key) 218 219 }