Support, but warn, about top level language custom params

Updates #10947
This commit is contained in:
Bjørn Erik Pedersen 2023-05-17 16:29:06 +02:00
parent 05542130ba
commit 7ce033a89d
4 changed files with 103 additions and 16 deletions

View file

@ -70,7 +70,7 @@ func (p Params) IsZero() bool {
} }
for k := range p { for k := range p {
return k == mergeStrategyKey return k == MergeStrategyKey
} }
return false return false
@ -103,7 +103,7 @@ func (p Params) merge(ps ParamsMergeStrategy, pp Params) {
for k, v := range pp { for k, v := range pp {
if k == mergeStrategyKey { if k == MergeStrategyKey {
continue continue
} }
vv, found := p[k] vv, found := p[k]
@ -124,7 +124,7 @@ func (p Params) merge(ps ParamsMergeStrategy, pp Params) {
// For internal use. // For internal use.
func (p Params) GetMergeStrategy() (ParamsMergeStrategy, bool) { func (p Params) GetMergeStrategy() (ParamsMergeStrategy, bool) {
if v, found := p[mergeStrategyKey]; found { if v, found := p[MergeStrategyKey]; found {
if s, ok := v.(ParamsMergeStrategy); ok { if s, ok := v.(ParamsMergeStrategy); ok {
return s, true return s, true
} }
@ -134,8 +134,8 @@ func (p Params) GetMergeStrategy() (ParamsMergeStrategy, bool) {
// For internal use. // For internal use.
func (p Params) DeleteMergeStrategy() bool { func (p Params) DeleteMergeStrategy() bool {
if _, found := p[mergeStrategyKey]; found { if _, found := p[MergeStrategyKey]; found {
delete(p, mergeStrategyKey) delete(p, MergeStrategyKey)
return true return true
} }
return false return false
@ -148,7 +148,7 @@ func (p Params) SetMergeStrategy(s ParamsMergeStrategy) {
default: default:
panic(fmt.Sprintf("invalid merge strategy %q", s)) 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) { func getNested(m map[string]any, indices []string) (any, string, map[string]any) {
@ -242,7 +242,7 @@ const (
// Add new keys, merge existing. // Add new keys, merge existing.
ParamsMergeStrategyDeep ParamsMergeStrategy = "deep" ParamsMergeStrategyDeep ParamsMergeStrategy = "deep"
mergeStrategyKey = "_merge" MergeStrategyKey = "_merge"
) )
// CleanConfigStringMapString removes any processing instructions from m, // CleanConfigStringMapString removes any processing instructions from m,
@ -251,13 +251,13 @@ func CleanConfigStringMapString(m map[string]string) map[string]string {
if m == nil || len(m) == 0 { if m == nil || len(m) == 0 {
return m return m
} }
if _, found := m[mergeStrategyKey]; !found { if _, found := m[MergeStrategyKey]; !found {
return m return m
} }
// Create a new map and copy all the keys except the merge strategy key. // Create a new map and copy all the keys except the merge strategy key.
m2 := make(map[string]string, len(m)-1) m2 := make(map[string]string, len(m)-1)
for k, v := range m { for k, v := range m {
if k != mergeStrategyKey { if k != MergeStrategyKey {
m2[k] = v m2[k] = v
} }
} }
@ -270,13 +270,13 @@ func CleanConfigStringMap(m map[string]any) map[string]any {
if m == nil || len(m) == 0 { if m == nil || len(m) == 0 {
return m return m
} }
if _, found := m[mergeStrategyKey]; !found { if _, found := m[MergeStrategyKey]; !found {
return m return m
} }
// Create a new map and copy all the keys except the merge strategy key. // Create a new map and copy all the keys except the merge strategy key.
m2 := make(map[string]any, len(m)-1) m2 := make(map[string]any, len(m)-1)
for k, v := range m { for k, v := range m {
if k != mergeStrategyKey { if k != MergeStrategyKey {
m2[k] = v m2[k] = v
} }
switch v2 := v.(type) { switch v2 := v.(type) {
@ -313,7 +313,7 @@ func PrepareParams(m Params) {
for k, v := range m { for k, v := range m {
var retyped bool var retyped bool
lKey := strings.ToLower(k) lKey := strings.ToLower(k)
if lKey == mergeStrategyKey { if lKey == MergeStrategyKey {
v = toMergeStrategy(v) v = toMergeStrategy(v)
retyped = true retyped = true
} else { } else {

View file

@ -75,7 +75,7 @@ func TestParamsSetAndMerge(t *testing.T) {
createParamsPair := func() (Params, Params) { createParamsPair := func() (Params, Params) {
p1 := Params{"a": "av", "c": "cv", "nested": Params{"al2": "al2v", "cl2": "cl2v"}} 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 return p1, p2
} }
@ -92,7 +92,7 @@ func TestParamsSetAndMerge(t *testing.T) {
"bl2": "bl2v", "bl2": "bl2v",
}, },
"b": "bv", "b": "bv",
mergeStrategyKey: ParamsMergeStrategyDeep, MergeStrategyKey: ParamsMergeStrategyDeep,
}) })
p1, p2 = createParamsPair() p1, p2 = createParamsPair()

View file

@ -63,6 +63,31 @@ type InternalConfig struct {
LiveReloadPort int 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 { type Config struct {
// For internal use only. // For internal use only.
Internal InternalConfig `mapstructure:"-" json:"-"` Internal InternalConfig `mapstructure:"-" json:"-"`
@ -328,7 +353,7 @@ type ConfigCompiled struct {
Clock time.Time Clock time.Time
// This is set to the last transient error found during config compilation. // 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. // errors with missing output format definitions may resolve itself.
transientErr error transientErr error
} }
@ -659,7 +684,30 @@ func FromLoadConfigResult(fs afero.Fs, res config.LoadConfigResult) (*Configs, e
var differentRootKeys []string var differentRootKeys []string
switch x := v.(type) { switch x := v.(type) {
case maps.Params: 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 { 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" { if kk == "baseurl" {
// baseURL configure don the language level is a multihost setup. // baseURL configure don the language level is a multihost setup.
isMultiHost = true isMultiHost = true

View file

@ -778,6 +778,43 @@ Home.
} }
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) { func TestReproCommentsIn10947(t *testing.T) {
t.Parallel() t.Parallel()
@ -817,7 +854,9 @@ title: "My Swedish Section"
}, },
).Build() ).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", ` b.AssertFileContent("public/index.html", `
AllPages: 4| AllPages: 4|
Sections: true| Sections: true|