Repository: gohugoio/hugo (language: go)

Issue:
Regression: cannot define output formats per language
This worked in v0.111.3 and earlier:

```
[languages.de.outputFormats.json]
path = 'xx'
```

With v0.112.0 and later:

> Error: failed to create config from result: failed to decode config for language "de": unknown config key "outputformats"

Reference: <https://discourse.gohugo.io/t/44976>

Minimal example:

```text
git clone --single-branch -b hugo-forum-topic-44976 https://github.com/jmooring/hugo-testing hugo-forum-topic-44976
cd hugo-forum-topic-44976
rm -rf public/ && hugo && tree public
```




Discussion / hints:

Fix patch:
diff --git a/config/allconfig/alldecoders.go b/config/allconfig/alldecoders.go
index 4d9ef4f85af..bda3122d3ef 100644
--- a/config/allconfig/alldecoders.go
+++ b/config/allconfig/alldecoders.go
@@ -138,8 +138,8 @@ var allDecoderSetups = map[string]decodeWeight{
 			return err
 		},
 	},
-	"mediaTypes": {
-		key: "mediaTypes",
+	"mediatypes": {
+		key: "mediatypes",
 		decode: func(d decodeWeight, p decodeConfig) error {
 			var err error
 			p.c.MediaTypes, err = media.DecodeTypes(p.p.GetStringMap(d.key))
@@ -168,8 +168,8 @@ var allDecoderSetups = map[string]decodeWeight{
 			return nil
 		},
 	},
-	"outputFormats": {
-		key: "outputFormats",
+	"outputformats": {
+		key: "outputformats",
 		decode: func(d decodeWeight, p decodeConfig) error {
 			var err error
 			p.c.OutputFormats, err = output.DecodeConfig(p.c.MediaTypes.Config, p.p.Get(d.key))
@@ -221,9 +221,9 @@ var allDecoderSetups = map[string]decodeWeight{
 					//   key = '...'
 
 					// To sucessfully be backward compatible, "default" patterns need to be set for both page and term
-					p.c.Permalinks["page"][k] = v;
-					p.c.Permalinks["term"][k] = v;
-				
+					p.c.Permalinks["page"][k] = v
+					p.c.Permalinks["term"][k] = v
+
 				case maps.Params:
 					// [permalinks.key]
 					//   xyz = ???
@@ -234,7 +234,7 @@ var allDecoderSetups = map[string]decodeWeight{
 							switch v2 := v2.(type) {
 							case string:
 								p.c.Permalinks[k][k2] = v2
-							
+
 							default:
 								return fmt.Errorf("permalinks configuration invalid: unknown value %q for key %q for kind %q", v2, k2, k)
 							}
@@ -410,3 +410,19 @@ var allDecoderSetups = map[string]decodeWeight{
 		},
 	},
 }
+
+func init() {
+	for k, v := range allDecoderSetups {
+		// Verify that k and v.key is all lower case.
+		if k != strings.ToLower(k) {
+			panic(fmt.Sprintf("key %q is not lower case", k))
+		}
+		if v.key != strings.ToLower(v.key) {
+			panic(fmt.Sprintf("key %q is not lower case", v.key))
+		}
+
+		if k != v.key {
+			panic(fmt.Sprintf("key %q is not the same as the map key %q", k, v.key))
+		}
+	}
+}


Test patch:
diff --git a/hugolib/config_test.go b/hugolib/config_test.go
index 56a03c6dfba..f87d8b936f3 100644
--- a/hugolib/config_test.go
+++ b/hugolib/config_test.go
@@ -1144,6 +1144,48 @@ LanguageCode: {{ .Site.LanguageCode }}|{{ site.Language.LanguageCode }}|
 
 }
 
+// See #11159
+func TestConfigOutputFormatsPerLanguage(t *testing.T) {
+	t.Parallel()
+
+	files := `
+-- hugo.toml --
+[languages]
+[languages.en]
+title = "English Title"
+[languages.sv]
+title = "Swedish Title"
+[languages.sv.outputFormats.html]
+path = "foo"
+[languages.sv.mediatypes."text/html"]
+suffixes = ["bar"]
+
+-- layouts/index.html --
+Home.
+
+	
+`
+	b := NewIntegrationTestBuilder(
+		IntegrationTestConfig{
+			T:           t,
+			TxtarString: files,
+		},
+	).Build()
+
+	b.AssertFileContent("public/index.html", "Home.")
+
+	enConfig := b.H.Sites[0].conf
+	m, _ := enConfig.MediaTypes.Config.GetByType("text/html")
+	b.Assert(m.Suffixes(), qt.DeepEquals, []string{"html"})
+
+	svConfig := b.H.Sites[1].conf
+	f, _ := svConfig.OutputFormats.Config.GetByName("html")
+	b.Assert(f.Path, qt.Equals, "foo")
+	m, _ = svConfig.MediaTypes.Config.GetByType("text/html")
+	b.Assert(m.Suffixes(), qt.DeepEquals, []string{"bar"})
+
+}
+
 func TestConfigMiscPanics(t *testing.T) {
 	t.Parallel()
 
diff --git a/tpl/collections/integration_test.go b/tpl/collections/integration_test.go
index 829aee355b4..80d2f043ab3 100644
--- a/tpl/collections/integration_test.go
+++ b/tpl/collections/integration_test.go
@@ -87,21 +87,16 @@ func TestAppendSliceToASliceOfSlices(t *testing.T) {
 
 {{ $obj }}
 
-
   `
 
-	for i := 0; i < 4; i++ {
-
-		b := hugolib.NewIntegrationTestBuilder(
-			hugolib.IntegrationTestConfig{
-				T:           t,
-				TxtarString: files,
-			},
-		).Build()
-
-		b.AssertFileContent("public/index.html", "[[a] [b] [c]]")
+	b := hugolib.NewIntegrationTestBuilder(
+		hugolib.IntegrationTestConfig{
+			T:           t,
+			TxtarString: files,
+		},
+	).Build()
 
-	}
+	b.AssertFileContent("public/index.html", "[[a] [b] [c]]")
 
 }
 
@@ -120,18 +115,14 @@ func TestAppendNilToSlice(t *testing.T) {
 
   `
 
-	for i := 0; i < 4; i++ {
-
-		b := hugolib.NewIntegrationTestBuilder(
-			hugolib.IntegrationTestConfig{
-				T:           t,
-				TxtarString: files,
-			},
-		).Build()
-
-		b.AssertFileContent("public/index.html", "[a &lt;nil&gt;]")
+	b := hugolib.NewIntegrationTestBuilder(
+		hugolib.IntegrationTestConfig{
+			T:           t,
+			TxtarString: files,
+		},
+	).Build()
 
-	}
+	b.AssertFileContent("public/index.html", "[a &lt;nil&gt;]")
 
 }