summaryrefslogtreecommitdiffstats
path: root/hugolib
diff options
context:
space:
mode:
authorBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>2018-03-21 17:21:46 +0100
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>2018-04-02 08:06:21 +0200
commiteb42774e587816b1fbcafbcea59ed65df703882a (patch)
treefdb62cf17355b47fa485941f3c3fffd604896daa /hugolib
parentf27977809ce5d5dce4db41db6323a4ad1b095985 (diff)
Add support for a content dir set per language
A sample config: ```toml defaultContentLanguage = "en" defaultContentLanguageInSubdir = true [Languages] [Languages.en] weight = 10 title = "In English" languageName = "English" contentDir = "content/english" [Languages.nn] weight = 20 title = "På Norsk" languageName = "Norsk" contentDir = "content/norwegian" ``` The value of `contentDir` can be any valid path, even absolute path references. The only restriction is that the content dirs cannot overlap. The content files will be assigned a language by 1. The placement: `content/norwegian/post/my-post.md` will be read as Norwegian content. 2. The filename: `content/english/post/my-post.nn.md` will be read as Norwegian even if it lives in the English content folder. The content directories will be merged into a big virtual filesystem with one simple rule: The most specific language file will win. This means that if both `content/norwegian/post/my-post.md` and `content/english/post/my-post.nn.md` exists, they will be considered duplicates and the version inside `content/norwegian` will win. Note that translations will be automatically assigned by Hugo by the content file's relative placement, so `content/norwegian/post/my-post.md` will be a translation of `content/english/post/my-post.md`. If this does not work for you, you can connect the translations together by setting a `translationKey` in the content files' front matter. Fixes #4523 Fixes #4552 Fixes #4553
Diffstat (limited to 'hugolib')
-rw-r--r--hugolib/config.go8
-rw-r--r--hugolib/disableKinds_test.go4
-rw-r--r--hugolib/fileInfo.go19
-rw-r--r--hugolib/fileInfo_test.go61
-rw-r--r--hugolib/hugo_sites.go78
-rw-r--r--hugolib/hugo_sites_build_test.go52
-rw-r--r--hugolib/language_content_dir_test.go253
-rw-r--r--hugolib/menu_test.go4
-rw-r--r--hugolib/multilingual.go4
-rw-r--r--hugolib/page.go22
-rw-r--r--hugolib/page_bundler.go28
-rw-r--r--hugolib/page_bundler_capture.go185
-rw-r--r--hugolib/page_bundler_capture_test.go53
-rw-r--r--hugolib/page_bundler_handlers.go9
-rw-r--r--hugolib/page_bundler_test.go42
-rw-r--r--hugolib/page_collections.go5
-rw-r--r--hugolib/page_test.go54
-rw-r--r--hugolib/prune_resources.go10
-rw-r--r--hugolib/site.go21
-rw-r--r--hugolib/site_url_test.go2
-rw-r--r--hugolib/taxonomy_test.go4
-rw-r--r--hugolib/testhelpers_test.go23
22 files changed, 602 insertions, 339 deletions
diff --git a/hugolib/config.go b/hugolib/config.go
index 6eca1a969..9f206bc77 100644
--- a/hugolib/config.go
+++ b/hugolib/config.go
@@ -130,21 +130,17 @@ func loadLanguageSettings(cfg config.Provider, oldLangs helpers.Languages) error
} else {
languages = make(map[string]interface{})
for k, v := range languagesFromConfig {
- isDisabled := false
for _, disabled := range disableLanguages {
if disabled == defaultLang {
return fmt.Errorf("cannot disable default language %q", defaultLang)
}
if strings.EqualFold(k, disabled) {
- isDisabled = true
+ v.(map[string]interface{})["disabled"] = true
break
}
}
- if !isDisabled {
- languages[k] = v
- }
-
+ languages[k] = v
}
}
diff --git a/hugolib/disableKinds_test.go b/hugolib/disableKinds_test.go
index d689f9dcc..edada1419 100644
--- a/hugolib/disableKinds_test.go
+++ b/hugolib/disableKinds_test.go
@@ -104,8 +104,8 @@ categories:
writeSource(t, fs, "content/sect/p1.md", fmt.Sprintf(pageTemplate, "P1", "- tag1"))
- writeNewContentFile(t, fs, "Category Terms", "2017-01-01", "content/categories/_index.md", 10)
- writeNewContentFile(t, fs, "Tag1 List", "2017-01-01", "content/tags/tag1/_index.md", 10)
+ writeNewContentFile(t, fs.Source, "Category Terms", "2017-01-01", "content/categories/_index.md", 10)
+ writeNewContentFile(t, fs.Source, "Tag1 List", "2017-01-01", "content/tags/tag1/_index.md", 10)
h, err := NewHugoSites(deps.DepsCfg{Fs: fs, Cfg: cfg})
diff --git a/hugolib/fileInfo.go b/hugolib/fileInfo.go
index f819f6bfc..90cf91377 100644
--- a/hugolib/fileInfo.go
+++ b/hugolib/fileInfo.go
@@ -14,7 +14,6 @@
package hugolib
import (
- "os"
"strings"
"github.com/gohugoio/hugo/helpers"
@@ -25,11 +24,22 @@ import (
var (
_ source.File = (*fileInfo)(nil)
_ source.ReadableFile = (*fileInfo)(nil)
+ _ pathLangFile = (*fileInfo)(nil)
)
+// A partial interface to prevent ambigous compiler error.
+type basePather interface {
+ Filename() string
+ RealName() string
+ BaseDir() string
+}
+
type fileInfo struct {
bundleTp bundleDirType
+
source.ReadableFile
+ basePather
+
overriddenLang string
// Set if the content language for this file is disabled.
@@ -43,6 +53,10 @@ func (fi *fileInfo) Lang() string {
return fi.ReadableFile.Lang()
}
+func (fi *fileInfo) Filename() string {
+ return fi.basePather.Filename()
+}
+
func (fi *fileInfo) isOwner() bool {
return fi.bundleTp > bundleNot
}
@@ -55,12 +69,13 @@ func (fi *fileInfo) isContentFile() bool {
return contentFileExtensionsSet[fi.Ext()]
}
-func newFileInfo(sp *source.SourceSpec, baseDir, filename string, fi os.FileInfo, tp bundleDirType) *fileInfo {
+func newFileInfo(sp *source.SourceSpec, baseDir, filename string, fi pathLangFileFi, tp bundleDirType) *fileInfo {
baseFi := sp.NewFileInfo(baseDir, filename, tp == bundleLeaf, fi)
f := &fileInfo{
bundleTp: tp,
ReadableFile: baseFi,
+ basePather: fi,
}
lang := f.Lang()
diff --git a/hugolib/fileInfo_test.go b/hugolib/fileInfo_test.go
deleted file mode 100644
index 18579c078..000000000
--- a/hugolib/fileInfo_test.go
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright 2017-present The Hugo Authors. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package hugolib
-
-import (
- "testing"
-
- "path/filepath"
-
- "github.com/gohugoio/hugo/source"
- "github.com/stretchr/testify/require"
-)
-
-func TestBundleFileInfo(t *testing.T) {
- t.Parallel()
-
- assert := require.New(t)
- cfg, fs := newTestBundleSourcesMultilingual(t)
- sourceSpec := source.NewSourceSpec(cfg, fs)
-
- for _, this := range []struct {
- filename string
- check func(f *fileInfo)
- }{
- {"/path/to/file.md", func(fi *fileInfo) {
- assert.Equal("md", fi.Ext())
- assert.Equal("en", fi.Lang())
- assert.False(fi.isOwner())
- assert.True(fi.isContentFile())
- }},
- {"/path/to/file.JPG", func(fi *fileInfo) {
- assert.Equal("jpg", fi.Ext())
- assert.False(fi.isContentFile())
- }},
- {"/path/to/file.nn.png", func(fi *fileInfo) {
- assert.Equal("png", fi.Ext())
- assert.Equal("nn", fi.Lang())
- assert.Equal("file", fi.TranslationBaseName())
- assert.False(fi.isContentFile())
- }},
- } {
- fi := newFileInfo(
- sourceSpec,
- filepath.FromSlash("/work/base"),
- filepath.FromSlash(this.filename),
- nil, bundleNot)
- this.check(fi)
- }
-
-}
diff --git a/hugolib/hugo_sites.go b/hugolib/hugo_sites.go
index 4e802270d..f0eb21dc1 100644
--- a/hugolib/hugo_sites.go
+++ b/hugolib/hugo_sites.go
@@ -75,19 +75,8 @@ func (h *HugoSites) langSite() map[string]*Site {
// GetContentPage finds a Page with content given the absolute filename.
// Returns nil if none found.
func (h *HugoSites) GetContentPage(filename string) *Page {
- s := h.Sites[0]
- contendDir := filepath.Join(s.PathSpec.AbsPathify(s.Cfg.GetString("contentDir")))
- if !strings.HasPrefix(filename, contendDir) {
- return nil
- }
-
- rel := strings.TrimPrefix(filename, contendDir)
- rel = strings.TrimPrefix(rel, helpers.FilePathSeparator)
-
for _, s := range h.Sites {
-
- pos := s.rawAllPages.findPagePosByFilePath(rel)
-
+ pos := s.rawAllPages.findPagePosByFilename(filename)
if pos == -1 {
continue
}
@@ -95,19 +84,16 @@ func (h *HugoSites) GetContentPage(filename string) *Page {
}
// If not found already, this may be bundled in another content file.
- rel = filepath.Dir(rel)
- for _, s := range h.Sites {
-
- pos := s.rawAllPages.findFirstPagePosByFilePathPrefix(rel)
+ dir := filepath.Dir(filename)
+ for _, s := range h.Sites {
+ pos := s.rawAllPages.findPagePosByFilnamePrefix(dir)
if pos == -1 {
continue
}
return s.rawAllPages[pos]
}
-
return nil
-
}
// NewHugoSites creates a new collection of sites given the input sites, building
@@ -126,18 +112,11 @@ func newHugoSites(cfg deps.DepsCfg, sites ...*Site) (*HugoSites, error) {
var contentChangeTracker *contentChangeMap
- // Only needed in server mode.
- // TODO(bep) clean up the running vs watching terms
- if cfg.Running {
- contentChangeTracker = &contentChangeMap{symContent: make(map[string]map[string]bool)}
- }
-
h := &HugoSites{
- running: cfg.Running,
- multilingual: langConfig,
- multihost: cfg.Cfg.GetBool("multihost"),
- ContentChanges: contentChangeTracker,
- Sites: sites}
+ running: cfg.Running,
+ multilingual: langConfig,
+ multihost: cfg.Cfg.GetBool("multihost"),
+ Sites: sites}
for _, s := range sites {
s.owner = h
@@ -149,6 +128,13 @@ func newHugoSites(cfg deps.DepsCfg, sites ...*Site) (*HugoSites, error) {
h.Deps = sites[0].Deps
+ // Only needed in server mode.
+ // TODO(bep) clean up the running vs watching terms
+ if cfg.Running {
+ contentChangeTracker = &contentChangeMap{pathSpec: h.PathSpec, symContent: make(map[string]map[string]bool)}
+ h.ContentChanges = contentChangeTracker
+ }
+
if err := h.initGitInfo(); err != nil {
return nil, err
}
@@ -212,6 +198,7 @@ func applyDepsIfNeeded(cfg deps.DepsCfg, sites ...*Site) error {
d.OutputFormatsConfig = s.outputFormatsConfig
s.Deps = d
}
+
s.resourceSpec, err = resource.NewSpec(s.Deps.PathSpec, s.mediaTypesConfig)
if err != nil {
return err
@@ -260,6 +247,9 @@ func createSitesFromConfig(cfg deps.DepsCfg) ([]*Site, error) {
languages := getLanguages(cfg.Cfg)
for _, lang := range languages {
+ if lang.Disabled {
+ continue
+ }
var s *Site
var err error
cfg.Language = lang
@@ -517,9 +507,9 @@ func (h *HugoSites) createMissingPages() error {
return nil
}
-func (h *HugoSites) removePageByPath(path string) {
+func (h *HugoSites) removePageByFilename(filename string) {
for _, s := range h.Sites {
- s.removePageByPath(path)
+ s.removePageFilename(filename)
}
}
@@ -671,6 +661,8 @@ type contentChangeMap struct {
branches []string
leafs []string
+ pathSpec *helpers.PathSpec
+
// Hugo supports symlinked content (both directories and files). This
// can lead to situations where the same file can be referenced from several
// locations in /content -- which is really cool, but also means we have to
@@ -683,7 +675,7 @@ type contentChangeMap struct {
func (m *contentChangeMap) add(filename string, tp bundleDirType) {
m.mu.Lock()
- dir := filepath.Dir(filename)
+ dir := filepath.Dir(filename) + helpers.FilePathSeparator
switch tp {
case bundleBranch:
m.branches = append(m.branches, dir)
@@ -698,7 +690,7 @@ func (m *contentChangeMap) add(filename string, tp bundleDirType) {
// Track the addition of bundle dirs.
func (m *contentChangeMap) handleBundles(b *bundleDirs) {
for _, bd := range b.bundles {
- m.add(bd.fi.Filename(), bd.tp)
+ m.add(bd.fi.Path(), bd.tp)
}
}
@@ -709,21 +701,21 @@ func (m *contentChangeMap) resolveAndRemove(filename string) (string, string, bu
m.mu.RLock()
defer m.mu.RUnlock()
- dir, name := filepath.Split(filename)
- dir = strings.TrimSuffix(dir, helpers.FilePathSeparator)
- fileTp, isContent := classifyBundledFile(name)
-
- // If the file itself is a bundle, no need to look further:
- if fileTp > bundleNot {
- return dir, dir, fileTp
+ // Bundles share resources, so we need to start from the virtual root.
+ relPath, _ := m.pathSpec.RelContentDir(filename)
+ dir, name := filepath.Split(relPath)
+ if !strings.HasSuffix(dir, helpers.FilePathSeparator) {
+ dir += helpers.FilePathSeparator
}
+ fileTp, _ := classifyBundledFile(name)
+
// This may be a member of a bundle. Start with branch bundles, the most specific.
- if !isContent {
+ if fileTp != bundleLeaf {
for i, b := range m.branches {
if b == dir {
m.branches = append(m.branches[:i], m.branches[i+1:]...)
- return dir, dir, bundleBranch
+ return dir, b, bundleBranch
}
}
}
@@ -732,7 +724,7 @@ func (m *contentChangeMap) resolveAndRemove(filename string) (string, string, bu
for i, l := range m.leafs {
if strings.HasPrefix(dir, l) {
m.leafs = append(m.leafs[:i], m.leafs[i+1:]...)
- return dir, dir, bundleLeaf
+ return dir, l, bundleLeaf
}
}
diff --git a/hugolib/hugo_sites_build_test.go b/hugolib/hugo_sites_build_test.go
index 5e4f171da..1626fadcf 100644
--- a/hugolib/hugo_sites_build_test.go
+++ b/hugolib/hugo_sites_build_test.go
@@ -3,6 +3,7 @@ package hugolib
import (
"bytes"
"fmt"
+ "io"
"strings"
"testing"
@@ -433,7 +434,7 @@ 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)()
+ defer leaktest.CheckTimeout(t, 10*time.Second)()
}
assert := require.New(t)
@@ -459,6 +460,8 @@ func TestMultiSitesRebuild(t *testing.T) {
b.AssertFileContent("public/fr/sect/doc1/index.html", "Single", "Shortcode: Bonjour")
b.AssertFileContent("public/en/sect/doc1-slug/index.html", "Single", "Shortcode: Hello")
+ contentFs := b.H.BaseFs.ContentFs
+
for i, this := range []struct {
preFunc func(t *testing.T)
events []fsnotify.Event
@@ -490,9 +493,9 @@ func TestMultiSitesRebuild(t *testing.T) {
},
{
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)
+ writeNewContentFile(t, contentFs, "new_en_1", "2016-07-31", "new1.en.md", -5)
+ writeNewContentFile(t, contentFs, "new_en_2", "1989-07-30", "new2.en.md", -10)
+ writeNewContentFile(t, contentFs, "new_fr_1", "2016-07-30", "new1.fr.md", 10)
},
[]fsnotify.Event{
{Name: filepath.FromSlash("content/new1.en.md"), Op: fsnotify.Create},
@@ -513,10 +516,10 @@ func TestMultiSitesRebuild(t *testing.T) {
},
{
func(t *testing.T) {
- p := "content/sect/doc1.en.md"
- doc1 := readSource(t, fs, p)
+ p := "sect/doc1.en.md"
+ doc1 := readFileFromFs(t, contentFs, p)
doc1 += "CHANGED"
- writeSource(t, fs, p, doc1)
+ writeToFs(t, contentFs, p, doc1)
},
[]fsnotify.Event{{Name: filepath.FromSlash("content/sect/doc1.en.md"), Op: fsnotify.Write}},
func(t *testing.T) {
@@ -529,7 +532,7 @@ func TestMultiSitesRebuild(t *testing.T) {
// Rename a file
{
func(t *testing.T) {
- if err := fs.Source.Rename("content/new1.en.md", "content/new1renamed.en.md"); err != nil {
+ if err := contentFs.Rename("new1.en.md", "new1renamed.en.md"); err != nil {
t.Fatalf("Rename failed: %s", err)
}
},
@@ -650,7 +653,7 @@ weight = 15
title = "Svenska"
`
- writeNewContentFile(t, fs, "Swedish Contentfile", "2016-01-01", "content/sect/doc1.sv.md", 10)
+ writeNewContentFile(t, fs.Source, "Swedish Contentfile", "2016-01-01", "content/sect/doc1.sv.md", 10)
// replace the config
b.WithNewConfig(newConfig)
@@ -1038,18 +1041,31 @@ func readFileFromFs(t testing.TB, fs afero.Fs, filename string) string {
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
- })
+ printFs(fs, root, os.Stdout)
Fatalf(t, "Failed to read file: %s", err)
}
return string(b)
}
+func printFs(fs afero.Fs, path string, w io.Writer) {
+ if fs == nil {
+ return
+ }
+ afero.Walk(fs, path, func(path string, info os.FileInfo, err error) error {
+ if info != nil && !info.IsDir() {
+ s := path
+ if lang, ok := info.(hugofs.LanguageAnnouncer); ok {
+ s = s + "\tLANG: " + lang.Lang()
+ }
+ if fp, ok := info.(hugofs.FilePather); ok {
+ s = s + "\tRF: " + fp.Filename() + "\tBP: " + fp.BaseDir()
+ }
+ fmt.Fprintln(w, " ", s)
+ }
+ return nil
+ })
+}
+
const testPageTemplate = `---
title: "%s"
publishdate: "%s"
@@ -1062,9 +1078,9 @@ 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) {
+func writeNewContentFile(t *testing.T, fs afero.Fs, title, date, filename string, weight int) {
content := newTestPage(title, date, weight)
- writeSource(t, fs, filename, content)
+ writeToFs(t, fs, filename, content)
}
type multiSiteTestBuilder struct {
diff --git a/hugolib/language_content_dir_test.go b/hugolib/language_content_dir_test.go
new file mode 100644
index 000000000..7195e8e7b
--- /dev/null
+++ b/hugolib/language_content_dir_test.go
@@ -0,0 +1,253 @@
+// Copyright 2018 The Hugo Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package hugolib
+
+import (
+ "fmt"
+ "os"
+ "path/filepath"
+ "testing"
+
+ "github.com/stretchr/testify/require"
+)
+
+/*
+
+/en/p1.md
+/nn/p1.md
+
+.Readdir
+
+- Name() => p1.en.md, p1.nn.md
+
+.Stat(name)
+
+.Open() --- real file name
+
+
+*/
+
+func TestLanguageContentRoot(t *testing.T) {
+ t.Parallel()
+ assert := require.New(t)
+
+ config := `
+baseURL = "https://example.org/"
+
+defaultContentLanguage = "en"
+defaultContentLanguageInSubdir = true
+
+contentDir = "content/main"
+workingDir = "/my/project"
+
+[Languages]
+[Languages.en]
+weight = 10
+title = "In English"
+languageName = "English"
+
+[Languages.nn]
+weight = 20
+title = "På Norsk"
+languageName = "Norsk"
+# This tells Hugo that all content in this directory is in the Norwegian language.
+# It does not have to have the "my-page.nn.md" format. It can, but that is optional.
+contentDir = "content/norsk"
+
+[Languages.sv]
+weight = 30
+title = "På Svenska"
+languageName = "Svensk"
+contentDir = "content/svensk"
+`
+
+ pageTemplate := `
+---
+title: %s
+slug: %s
+weight: %d
+---
+
+Content.
+
+`
+
+ pageBundleTemplate := `
+---
+title: %s
+weight: %d
+---
+
+Content.
+
+`
+ var contentFiles []string
+ section := "sect"
+
+ var contentRoot = func(lang string) string {
+ contentRoot := "content/main"
+
+ switch lang {
+ case "nn":
+ contentRoot = "content/norsk"
+ case "sv":
+ contentRoot = "content/svensk"
+ }
+ return contentRoot + "/" + section
+ }
+
+ for _, lang := range []string{"en", "nn", "sv"} {
+ for j := 1; j <= 10; j++ {
+ if (lang == "nn" || lang == "en") && j%4 == 0 {
+ // Skip 4 and 8 for nn
+ // We also skip it for en, but that is added to the Swedish directory below.
+ continue
+ }
+
+ if lang == "sv" && j%5 == 0 {
+ // Skip 5 and 10 for sv
+ continue
+ }
+
+ base := fmt.Sprintf("p-%s-%d", lang, j)
+ slug := fmt.Sprintf("%s", base)
+ langID := ""
+
+ if lang == "sv" && j%4 == 0 {
+ // Put an English page in the Swedish content dir.
+ langID = ".en"
+ }
+
+ if lang == "en" && j == 8 {
+ // This should win over the sv variant above.
+ langID = ".en"
+ }
+
+ slug += langID
+
+ contentRoot := contentRoot(lang)
+
+ filename := filepath.Join(contentRoot, fmt.Sprintf("page%d%s.md", j, langID))
+ contentFiles = append(contentFiles, filename, fmt.Sprintf(pageTemplate, slug, slug, j))
+ }
+ }
+
+ // Put common translations in all of them
+ for i, lang := range []string{"en", "nn", "sv"} {
+ contentRoot := contentRoot(lang)
+
+ slug := fmt.Sprintf("common_%s", lang)
+
+ filename := filepath.Join(contentRoot, "common.md")
+ contentFiles = append(contentFiles, filename, fmt.Sprintf(pageTemplate, slug, slug, 100+i))
+
+ for j, lang2 := range []string{"en", "nn", "sv"} {
+ filename := filepath.Join(contentRoot, fmt.Sprintf("translated_all.%s.md", lang2))
+ langSlug := slug + "_translated_all_" + lang2
+ contentFiles = append(contentFiles, filename, fmt.Sprintf(pageTemplate, langSlug, langSlug, 200+i+j))
+ }
+
+ for j, lang2 := range []string{"sv", "nn"} {
+ if lang == "en" {
+ continue
+ }
+ filename := filepath.Join(contentRoot, fmt.Sprintf("translated_some.%s.md", lang2))
+ langSlug := slug + "_translated_some_" + lang2
+ contentFiles = append(contentFiles, filename, fmt.Sprintf(pageTemplate, langSlug, langSlug, 300+i+j))
+ }
+ }
+
+ // Add a bundle with some images
+ for i, lang := range []string{"en", "nn", "sv"} {
+ contentRoot := contentRoot(lang)
+ slug := fmt.Sprintf("bundle_%s", lang)
+ filename := filepath.Join(contentRoot, "mybundle", "index.md")
+ contentFiles = append(contentFiles, filename, fmt.Sprintf(pageBundleTemplate, slug, 400+i))
+ if lang == "en" {
+ imageFilename := filepath.Join(contentRoot, "mybundle", "logo.png")
+ contentFiles = append(contentFiles, imageFilename, "PNG Data")
+ }
+ imageFilename := filepath.Join(contentRoot, "mybundle", "featured.png")
+ contentFiles = append(contentFiles, imageFilename, fmt.Sprintf("PNG Data for %s", lang))
+
+ // Add some bundled pages
+ contentFiles = append(contentFiles, filepath.Join(contentRoot, "mybundle", "p1.md"), fmt.Sprintf(pageBundleTemplate, slug, 401+i))
+ contentFiles = append(contentFiles, filepath.Join(contentRoot, "mybundle", "sub", "p1.md"), fmt.Sprintf(pageBundleTemplate, slug, 402+i))
+
+ }
+
+ b := newTestSitesBuilder(t)
+ b.WithWorkingDir("/my/project").WithConfigFile("toml", config).WithContent(contentFiles...).CreateSites()
+
+ _ = os.Stdout
+ //printFs(b.H.BaseFs.ContentFs, "/", os.Stdout)
+
+ b.Build(BuildCfg{})
+
+ assert.Equal(3, len(b.H.Sites))
+
+ enSite := b.H.Sites[0]
+ nnSite := b.H.Sites[1]
+ svSite := b.H.Sites[2]
+
+ //dumpPages(nnSite.RegularPages...)
+ assert.Equal(12, len(nnSite.RegularPages))
+ assert.Equal(13, len(enSite.RegularPages))
+
+ assert.Equal(10, len(svSite.RegularPages))
+
+ for i, p := range enSite.RegularPages {
+ j := i + 1
+ msg := fmt.Sprintf("Test %d", j)
+ assert.Equal("en", p.Lang(), msg)
+ assert.Equal("sect", p.Section())
+ if j < 9 {
+ if j%4 == 0 {
+ assert.Contains(p.Title(), fmt.Sprintf("p-sv-%d.en", i+1), msg)
+ } else {
+ assert.Contains(p.Title(), "p-en", msg)
+ }
+ }
+ }
+
+ // Check bundles
+ bundleEn := enSite.RegularPages[len(enSite.RegularPages)-1]
+ bundleNn := nnSite.RegularPages[len(nnSite.RegularPages)-1]
+ bundleSv := svSite.RegularPages[len(svSite.RegularPages)-1]
+
+ assert.Equal("/en/sect/mybundle/", bundleEn.RelPermalink())
+ assert.Equal("/sv/sect/mybundle/", bundleSv.RelPermalink())
+
+ assert.Equal(4, len(bundleEn.Resources))
+ assert.Equal(4, len(bundleNn.Resources))
+ assert.Equal(4, len(bundleSv.Resources))
+
+ assert.Equal("/en/sect/mybundle/logo.png", bundleEn.Resources.GetMatch("logo*").RelPermalink())
+ assert.Equal("/nn/sect/mybundle/logo.png", bundleNn.Resources.GetMatch("logo*").RelPermalink())
+ assert.Equal("/sv/sect/mybundle/logo.png", bundleSv.Resources.GetMatch("logo*").RelPermalink())
+
+ b.AssertFileContent("/my/project/public/sv/sect/mybundle/featured.png", "PNG Data for sv")
+ b.AssertFileContent("/my/project/public/nn/sect/mybundle/featured.png", "PNG Data for nn")
+ b.AssertFileContent("/my/project/public/en/sect/mybundle/featured.png", "PNG Data for en")
+ b.AssertFileContent("/my/project/public/en/sect/mybundle/logo.png", "PNG Data")
+ b.AssertFileContent("/my/project/public/sv/sect/mybundle/logo.png", "PNG Data")
+ b.AssertFileContent("/my/project/public/nn/sect/mybundle/logo.png", "PNG Data")
+