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  }