mirror of
https://github.com/gohugoio/hugo.git
synced 2024-12-29 14:12:50 +00:00
ffaec4ca8c
As an example: ```html {{ $pages := .Site.RegularPages | lang.Merge $frSite.RegularPages | lang.Merge $enSite.RegularPages }} ``` Will "fill in the gaps" in the current site with, from left to right, content from the French site, and lastly the English. Fixes #4463
1414 lines
41 KiB
Go
1414 lines
41 KiB
Go
package hugolib
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"strings"
|
|
"testing"
|
|
|
|
"html/template"
|
|
"os"
|
|
"path/filepath"
|
|
"time"
|
|
|
|
"github.com/fortytw2/leaktest"
|
|
"github.com/fsnotify/fsnotify"
|
|
"github.com/gohugoio/hugo/deps"
|
|
"github.com/gohugoio/hugo/helpers"
|
|
"github.com/gohugoio/hugo/hugofs"
|
|
"github.com/spf13/afero"
|
|
"github.com/spf13/viper"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
type testSiteConfig struct {
|
|
DefaultContentLanguage string
|
|
DefaultContentLanguageInSubdir bool
|
|
Fs afero.Fs
|
|
Running bool
|
|
}
|
|
|
|
func TestMultiSitesMainLangInRoot(t *testing.T) {
|
|
t.Parallel()
|
|
for _, b := range []bool{true, false} {
|
|
doTestMultiSitesMainLangInRoot(t, b)
|
|
}
|
|
}
|
|
|
|
func doTestMultiSitesMainLangInRoot(t *testing.T, defaultInSubDir bool) {
|
|
|
|
siteConfig := testSiteConfig{Fs: afero.NewMemMapFs(), DefaultContentLanguage: "fr", DefaultContentLanguageInSubdir: defaultInSubDir}
|
|
|
|
sites := createMultiTestSites(t, siteConfig, multiSiteTOMLConfigTemplate)
|
|
fs := sites.Fs
|
|
th := testHelper{sites.Cfg, fs, t}
|
|
|
|
err := sites.Build(BuildCfg{})
|
|
|
|
if err != nil {
|
|
t.Fatalf("Failed to build sites: %s", err)
|
|
}
|
|
|
|
require.Len(t, sites.Sites, 4)
|
|
|
|
enSite := sites.Sites[0]
|
|
frSite := sites.Sites[1]
|
|
|
|
require.Equal(t, "/en", enSite.Info.LanguagePrefix)
|
|
|
|
if defaultInSubDir {
|
|
require.Equal(t, "/fr", frSite.Info.LanguagePrefix)
|
|
} else {
|
|
require.Equal(t, "", frSite.Info.LanguagePrefix)
|
|
}
|
|
|
|
require.Equal(t, "/blog/en/foo", enSite.PathSpec.RelURL("foo", true))
|
|
|
|
doc1en := enSite.RegularPages[0]
|
|
doc1fr := frSite.RegularPages[0]
|
|
|
|
enPerm := doc1en.Permalink()
|
|
enRelPerm := doc1en.RelPermalink()
|
|
require.Equal(t, "http://example.com/blog/en/sect/doc1-slug/", enPerm)
|
|
require.Equal(t, "/blog/en/sect/doc1-slug/", enRelPerm)
|
|
|
|
frPerm := doc1fr.Permalink()
|
|
frRelPerm := doc1fr.RelPermalink()
|
|
// Main language in root
|
|
require.Equal(t, th.replaceDefaultContentLanguageValue("http://example.com/blog/fr/sect/doc1/"), frPerm)
|
|
require.Equal(t, th.replaceDefaultContentLanguageValue("/blog/fr/sect/doc1/"), frRelPerm)
|
|
|
|
th.assertFileContent("public/fr/sect/doc1/index.html", "Single", "Bonjour")
|
|
th.assertFileContent("public/en/sect/doc1-slug/index.html", "Single", "Hello")
|
|
|
|
// Check home
|
|
if defaultInSubDir {
|
|
// should have a redirect on top level.
|
|
th.assertFileContentStraight("public/index.html", `<meta http-equiv="refresh" content="0; url=http://example.com/blog/fr" />`)
|
|
} else {
|
|
// should have redirect back to root
|
|
th.assertFileContentStraight("public/fr/index.html", `<meta http-equiv="refresh" content="0; url=http://example.com/blog" />`)
|
|
}
|
|
th.assertFileContent("public/fr/index.html", "Home", "Bonjour")
|
|
th.assertFileContent("public/en/index.html", "Home", "Hello")
|
|
|
|
// Check list pages
|
|
th.assertFileContent("public/fr/sect/index.html", "List", "Bonjour")
|
|
th.assertFileContent("public/en/sect/index.html", "List", "Hello")
|
|
th.assertFileContent("public/fr/plaques/frtag1/index.html", "List", "Bonjour")
|
|
th.assertFileContent("public/en/tags/tag1/index.html", "List", "Hello")
|
|
|
|
// Check sitemaps
|
|
// Sitemaps behaves different: In a multilanguage setup there will always be a index file and
|
|
// one sitemap in each lang folder.
|
|
th.assertFileContentStraight("public/sitemap.xml",
|
|
"<loc>http://example.com/blog/en/sitemap.xml</loc>",
|
|
"<loc>http://example.com/blog/fr/sitemap.xml</loc>")
|
|
|
|
if defaultInSubDir {
|
|
th.assertFileContentStraight("public/fr/sitemap.xml", "<loc>http://example.com/blog/fr/</loc>")
|
|
} else {
|
|
th.assertFileContentStraight("public/fr/sitemap.xml", "<loc>http://example.com/blog/</loc>")
|
|
}
|
|
th.assertFileContent("public/en/sitemap.xml", "<loc>http://example.com/blog/en/</loc>")
|
|
|
|
// Check rss
|
|
th.assertFileContent("public/fr/index.xml", `<atom:link href="http://example.com/blog/fr/index.xml"`,
|
|
`rel="self" type="application/rss+xml"`)
|
|
th.assertFileContent("public/en/index.xml", `<atom:link href="http://example.com/blog/en/index.xml"`)
|
|
th.assertFileContent("public/fr/sect/index.xml", `<atom:link href="http://example.com/blog/fr/sect/index.xml"`)
|
|
th.assertFileContent("public/en/sect/index.xml", `<atom:link href="http://example.com/blog/en/sect/index.xml"`)
|
|
th.assertFileContent("public/fr/plaques/frtag1/index.xml", `<atom:link href="http://example.com/blog/fr/plaques/frtag1/index.xml"`)
|
|
th.assertFileContent("public/en/tags/tag1/index.xml", `<atom:link href="http://example.com/blog/en/tags/tag1/index.xml"`)
|
|
|
|
// Check paginators
|
|
th.assertFileContent("public/fr/page/1/index.html", `refresh" content="0; url=http://example.com/blog/fr/"`)
|
|
th.assertFileContent("public/en/page/1/index.html", `refresh" content="0; url=http://example.com/blog/en/"`)
|
|
th.assertFileContent("public/fr/page/2/index.html", "Home Page 2", "Bonjour", "http://example.com/blog/fr/")
|
|
th.assertFileContent("public/en/page/2/index.html", "Home Page 2", "Hello", "http://example.com/blog/en/")
|
|
th.assertFileContent("public/fr/sect/page/1/index.html", `refresh" content="0; url=http://example.com/blog/fr/sect/"`)
|
|
th.assertFileContent("public/en/sect/page/1/index.html", `refresh" content="0; url=http://example.com/blog/en/sect/"`)
|
|
th.assertFileContent("public/fr/sect/page/2/index.html", "List Page 2", "Bonjour", "http://example.com/blog/fr/sect/")
|
|
th.assertFileContent("public/en/sect/page/2/index.html", "List Page 2", "Hello", "http://example.com/blog/en/sect/")
|
|
th.assertFileContent("public/fr/plaques/frtag1/page/1/index.html", `refresh" content="0; url=http://example.com/blog/fr/plaques/frtag1/"`)
|
|
th.assertFileContent("public/en/tags/tag1/page/1/index.html", `refresh" content="0; url=http://example.com/blog/en/tags/tag1/"`)
|
|
th.assertFileContent("public/fr/plaques/frtag1/page/2/index.html", "List Page 2", "Bonjour", "http://example.com/blog/fr/plaques/frtag1/")
|
|
th.assertFileContent("public/en/tags/tag1/page/2/index.html", "List Page 2", "Hello", "http://example.com/blog/en/tags/tag1/")
|
|
// nn (Nynorsk) and nb (Bokmål) have custom pagePath: side ("page" in Norwegian)
|
|
th.assertFileContent("public/nn/side/1/index.html", `refresh" content="0; url=http://example.com/blog/nn/"`)
|
|
th.assertFileContent("public/nb/side/1/index.html", `refresh" content="0; url=http://example.com/blog/nb/"`)
|
|
}
|
|
|
|
func TestMultiSitesWithTwoLanguages(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
assert := require.New(t)
|
|
|
|
mm := afero.NewMemMapFs()
|
|
|
|
writeToFs(t, mm, "config.toml", `
|
|
|
|
defaultContentLanguage = "nn"
|
|
|
|
[languages]
|
|
[languages.nn]
|
|
languageName = "Nynorsk"
|
|
weight = 1
|
|
title = "Tittel på Nynorsk"
|
|
[languages.nn.params]
|
|
p1 = "p1nn"
|
|
|
|
[languages.en]
|
|
title = "Title in English"
|
|
languageName = "English"
|
|
weight = 2
|
|
[languages.en.params]
|
|
p1 = "p1en"
|
|
`,
|
|
)
|
|
|
|
cfg, err := LoadConfig(mm, "", "config.toml")
|
|
require.NoError(t, err)
|
|
|
|
fs := hugofs.NewFrom(mm, cfg)
|
|
|
|
sites, err := NewHugoSites(deps.DepsCfg{Fs: fs, Cfg: cfg})
|
|
|
|
if err != nil {
|
|
t.Fatalf("Failed to create sites: %s", err)
|
|
}
|
|
|
|
writeSource(t, fs, filepath.Join("content", "foo.md"), "foo")
|
|
|
|
// Add some data
|
|
writeSource(t, fs, filepath.Join("data", "hugo.toml"), "slogan = \"Hugo Rocks!\"")
|
|
|
|
assert.NoError(sites.Build(BuildCfg{}))
|
|
assert.Len(sites.Sites, 2)
|
|
|
|
nnSite := sites.Sites[0]
|
|
nnHome := nnSite.getPage(KindHome)
|
|
assert.Len(nnHome.AllTranslations(), 2)
|
|
assert.Len(nnHome.Translations(), 1)
|
|
assert.True(nnHome.IsTranslated())
|
|
|
|
enHome := sites.Sites[1].getPage(KindHome)
|
|
|
|
p1, err := enHome.Param("p1")
|
|
assert.NoError(err)
|
|
assert.Equal("p1en", p1)
|
|
|
|
p1, err = nnHome.Param("p1")
|
|
assert.NoError(err)
|
|
assert.Equal("p1nn", p1)
|
|
}
|
|
|
|
//
|
|
func TestMultiSitesBuild(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
for _, config := range []struct {
|
|
content string
|
|
suffix string
|
|
}{
|
|
{multiSiteTOMLConfigTemplate, "toml"},
|
|
{multiSiteYAMLConfigTemplate, "yml"},
|
|
{multiSiteJSONConfigTemplate, "json"},
|
|
} {
|
|
doTestMultiSitesBuild(t, config.content, config.suffix)
|
|
}
|
|
}
|
|
|
|
func doTestMultiSitesBuild(t *testing.T, configTemplate, configSuffix string) {
|
|
siteConfig := testSiteConfig{Fs: afero.NewMemMapFs(), DefaultContentLanguage: "fr", DefaultContentLanguageInSubdir: true}
|
|
sites := createMultiTestSitesForConfig(t, siteConfig, configTemplate, configSuffix)
|
|
|
|
require.Len(t, sites.Sites, 4)
|
|
|
|
fs := sites.Fs
|
|
th := testHelper{sites.Cfg, fs, t}
|
|
err := sites.Build(BuildCfg{})
|
|
|
|
if err != nil {
|
|
t.Fatalf("Failed to build sites: %s", err)
|
|
}
|
|
|
|
// Check site config
|
|
for _, s := range sites.Sites {
|
|
require.True(t, s.Info.defaultContentLanguageInSubdir, s.Info.Title)
|
|
require.NotNil(t, s.disabledKinds)
|
|
}
|
|
|
|
gp1 := sites.GetContentPage(filepath.FromSlash("content/sect/doc1.en.md"))
|
|
require.NotNil(t, gp1)
|
|
require.Equal(t, "doc1", gp1.title)
|
|
gp2 := sites.GetContentPage(filepath.FromSlash("content/dummysect/notfound.md"))
|
|
require.Nil(t, gp2)
|
|
|
|
enSite := sites.Sites[0]
|
|
enSiteHome := enSite.getPage(KindHome)
|
|
require.True(t, enSiteHome.IsTranslated())
|
|
|
|
require.Equal(t, "en", enSite.Language.Lang)
|
|
|
|
if len(enSite.RegularPages) != 5 {
|
|
t.Fatal("Expected 5 english pages")
|
|
}
|
|
|
|
require.Len(t, enSite.AllPages, 32, "should have 32 total pages (including translations and index types)")
|
|
|
|
doc1en := enSite.RegularPages[0]
|
|
permalink := doc1en.Permalink()
|
|
require.NoError(t, err, "permalink call failed")
|
|
require.Equal(t, "http://example.com/blog/en/sect/doc1-slug/", permalink, "invalid doc1.en permalink")
|
|
require.Len(t, doc1en.Translations(), 1, "doc1-en should have one translation, excluding itself")
|
|
|
|
doc2 := enSite.RegularPages[1]
|
|
permalink = doc2.Permalink()
|
|
require.NoError(t, err, "permalink call failed")
|
|
require.Equal(t, "http://example.com/blog/en/sect/doc2/", permalink, "invalid doc2 permalink")
|
|
|
|
doc3 := enSite.RegularPages[2]
|
|
permalink = doc3.Permalink()
|
|
// Note that /superbob is a custom URL set in frontmatter.
|
|
// We respect that URL literally (it can be /search.json)
|
|
// and do no not do any language code prefixing.
|
|
require.Equal(t, "http://example.com/blog/superbob/", permalink, "invalid doc3 permalink")
|
|
|
|
require.Equal(t, "/superbob", doc3.URL(), "invalid url, was specified on doc3")
|
|
th.assertFileContent("public/superbob/index.html", "doc3|Hello|en")
|
|
require.Equal(t, doc2.Next, doc3, "doc3 should follow doc2, in .Next")
|
|
|
|
doc1fr := doc1en.Translations()[0]
|
|
permalink = doc1fr.Permalink()
|
|
require.NoError(t, err, "permalink call failed")
|
|
require.Equal(t, "http://example.com/blog/fr/sect/doc1/", permalink, "invalid doc1fr permalink")
|
|
|
|
require.Equal(t, doc1en.Translations()[0], doc1fr, "doc1-en should have doc1-fr as translation")
|
|
require.Equal(t, doc1fr.Translations()[0], doc1en, "doc1-fr should have doc1-en as translation")
|
|
require.Equal(t, "fr", doc1fr.Language().Lang)
|
|
|
|
doc4 := enSite.AllPages[4]
|
|
permalink = doc4.Permalink()
|
|
require.Equal(t, "http://example.com/blog/fr/sect/doc4/", permalink, "invalid doc4 permalink")
|
|
require.Equal(t, "/blog/fr/sect/doc4/", doc4.URL())
|
|
|
|
require.Len(t, doc4.Translations(), 0, "found translations for doc4")
|
|
|
|
doc5 := enSite.AllPages[5]
|
|
permalink = doc5.Permalink()
|
|
require.Equal(t, "http://example.com/blog/fr/somewhere/else/doc5/", permalink, "invalid doc5 permalink")
|
|
|
|
// Taxonomies and their URLs
|
|
require.Len(t, enSite.Taxonomies, 1, "should have 1 taxonomy")
|
|
tags := enSite.Taxonomies["tags"]
|
|
require.Len(t, tags, 2, "should have 2 different tags")
|
|
require.Equal(t, tags["tag1"][0].Page, doc1en, "first tag1 page should be doc1")
|
|
|
|
frSite := sites.Sites[1]
|
|
|
|
require.Equal(t, "fr", frSite.Language.Lang)
|
|
require.Len(t, frSite.RegularPages, 4, "should have 3 pages")
|
|
require.Len(t, frSite.AllPages, 32, "should have 32 total pages (including translations and nodes)")
|
|
|
|
for _, frenchPage := range frSite.RegularPages {
|
|
require.Equal(t, "fr", frenchPage.Lang())
|
|
}
|
|
|
|
// See https://github.com/gohugoio/hugo/issues/4285
|
|
// Before Hugo 0.33 you had to be explicit with the content path to get the correct Page, which
|
|
// isn't ideal in a multilingual setup. You want a way to get the current language version if available.
|
|
// Now you can do lookups with translation base name to get that behaviour.
|
|
// Let us test all the regular page variants:
|
|
getPageDoc1En := enSite.getPage(KindPage, filepath.ToSlash(doc1en.Path()))
|
|
getPageDoc1EnBase := enSite.getPage(KindPage, "sect/doc1")
|
|
getPageDoc1Fr := frSite.getPage(KindPage, filepath.ToSlash(doc1fr.Path()))
|
|
getPageDoc1FrBase := frSite.getPage(KindPage, "sect/doc1")
|
|
require.Equal(t, doc1en, getPageDoc1En)
|
|
require.Equal(t, doc1fr, getPageDoc1Fr)
|
|
require.Equal(t, doc1en, getPageDoc1EnBase)
|
|
require.Equal(t, doc1fr, getPageDoc1FrBase)
|
|
|
|
// Check redirect to main language, French
|
|
languageRedirect := readDestination(t, fs, "public/index.html")
|
|
require.True(t, strings.Contains(languageRedirect, "0; url=http://example.com/blog/fr"), languageRedirect)
|
|
|
|
// check home page content (including data files rendering)
|
|
th.assertFileContent("public/en/index.html", "Default Home Page 1", "Hello", "Hugo Rocks!")
|
|
th.assertFileContent("public/fr/index.html", "French Home Page 1", "Bonjour", "Hugo Rocks!")
|
|
|
|
// check single page content
|
|
th.assertFileContent("public/fr/sect/doc1/index.html", "Single", "Shortcode: Bonjour", "LingoFrench")
|
|
th.assertFileContent("public/en/sect/doc1-slug/index.html", "Single", "Shortcode: Hello", "LingoDefault")
|
|
|
|
// Check node translations
|
|
homeEn := enSite.getPage(KindHome)
|
|
require.NotNil(t, homeEn)
|
|
require.Len(t, homeEn.Translations(), 3)
|
|
require.Equal(t, "fr", homeEn.Translations()[0].Lang())
|
|
require.Equal(t, "nn", homeEn.Translations()[1].Lang())
|
|
require.Equal(t, "På nynorsk", homeEn.Translations()[1].title)
|
|
require.Equal(t, "nb", homeEn.Translations()[2].Lang())
|
|
require.Equal(t, "På bokmål", homeEn.Translations()[2].title, configSuffix)
|
|
require.Equal(t, "Bokmål", homeEn.Translations()[2].Language().LanguageName, configSuffix)
|
|
|
|
sectFr := frSite.getPage(KindSection, "sect")
|
|
require.NotNil(t, sectFr)
|
|
|
|
require.Equal(t, "fr", sectFr.Lang())
|
|
require.Len(t, sectFr.Translations(), 1)
|
|
require.Equal(t, "en", sectFr.Translations()[0].Lang())
|
|
require.Equal(t, "Sects", sectFr.Translations()[0].title)
|
|
|
|
nnSite := sites.Sites[2]
|
|
require.Equal(t, "nn", nnSite.Language.Lang)
|
|
taxNn := nnSite.getPage(KindTaxonomyTerm, "lag")
|
|
require.NotNil(t, taxNn)
|
|
require.Len(t, taxNn.Translations(), 1)
|
|
require.Equal(t, "nb", taxNn.Translations()[0].Lang())
|
|
|
|
taxTermNn := nnSite.getPage(KindTaxonomy, "lag", "sogndal")
|
|
require.NotNil(t, taxTermNn)
|
|
require.Len(t, taxTermNn.Translations(), 1)
|
|
require.Equal(t, "nb", taxTermNn.Translations()[0].Lang())
|
|
|
|
// Check sitemap(s)
|
|
sitemapIndex := readDestination(t, fs, "public/sitemap.xml")
|
|
require.True(t, strings.Contains(sitemapIndex, "<loc>http://example.com/blog/en/sitemap.xml</loc>"), sitemapIndex)
|
|
require.True(t, strings.Contains(sitemapIndex, "<loc>http://example.com/blog/fr/sitemap.xml</loc>"), sitemapIndex)
|
|
sitemapEn := readDestination(t, fs, "public/en/sitemap.xml")
|
|
sitemapFr := readDestination(t, fs, "public/fr/sitemap.xml")
|
|
require.True(t, strings.Contains(sitemapEn, "http://example.com/blog/en/sect/doc2/"), sitemapEn)
|
|
require.True(t, strings.Contains(sitemapFr, "http://example.com/blog/fr/sect/doc1/"), sitemapFr)
|
|
|
|
// Check taxonomies
|
|
enTags := enSite.Taxonomies["tags"]
|
|
frTags := frSite.Taxonomies["plaques"]
|
|
require.Len(t, enTags, 2, fmt.Sprintf("Tags in en: %v", enTags))
|
|
require.Len(t, frTags, 2, fmt.Sprintf("Tags in fr: %v", frTags))
|
|
require.NotNil(t, enTags["tag1"])
|
|
require.NotNil(t, frTags["frtag1"])
|
|
readDestination(t, fs, "public/fr/plaques/frtag1/index.html")
|
|
readDestination(t, fs, "public/en/tags/tag1/index.html")
|
|
|
|
// Check Blackfriday config
|
|
require.True(t, strings.Contains(string(doc1fr.Content), "«"), string(doc1fr.Content))
|
|
require.False(t, strings.Contains(string(doc1en.Content), "«"), string(doc1en.Content))
|
|
require.True(t, strings.Contains(string(doc1en.Content), "“"), string(doc1en.Content))
|
|
|
|
// Check that the drafts etc. are not built/processed/rendered.
|
|
assertShouldNotBuild(t, sites)
|
|
|
|
// en and nn have custom site menus
|
|
require.Len(t, frSite.Menus, 0, "fr: "+configSuffix)
|
|
require.Len(t, enSite.Menus, 1, "en: "+configSuffix)
|
|
require.Len(t, nnSite.Menus, 1, "nn: "+configSuffix)
|
|
|
|
require.Equal(t, "Home", enSite.Menus["main"].ByName()[0].Name)
|
|
require.Equal(t, "Heim", nnSite.Menus["main"].ByName()[0].Name)
|
|
|
|
// Issue #1302
|
|
require.Equal(t, template.URL(""), enSite.RegularPages[0].RSSLink())
|
|
|
|
// Issue #3108
|
|
next := enSite.RegularPages[0].Next
|
|
require.NotNil(t, next)
|
|
require.Equal(t, KindPage, next.Kind)
|
|
|
|
for {
|
|
if next == nil {
|
|
break
|
|
}
|
|
require.Equal(t, KindPage, next.Kind)
|
|
next = next.Next
|
|
}
|
|
|
|
// Check bundles
|
|
bundleFr := frSite.getPage(KindPage, "bundles/b1/index.md")
|
|
require.NotNil(t, bundleFr)
|
|
require.Equal(t, "/blog/fr/bundles/b1/", bundleFr.RelPermalink())
|
|
require.Equal(t, 1, len(bundleFr.Resources))
|
|
logoFr := bundleFr.Resources.GetByPrefix("logo")
|
|
require.NotNil(t, logoFr)
|
|
require.Equal(t, "/blog/fr/bundles/b1/logo.png", logoFr.RelPermalink())
|
|
require.Contains(t, readFileFromFs(t, fs.Destination, filepath.FromSlash("public/fr/bundles/b1/logo.png")), "PNG Data")
|
|
|
|
bundleEn := enSite.getPage(KindPage, "bundles/b1/index.en.md")
|
|
require.NotNil(t, bundleEn)
|
|
require.Equal(t, "/blog/en/bundles/b1/", bundleEn.RelPermalink())
|
|
require.Equal(t, 1, len(bundleEn.Resources))
|
|
logoEn := bundleEn.Resources.GetByPrefix("logo")
|
|
require.NotNil(t, logoEn)
|
|
require.Equal(t, "/blog/en/bundles/b1/logo.png", logoEn.RelPermalink())
|
|
require.Contains(t, readFileFromFs(t, fs.Destination, filepath.FromSlash("public/en/bundles/b1/logo.png")), "PNG Data")
|
|
|
|
}
|
|
|
|
func TestMultiSitesRebuild(t *testing.T) {
|
|
// t.Parallel() not supported, see https://github.com/fortytw2/leaktest/issues/4
|
|
// This leaktest seems to be a little bit shaky on Travis.
|
|
if !isCI() {
|
|
defer leaktest.CheckTimeout(t, 30*time.Second)()
|
|
}
|
|
siteConfig := testSiteConfig{Running: true, Fs: afero.NewMemMapFs(), DefaultContentLanguage: "fr", DefaultContentLanguageInSubdir: true}
|
|
sites := createMultiTestSites(t, siteConfig, multiSiteTOMLConfigTemplate)
|
|
fs := sites.Fs
|
|
th := testHelper{sites.Cfg, fs, t}
|
|
cfg := BuildCfg{}
|
|
err := sites.Build(cfg)
|
|
|
|
if err != nil {
|
|
t.Fatalf("Failed to build sites: %s", err)
|
|
}
|
|
|
|
_, err = fs.Destination.Open("public/en/sect/doc2/index.html")
|
|
|
|
if err != nil {
|
|
t.Fatalf("Unable to locate file")
|
|
}
|
|
|
|
enSite := sites.Sites[0]
|
|
frSite := sites.Sites[1]
|
|
|
|
require.Len(t, enSite.RegularPages, 5)
|
|
require.Len(t, frSite.RegularPages, 4)
|
|
|
|
// Verify translations
|
|
th.assertFileContent("public/en/sect/doc1-slug/index.html", "Hello")
|
|
th.assertFileContent("public/fr/sect/doc1/index.html", "Bonjour")
|
|
|
|
// check single page content
|
|
th.assertFileContent("public/fr/sect/doc1/index.html", "Single", "Shortcode: Bonjour")
|
|
th.assertFileContent("public/en/sect/doc1-slug/index.html", "Single", "Shortcode: Hello")
|
|
|
|
for i, this := range []struct {
|
|
preFunc func(t *testing.T)
|
|
events []fsnotify.Event
|
|
assertFunc func(t *testing.T)
|
|
}{
|
|
// * Remove doc
|
|
// * Add docs existing languages
|
|
// (Add doc new language: TODO(bep) we should load config.toml as part of these so we can add languages).
|
|
// * Rename file
|
|
// * Change doc
|
|
// * Change a template
|
|
// * Change language file
|
|
{
|
|
func(t *testing.T) {
|
|
fs.Source.Remove("content/sect/doc2.en.md")
|
|
},
|
|
[]fsnotify.Event{{Name: filepath.FromSlash("content/sect/doc2.en.md"), Op: fsnotify.Remove}},
|
|
func(t *testing.T) {
|
|
require.Len(t, enSite.RegularPages, 4, "1 en removed")
|
|
|
|
// Check build stats
|
|
require.Equal(t, 1, enSite.draftCount, "Draft")
|
|
require.Equal(t, 1, enSite.futureCount, "Future")
|
|
require.Equal(t, 1, enSite.expiredCount, "Expired")
|
|
require.Equal(t, 0, frSite.draftCount, "Draft")
|
|
require.Equal(t, 1, frSite.futureCount, "Future")
|
|
require.Equal(t, 1, frSite.expiredCount, "Expired")
|
|
},
|
|
},
|
|
{
|
|
func(t *testing.T) {
|
|
writeNewContentFile(t, fs, "new_en_1", "2016-07-31", "content/new1.en.md", -5)
|
|
writeNewContentFile(t, fs, "new_en_2", "1989-07-30", "content/new2.en.md", -10)
|
|
writeNewContentFile(t, fs, "new_fr_1", "2016-07-30", "content/new1.fr.md", 10)
|
|
},
|
|
[]fsnotify.Event{
|
|
{Name: filepath.FromSlash("content/new1.en.md"), Op: fsnotify.Create},
|
|
{Name: filepath.FromSlash("content/new2.en.md"), Op: fsnotify.Create},
|
|
{Name: filepath.FromSlash("content/new1.fr.md"), Op: fsnotify.Create},
|
|
},
|
|
func(t *testing.T) {
|
|
require.Len(t, enSite.RegularPages, 6)
|
|
require.Len(t, enSite.AllPages, 34)
|
|
require.Len(t, frSite.RegularPages, 5)
|
|
require.Equal(t, "new_fr_1", frSite.RegularPages[3].title)
|
|
require.Equal(t, "new_en_2", enSite.RegularPages[0].title)
|
|
require.Equal(t, "new_en_1", enSite.RegularPages[1].title)
|
|
|
|
rendered := readDestination(t, fs, "public/en/new1/index.html")
|
|
require.True(t, strings.Contains(rendered, "new_en_1"), rendered)
|
|
},
|
|
},
|
|
{
|
|
func(t *testing.T) {
|
|
p := "content/sect/doc1.en.md"
|
|
doc1 := readSource(t, fs, p)
|
|
doc1 += "CHANGED"
|
|
writeSource(t, fs, p, doc1)
|
|
},
|
|
[]fsnotify.Event{{Name: filepath.FromSlash("content/sect/doc1.en.md"), Op: fsnotify.Write}},
|
|
func(t *testing.T) {
|
|
require.Len(t, enSite.RegularPages, 6)
|
|
doc1 := readDestination(t, fs, "public/en/sect/doc1-slug/index.html")
|
|
require.True(t, strings.Contains(doc1, "CHANGED"), doc1)
|
|
|
|
},
|
|
},
|
|
// Rename a file
|
|
{
|
|
func(t *testing.T) {
|
|
if err := fs.Source.Rename("content/new1.en.md", "content/new1renamed.en.md"); err != nil {
|
|
t.Fatalf("Rename failed: %s", err)
|
|
}
|
|
},
|
|
[]fsnotify.Event{
|
|
{Name: filepath.FromSlash("content/new1renamed.en.md"), Op: fsnotify.Rename},
|
|
{Name: filepath.FromSlash("content/new1.en.md"), Op: fsnotify.Rename},
|
|
},
|
|
func(t *testing.T) {
|
|
require.Len(t, enSite.RegularPages, 6, "Rename")
|
|
require.Equal(t, "new_en_1", enSite.RegularPages[1].title)
|
|
rendered := readDestination(t, fs, "public/en/new1renamed/index.html")
|
|
require.True(t, strings.Contains(rendered, "new_en_1"), rendered)
|
|
}},
|
|
{
|
|
// Change a template
|
|
func(t *testing.T) {
|
|
template := "layouts/_default/single.html"
|
|
templateContent := readSource(t, fs, template)
|
|
templateContent += "{{ print \"Template Changed\"}}"
|
|
writeSource(t, fs, template, templateContent)
|
|
},
|
|
[]fsnotify.Event{{Name: filepath.FromSlash("layouts/_default/single.html"), Op: fsnotify.Write}},
|
|
func(t *testing.T) {
|
|
require.Len(t, enSite.RegularPages, 6)
|
|
require.Len(t, enSite.AllPages, 34)
|
|
require.Len(t, frSite.RegularPages, 5)
|
|
doc1 := readDestination(t, fs, "public/en/sect/doc1-slug/index.html")
|
|
require.True(t, strings.Contains(doc1, "Template Changed"), doc1)
|
|
},
|
|
},
|
|
{
|
|
// Change a language file
|
|
func(t *testing.T) {
|
|
languageFile := "i18n/fr.yaml"
|
|
langContent := readSource(t, fs, languageFile)
|
|
langContent = strings.Replace(langContent, "Bonjour", "Salut", 1)
|
|
writeSource(t, fs, languageFile, langContent)
|
|
},
|
|
[]fsnotify.Event{{Name: filepath.FromSlash("i18n/fr.yaml"), Op: fsnotify.Write}},
|
|
func(t *testing.T) {
|
|
require.Len(t, enSite.RegularPages, 6)
|
|
require.Len(t, enSite.AllPages, 34)
|
|
require.Len(t, frSite.RegularPages, 5)
|
|
docEn := readDestination(t, fs, "public/en/sect/doc1-slug/index.html")
|
|
require.True(t, strings.Contains(docEn, "Hello"), "No Hello")
|
|
docFr := readDestination(t, fs, "public/fr/sect/doc1/index.html")
|
|
require.True(t, strings.Contains(docFr, "Salut"), "No Salut")
|
|
|
|
homeEn := enSite.getPage(KindHome)
|
|
require.NotNil(t, homeEn)
|
|
require.Len(t, homeEn.Translations(), 3)
|
|
require.Equal(t, "fr", homeEn.Translations()[0].Lang())
|
|
|
|
},
|
|
},
|
|
// Change a shortcode
|
|
{
|
|
func(t *testing.T) {
|
|
writeSource(t, fs, "layouts/shortcodes/shortcode.html", "Modified Shortcode: {{ i18n \"hello\" }}")
|
|
},
|
|
[]fsnotify.Event{
|
|
{Name: filepath.FromSlash("layouts/shortcodes/shortcode.html"), Op: fsnotify.Write},
|
|
},
|
|
func(t *testing.T) {
|
|
require.Len(t, enSite.RegularPages, 6)
|
|
require.Len(t, enSite.AllPages, 34)
|
|
require.Len(t, frSite.RegularPages, 5)
|
|
th.assertFileContent("public/fr/sect/doc1/index.html", "Single", "Modified Shortcode: Salut")
|
|
th.assertFileContent("public/en/sect/doc1-slug/index.html", "Single", "Modified Shortcode: Hello")
|
|
},
|
|
},
|
|
} {
|
|
|
|
if this.preFunc != nil {
|
|
this.preFunc(t)
|
|
}
|
|
|
|
err = sites.Build(cfg, this.events...)
|
|
|
|
if err != nil {
|
|
t.Fatalf("[%d] Failed to rebuild sites: %s", i, err)
|
|
}
|
|
|
|
this.assertFunc(t)
|
|
}
|
|
|
|
// Check that the drafts etc. are not built/processed/rendered.
|
|
assertShouldNotBuild(t, sites)
|
|
|
|
}
|
|
|
|
func assertShouldNotBuild(t *testing.T, sites *HugoSites) {
|
|
s := sites.Sites[0]
|
|
|
|
for _, p := range s.rawAllPages {
|
|
// No HTML when not processed
|
|
require.Equal(t, p.shouldBuild(), bytes.Contains(p.workContent, []byte("</")), p.BaseFileName()+": "+string(p.workContent))
|
|
require.Equal(t, p.shouldBuild(), p.Content != "", p.BaseFileName())
|
|
|
|
require.Equal(t, p.shouldBuild(), p.Content != "", p.BaseFileName())
|
|
|
|
}
|
|
}
|
|
|
|
func TestAddNewLanguage(t *testing.T) {
|
|
t.Parallel()
|
|
siteConfig := testSiteConfig{Fs: afero.NewMemMapFs(), DefaultContentLanguage: "fr", DefaultContentLanguageInSubdir: true}
|
|
|
|
sites := createMultiTestSites(t, siteConfig, multiSiteTOMLConfigTemplate)
|
|
cfg := BuildCfg{}
|
|
|
|
err := sites.Build(cfg)
|
|
|
|
if err != nil {
|
|
t.Fatalf("Failed to build sites: %s", err)
|
|
}
|
|
|
|
fs := sites.Fs
|
|
|
|
newConfig := multiSiteTOMLConfigTemplate + `
|
|
|
|
[Languages.sv]
|
|
weight = 15
|
|
title = "Svenska"
|
|
`
|
|
|
|
newConfig = createConfig(t, siteConfig, newConfig)
|
|
|
|
writeNewContentFile(t, fs, "Swedish Contentfile", "2016-01-01", "content/sect/doc1.sv.md", 10)
|
|
// replace the config
|
|
writeSource(t, fs, "multilangconfig.toml", newConfig)
|
|
|
|
// Watching does not work with in-memory fs, so we trigger a reload manually
|
|
require.NoError(t, sites.Cfg.(*helpers.Language).Cfg.(*viper.Viper).ReadInConfig())
|
|
err = sites.Build(BuildCfg{CreateSitesFromConfig: true})
|
|
|
|
if err != nil {
|
|
t.Fatalf("Failed to rebuild sites: %s", err)
|
|
}
|
|
|
|
require.Len(t, sites.Sites, 5, fmt.Sprintf("Len %d", len(sites.Sites)))
|
|
|
|
// The Swedish site should be put in the middle (language weight=15)
|
|
enSite := sites.Sites[0]
|
|
svSite := sites.Sites[1]
|
|
frSite := sites.Sites[2]
|
|
require.True(t, enSite.Language.Lang == "en", enSite.Language.Lang)
|
|
require.True(t, svSite.Language.Lang == "sv", svSite.Language.Lang)
|
|
require.True(t, frSite.Language.Lang == "fr", frSite.Language.Lang)
|
|
|
|
homeEn := enSite.getPage(KindHome)
|
|
require.NotNil(t, homeEn)
|
|
require.Len(t, homeEn.Translations(), 4)
|
|
require.Equal(t, "sv", homeEn.Translations()[0].Lang())
|
|
|
|
require.Len(t, enSite.RegularPages, 5)
|
|
require.Len(t, frSite.RegularPages, 4)
|
|
|
|
// Veriy Swedish site
|
|
require.Len(t, svSite.RegularPages, 1)
|
|
svPage := svSite.RegularPages[0]
|
|
|
|
require.Equal(t, "Swedish Contentfile", svPage.title)
|
|
require.Equal(t, "sv", svPage.Lang())
|
|
require.Len(t, svPage.Translations(), 2)
|
|
require.Len(t, svPage.AllTranslations(), 3)
|
|
require.Equal(t, "en", svPage.Translations()[0].Lang())
|
|
|
|
// Regular pages have no children
|
|
require.Len(t, svPage.Pages, 0)
|
|
require.Len(t, svPage.Data["Pages"], 0)
|
|
|
|
}
|
|
|
|
func TestChangeDefaultLanguage(t *testing.T) {
|
|
t.Parallel()
|
|
mf := afero.NewMemMapFs()
|
|
|
|
sites := createMultiTestSites(t, testSiteConfig{Fs: mf, DefaultContentLanguage: "fr", DefaultContentLanguageInSubdir: false}, multiSiteTOMLConfigTemplate)
|
|
|
|
require.Equal(t, mf, sites.Fs.Source)
|
|
|
|
cfg := BuildCfg{}
|
|
fs := sites.Fs
|
|
th := testHelper{sites.Cfg, fs, t}
|
|
|
|
err := sites.Build(cfg)
|
|
|
|
if err != nil {
|
|
t.Fatalf("Failed to build sites: %s", err)
|
|
}
|
|
|
|
th.assertFileContent("public/sect/doc1/index.html", "Single", "Bonjour")
|
|
th.assertFileContent("public/en/sect/doc2/index.html", "Single", "Hello")
|
|
|
|
newConfig := createConfig(t, testSiteConfig{Fs: mf, DefaultContentLanguage: "en", DefaultContentLanguageInSubdir: false}, multiSiteTOMLConfigTemplate)
|
|
|
|
// replace the config
|
|
writeSource(t, fs, "multilangconfig.toml", newConfig)
|
|
|
|
// Watching does not work with in-memory fs, so we trigger a reload manually
|
|
// This does not look pretty, so we should think of something else.
|
|
require.NoError(t, th.Cfg.(*helpers.Language).Cfg.(*viper.Viper).ReadInConfig())
|
|
err = sites.Build(BuildCfg{CreateSitesFromConfig: true})
|
|
|
|
if err != nil {
|
|
t.Fatalf("Failed to rebuild sites: %s", err)
|
|
}
|
|
|
|
// Default language is now en, so that should now be the "root" language
|
|
th.assertFileContent("public/fr/sect/doc1/index.html", "Single", "Bonjour")
|
|
th.assertFileContent("public/sect/doc2/index.html", "Single", "Hello")
|
|
}
|
|
|
|
func TestTableOfContentsInShortcodes(t *testing.T) {
|
|
t.Parallel()
|
|
mf := afero.NewMemMapFs()
|
|
|
|
writeToFs(t, mf, "layouts/shortcodes/toc.html", tocShortcode)
|
|
writeToFs(t, mf, "content/post/simple.en.md", tocPageSimple)
|
|
writeToFs(t, mf, "content/post/withSCInHeading.en.md", tocPageWithShortcodesInHeadings)
|
|
|
|
sites := createMultiTestSites(t, testSiteConfig{Fs: mf, DefaultContentLanguage: "en", DefaultContentLanguageInSubdir: true}, multiSiteTOMLConfigTemplate)
|
|
|
|
cfg := BuildCfg{}
|
|
|
|
err := sites.Build(cfg)
|
|
|
|
if err != nil {
|
|
t.Fatalf("Failed to build sites: %s", err)
|
|
}
|
|
|
|
fs := sites.Fs
|
|
th := testHelper{sites.Cfg, fs, t}
|
|
|
|
th.assertFileContent("public/en/post/simple/index.html", tocPageSimpleExpected)
|
|
th.assertFileContent("public/en/post/withSCInHeading/index.html", tocPageWithShortcodesInHeadingsExpected)
|
|
}
|
|
|
|
var tocShortcode = `
|
|
{{ .Page.TableOfContents }}
|
|
`
|
|
|
|
var tocPageSimple = `---
|
|
title: tocTest
|
|
publishdate: "2000-01-01"
|
|
---
|
|
|
|
{{< toc >}}
|
|
|
|
# Heading 1 {#1}
|
|
|
|
Some text.
|
|
|
|
## Subheading 1.1 {#1-1}
|
|
|
|
Some more text.
|
|
|
|
# Heading 2 {#2}
|
|
|
|
Even more text.
|
|
|
|
## Subheading 2.1 {#2-1}
|
|
|
|
Lorem ipsum...
|
|
`
|
|
|
|
var tocPageSimpleExpected = `<nav id="TableOfContents">
|
|
<ul>
|
|
<li><a href="#1">Heading 1</a>
|
|
<ul>
|
|
<li><a href="#1-1">Subheading 1.1</a></li>
|
|
</ul></li>
|
|
<li><a href="#2">Heading 2</a>
|
|
<ul>
|
|
<li><a href="#2-1">Subheading 2.1</a></li>
|
|
</ul></li>
|
|
</ul>
|
|
</nav>`
|
|
|
|
var tocPageWithShortcodesInHeadings = `---
|
|
title: tocTest
|
|
publishdate: "2000-01-01"
|
|
---
|
|
|
|
{{< toc >}}
|
|
|
|
# Heading 1 {#1}
|
|
|
|
Some text.
|
|
|
|
## Subheading 1.1 {{< shortcode >}} {#1-1}
|
|
|
|
Some more text.
|
|
|
|
# Heading 2 {{% shortcode %}} {#2}
|
|
|
|
Even more text.
|
|
|
|
## Subheading 2.1 {#2-1}
|
|
|
|
Lorem ipsum...
|
|
`
|
|
|
|
var tocPageWithShortcodesInHeadingsExpected = `<nav id="TableOfContents">
|
|
<ul>
|
|
<li><a href="#1">Heading 1</a>
|
|
<ul>
|
|
<li><a href="#1-1">Subheading 1.1 Shortcode: Hello</a></li>
|
|
</ul></li>
|
|
<li><a href="#2">Heading 2 Shortcode: Hello</a>
|
|
<ul>
|
|
<li><a href="#2-1">Subheading 2.1</a></li>
|
|
</ul></li>
|
|
</ul>
|
|
</nav>`
|
|
|
|
var multiSiteTOMLConfigTemplate = `
|
|
baseURL = "http://example.com/blog"
|
|
rssURI = "index.xml"
|
|
|
|
paginate = 1
|
|
disablePathToLower = true
|
|
defaultContentLanguage = "{{ .DefaultContentLanguage }}"
|
|
defaultContentLanguageInSubdir = {{ .DefaultContentLanguageInSubdir }}
|
|
|
|
[permalinks]
|
|
other = "/somewhere/else/:filename"
|
|
|
|
[blackfriday]
|
|
angledQuotes = true
|
|
|
|
[Taxonomies]
|
|
tag = "tags"
|
|
|
|
[Languages]
|
|
[Languages.en]
|
|
weight = 10
|
|
title = "In English"
|
|
languageName = "English"
|
|
[Languages.en.blackfriday]
|
|
angledQuotes = false
|
|
[[Languages.en.menu.main]]
|
|
url = "/"
|
|
name = "Home"
|
|
weight = 0
|
|
|
|
[Languages.fr]
|
|
weight = 20
|
|
title = "Le Français"
|
|
languageName = "Français"
|
|
[Languages.fr.Taxonomies]
|
|
plaque = "plaques"
|
|
|
|
[Languages.nn]
|
|
weight = 30
|
|
title = "På nynorsk"
|
|
languageName = "Nynorsk"
|
|
paginatePath = "side"
|
|
[Languages.nn.Taxonomies]
|
|
lag = "lag"
|
|
[[Languages.nn.menu.main]]
|
|
url = "/"
|
|
name = "Heim"
|
|
weight = 1
|
|
|
|
[Languages.nb]
|
|
weight = 40
|
|
title = "På bokmål"
|
|
languageName = "Bokmål"
|
|
paginatePath = "side"
|
|
[Languages.nb.Taxonomies]
|
|
lag = "lag"
|
|
`
|
|
|
|
var multiSiteYAMLConfigTemplate = `
|
|
baseURL: "http://example.com/blog"
|
|
rssURI: "index.xml"
|
|
|
|
disablePathToLower: true
|
|
paginate: 1
|
|
defaultContentLanguage: "{{ .DefaultContentLanguage }}"
|
|
defaultContentLanguageInSubdir: {{ .DefaultContentLanguageInSubdir }}
|
|
|
|
permalinks:
|
|
other: "/somewhere/else/:filename"
|
|
|
|
blackfriday:
|
|
angledQuotes: true
|
|
|
|
Taxonomies:
|
|
tag: "tags"
|
|
|
|
Languages:
|
|
en:
|
|
weight: 10
|
|
title: "In English"
|
|
languageName: "English"
|
|
blackfriday:
|
|
angledQuotes: false
|
|
menu:
|
|
main:
|
|
- url: "/"
|
|
name: "Home"
|
|
weight: 0
|
|
fr:
|
|
weight: 20
|
|
title: "Le Français"
|
|
languageName: "Français"
|
|
Taxonomies:
|
|
plaque: "plaques"
|
|
nn:
|
|
weight: 30
|
|
title: "På nynorsk"
|
|
languageName: "Nynorsk"
|
|
paginatePath: "side"
|
|
Taxonomies:
|
|
lag: "lag"
|
|
menu:
|
|
main:
|
|
- url: "/"
|
|
name: "Heim"
|
|
weight: 1
|
|
nb:
|
|
weight: 40
|
|
title: "På bokmål"
|
|
languageName: "Bokmål"
|
|
paginatePath: "side"
|
|
Taxonomies:
|
|
lag: "lag"
|
|
|
|
`
|
|
|
|
var multiSiteJSONConfigTemplate = `
|
|
{
|
|
"baseURL": "http://example.com/blog",
|
|
"rssURI": "index.xml",
|
|
"paginate": 1,
|
|
"disablePathToLower": true,
|
|
"defaultContentLanguage": "{{ .DefaultContentLanguage }}",
|
|
"defaultContentLanguageInSubdir": true,
|
|
"permalinks": {
|
|
"other": "/somewhere/else/:filename"
|
|
},
|
|
"blackfriday": {
|
|
"angledQuotes": true
|
|
},
|
|
"Taxonomies": {
|
|
"tag": "tags"
|
|
},
|
|
"Languages": {
|
|
"en": {
|
|
"weight": 10,
|
|
"title": "In English",
|
|
"languageName": "English",
|
|
"blackfriday": {
|
|
"angledQuotes": false
|
|
},
|
|
"menu": {
|
|
"main": [
|
|
{
|
|
"url": "/",
|
|
"name": "Home",
|
|
"weight": 0
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"fr": {
|
|
"weight": 20,
|
|
"title": "Le Français",
|
|
"languageName": "Français",
|
|
"Taxonomies": {
|
|
"plaque": "plaques"
|
|
}
|
|
},
|
|
"nn": {
|
|
"weight": 30,
|
|
"title": "På nynorsk",
|
|
"paginatePath": "side",
|
|
"languageName": "Nynorsk",
|
|
"Taxonomies": {
|
|
"lag": "lag"
|
|
},
|
|
"menu": {
|
|
"main": [
|
|
{
|
|
"url": "/",
|
|
"name": "Heim",
|
|
"weight": 1
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"nb": {
|
|
"weight": 40,
|
|
"title": "På bokmål",
|
|
"paginatePath": "side",
|
|
"languageName": "Bokmål",
|
|
"Taxonomies": {
|
|
"lag": "lag"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
`
|
|
|
|
func createMultiTestSites(t *testing.T, siteConfig testSiteConfig, tomlConfigTemplate string) *HugoSites {
|
|
return createMultiTestSitesForConfig(t, siteConfig, tomlConfigTemplate, "toml")
|
|
}
|
|
|
|
func createMultiTestSitesForConfig(t *testing.T, siteConfig testSiteConfig, configTemplate, configSuffix string) *HugoSites {
|
|
|
|
configContent := createConfig(t, siteConfig, configTemplate)
|
|
|
|
mf := siteConfig.Fs
|
|
|
|
// TODO(bep) cleanup/remove duplication, use the new testBuilder in testhelpers_test
|
|
// Add some layouts
|
|
if err := afero.WriteFile(mf,
|
|
filepath.Join("layouts", "_default/single.html"),
|
|
[]byte("Single: {{ .Title }}|{{ i18n \"hello\" }}|{{.Lang}}|{{ .Content }}"),
|
|
0755); err != nil {
|
|
t.Fatalf("Failed to write layout file: %s", err)
|
|
}
|
|
|
|
if err := afero.WriteFile(mf,
|
|
filepath.Join("layouts", "_default/list.html"),
|
|
[]byte("{{ $p := .Paginator }}List Page {{ $p.PageNumber }}: {{ .Title }}|{{ i18n \"hello\" }}|{{ .Permalink }}|Pager: {{ template \"_internal/pagination.html\" . }}"),
|
|
0755); err != nil {
|
|
t.Fatalf("Failed to write layout file: %s", err)
|
|
}
|
|
|
|
if err := afero.WriteFile(mf,
|
|
filepath.Join("layouts", "index.html"),
|
|
[]byte("{{ $p := .Paginator }}Default Home Page {{ $p.PageNumber }}: {{ .Title }}|{{ .IsHome }}|{{ i18n \"hello\" }}|{{ .Permalink }}|{{ .Site.Data.hugo.slogan }}"),
|
|
0755); err != nil {
|
|
t.Fatalf("Failed to write layout file: %s", err)
|
|
}
|
|
|
|
if err := afero.WriteFile(mf,
|
|
filepath.Join("layouts", "index.fr.html"),
|
|
[]byte("{{ $p := .Paginator }}French Home Page {{ $p.PageNumber }}: {{ .Title }}|{{ .IsHome }}|{{ i18n \"hello\" }}|{{ .Permalink }}|{{ .Site.Data.hugo.slogan }}"),
|
|
0755); err != nil {
|
|
t.Fatalf("Failed to write layout file: %s", err)
|
|
}
|
|
|
|
// Add a shortcode
|
|
if err := afero.WriteFile(mf,
|
|
filepath.Join("layouts", "shortcodes", "shortcode.html"),
|
|
[]byte("Shortcode: {{ i18n \"hello\" }}"),
|
|
0755); err != nil {
|
|
t.Fatalf("Failed to write layout file: %s", err)
|
|
}
|
|
|
|
// A shortcode in multiple languages
|
|
if err := afero.WriteFile(mf,
|
|
filepath.Join("layouts", "shortcodes", "lingo.html"),
|
|
[]byte("LingoDefault"),
|
|
0755); err != nil {
|
|
t.Fatalf("Failed to write layout file: %s", err)
|
|
}
|
|
|
|
if err := afero.WriteFile(mf,
|
|
filepath.Join("layouts", "shortcodes", "lingo.fr.html"),
|
|
[]byte("LingoFrench"),
|
|
0755); err != nil {
|
|
t.Fatalf("Failed to write layout file: %s", err)
|
|
}
|
|
|
|
// Add some language files
|
|
if err := afero.WriteFile(mf,
|
|
filepath.Join("i18n", "en.yaml"),
|
|
[]byte(`
|
|
hello:
|
|
other: "Hello"
|
|
`),
|
|
0755); err != nil {
|
|
t.Fatalf("Failed to write language file: %s", err)
|
|
}
|
|
if err := afero.WriteFile(mf,
|
|
filepath.Join("i18n", "fr.yaml"),
|
|
[]byte(`
|
|
hello:
|
|
other: "Bonjour"
|
|
`),
|
|
0755); err != nil {
|
|
t.Fatalf("Failed to write language file: %s", err)
|
|
}
|
|
|
|
// Sources
|
|
sources := [][2]string{
|
|
{filepath.FromSlash("root.en.md"), `---
|
|
title: root
|
|
weight: 10000
|
|
slug: root
|
|
publishdate: "2000-01-01"
|
|
---
|
|
# root
|
|
`},
|
|
{filepath.FromSlash("sect/doc1.en.md"), `---
|
|
title: doc1
|
|
weight: 1
|
|
slug: doc1-slug
|
|
tags:
|
|
- tag1
|
|
publishdate: "2000-01-01"
|
|
---
|
|
# doc1
|
|
*some "content"*
|
|
|
|
{{< shortcode >}}
|
|
|
|
{{< lingo >}}
|
|
|
|
NOTE: slug should be used as URL
|
|
`},
|
|
{filepath.FromSlash("sect/doc1.fr.md"), `---
|
|
title: doc1
|
|
weight: 1
|
|
plaques:
|
|
- frtag1
|
|
- frtag2
|
|
publishdate: "2000-01-04"
|
|
---
|
|
# doc1
|
|
*quelque "contenu"*
|
|
|
|
{{< shortcode >}}
|
|
|
|
{{< lingo >}}
|
|
|
|
NOTE: should be in the 'en' Page's 'Translations' field.
|
|
NOTE: date is after "doc3"
|
|
`},
|
|
{filepath.FromSlash("sect/doc2.en.md"), `---
|
|
title: doc2
|
|
weight: 2
|
|
publishdate: "2000-01-02"
|
|
---
|
|
# doc2
|
|
*some content*
|
|
NOTE: without slug, "doc2" should be used, without ".en" as URL
|
|
`},
|
|
{filepath.FromSlash("sect/doc3.en.md"), `---
|
|
title: doc3
|
|
weight: 3
|
|
publishdate: "2000-01-03"
|
|
aliases: [/en/al/alias1,/al/alias2/]
|
|
tags:
|
|
- tag2
|
|
- tag1
|
|
url: /superbob
|
|
---
|
|
# doc3
|
|
*some content*
|
|
NOTE: third 'en' doc, should trigger pagination on home page.
|
|
`},
|
|
{filepath.FromSlash("sect/doc4.md"), `---
|
|
title: doc4
|
|
weight: 4
|
|
plaques:
|
|
- frtag1
|
|
publishdate: "2000-01-05"
|
|
---
|
|
# doc4
|
|
*du contenu francophone*
|
|
NOTE: should use the defaultContentLanguage and mark this doc as 'fr'.
|
|
NOTE: doesn't have any corresponding translation in 'en'
|
|
`},
|
|
{filepath.FromSlash("other/doc5.fr.md"), `---
|
|
title: doc5
|
|
weight: 5
|
|
publishdate: "2000-01-06"
|
|
---
|
|
# doc5
|
|
*autre contenu francophone*
|
|
NOTE: should use the "permalinks" configuration with :filename
|
|
`},
|
|
// Add some for the stats
|
|
{filepath.FromSlash("stats/expired.fr.md"), `---
|
|
title: expired
|
|
publishdate: "2000-01-06"
|
|
expiryDate: "2001-01-06"
|
|
---
|
|
# Expired
|
|
`},
|
|
{filepath.FromSlash("stats/future.fr.md"), `---
|
|
title: future
|
|
weight: 6
|
|
publishdate: "2100-01-06"
|
|
---
|
|
# Future
|
|
`},
|
|
{filepath.FromSlash("stats/expired.en.md"), `---
|
|
title: expired
|
|
weight: 7
|
|
publishdate: "2000-01-06"
|
|
expiryDate: "2001-01-06"
|
|
---
|
|
# Expired
|
|
`},
|
|
{filepath.FromSlash("stats/future.en.md"), `---
|
|
title: future
|
|
weight: 6
|
|
publishdate: "2100-01-06"
|
|
---
|
|
# Future
|
|
`},
|
|
{filepath.FromSlash("stats/draft.en.md"), `---
|
|
title: expired
|
|
publishdate: "2000-01-06"
|
|
draft: true
|
|
---
|
|
# Draft
|
|
`},
|
|
{filepath.FromSlash("stats/tax.nn.md"), `---
|
|
title: Tax NN
|
|
weight: 8
|
|
publishdate: "2000-01-06"
|
|
weight: 1001
|
|
lag:
|
|
- Sogndal
|
|
---
|
|
# Tax NN
|
|
`},
|
|
{filepath.FromSlash("stats/tax.nb.md"), `---
|
|
title: Tax NB
|
|
weight: 8
|
|
publishdate: "2000-01-06"
|
|
weight: 1002
|
|
lag:
|
|
- Sogndal
|
|
---
|
|
# Tax NB
|
|
`},
|
|
// Bundle
|
|
{filepath.FromSlash("bundles/b1/index.en.md"), `---
|
|
title: Bundle EN
|
|
publishdate: "2000-01-06"
|
|
weight: 2001
|
|
---
|
|
# Bundle Content EN
|
|
`},
|
|
{filepath.FromSlash("bundles/b1/index.md"), `---
|
|
title: Bundle Default
|
|
publishdate: "2000-01-06"
|
|
weight: 2002
|
|
---
|
|
# Bundle Content Default
|
|
`},
|
|
{filepath.FromSlash("bundles/b1/logo.png"), `
|
|
PNG Data
|
|
`},
|
|
}
|
|
|
|
configFile := "multilangconfig." + configSuffix
|
|
writeToFs(t, mf, configFile, configContent)
|
|
|
|
cfg, err := LoadConfig(mf, "", configFile)
|
|
require.NoError(t, err)
|
|
|
|
fs := hugofs.NewFrom(mf, cfg)
|
|
|
|
for _, s := range sources {
|
|
if err := afero.WriteFile(mf, filepath.Join("content", s[0]), []byte(s[1]), 0755); err != nil {
|
|
t.Fatalf("Failed to write file: %s", err)
|
|
}
|
|
}
|
|
|
|
// Add some data
|
|
writeSource(t, fs, "data/hugo.toml", "slogan = \"Hugo Rocks!\"")
|
|
|
|
sites, err := NewHugoSites(deps.DepsCfg{Fs: fs, Cfg: cfg, Running: siteConfig.Running}) //, Logger: newDebugLogger()})
|
|
|
|
if err != nil {
|
|
t.Fatalf("Failed to create sites: %s", err)
|
|
}
|
|
|
|
if len(sites.Sites) == 0 {
|
|
t.Fatalf("Got %d sites", len(sites.Sites))
|
|
}
|
|
|
|
if sites.Fs.Source != mf {
|
|
t.Fatal("FS mismatch")
|
|
}
|
|
|
|
return sites
|
|
}
|
|
|
|
func writeSource(t testing.TB, fs *hugofs.Fs, filename, content string) {
|
|
writeToFs(t, fs.Source, filename, content)
|
|
}
|
|
|
|
func writeToFs(t testing.TB, fs afero.Fs, filename, content string) {
|
|
if err := afero.WriteFile(fs, filepath.FromSlash(filename), []byte(content), 0755); err != nil {
|
|
t.Fatalf("Failed to write file: %s", err)
|
|
}
|
|
}
|
|
|
|
func readDestination(t testing.TB, fs *hugofs.Fs, filename string) string {
|
|
return readFileFromFs(t, fs.Destination, filename)
|
|
}
|
|
|
|
func destinationExists(fs *hugofs.Fs, filename string) bool {
|
|
b, err := helpers.Exists(filename, fs.Destination)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return b
|
|
}
|
|
|
|
func readSource(t *testing.T, fs *hugofs.Fs, filename string) string {
|
|
return readFileFromFs(t, fs.Source, filename)
|
|
}
|
|
|
|
func readFileFromFs(t testing.TB, fs afero.Fs, filename string) string {
|
|
filename = filepath.Clean(filename)
|
|
b, err := afero.ReadFile(fs, filename)
|
|
if err != nil {
|
|
// Print some debug info
|
|
root := "" //strings.Split(filename, helpers.FilePathSeparator)[0]
|
|
afero.Walk(fs, root, func(path string, info os.FileInfo, err error) error {
|
|
if info != nil && !info.IsDir() {
|
|
fmt.Println(" ", path)
|
|
}
|
|
|
|
return nil
|
|
})
|
|
t.Fatalf("Failed to read file: %s", err)
|
|
}
|
|
return string(b)
|
|
}
|
|
|
|
const testPageTemplate = `---
|
|
title: "%s"
|
|
publishdate: "%s"
|
|
weight: %d
|
|
---
|
|
# Doc %s
|
|
`
|
|
|
|
func newTestPage(title, date string, weight int) string {
|
|
return fmt.Sprintf(testPageTemplate, title, date, weight, title)
|
|
}
|
|
|
|
func writeNewContentFile(t *testing.T, fs *hugofs.Fs, title, date, filename string, weight int) {
|
|
content := newTestPage(title, date, weight)
|
|
writeSource(t, fs, filename, content)
|
|
}
|
|
|
|
func createConfig(t *testing.T, config testSiteConfig, configTemplate string) string {
|
|
templ, err := template.New("test").Parse(configTemplate)
|
|
if err != nil {
|
|
t.Fatal("Template parse failed:", err)
|
|
}
|
|
var b bytes.Buffer
|
|
templ.Execute(&b, config)
|
|
return b.String()
|
|
}
|