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