summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--hugolib/hugo_sites_build_test.go36
-rw-r--r--hugolib/page.go1
-rw-r--r--hugolib/shortcode.go21
-rw-r--r--hugolib/shortcode_test.go4
-rw-r--r--output/docshelper.go1
-rw-r--r--output/layout.go84
-rw-r--r--output/layout_test.go2
7 files changed, 109 insertions, 40 deletions
diff --git a/hugolib/hugo_sites_build_test.go b/hugolib/hugo_sites_build_test.go
index c343f6087..96e2c66b2 100644
--- a/hugolib/hugo_sites_build_test.go
+++ b/hugolib/hugo_sites_build_test.go
@@ -305,12 +305,12 @@ func doTestMultiSitesBuild(t *testing.T, configTemplate, configSuffix string) {
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", "Home Page 1", "Hello", "Hugo Rocks!")
- th.assertFileContent("public/fr/index.html", "Home Page 1", "Bonjour", "Hugo Rocks!")
+ 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")
- th.assertFileContent("public/en/sect/doc1-slug/index.html", "Single", "Shortcode: Hello")
+ 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)
@@ -1042,7 +1042,14 @@ func createMultiTestSitesForConfig(t *testing.T, siteConfig testSiteConfig, conf
if err := afero.WriteFile(mf,
filepath.Join("layouts", "index.html"),
- []byte("{{ $p := .Paginator }}Home Page {{ $p.PageNumber }}: {{ .Title }}|{{ .IsHome }}|{{ i18n \"hello\" }}|{{ .Permalink }}|{{ .Site.Data.hugo.slogan }}"),
+ []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)
}
@@ -1055,6 +1062,21 @@ func createMultiTestSitesForConfig(t *testing.T, siteConfig testSiteConfig, conf
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"),
@@ -1098,6 +1120,8 @@ publishdate: "2000-01-01"
{{< shortcode >}}
+{{< lingo >}}
+
NOTE: slug should be used as URL
`)},
{Name: filepath.FromSlash("sect/doc1.fr.md"), Content: []byte(`---
@@ -1113,6 +1137,8 @@ publishdate: "2000-01-04"
{{< shortcode >}}
+{{< lingo >}}
+
NOTE: should be in the 'en' Page's 'Translations' field.
NOTE: date is after "doc3"
`)},
diff --git a/hugolib/page.go b/hugolib/page.go
index cf0a2144c..0f44b8b99 100644
--- a/hugolib/page.go
+++ b/hugolib/page.go
@@ -250,6 +250,7 @@ func (p *Page) createLayoutDescriptor() output.LayoutDescriptor {
return output.LayoutDescriptor{
Kind: p.Kind,
Type: p.Type(),
+ Lang: p.Lang(),
Layout: p.Layout,
Section: section,
}
diff --git a/hugolib/shortcode.go b/hugolib/shortcode.go
index 150d82c44..3cf472f82 100644
--- a/hugolib/shortcode.go
+++ b/hugolib/shortcode.go
@@ -157,6 +157,7 @@ func (sc shortcode) String() string {
// Note that in the below, OutputFormat may be empty.
// We will try to look for the most specific shortcode template available.
type scKey struct {
+ Lang string
OutputFormat string
Suffix string
ShortcodePlaceholder string
@@ -166,8 +167,8 @@ func newScKey(m media.Type, shortcodeplaceholder string) scKey {
return scKey{Suffix: m.Suffix, ShortcodePlaceholder: shortcodeplaceholder}
}
-func newScKeyFromOutputFormat(o output.Format, shortcodeplaceholder string) scKey {
- return scKey{Suffix: o.MediaType.Suffix, OutputFormat: o.Name, ShortcodePlaceholder: shortcodeplaceholder}
+func newScKeyFromLangAndOutputFormat(lang string, o output.Format, shortcodeplaceholder string) scKey {
+ return scKey{Lang: lang, Suffix: o.MediaType.Suffix, OutputFormat: o.Name, ShortcodePlaceholder: shortcodeplaceholder}
}
func newDefaultScKey(shortcodeplaceholder string) scKey {
@@ -251,10 +252,11 @@ const innerCleanupExpand = "$1"
func prepareShortcodeForPage(placeholder string, sc shortcode, parent *ShortcodeWithPage, p *Page) map[scKey]func() (string, error) {
m := make(map[scKey]func() (string, error))
+ lang := p.Lang()
for _, f := range p.outputFormats {
// The most specific template will win.
- key := newScKeyFromOutputFormat(f, placeholder)
+ key := newScKeyFromLangAndOutputFormat(lang, f, placeholder)
m[key] = func() (string, error) {
return renderShortcode(key, sc, nil, p), nil
}
@@ -371,9 +373,11 @@ func (s *shortcodeHandler) updateDelta() bool {
func (s *shortcodeHandler) contentShortcodesForOutputFormat(f output.Format) map[scKey]func() (string, error) {
contentShortcodesForOuputFormat := make(map[scKey]func() (string, error))
+ lang := s.p.Lang()
+
for shortcodePlaceholder := range s.shortcodes {
- key := newScKeyFromOutputFormat(f, shortcodePlaceholder)
+ key := newScKeyFromLangAndOutputFormat(lang, f, shortcodePlaceholder)
renderFn, found := s.contentShortcodes[key]
if !found {
@@ -390,7 +394,7 @@ func (s *shortcodeHandler) contentShortcodesForOutputFormat(f output.Format) map
if !found {
panic(fmt.Sprintf("Shortcode %q could not be found", shortcodePlaceholder))
}
- contentShortcodesForOuputFormat[newScKeyFromOutputFormat(f, shortcodePlaceholder)] = renderFn
+ contentShortcodesForOuputFormat[newScKeyFromLangAndOutputFormat(lang, f, shortcodePlaceholder)] = renderFn
}
return contentShortcodesForOuputFormat
@@ -676,12 +680,19 @@ func getShortcodeTemplateForTemplateKey(key scKey, shortcodeName string, t tpl.T
suffix := strings.ToLower(key.Suffix)
outFormat := strings.ToLower(key.OutputFormat)
+ lang := strings.ToLower(key.Lang)
if outFormat != "" && suffix != "" {
+ if lang != "" {
+ names = append(names, fmt.Sprintf("%s.%s.%s.%s", shortcodeName, lang, outFormat, suffix))
+ }
names = append(names, fmt.Sprintf("%s.%s.%s", shortcodeName, outFormat, suffix))
}
if suffix != "" {
+ if lang != "" {
+ names = append(names, fmt.Sprintf("%s.%s.%s", shortcodeName, lang, suffix))
+ }
names = append(names, fmt.Sprintf("%s.%s", shortcodeName, suffix))
}
diff --git a/hugolib/shortcode_test.go b/hugolib/shortcode_test.go
index 42da9e465..3d355f947 100644
--- a/hugolib/shortcode_test.go
+++ b/hugolib/shortcode_test.go
@@ -837,8 +837,8 @@ func TestReplaceShortcodeTokens(t *testing.T) {
func TestScKey(t *testing.T) {
require.Equal(t, scKey{Suffix: "xml", ShortcodePlaceholder: "ABCD"},
newScKey(media.XMLType, "ABCD"))
- require.Equal(t, scKey{Suffix: "html", OutputFormat: "AMP", ShortcodePlaceholder: "EFGH"},
- newScKeyFromOutputFormat(output.AMPFormat, "EFGH"))
+ require.Equal(t, scKey{Lang: "en", Suffix: "html", OutputFormat: "AMP", ShortcodePlaceholder: "EFGH"},
+ newScKeyFromLangAndOutputFormat("en", output.AMPFormat, "EFGH"))
require.Equal(t, scKey{Suffix: "html", ShortcodePlaceholder: "IJKL"},
newDefaultScKey("IJKL"))
diff --git a/output/docshelper.go b/output/docshelper.go
index 1df45726c..c45e956e6 100644
--- a/output/docshelper.go
+++ b/output/docshelper.go
@@ -44,6 +44,7 @@ func createLayoutExamples() interface{} {
f Format
}{
{`AMP home, with theme "demoTheme".`, LayoutDescriptor{Kind: "home"}, true, "", AMPFormat},
+ {`AMP home, French language".`, LayoutDescriptor{Kind: "home", Lang: "fr"}, false, "", AMPFormat},
{"JSON home, no theme.", LayoutDescriptor{Kind: "home"}, false, "", JSONFormat},
{fmt.Sprintf(`CSV regular, "layout: %s" in front matter.`, demoLayout), LayoutDescriptor{Kind: "page", Layout: demoLayout}, false, "", CSVFormat},
{fmt.Sprintf(`JSON regular, "type: %s" in front matter.`, demoType), LayoutDescriptor{Kind: "page", Type: demoType}, false, "", JSONFormat},
diff --git a/output/layout.go b/output/layout.go
index cacb92b80..6c054b6c4 100644
--- a/output/layout.go
+++ b/output/layout.go
@@ -26,6 +26,7 @@ type LayoutDescriptor struct {
Type string
Section string
Kind string
+ Lang string
Layout string
}
@@ -55,31 +56,33 @@ func NewLayoutHandler(hasTheme bool) *LayoutHandler {
const (
+ // TODO(bep) variations reduce to 1 "."
+
// The RSS templates doesn't map easily into the regular pages.
- layoutsRSSHome = `NAME.SUFFIX _default/NAME.SUFFIX _internal/_default/rss.xml`
- layoutsRSSSection = `section/SECTION.NAME.SUFFIX _default/NAME.SUFFIX NAME.SUFFIX _internal/_default/rss.xml`
- layoutsRSSTaxonomy = `taxonomy/SECTION.NAME.SUFFIX _default/NAME.SUFFIX NAME.SUFFIX _internal/_default/rss.xml`
- layoutsRSSTaxonomyTerm = `taxonomy/SECTION.terms.NAME.SUFFIX _default/NAME.SUFFIX NAME.SUFFIX _internal/_default/rss.xml`
+ layoutsRSSHome = `VARIATIONS _default/VARIATIONS _internal/_default/rss.xml`
+ layoutsRSSSection = `section/SECTION.VARIATIONS _default/VARIATIONS VARIATIONS _internal/_default/rss.xml`
+ layoutsRSSTaxonomy = `taxonomy/SECTION.VARIATIONS _default/VARIATIONS VARIATIONS _internal/_default/rss.xml`
+ layoutsRSSTaxonomyTerm = `taxonomy/SECTION.terms.VARIATIONS _default/VARIATIONS VARIATIONS _internal/_default/rss.xml`
- layoutsHome = "index.NAME.SUFFIX index.SUFFIX _default/list.NAME.SUFFIX _default/list.SUFFIX"
+ layoutsHome = "index.VARIATIONS _default/list.VARIATIONS"
layoutsSection = `
-section/SECTION.NAME.SUFFIX section/SECTION.SUFFIX
-SECTION/list.NAME.SUFFIX SECTION/list.SUFFIX
-_default/section.NAME.SUFFIX _default/section.SUFFIX
-_default/list.NAME.SUFFIX _default/list.SUFFIX
-indexes/SECTION.NAME.SUFFIX indexes/SECTION.SUFFIX
-_default/indexes.NAME.SUFFIX _default/indexes.SUFFIX
+section/SECTION.VARIATIONS
+SECTION/list.VARIATIONS
+_default/section.VARIATIONS
+_default/list.VARIATIONS
+indexes/SECTION.VARIATIONS
+_default/indexes.VARIATIONS
`
layoutsTaxonomy = `
-taxonomy/SECTION.NAME.SUFFIX taxonomy/SECTION.SUFFIX
-indexes/SECTION.NAME.SUFFIX indexes/SECTION.SUFFIX
-_default/taxonomy.NAME.SUFFIX _default/taxonomy.SUFFIX
-_default/list.NAME.SUFFIX _default/list.SUFFIX
+taxonomy/SECTION.VARIATIONS
+indexes/SECTION.VARIATIONS
+_default/taxonomy.VARIATIONS
+_default/list.VARIATIONS
`
layoutsTaxonomyTerm = `
-taxonomy/SECTION.terms.NAME.SUFFIX taxonomy/SECTION.terms.SUFFIX
-_default/terms.NAME.SUFFIX _default/terms.SUFFIX
-indexes/indexes.NAME.SUFFIX indexes/indexes.SUFFIX
+taxonomy/SECTION.terms.VARIATIONS
+_default/terms.VARIATIONS
+indexes/indexes.VARIATIONS
`
)
@@ -185,14 +188,41 @@ func resolveListTemplate(d LayoutDescriptor, f Format,
}
func resolveTemplate(templ string, d LayoutDescriptor, f Format) []string {
- delim := "."
- if f.MediaType.Delimiter == "" {
- delim = ""
+
+ // VARIATIONS will be replaced with
+ // .lang.name.suffix
+ // .name.suffix
+ // .lang.suffix
+ // .suffix
+ var replacementValues []string
+
+ name := strings.ToLower(f.Name)
+
+ if d.Lang != "" {
+ replacementValues = append(replacementValues, fmt.Sprintf("%s.%s.%s", d.Lang, name, f.MediaType.Suffix))
+ }
+
+ replacementValues = append(replacementValues, fmt.Sprintf("%s.%s", name, f.MediaType.Suffix))
+
+ if d.Lang != "" {
+ replacementValues = append(replacementValues, fmt.Sprintf("%s.%s", d.Lang, f.MediaType.Suffix))
+ }
+
+ isRSS := f.Name == RSSFormat.Name
+
+ if !isRSS {
+ replacementValues = append(replacementValues, f.MediaType.Suffix)
+ }
+
+ var layouts []string
+
+ templFields := strings.Fields(templ)
+
+ for _, field := range templFields {
+ for _, replacements := range replacementValues {
+ layouts = append(layouts, replaceKeyValues(field, "VARIATIONS", replacements, "SECTION", d.Section))
+ }
}
- layouts := strings.Fields(replaceKeyValues(templ,
- ".SUFFIX", delim+f.MediaType.Suffix,
- "NAME", strings.ToLower(f.Name),
- "SECTION", d.Section))
return filterDotLess(layouts)
}
@@ -201,9 +231,7 @@ func filterDotLess(layouts []string) []string {
var filteredLayouts []string
for _, l := range layouts {
- // This may be constructed, but media types can be suffix-less, but can contain
- // a delimiter.
- l = strings.TrimSuffix(l, ".")
+ l = strings.Trim(l, ".")
// If media type has no suffix, we have "index" type of layouts in this list, which
// doesn't make much sense.
if strings.Contains(l, ".") {
diff --git a/output/layout_test.go b/output/layout_test.go
index 9d4d2f6d5..6fb958c9d 100644
--- a/output/layout_test.go
+++ b/output/layout_test.go
@@ -59,6 +59,8 @@ func TestLayout(t *testing.T) {
}{
{"Home", LayoutDescriptor{Kind: "home"}, true, "", ampType,
[]string{"index.amp.html", "index.html", "_default/list.amp.html", "_default/list.html", "theme/index.amp.html", "theme/index.html"}},
+ {"Home, french language", LayoutDescriptor{Kind: "home", Lang: "fr"}, true, "", ampType,
+ []string{"index.fr.amp.html", "index.amp.html", "index.fr.html", "index.html", "_default/list.fr.amp.html", "_default/list.amp.html", "_default/list.fr.html", "_default/list.html", "theme/index.fr.amp.html", "theme/index.amp.html", "theme/index.fr.html"}},
{"Home, no ext or delim", LayoutDescriptor{Kind: "home"}, true, "", noExtDelimFormat,
[]string{"index.nem", "_default/list.nem"}},
{"Home, no ext", LayoutDescriptor{Kind: "home"}, true, "", noExt,