}
for k := range p {
- return k == mergeStrategyKey
+ return k == MergeStrategyKey
}
return false
for k, v := range pp {
- if k == mergeStrategyKey {
+ if k == MergeStrategyKey {
continue
}
vv, found := p[k]
// For internal use.
func (p Params) GetMergeStrategy() (ParamsMergeStrategy, bool) {
- if v, found := p[mergeStrategyKey]; found {
+ if v, found := p[MergeStrategyKey]; found {
if s, ok := v.(ParamsMergeStrategy); ok {
return s, true
}
// For internal use.
func (p Params) DeleteMergeStrategy() bool {
- if _, found := p[mergeStrategyKey]; found {
- delete(p, mergeStrategyKey)
+ if _, found := p[MergeStrategyKey]; found {
+ delete(p, MergeStrategyKey)
return true
}
return false
default:
panic(fmt.Sprintf("invalid merge strategy %q", s))
}
- p[mergeStrategyKey] = s
+ p[MergeStrategyKey] = s
}
func getNested(m map[string]any, indices []string) (any, string, map[string]any) {
// Add new keys, merge existing.
ParamsMergeStrategyDeep ParamsMergeStrategy = "deep"
- mergeStrategyKey = "_merge"
+ MergeStrategyKey = "_merge"
)
// CleanConfigStringMapString removes any processing instructions from m,
if m == nil || len(m) == 0 {
return m
}
- if _, found := m[mergeStrategyKey]; !found {
+ if _, found := m[MergeStrategyKey]; !found {
return m
}
// Create a new map and copy all the keys except the merge strategy key.
m2 := make(map[string]string, len(m)-1)
for k, v := range m {
- if k != mergeStrategyKey {
+ if k != MergeStrategyKey {
m2[k] = v
}
}
if m == nil || len(m) == 0 {
return m
}
- if _, found := m[mergeStrategyKey]; !found {
+ if _, found := m[MergeStrategyKey]; !found {
return m
}
// Create a new map and copy all the keys except the merge strategy key.
m2 := make(map[string]any, len(m)-1)
for k, v := range m {
- if k != mergeStrategyKey {
+ if k != MergeStrategyKey {
m2[k] = v
}
switch v2 := v.(type) {
for k, v := range m {
var retyped bool
lKey := strings.ToLower(k)
- if lKey == mergeStrategyKey {
+ if lKey == MergeStrategyKey {
v = toMergeStrategy(v)
retyped = true
} else {
createParamsPair := func() (Params, Params) {
p1 := Params{"a": "av", "c": "cv", "nested": Params{"al2": "al2v", "cl2": "cl2v"}}
- p2 := Params{"b": "bv", "a": "abv", "nested": Params{"bl2": "bl2v", "al2": "al2bv"}, mergeStrategyKey: ParamsMergeStrategyDeep}
+ p2 := Params{"b": "bv", "a": "abv", "nested": Params{"bl2": "bl2v", "al2": "al2bv"}, MergeStrategyKey: ParamsMergeStrategyDeep}
return p1, p2
}
"bl2": "bl2v",
},
"b": "bv",
- mergeStrategyKey: ParamsMergeStrategyDeep,
+ MergeStrategyKey: ParamsMergeStrategyDeep,
})
p1, p2 = createParamsPair()
LiveReloadPort int
}
+// All non-params config keys for language.
+var configLanguageKeys map[string]bool
+
+func init() {
+ skip := map[string]bool{
+ "internal": true,
+ "c": true,
+ "rootconfig": true,
+ }
+ configLanguageKeys = make(map[string]bool)
+ addKeys := func(v reflect.Value) {
+ for i := 0; i < v.NumField(); i++ {
+ name := strings.ToLower(v.Type().Field(i).Name)
+ if skip[name] {
+ continue
+ }
+ configLanguageKeys[name] = true
+ }
+ }
+ addKeys(reflect.ValueOf(Config{}))
+ addKeys(reflect.ValueOf(RootConfig{}))
+ addKeys(reflect.ValueOf(config.CommonDirs{}))
+ addKeys(reflect.ValueOf(langs.LanguageConfig{}))
+}
+
type Config struct {
// For internal use only.
Internal InternalConfig `mapstructure:"-" json:"-"`
Clock time.Time
// This is set to the last transient error found during config compilation.
- // With themes/modules we compule the configuration in multiple passes, and
+ // With themes/modules we compute the configuration in multiple passes, and
// errors with missing output format definitions may resolve itself.
transientErr error
}
var differentRootKeys []string
switch x := v.(type) {
case maps.Params:
+ var params maps.Params
+ pv, found := x["params"]
+ if found {
+ params = pv.(maps.Params)
+ } else {
+ params = maps.Params{
+ maps.MergeStrategyKey: maps.ParamsMergeStrategyDeep,
+ }
+ x["params"] = params
+ }
+
for kk, vv := range x {
+ if kk == "_merge" {
+ continue
+ }
+ if kk != maps.MergeStrategyKey && !configLanguageKeys[kk] {
+ // This should have been placed below params.
+ // We accidently allowed it in the past, so we need to support it a little longer,
+ // But log a warning.
+ if _, found := params[kk]; !found {
+ helpers.Deprecated(fmt.Sprintf("config: languages.%s.%s: custom params on the language top level", k, kk), fmt.Sprintf("Put the value below [languages.%s.params]. See See https://gohugo.io/content-management/multilingual/#changes-in-hugo-01120", k), false)
+ params[kk] = vv
+ }
+ }
if kk == "baseurl" {
// baseURL configure don the language level is a multihost setup.
isMultiHost = true
}
+func TestConfigParamSetOnLanguageLevel(t *testing.T) {
+ t.Parallel()
+
+ files := `
+-- hugo.toml --
+disableKinds = ["taxonomy", "term", "RSS", "sitemap", "robotsTXT"]
+[languages]
+[languages.en]
+title = "English Title"
+thisIsAParam = "thisIsAParamValue"
+[languages.en.params]
+myparam = "enParamValue"
+[languages.sv]
+title = "Svensk Title"
+[languages.sv.params]
+myparam = "svParamValue"
+-- layouts/index.html --
+MyParam: {{ site.Params.myparam }}
+ThisIsAParam: {{ site.Params.thisIsAParam }}
+
+
+`
+
+ b, err := NewIntegrationTestBuilder(
+ IntegrationTestConfig{
+ T: t,
+ TxtarString: files,
+ },
+ ).BuildE()
+
+ b.Assert(err, qt.IsNil)
+ b.AssertFileContent("public/index.html", `
+MyParam: enParamValue
+ThisIsAParam: thisIsAParamValue
+`)
+}
+
func TestReproCommentsIn10947(t *testing.T) {
t.Parallel()
},
).Build()
- b.Assert(b.H.Log.LogCounters().WarnCounter.Count(), qt.Equals, uint64(2))
+ {
+ b.Assert(b.H.Log.LogCounters().WarnCounter.Count(), qt.Equals, uint64(2))
+ }
b.AssertFileContent("public/index.html", `
AllPages: 4|
Sections: true|