github.com/neohugo/neohugo@v0.123.8/hugolib/config_test.go (about) 1 // Copyright 2016-present 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 hugolib 15 16 import ( 17 "bytes" 18 "fmt" 19 "path/filepath" 20 "strings" 21 "testing" 22 23 "github.com/bep/logg" 24 "github.com/neohugo/neohugo/config" 25 "github.com/neohugo/neohugo/config/allconfig" 26 27 qt "github.com/frankban/quicktest" 28 "github.com/neohugo/neohugo/common/maps" 29 "github.com/spf13/afero" 30 ) 31 32 func TestLoadConfigLanguageParamsOverrideIssue10620(t *testing.T) { 33 t.Parallel() 34 35 files := ` 36 -- hugo.toml -- 37 baseURL = "https://example.com" 38 disableKinds = ["taxonomy", "term", "RSS", "sitemap", "robotsTXT", "page", "section"] 39 title = "Base Title" 40 staticDir = "mystatic" 41 [params] 42 [params.comments] 43 color = "blue" 44 title = "Default Comments Title" 45 [languages] 46 [languages.en] 47 title = "English Title" 48 [languages.en.params.comments] 49 title = "English Comments Title" 50 51 ` 52 b := Test(t, files) 53 54 enSite := b.H.Sites[0] 55 b.Assert(enSite.Title(), qt.Equals, "English Title") 56 b.Assert(enSite.Home().Title(), qt.Equals, "English Title") 57 b.Assert(enSite.Params(), qt.DeepEquals, maps.Params{ 58 "comments": maps.Params{ 59 "color": "blue", 60 "title": "English Comments Title", 61 }, 62 }, 63 ) 64 } 65 66 func TestLoadConfig(t *testing.T) { 67 t.Run("2 languages", func(t *testing.T) { 68 t.Parallel() 69 70 files := ` 71 -- hugo.toml -- 72 baseURL = "https://example.com" 73 disableKinds = ["taxonomy", "term", "RSS", "sitemap", "robotsTXT", "page", "section"] 74 title = "Base Title" 75 staticDir = "mystatic" 76 [params] 77 p1 = "p1base" 78 p2 = "p2base" 79 [languages] 80 [languages.en] 81 title = "English Title" 82 [languages.en.params] 83 myparam = "enParamValue" 84 p1 = "p1en" 85 weight = 1 86 [languages.sv] 87 title = "Svensk Title" 88 staticDir = "mysvstatic" 89 weight = 2 90 [languages.sv.params] 91 myparam = "svParamValue" 92 93 ` 94 b := Test(t, files) 95 96 enSite := b.H.Sites[0] 97 svSite := b.H.Sites[1] 98 b.Assert(enSite.Title(), qt.Equals, "English Title") 99 b.Assert(enSite.Home().Title(), qt.Equals, "English Title") 100 b.Assert(enSite.Params()["myparam"], qt.Equals, "enParamValue") 101 b.Assert(enSite.Params()["p1"], qt.Equals, "p1en") 102 b.Assert(enSite.Params()["p2"], qt.Equals, "p2base") 103 b.Assert(svSite.Params()["p1"], qt.Equals, "p1base") 104 b.Assert(enSite.conf.StaticDir[0], qt.Equals, "mystatic") 105 106 b.Assert(svSite.Title(), qt.Equals, "Svensk Title") 107 b.Assert(svSite.Home().Title(), qt.Equals, "Svensk Title") 108 b.Assert(svSite.Params()["myparam"], qt.Equals, "svParamValue") 109 b.Assert(svSite.conf.StaticDir[0], qt.Equals, "mysvstatic") 110 }) 111 112 t.Run("disable default language", func(t *testing.T) { 113 t.Parallel() 114 115 files := ` 116 -- hugo.toml -- 117 baseURL = "https://example.com" 118 disableKinds = ["taxonomy", "term", "RSS", "sitemap", "robotsTXT", "page", "section"] 119 title = "Base Title" 120 defaultContentLanguage = "sv" 121 disableLanguages = ["sv"] 122 [languages.en] 123 weight = 1 124 [languages.sv] 125 weight = 2 126 ` 127 b, err := NewIntegrationTestBuilder( 128 IntegrationTestConfig{ 129 T: t, 130 TxtarString: files, 131 }, 132 ).BuildE() 133 134 b.Assert(err, qt.IsNotNil) 135 b.Assert(err.Error(), qt.Contains, "cannot disable default content language") 136 }) 137 138 t.Run("no internal config from outside", func(t *testing.T) { 139 t.Parallel() 140 141 files := ` 142 -- hugo.toml -- 143 baseURL = "https://example.com" 144 [internal] 145 running = true 146 ` 147 b := Test(t, files) 148 149 b.Assert(b.H.Conf.Running(), qt.Equals, false) 150 }) 151 152 t.Run("env overrides", func(t *testing.T) { 153 t.Parallel() 154 155 files := ` 156 -- hugo.toml -- 157 baseURL = "https://example.com" 158 disableKinds = ["taxonomy", "term", "RSS", "sitemap", "robotsTXT", "page", "section"] 159 title = "Base Title" 160 [params] 161 p1 = "p1base" 162 p2 = "p2base" 163 [params.pm2] 164 pm21 = "pm21base" 165 pm22 = "pm22base" 166 -- layouts/index.html -- 167 p1: {{ .Site.Params.p1 }} 168 p2: {{ .Site.Params.p2 }} 169 pm21: {{ .Site.Params.pm2.pm21 }} 170 pm22: {{ .Site.Params.pm2.pm22 }} 171 pm31: {{ .Site.Params.pm3.pm31 }} 172 173 174 175 ` 176 b := NewIntegrationTestBuilder( 177 IntegrationTestConfig{ 178 T: t, 179 TxtarString: files, 180 Environ: []string{"HUGO_PARAMS_P2=p2env", "HUGO_PARAMS_PM2_PM21=pm21env", "HUGO_PARAMS_PM3_PM31=pm31env"}, 181 }, 182 ).Build() 183 184 b.AssertFileContent("public/index.html", "p1: p1base\np2: p2env\npm21: pm21env\npm22: pm22base\npm31: pm31env") 185 }) 186 } 187 188 func TestLoadConfigThemeLanguage(t *testing.T) { 189 t.Parallel() 190 191 files := ` 192 -- /hugo.toml -- 193 baseURL = "https://example.com" 194 defaultContentLanguage = "en" 195 defaultContentLanguageInSubdir = true 196 theme = "mytheme" 197 [languages] 198 [languages.en] 199 title = "English Title" 200 weight = 1 201 [languages.sv] 202 weight = 2 203 -- themes/mytheme/hugo.toml -- 204 [params] 205 p1 = "p1base" 206 [languages] 207 [languages.en] 208 title = "English Title Theme" 209 [languages.en.params] 210 p2 = "p2en" 211 [languages.en.params.sub] 212 sub1 = "sub1en" 213 [languages.sv] 214 title = "Svensk Title Theme" 215 -- layouts/index.html -- 216 title: {{ .Title }}| 217 p1: {{ .Site.Params.p1 }}| 218 p2: {{ .Site.Params.p2 }}| 219 sub: {{ .Site.Params.sub }}| 220 ` 221 b := Test(t, files) 222 223 b.AssertFileContent("public/en/index.html", ` 224 title: English Title| 225 p1: p1base 226 p2: p2en 227 sub: map[sub1:sub1en] 228 `) 229 } 230 231 func TestDisableRootSlicesFromEnv(t *testing.T) { 232 t.Parallel() 233 234 files := ` 235 -- hugo.toml -- 236 baseURL = "https://example.com" 237 defaultContentLanguage = "en" 238 defaultContentLanguageInSubdir = true 239 [languages] 240 [languages.en] 241 weight = 1 242 [languages.sv] 243 weight = 2 244 [languages.no] 245 weight = 3 246 247 -- layouts/index.html -- 248 Home. 249 ` 250 251 for _, delim := range []string{" ", ","} { 252 environ := []string{"HUGO_DISABLELANGUAGES=sv no", "HUGO_DISABLEKINDS=taxonomy term"} 253 for i, v := range environ { 254 environ[i] = strings.ReplaceAll(v, " ", delim) 255 } 256 b := NewIntegrationTestBuilder( 257 IntegrationTestConfig{ 258 T: t, 259 TxtarString: files, 260 Environ: environ, 261 BuildCfg: BuildCfg{SkipRender: true}, 262 }, 263 ).Build() 264 265 conf := b.H.Configs.Base 266 b.Assert(conf.DisableLanguages, qt.DeepEquals, []string{"sv", "no"}) 267 b.Assert(conf.DisableKinds, qt.DeepEquals, []string{"taxonomy", "term"}) 268 } 269 } 270 271 func TestLoadMultiConfig(t *testing.T) { 272 t.Parallel() 273 274 c := qt.New(t) 275 276 // Add a random config variable for testing. 277 // side = page in Norwegian. 278 configContentBase := ` 279 Paginate = 32 280 PaginatePath = "side" 281 ` 282 configContentSub := ` 283 PaginatePath = "top" 284 ` 285 mm := afero.NewMemMapFs() 286 287 writeToFs(t, mm, "base.toml", configContentBase) 288 289 writeToFs(t, mm, "override.toml", configContentSub) 290 291 all, err := allconfig.LoadConfig(allconfig.ConfigSourceDescriptor{Fs: mm, Filename: "base.toml,override.toml"}) 292 c.Assert(err, qt.IsNil) 293 cfg := all.Base 294 295 c.Assert(cfg.PaginatePath, qt.Equals, "top") 296 c.Assert(cfg.Paginate, qt.Equals, 32) 297 } 298 299 func TestLoadConfigFromThemes(t *testing.T) { 300 t.Parallel() 301 302 c := qt.New(t) 303 304 mainConfigTemplate := ` 305 theme = "test-theme" 306 baseURL = "https://example.com/" 307 308 [frontmatter] 309 date = ["date","publishDate"] 310 311 [params] 312 MERGE_PARAMS 313 p1 = "p1 main" 314 [params.b] 315 b1 = "b1 main" 316 [params.b.c] 317 bc1 = "bc1 main" 318 319 [mediaTypes] 320 [mediaTypes."text/m1"] 321 suffixes = ["m1main"] 322 323 [outputFormats.o1] 324 mediaType = "text/m1" 325 baseName = "o1main" 326 327 [languages] 328 [languages.en] 329 languageName = "English" 330 [languages.en.params] 331 pl1 = "p1-en-main" 332 [languages.nb] 333 languageName = "Norsk" 334 [languages.nb.params] 335 pl1 = "p1-nb-main" 336 337 [[menu.main]] 338 name = "menu-main-main" 339 340 [[menu.top]] 341 name = "menu-top-main" 342 343 ` 344 345 themeConfig := ` 346 baseURL = "http://bep.is/" 347 348 # Can not be set in theme. 349 disableKinds = ["taxonomy", "term"] 350 351 # Can not be set in theme. 352 [frontmatter] 353 expiryDate = ["date"] 354 355 [params] 356 p1 = "p1 theme" 357 p2 = "p2 theme" 358 [params.b] 359 b1 = "b1 theme" 360 b2 = "b2 theme" 361 [params.b.c] 362 bc1 = "bc1 theme" 363 bc2 = "bc2 theme" 364 [params.b.c.d] 365 bcd1 = "bcd1 theme" 366 367 [mediaTypes] 368 [mediaTypes."text/m1"] 369 suffixes = ["m1theme"] 370 [mediaTypes."text/m2"] 371 suffixes = ["m2theme"] 372 373 [outputFormats.o1] 374 mediaType = "text/m1" 375 baseName = "o1theme" 376 [outputFormats.o2] 377 mediaType = "text/m2" 378 baseName = "o2theme" 379 380 [languages] 381 [languages.en] 382 languageName = "English2" 383 [languages.en.params] 384 pl1 = "p1-en-theme" 385 pl2 = "p2-en-theme" 386 [[languages.en.menu.main]] 387 name = "menu-lang-en-main" 388 [[languages.en.menu.theme]] 389 name = "menu-lang-en-theme" 390 [languages.nb] 391 languageName = "Norsk2" 392 [languages.nb.params] 393 pl1 = "p1-nb-theme" 394 pl2 = "p2-nb-theme" 395 top = "top-nb-theme" 396 [[languages.nb.menu.main]] 397 name = "menu-lang-nb-main" 398 [[languages.nb.menu.theme]] 399 name = "menu-lang-nb-theme" 400 [[languages.nb.menu.top]] 401 name = "menu-lang-nb-top" 402 403 [[menu.main]] 404 name = "menu-main-theme" 405 406 [[menu.thememenu]] 407 name = "menu-theme" 408 409 ` 410 411 buildForConfig := func(t testing.TB, mainConfig, themeConfig string) *sitesBuilder { 412 b := newTestSitesBuilder(t) 413 b.WithConfigFile("toml", mainConfig).WithThemeConfigFile("toml", themeConfig) 414 return b.Build(BuildCfg{}) 415 } 416 417 buildForStrategy := func(t testing.TB, s string) *sitesBuilder { 418 mainConfig := strings.ReplaceAll(mainConfigTemplate, "MERGE_PARAMS", s) 419 return buildForConfig(t, mainConfig, themeConfig) 420 } 421 422 c.Run("Merge default", func(c *qt.C) { 423 b := buildForStrategy(c, "") 424 425 got := b.Configs.Base 426 427 b.Assert(got.Params, qt.DeepEquals, maps.Params{ 428 "b": maps.Params{ 429 "b1": "b1 main", 430 "c": maps.Params{ 431 "bc1": "bc1 main", 432 "bc2": "bc2 theme", 433 "d": maps.Params{"bcd1": string("bcd1 theme")}, 434 }, 435 "b2": "b2 theme", 436 }, 437 "p2": "p2 theme", 438 "p1": "p1 main", 439 }) 440 441 c.Assert(got.BaseURL, qt.Equals, "https://example.com/") 442 }) 443 444 c.Run("Merge shallow", func(c *qt.C) { 445 b := buildForStrategy(c, fmt.Sprintf("_merge=%q", "shallow")) 446 447 got := b.Configs.Base.Params 448 449 // Shallow merge, only add new keys to params. 450 b.Assert(got, qt.DeepEquals, maps.Params{ 451 "p1": "p1 main", 452 "b": maps.Params{ 453 "b1": "b1 main", 454 "c": maps.Params{ 455 "bc1": "bc1 main", 456 }, 457 }, 458 "p2": "p2 theme", 459 }) 460 }) 461 462 c.Run("Merge no params in project", func(c *qt.C) { 463 b := buildForConfig( 464 c, 465 "baseURL=\"https://example.org\"\ntheme = \"test-theme\"\n", 466 "[params]\np1 = \"p1 theme\"\n", 467 ) 468 469 got := b.Configs.Base.Params 470 471 b.Assert(got, qt.DeepEquals, maps.Params{ 472 "p1": "p1 theme", 473 }) 474 }) 475 476 // Issue #8724 477 for _, mergeStrategy := range []string{"none", "shallow"} { 478 c.Run(fmt.Sprintf("Merge with sitemap config in theme, mergestrategy %s", mergeStrategy), func(c *qt.C) { 479 smapConfigTempl := `[sitemap] 480 changefreq = %q 481 filename = "sitemap.xml" 482 priority = 0.5` 483 484 b := buildForConfig( 485 c, 486 fmt.Sprintf("_merge=%q\nbaseURL=\"https://example.org\"\ntheme = \"test-theme\"\n", mergeStrategy), 487 "baseURL=\"http://example.com\"\n"+fmt.Sprintf(smapConfigTempl, "monthly"), 488 ) 489 490 got := b.Configs.Base 491 492 if mergeStrategy == "none" { 493 b.Assert(got.Sitemap, qt.DeepEquals, config.SitemapConfig{ChangeFreq: "", Priority: -1, Filename: "sitemap.xml"}) 494 495 b.AssertFileContent("public/sitemap.xml", "schemas/sitemap") 496 } else { 497 b.Assert(got.Sitemap, qt.DeepEquals, config.SitemapConfig{ChangeFreq: "monthly", Priority: -1, Filename: "sitemap.xml"}) 498 b.AssertFileContent("public/sitemap.xml", "<changefreq>monthly</changefreq>") 499 } 500 }) 501 } 502 } 503 504 func TestLoadConfigFromThemeDir(t *testing.T) { 505 t.Parallel() 506 507 mainConfig := ` 508 theme = "test-theme" 509 510 [params] 511 m1 = "mv1" 512 ` 513 514 themeConfig := ` 515 [params] 516 t1 = "tv1" 517 t2 = "tv2" 518 ` 519 520 themeConfigDir := filepath.Join("themes", "test-theme", "config") 521 themeConfigDirDefault := filepath.Join(themeConfigDir, "_default") 522 themeConfigDirProduction := filepath.Join(themeConfigDir, "production") 523 524 projectConfigDir := "config" 525 526 b := newTestSitesBuilder(t) 527 b.WithConfigFile("toml", mainConfig).WithThemeConfigFile("toml", themeConfig) 528 b.Assert(b.Fs.Source.MkdirAll(themeConfigDirDefault, 0o777), qt.IsNil) 529 b.Assert(b.Fs.Source.MkdirAll(themeConfigDirProduction, 0o777), qt.IsNil) 530 b.Assert(b.Fs.Source.MkdirAll(projectConfigDir, 0o777), qt.IsNil) 531 532 b.WithSourceFile(filepath.Join(projectConfigDir, "config.toml"), `[params] 533 m2 = "mv2" 534 `) 535 b.WithSourceFile(filepath.Join(themeConfigDirDefault, "config.toml"), `[params] 536 t2 = "tv2d" 537 t3 = "tv3d" 538 `) 539 540 b.WithSourceFile(filepath.Join(themeConfigDirProduction, "config.toml"), `[params] 541 t3 = "tv3p" 542 `) 543 544 b.Build(BuildCfg{}) 545 546 got := b.Configs.Base.Params 547 548 b.Assert(got, qt.DeepEquals, maps.Params{ 549 "t3": "tv3p", 550 "m1": "mv1", 551 "t1": "tv1", 552 "t2": "tv2d", 553 }) 554 } 555 556 func TestPrivacyConfig(t *testing.T) { 557 t.Parallel() 558 559 c := qt.New(t) 560 561 tomlConfig := ` 562 563 someOtherValue = "foo" 564 565 [privacy] 566 [privacy.youtube] 567 privacyEnhanced = true 568 ` 569 570 b := newTestSitesBuilder(t) 571 b.WithConfigFile("toml", tomlConfig) 572 b.Build(BuildCfg{SkipRender: true}) 573 574 c.Assert(b.H.Sites[0].Config().Privacy.YouTube.PrivacyEnhanced, qt.Equals, true) 575 } 576 577 func TestLoadConfigModules(t *testing.T) { 578 t.Parallel() 579 580 c := qt.New(t) 581 582 // https://github.com/neohugo/neohugoThemes#themetoml 583 584 const ( 585 // Before Hugo 0.56 each theme/component could have its own theme.toml 586 // with some settings, mostly used on the Hugo themes site. 587 // To preserve combability we read these files into the new "modules" 588 // section in config.toml. 589 o1t = ` 590 name = "Component o1" 591 license = "MIT" 592 min_version = 0.38 593 ` 594 // This is the component's config.toml, using the old theme syntax. 595 o1c = ` 596 theme = ["n2"] 597 ` 598 599 n1 = ` 600 title = "Component n1" 601 602 [module] 603 description = "Component n1 description" 604 [module.hugoVersion] 605 min = "0.40.0" 606 max = "0.50.0" 607 extended = true 608 [[module.imports]] 609 path="o1" 610 [[module.imports]] 611 path="n3" 612 613 614 ` 615 616 n2 = ` 617 title = "Component n2" 618 ` 619 620 n3 = ` 621 title = "Component n3" 622 ` 623 624 n4 = ` 625 title = "Component n4" 626 ` 627 ) 628 629 b := newTestSitesBuilder(t) 630 631 writeThemeFiles := func(name, configTOML, themeTOML string) { 632 b.WithSourceFile(filepath.Join("themes", name, "data", "module.toml"), fmt.Sprintf("name=%q", name)) 633 if configTOML != "" { 634 b.WithSourceFile(filepath.Join("themes", name, "config.toml"), configTOML) 635 } 636 if themeTOML != "" { 637 b.WithSourceFile(filepath.Join("themes", name, "theme.toml"), themeTOML) 638 } 639 } 640 641 writeThemeFiles("n1", n1, "") 642 writeThemeFiles("n2", n2, "") 643 writeThemeFiles("n3", n3, "") 644 writeThemeFiles("n4", n4, "") 645 writeThemeFiles("o1", o1c, o1t) 646 647 b.WithConfigFile("toml", ` 648 [module] 649 [[module.imports]] 650 path="n1" 651 [[module.imports]] 652 path="n4" 653 654 `) 655 656 b.Build(BuildCfg{}) 657 658 modulesClient := b.H.Configs.ModulesClient 659 var graphb bytes.Buffer 660 c.Assert(modulesClient.Graph(&graphb), qt.IsNil) 661 662 expected := `project n1 663 n1 o1 664 o1 n2 665 n1 n3 666 project n4 667 ` 668 669 c.Assert(graphb.String(), qt.Equals, expected) 670 } 671 672 func TestInvalidDefaultMarkdownHandler(t *testing.T) { 673 t.Parallel() 674 675 files := ` 676 -- config.toml -- 677 [markup] 678 defaultMarkdownHandler = 'blackfriday' 679 -- content/_index.md -- 680 ## Foo 681 -- layouts/index.html -- 682 {{ .Content }} 683 684 ` 685 686 b, err := NewIntegrationTestBuilder( 687 IntegrationTestConfig{ 688 T: t, 689 TxtarString: files, 690 }, 691 ).BuildE() 692 693 b.Assert(err, qt.IsNotNil) 694 b.Assert(err.Error(), qt.Contains, "Configured defaultMarkdownHandler \"blackfriday\" not found. Did you mean to use goldmark? Blackfriday was removed in Hugo v0.100.0.") 695 } 696 697 // Issue 8979 698 func TestHugoConfig(t *testing.T) { 699 filesTemplate := ` 700 -- hugo.toml -- 701 theme = "mytheme" 702 [social] 703 twitter = "bepsays" 704 [author] 705 name = "bep" 706 [params] 707 rootparam = "rootvalue" 708 -- config/_default/hugo.toml -- 709 [params] 710 rootconfigparam = "rootconfigvalue" 711 -- themes/mytheme/config/_default/hugo.toml -- 712 [params] 713 themeconfigdirparam = "themeconfigdirvalue" 714 -- themes/mytheme/hugo.toml -- 715 [params] 716 themeparam = "themevalue" 717 -- layouts/index.html -- 718 rootparam: {{ site.Params.rootparam }} 719 rootconfigparam: {{ site.Params.rootconfigparam }} 720 themeparam: {{ site.Params.themeparam }} 721 themeconfigdirparam: {{ site.Params.themeconfigdirparam }} 722 social: {{ site.Social }} 723 author: {{ site.Author }} 724 725 726 ` 727 728 for _, configName := range []string{"hugo.toml", "config.toml"} { 729 configName := configName 730 t.Run(configName, func(t *testing.T) { 731 t.Parallel() 732 733 files := strings.ReplaceAll(filesTemplate, "hugo.toml", configName) 734 735 b, err := NewIntegrationTestBuilder( 736 IntegrationTestConfig{ 737 T: t, 738 TxtarString: files, 739 }, 740 ).BuildE() 741 742 b.Assert(err, qt.IsNil) 743 b.AssertFileContent("public/index.html", 744 "rootparam: rootvalue", 745 "rootconfigparam: rootconfigvalue", 746 "themeparam: themevalue", 747 "themeconfigdirparam: themeconfigdirvalue", 748 "social: map[twitter:bepsays]", 749 "author: map[name:bep]", 750 ) 751 }) 752 } 753 } 754 755 // Issue #11089 756 func TestHugoConfigSliceOverrides(t *testing.T) { 757 t.Parallel() 758 759 filesTemplate := ` 760 -- hugo.toml -- 761 disableKinds = ["section"] 762 [languages] 763 [languages.en] 764 disableKinds = [] 765 title = "English" 766 weigHt = WEIGHT_EN 767 [languages.sv] 768 title = "Swedish" 769 wEight = WEIGHT_SV 770 disableKinds = ["page"] 771 -- layouts/index.html -- 772 Home: {{ .Lang}}|{{ len site.RegularPages }}| 773 -- layouts/_default/single.html -- 774 Single. 775 -- content/p1.en.md -- 776 -- content/p2.en.md -- 777 -- content/p1.sv.md -- 778 -- content/p2.sv.md -- 779 780 ` 781 782 t.Run("En first", func(t *testing.T) { 783 files := strings.ReplaceAll(filesTemplate, "WEIGHT_EN", "1") 784 files = strings.ReplaceAll(files, "WEIGHT_SV", "2") 785 786 cfg := config.New() 787 b, err := NewIntegrationTestBuilder( 788 IntegrationTestConfig{ 789 T: t, 790 TxtarString: files, 791 BaseCfg: cfg, 792 }, 793 ).BuildE() 794 795 b.Assert(err, qt.IsNil) 796 b.AssertFileContent("public/index.html", "Home: en|2|") 797 b.AssertFileContent("public/sv/index.html", "Home: sv|0|") 798 }) 799 800 t.Run("Sv first", func(t *testing.T) { 801 files := strings.ReplaceAll(filesTemplate, "WEIGHT_EN", "2") 802 files = strings.ReplaceAll(files, "WEIGHT_SV", "1") 803 804 for i := 0; i < 20; i++ { 805 cfg := config.New() 806 b, err := NewIntegrationTestBuilder( 807 IntegrationTestConfig{ 808 T: t, 809 TxtarString: files, 810 BaseCfg: cfg, 811 }, 812 ).BuildE() 813 814 b.Assert(err, qt.IsNil) 815 b.AssertFileContent("public/index.html", "Home: en|2|") 816 b.AssertFileContent("public/sv/index.html", "Home: sv|0|") 817 } 818 }) 819 } 820 821 func TestConfigOutputFormatDefinedInTheme(t *testing.T) { 822 t.Parallel() 823 824 files := ` 825 -- hugo.toml -- 826 theme = "mytheme" 827 [outputFormats] 828 [outputFormats.myotherformat] 829 baseName = 'myotherindex' 830 mediaType = 'text/html' 831 [outputs] 832 home = ['myformat'] 833 -- themes/mytheme/hugo.toml -- 834 [outputFormats] 835 [outputFormats.myformat] 836 baseName = 'myindex' 837 mediaType = 'text/html' 838 -- layouts/index.html -- 839 Home. 840 841 842 843 ` 844 845 b, err := NewIntegrationTestBuilder( 846 IntegrationTestConfig{ 847 T: t, 848 TxtarString: files, 849 }, 850 ).BuildE() 851 852 b.Assert(err, qt.IsNil) 853 b.AssertFileContent("public/myindex.html", "Home.") 854 } 855 856 func TestConfigParamSetOnLanguageLevel(t *testing.T) { 857 t.Skip("this has correctly started to fail now.") 858 t.Parallel() 859 860 files := ` 861 -- hugo.toml -- 862 disableKinds = ["taxonomy", "term", "RSS", "sitemap", "robotsTXT"] 863 [languages] 864 [languages.en] 865 title = "English Title" 866 thisIsAParam = "thisIsAParamValue" 867 [languages.en.params] 868 myparam = "enParamValue" 869 [languages.sv] 870 title = "Svensk Title" 871 [languages.sv.params] 872 myparam = "svParamValue" 873 -- layouts/index.html -- 874 MyParam: {{ site.Params.myparam }} 875 ThisIsAParam: {{ site.Params.thisIsAParam }} 876 877 878 ` 879 880 b, err := NewIntegrationTestBuilder( 881 IntegrationTestConfig{ 882 T: t, 883 TxtarString: files, 884 }, 885 ).BuildE() 886 887 b.Assert(err, qt.IsNil) 888 b.AssertFileContent("public/index.html", ` 889 MyParam: enParamValue 890 ThisIsAParam: thisIsAParamValue 891 `) 892 } 893 894 func TestReproCommentsIn10947(t *testing.T) { 895 t.Parallel() 896 897 files := ` 898 -- hugo.toml -- 899 baseURL = "https://example.com" 900 disableKinds = ["taxonomy", "term", "RSS", "sitemap", "robotsTXT"] 901 [languages] 902 [languages.en] 903 languageCode = "en-US" 904 title = "English Title" 905 [languages.en.params] 906 myparam = "enParamValue" 907 [languages.sv] 908 title = "Svensk Title" 909 [languages.sv.params] 910 myparam = "svParamValue" 911 -- content/mysection/_index.en.md -- 912 --- 913 title: "My English Section" 914 --- 915 -- content/mysection/_index.sv.md -- 916 --- 917 title: "My Swedish Section" 918 --- 919 -- layouts/index.html -- 920 LanguageCode: {{ eq site.LanguageCode site.Language.LanguageCode }}|{{ site.Language.LanguageCode }}| 921 {{ range $i, $e := (slice site .Site) }} 922 {{ $i }}|AllPages: {{ len .AllPages }}|Sections: {{ if .Sections }}true{{ end }}| Author: {{ .Authors }}|BuildDrafts: {{ .BuildDrafts }}|IsMultiLingual: {{ .IsMultiLingual }}|Param: {{ .Language.Params.myparam }}|Language string: {{ .Language }}|Languages: {{ .Languages }} 923 {{ end }} 924 925 926 927 ` 928 b := NewIntegrationTestBuilder( 929 IntegrationTestConfig{ 930 T: t, 931 TxtarString: files, 932 LogLevel: logg.LevelWarn, 933 }, 934 ).Build() 935 936 { 937 b.Assert(b.H.Log.LoggCount(logg.LevelWarn), qt.Equals, 1) 938 } 939 b.AssertFileContent("public/index.html", ` 940 AllPages: 4| 941 Sections: true| 942 Param: enParamValue 943 Param: enParamValue 944 IsMultiLingual: true 945 LanguageCode: true|en-US| 946 `) 947 948 b.AssertFileContent("public/sv/index.html", ` 949 Param: svParamValue 950 LanguageCode: true|sv| 951 952 `) 953 } 954 955 func TestConfigEmptyMainSections(t *testing.T) { 956 t.Parallel() 957 958 files := ` 959 -- hugo.yml -- 960 params: 961 mainSections: 962 -- content/mysection/_index.md -- 963 -- content/mysection/mycontent.md -- 964 -- layouts/index.html -- 965 mainSections: {{ site.Params.mainSections }} 966 967 ` 968 b := Test(t, files) 969 970 b.AssertFileContent("public/index.html", ` 971 mainSections: [] 972 `) 973 } 974 975 func TestConfigHugoWorkingDir(t *testing.T) { 976 t.Parallel() 977 978 files := ` 979 -- hugo.toml -- 980 -- layouts/index.html -- 981 WorkingDir: {{ hugo.WorkingDir }}| 982 983 ` 984 b := NewIntegrationTestBuilder( 985 IntegrationTestConfig{ 986 T: t, 987 TxtarString: files, 988 WorkingDir: "myworkingdir", 989 }, 990 ).Build() 991 992 b.AssertFileContent("public/index.html", ` 993 WorkingDir: myworkingdir| 994 `) 995 } 996 997 func TestConfigMergeLanguageDeepEmptyLefSide(t *testing.T) { 998 t.Parallel() 999 1000 files := ` 1001 -- hugo.toml -- 1002 [params] 1003 p1 = "p1base" 1004 [languages.en] 1005 languageCode = 'en-US' 1006 languageName = 'English' 1007 weight = 1 1008 [languages.en.markup.goldmark.extensions.typographer] 1009 leftDoubleQuote = '“' # default “ 1010 rightDoubleQuote = '”' # default ” 1011 1012 [languages.de] 1013 languageCode = 'de-DE' 1014 languageName = 'Deutsch' 1015 weight = 2 1016 [languages.de.params] 1017 p1 = "p1de" 1018 [languages.de.markup.goldmark.extensions.typographer] 1019 leftDoubleQuote = '«' # default “ 1020 rightDoubleQuote = '»' # default ” 1021 -- layouts/index.html -- 1022 {{ .Content }} 1023 p1: {{ site.Params.p1 }}| 1024 -- content/_index.en.md -- 1025 --- 1026 title: "English Title" 1027 --- 1028 A "quote" in English. 1029 -- content/_index.de.md -- 1030 --- 1031 title: "Deutsch Title" 1032 --- 1033 Ein "Zitat" auf Deutsch. 1034 1035 1036 1037 ` 1038 b := Test(t, files) 1039 1040 b.AssertFileContent("public/index.html", "p1: p1base", "<p>A “quote” in English.</p>") 1041 b.AssertFileContent("public/de/index.html", "p1: p1de", "<p>Ein «Zitat» auf Deutsch.</p>") 1042 } 1043 1044 func TestConfigLegacyValues(t *testing.T) { 1045 t.Parallel() 1046 1047 files := ` 1048 -- hugo.toml -- 1049 # taxonomyTerm was renamed to taxonomy in Hugo 0.60.0. 1050 disableKinds = ["taxonomyTerm"] 1051 1052 -- layouts/index.html -- 1053 Home 1054 1055 ` 1056 1057 b, err := NewIntegrationTestBuilder( 1058 IntegrationTestConfig{ 1059 T: t, 1060 TxtarString: files, 1061 }, 1062 ).BuildE() 1063 1064 b.Assert(err, qt.IsNil) 1065 b.AssertFileContent("public/index.html", ` 1066 Home 1067 `) 1068 1069 conf := b.H.Configs.Base 1070 b.Assert(conf.IsKindEnabled("taxonomy"), qt.Equals, false) 1071 } 1072 1073 // Issue #11000 1074 func TestConfigEmptyTOMLString(t *testing.T) { 1075 t.Parallel() 1076 1077 files := ` 1078 -- hugo.toml -- 1079 [mediaTypes] 1080 [mediaTypes."text/htaccess"] 1081 suffixes = ["htaccess"] 1082 [outputFormats] 1083 [outputFormats.htaccess] 1084 mediaType = "text/htaccess" 1085 baseName = "" 1086 isPlainText = false 1087 notAlternative = true 1088 -- content/_index.md -- 1089 --- 1090 outputs: ["html", "htaccess"] 1091 --- 1092 -- layouts/index.html -- 1093 HTML. 1094 -- layouts/_default/list.htaccess -- 1095 HTACCESS. 1096 1097 1098 1099 ` 1100 b := Test(t, files) 1101 1102 b.AssertFileContent("public/.htaccess", "HTACCESS") 1103 } 1104 1105 func TestConfigLanguageCodeTopLevel(t *testing.T) { 1106 t.Parallel() 1107 1108 files := ` 1109 -- hugo.toml -- 1110 languageCode = "en-US" 1111 -- layouts/index.html -- 1112 LanguageCode: {{ .Site.LanguageCode }}|{{ site.Language.LanguageCode }}| 1113 1114 1115 ` 1116 b := Test(t, files) 1117 1118 b.AssertFileContent("public/index.html", "LanguageCode: en-US|en-US|") 1119 } 1120 1121 // See #11159 1122 func TestConfigOutputFormatsPerLanguage(t *testing.T) { 1123 t.Parallel() 1124 1125 files := ` 1126 -- hugo.toml -- 1127 [languages] 1128 [languages.en] 1129 title = "English Title" 1130 [languages.sv] 1131 title = "Swedish Title" 1132 [languages.sv.outputFormats.html] 1133 path = "foo" 1134 [languages.sv.mediatypes."text/html"] 1135 suffixes = ["bar"] 1136 1137 -- layouts/index.html -- 1138 Home. 1139 1140 1141 ` 1142 b := Test(t, files) 1143 1144 b.AssertFileContent("public/index.html", "Home.") 1145 1146 enConfig := b.H.Sites[0].conf 1147 m, _ := enConfig.MediaTypes.Config.GetByType("text/html") 1148 b.Assert(m.Suffixes(), qt.DeepEquals, []string{"html"}) 1149 1150 svConfig := b.H.Sites[1].conf 1151 f, _ := svConfig.OutputFormats.Config.GetByName("html") 1152 b.Assert(f.Path, qt.Equals, "foo") 1153 m, _ = svConfig.MediaTypes.Config.GetByType("text/html") 1154 b.Assert(m.Suffixes(), qt.DeepEquals, []string{"bar"}) 1155 } 1156 1157 func TestConfigMiscPanics(t *testing.T) { 1158 t.Parallel() 1159 1160 // Issue 11047, 1161 t.Run("empty params", func(t *testing.T) { 1162 files := ` 1163 -- hugo.yaml -- 1164 params: 1165 -- layouts/index.html -- 1166 Foo: {{ site.Params.foo }}| 1167 1168 1169 ` 1170 b := Test(t, files) 1171 1172 b.AssertFileContent("public/index.html", "Foo: |") 1173 }) 1174 1175 // Issue 11046 1176 t.Run("invalid language setup", func(t *testing.T) { 1177 files := ` 1178 -- hugo.toml -- 1179 baseURL = "https://example.org" 1180 languageCode = "en-us" 1181 title = "Blog of me" 1182 defaultContentLanguage = "en" 1183 1184 [languages] 1185 [en] 1186 lang = "en" 1187 languageName = "English" 1188 weight = 1 1189 -- layouts/index.html -- 1190 Foo: {{ site.Params.foo }}| 1191 1192 1193 ` 1194 b, err := NewIntegrationTestBuilder( 1195 IntegrationTestConfig{ 1196 T: t, 1197 TxtarString: files, 1198 }, 1199 ).BuildE() 1200 1201 b.Assert(err, qt.IsNotNil) 1202 b.Assert(err.Error(), qt.Contains, "no languages") 1203 }) 1204 1205 // Issue 11044 1206 t.Run("invalid defaultContentLanguage", func(t *testing.T) { 1207 files := ` 1208 -- hugo.toml -- 1209 baseURL = "https://example.org" 1210 defaultContentLanguage = "sv" 1211 1212 [languages] 1213 [languages.en] 1214 languageCode = "en" 1215 languageName = "English" 1216 weight = 1 1217 1218 1219 1220 ` 1221 b, err := NewIntegrationTestBuilder( 1222 IntegrationTestConfig{ 1223 T: t, 1224 TxtarString: files, 1225 }, 1226 ).BuildE() 1227 1228 b.Assert(err, qt.IsNotNil) 1229 b.Assert(err.Error(), qt.Contains, "defaultContentLanguage does not match any language definition") 1230 }) 1231 } 1232 1233 // Issue #11040 1234 func TestConfigModuleDefaultMountsInConfig(t *testing.T) { 1235 t.Parallel() 1236 1237 files := ` 1238 -- hugo.toml -- 1239 baseURL = "https://example.org" 1240 contentDir = "mycontent" 1241 -- layouts/index.html -- 1242 Home. 1243 1244 1245 ` 1246 b := Test(t, files) 1247 1248 b.Assert(b.H.Configs.Base.Module.Mounts, qt.HasLen, 7) 1249 b.Assert(b.H.Configs.LanguageConfigSlice[0].Module.Mounts, qt.HasLen, 7) 1250 } 1251 1252 func TestDefaultContentLanguageInSubdirOnlyOneLanguage(t *testing.T) { 1253 t.Run("One language, default in sub dir", func(t *testing.T) { 1254 t.Parallel() 1255 1256 files := ` 1257 -- hugo.toml -- 1258 baseURL = "https://example.com" 1259 defaultContentLanguage = "en" 1260 defaultContentLanguageInSubdir = true 1261 disableKinds = ["taxonomy", "term", "page", "section"] 1262 -- content/foo/bar.txt -- 1263 Foo. 1264 -- layouts/index.html -- 1265 Home. 1266 ` 1267 b := Test(t, files) 1268 1269 b.AssertFileContent("public/en/index.html", "Home.") 1270 b.AssertFileContent("public/en/foo/bar.txt", "Foo.") 1271 b.AssertFileContent("public/index.html", "refresh") 1272 b.AssertFileContent("public/sitemap.xml", "sitemapindex") 1273 b.AssertFileContent("public/en/sitemap.xml", "urlset") 1274 }) 1275 1276 t.Run("Two languages, default in sub dir", func(t *testing.T) { 1277 t.Parallel() 1278 1279 files := ` 1280 -- hugo.toml -- 1281 baseURL = "https://example.com" 1282 defaultContentLanguage = "en" 1283 defaultContentLanguageInSubdir = true 1284 disableKinds = ["taxonomy", "term", "page", "section"] 1285 [languages] 1286 [languages.en] 1287 title = "English Title" 1288 [languages.sv] 1289 title = "Swedish Title" 1290 -- content/foo/bar.txt -- 1291 Foo. 1292 -- layouts/index.html -- 1293 Home. 1294 ` 1295 b := Test(t, files) 1296 1297 b.AssertFileContent("public/en/index.html", "Home.") 1298 b.AssertFileContent("public/en/foo/bar.txt", "Foo.") 1299 b.AssertFileContent("public/index.html", "refresh") 1300 b.AssertFileContent("public/sitemap.xml", "sitemapindex") 1301 b.AssertFileContent("public/en/sitemap.xml", "urlset") 1302 }) 1303 1304 t.Run("Two languages, default in root", func(t *testing.T) { 1305 t.Parallel() 1306 1307 files := ` 1308 -- hugo.toml -- 1309 baseURL = "https://example.com" 1310 defaultContentLanguage = "en" 1311 defaultContentLanguageInSubdir = false 1312 disableKinds = ["taxonomy", "term", "page", "section"] 1313 [languages] 1314 [languages.en] 1315 title = "English Title" 1316 [languages.sv] 1317 title = "Swedish Title" 1318 -- content/foo/bar.txt -- 1319 Foo. 1320 -- layouts/index.html -- 1321 Home. 1322 ` 1323 b := Test(t, files) 1324 1325 b.AssertFileContent("public/index.html", "Home.") 1326 b.AssertFileContent("public/foo/bar.txt", "Foo.") 1327 b.AssertFileContent("public/sitemap.xml", "sitemapindex") 1328 b.AssertFileContent("public/en/sitemap.xml", "urlset") 1329 }) 1330 } 1331 1332 func TestLanguagesDisabled(t *testing.T) { 1333 t.Parallel() 1334 1335 files := ` 1336 -- hugo.toml -- 1337 [languages] 1338 [languages.en] 1339 title = "English Title" 1340 [languages.sv] 1341 title = "Swedish Title" 1342 disabled = true 1343 -- layouts/index.html -- 1344 Home. 1345 1346 1347 ` 1348 b := Test(t, files) 1349 1350 b.Assert(len(b.H.Sites), qt.Equals, 1) 1351 } 1352 1353 func TestLoadConfigYamlEnvVar(t *testing.T) { 1354 defaultEnv := []string{`HUGO_OUTPUTS=home: ['json']`} 1355 1356 runVariant := func(t testing.TB, files string, env []string) *IntegrationTestBuilder { 1357 if env == nil { 1358 env = defaultEnv 1359 } 1360 1361 b := NewIntegrationTestBuilder( 1362 IntegrationTestConfig{ 1363 T: t, 1364 TxtarString: files, 1365 Environ: env, 1366 BuildCfg: BuildCfg{SkipRender: true}, 1367 }, 1368 ).Build() 1369 1370 outputs := b.H.Configs.Base.Outputs 1371 if env == nil { 1372 home := outputs["home"] 1373 b.Assert(home, qt.Not(qt.IsNil)) 1374 b.Assert(home, qt.DeepEquals, []string{"json"}) 1375 } 1376 1377 return b 1378 } 1379 1380 t.Run("with empty slice", func(t *testing.T) { 1381 t.Parallel() 1382 1383 files := ` 1384 -- hugo.toml -- 1385 baseURL = "https://example.com" 1386 disableKinds = ["taxonomy", "term", "RSS", "sitemap", "robotsTXT", "page", "section"] 1387 [outputs] 1388 home = ["html"] 1389 1390 ` 1391 b := runVariant(t, files, []string{`HUGO_OUTPUTS=section: []`}) 1392 outputs := b.H.Configs.Base.Outputs 1393 b.Assert(outputs, qt.DeepEquals, map[string][]string{ 1394 "home": {"html"}, 1395 "page": {"html"}, 1396 "rss": {"rss"}, 1397 "section": nil, 1398 "taxonomy": {"html", "rss"}, 1399 "term": {"html", "rss"}, 1400 }) 1401 }) 1402 1403 t.Run("with existing outputs", func(t *testing.T) { 1404 t.Parallel() 1405 1406 files := ` 1407 -- hugo.toml -- 1408 baseURL = "https://example.com" 1409 disableKinds = ["taxonomy", "term", "RSS", "sitemap", "robotsTXT", "page", "section"] 1410 [outputs] 1411 home = ["html"] 1412 1413 ` 1414 1415 runVariant(t, files, nil) 1416 }) 1417 1418 { 1419 t.Run("with existing outputs direct", func(t *testing.T) { 1420 t.Parallel() 1421 1422 files := ` 1423 -- hugo.toml -- 1424 baseURL = "https://example.com" 1425 disableKinds = ["taxonomy", "term", "RSS", "sitemap", "robotsTXT", "page", "section"] 1426 [outputs] 1427 home = ["html"] 1428 1429 ` 1430 runVariant(t, files, []string{"HUGO_OUTPUTS_HOME=json"}) 1431 }) 1432 } 1433 1434 t.Run("without existing outputs", func(t *testing.T) { 1435 t.Parallel() 1436 1437 files := ` 1438 -- hugo.toml -- 1439 baseURL = "https://example.com" 1440 disableKinds = ["taxonomy", "term", "RSS", "sitemap", "robotsTXT", "page", "section"] 1441 1442 ` 1443 1444 runVariant(t, files, nil) 1445 }) 1446 1447 t.Run("without existing outputs direct", func(t *testing.T) { 1448 t.Parallel() 1449 1450 files := ` 1451 -- hugo.toml -- 1452 baseURL = "https://example.com" 1453 disableKinds = ["taxonomy", "term", "RSS", "sitemap", "robotsTXT", "page", "section"] 1454 ` 1455 1456 runVariant(t, files, []string{"HUGO_OUTPUTS_HOME=json"}) 1457 }) 1458 } 1459 1460 // Issue #11257 1461 func TestDisableKindsTaxonomyTerm(t *testing.T) { 1462 t.Parallel() 1463 1464 files := ` 1465 -- hugo.toml -- 1466 baseURL = "https://example.com" 1467 disableKinds = ['taxonomyTerm'] 1468 [taxonomies] 1469 category = 'categories' 1470 -- content/p1.md -- 1471 --- 1472 title: "P1" 1473 categories: ["c1"] 1474 --- 1475 -- layouts/index.html -- 1476 Home. 1477 -- layouts/_default/list.html -- 1478 List. 1479 1480 1481 1482 ` 1483 b := Test(t, files) 1484 1485 b.AssertFileExists("public/index.html", true) 1486 b.AssertFileExists("public/categories/c1/index.html", true) 1487 b.AssertFileExists("public/categories/index.html", false) 1488 } 1489 1490 func TestKindsUnknown(t *testing.T) { 1491 t.Parallel() 1492 1493 files := ` 1494 -- hugo.toml -- 1495 disableKinds = ['foo', 'home'] 1496 [outputs] 1497 foo = ['HTML', 'AMP', 'RSS'] 1498 -- layouts/_default/list.html -- 1499 List. 1500 1501 1502 1503 ` 1504 b := NewIntegrationTestBuilder( 1505 IntegrationTestConfig{ 1506 T: t, 1507 TxtarString: files, 1508 LogLevel: logg.LevelWarn, 1509 }, 1510 ).Init() 1511 1512 b.AssertLogContains("WARN Unknown kind \"foo\" in disableKinds configuration.\n") 1513 b.AssertLogContains("WARN Unknown kind \"foo\" in outputs configuration.\n") 1514 } 1515 1516 func TestDeprecateTaxonomyTerm(t *testing.T) { 1517 t.Parallel() 1518 1519 files := ` 1520 -- hugo.toml -- 1521 disableKinds = ['taxonomyTerm'] 1522 [outputs] 1523 taxonomyterm = ['HTML', 'AMP', 'RSS'] 1524 -- layouts/_default/list.html -- 1525 List. 1526 1527 1528 1529 ` 1530 b := NewIntegrationTestBuilder( 1531 IntegrationTestConfig{ 1532 T: t, 1533 TxtarString: files, 1534 LogLevel: logg.LevelWarn, 1535 BuildCfg: BuildCfg{SkipRender: true}, 1536 }, 1537 ).Init() 1538 1539 b.AssertLogContains("WARN DEPRECATED: Kind \"taxonomyterm\" used in disableKinds is deprecated, use \"taxonomy\" instead.\n") 1540 b.AssertLogContains("WARN DEPRECATED: Kind \"taxonomyterm\" used in outputs configuration is deprecated, use \"taxonomy\" instead.\n") 1541 } 1542 1543 func TestDisableKindsIssue12144(t *testing.T) { 1544 files := ` 1545 -- hugo.toml -- 1546 disableKinds = ["page"] 1547 defaultContentLanguage = "pt-br" 1548 -- layouts/index.html -- 1549 Home. 1550 -- content/custom/index.pt-br.md -- 1551 --- 1552 title: "P1 pt" 1553 --- 1554 -- content/custom/index.en-us.md -- 1555 --- 1556 title: "P1 us" 1557 --- 1558 ` 1559 Test(t, files) 1560 }