ref: 089fe49309cd9cadba3ae9a5eddfd69622941a70
parent: 118b83d74b5caaae6646ec031d59b8ab3491c6b2
author: Bjørn Erik Pedersen <[email protected]>
date: Mon Nov 20 05:34:30 EST 2017
hugolib: Make sure everything ends up in its lang root in multihost mode Fixes #4105
--- a/hugolib/hugo_sites_build_test.go
+++ b/hugolib/hugo_sites_build_test.go
@@ -254,7 +254,6 @@
doc3 := enSite.RegularPages[2]
permalink = doc3.Permalink()
- require.NoError(t, err, "permalink call failed")
// 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.
@@ -1155,6 +1154,7 @@
title: doc3
weight: 3
publishdate: "2000-01-03"
+aliases: [/en/al/alias1,/al/alias2/]
tags:
- tag2
- tag1
--- a/hugolib/hugo_sites_multihost_test.go
+++ b/hugolib/hugo_sites_multihost_test.go
@@ -68,6 +68,22 @@
assert.Len(s1h.Translations(), 2)
assert.Equal("https://example.com/", s1h.Permalink())
+ // For “regular multilingual” we kept the aliases pages with url in front matter
+ // as a literal value that we use as is.
+ // There is an ambiguity in the guessing.
+ // For multihost, we never want any content in the root.
+ //
+ // check url in front matter:
+ pageWithURLInFrontMatter := s1.getPage(KindPage, "sect/doc3.en.md")
+ assert.NotNil(pageWithURLInFrontMatter)
+ assert.Equal("/superbob", pageWithURLInFrontMatter.URL())
+ assert.Equal("/superbob/", pageWithURLInFrontMatter.RelPermalink())
+ th.assertFileContent("public/en/superbob/index.html", "doc3|Hello|en")
+
+ // check alias:
+ th.assertFileContent("public/en/al/alias1/index.html", `content="0; url=https://example.com/superbob/"`)
+ th.assertFileContent("public/en/al/alias2/index.html", `content="0; url=https://example.com/superbob/"`)
+
s2 := sites.Sites[1]
assert.Equal([]string{"s1", "s2", "frs1", "frs2"}, s2.StaticDirs())
--- a/hugolib/page_paths.go
+++ b/hugolib/page_paths.go
@@ -53,6 +53,9 @@
// language subdir.
LangPrefix string
+ // Whether this is a multihost multilingual setup.
+ IsMultihost bool
+
// Page.URLPath.URL. Will override any Slug etc. for regular pages.
URL string
@@ -81,12 +84,13 @@
func (p *Page) initTargetPathDescriptor() error {
d := &targetPathDescriptor{
- PathSpec: p.s.PathSpec,
- Kind: p.Kind,
- Sections: p.sections,
- UglyURLs: p.s.Info.uglyURLs,
- Dir: filepath.ToSlash(p.Source.Dir()),
- URL: p.URLPath.URL,
+ PathSpec: p.s.PathSpec,
+ Kind: p.Kind,
+ Sections: p.sections,
+ UglyURLs: p.s.Info.uglyURLs,
+ Dir: filepath.ToSlash(p.Source.Dir()),
+ URL: p.URLPath.URL,
+ IsMultihost: p.s.owner.IsMultihost(),
}
if p.Slug != "" {
@@ -177,7 +181,11 @@
if d.Kind == KindPage {
// Always use URL if it's specified
if d.URL != "" {
- pagePath = filepath.Join(pagePath, d.URL)
+ if d.IsMultihost && d.LangPrefix != "" && !strings.HasPrefix(d.URL, "/"+d.LangPrefix) {
+ pagePath = filepath.Join(d.LangPrefix, pagePath, d.URL)
+ } else {
+ pagePath = filepath.Join(pagePath, d.URL)
+ }
if strings.HasSuffix(d.URL, "/") || !strings.Contains(d.URL, ".") {
pagePath = filepath.Join(pagePath, d.Type.BaseName+d.Type.MediaType.FullSuffix())
}
--- a/hugolib/page_paths_test.go
+++ b/hugolib/page_paths_test.go
@@ -40,151 +40,156 @@
BaseName: "_redirects",
}
- for _, langPrefix := range []string{"", "no"} {
- for _, uglyURLs := range []bool{false, true} {
- t.Run(fmt.Sprintf("langPrefix=%q,uglyURLs=%t", langPrefix, uglyURLs),
- func(t *testing.T) {
+ for _, multiHost := range []bool{false, true} {
+ for _, langPrefix := range []string{"", "no"} {
+ for _, uglyURLs := range []bool{false, true} {
+ t.Run(fmt.Sprintf("multihost=%t,langPrefix=%q,uglyURLs=%t", multiHost, langPrefix, uglyURLs),
+ func(t *testing.T) {
- tests := []struct {
- name string
- d targetPathDescriptor
- expected string
- }{
- {"JSON home", targetPathDescriptor{Kind: KindHome, Type: output.JSONFormat}, "/index.json"},
- {"AMP home", targetPathDescriptor{Kind: KindHome, Type: output.AMPFormat}, "/amp/index.html"},
- {"HTML home", targetPathDescriptor{Kind: KindHome, BaseName: "_index", Type: output.HTMLFormat}, "/index.html"},
- {"Netlify redirects", targetPathDescriptor{Kind: KindHome, BaseName: "_index", Type: noExtDelimFormat}, "/_redirects"},
- {"HTML section list", targetPathDescriptor{
- Kind: KindSection,
- Sections: []string{"sect1"},
- BaseName: "_index",
- Type: output.HTMLFormat}, "/sect1/index.html"},
- {"HTML taxonomy list", targetPathDescriptor{
- Kind: KindTaxonomy,
- Sections: []string{"tags", "hugo"},
- BaseName: "_index",
- Type: output.HTMLFormat}, "/tags/hugo/index.html"},
- {"HTML taxonomy term", targetPathDescriptor{
- Kind: KindTaxonomy,
- Sections: []string{"tags"},
- BaseName: "_index",
- Type: output.HTMLFormat}, "/tags/index.html"},
- {
- "HTML page", targetPathDescriptor{
- Kind: KindPage,
- Dir: "/a/b",
- BaseName: "mypage",
- Sections: []string{"a"},
- Type: output.HTMLFormat}, "/a/b/mypage/index.html"},
-
- {
- // Issue #3396
- "HTML page with index as base", targetPathDescriptor{
- Kind: KindPage,
- Dir: "/a/b",
- BaseName: "index",
- Sections: []string{"a"},
- Type: output.HTMLFormat}, "/a/b/index.html"},
-
- {
- "HTML page with special chars", targetPathDescriptor{
- Kind: KindPage,
- Dir: "/a/b",
- BaseName: "My Page!",
- Type: output.HTMLFormat}, "/a/b/My-Page/index.html"},
- {"RSS home", targetPathDescriptor{Kind: kindRSS, Type: output.RSSFormat}, "/index.xml"},
- {"RSS section list", targetPathDescriptor{
- Kind: kindRSS,
- Sections: []string{"sect1"},
- Type: output.RSSFormat}, "/sect1/index.xml"},
- {
- "AMP page", targetPathDescriptor{
- Kind: KindPage,
- Dir: "/a/b/c",
- BaseName: "myamp",
- Type: output.AMPFormat}, "/amp/a/b/c/myamp/index.html"},
- {
- "AMP page with URL with suffix", targetPathDescriptor{
- Kind: KindPage,
- Dir: "/sect/",
- BaseName: "mypage",
- URL: "/some/other/url.xhtml",
- Type: output.HTMLFormat}, "/some/other/url.xhtml"},
- {
- "JSON page with URL without suffix", targetPathDescriptor{
- Kind: KindPage,
- Dir: "/sect/",
- BaseName: "mypage",
- URL: "/some/other/path/",
- Type: output.JSONFormat}, "/some/other/path/index.json"},
- {
- "JSON page with URL without suffix and no trailing slash", targetPathDescriptor{
- Kind: KindPage,
- Dir: "/sect/",
- BaseName: "mypage",
- URL: "/some/other/path",
- Type: output.JSONFormat}, "/some/other/path/index.json"},
- {
- "HTML page with expanded permalink", targetPathDescriptor{
- Kind: KindPage,
- Dir: "/a/b",
- BaseName: "mypage",
- ExpandedPermalink: "/2017/10/my-title",
- Type: output.HTMLFormat}, "/2017/10/my-title/index.html"},
- {
- "Paginated HTML home", targetPathDescriptor{
- Kind: KindHome,
+ tests := []struct {
+ name string
+ d targetPathDescriptor
+ expected string
+ }{
+ {"JSON home", targetPathDescriptor{Kind: KindHome, Type: output.JSONFormat}, "/index.json"},
+ {"AMP home", targetPathDescriptor{Kind: KindHome, Type: output.AMPFormat}, "/amp/index.html"},
+ {"HTML home", targetPathDescriptor{Kind: KindHome, BaseName: "_index", Type: output.HTMLFormat}, "/index.html"},
+ {"Netlify redirects", targetPathDescriptor{Kind: KindHome, BaseName: "_index", Type: noExtDelimFormat}, "/_redirects"},
+ {"HTML section list", targetPathDescriptor{
+ Kind: KindSection,
+ Sections: []string{"sect1"},
BaseName: "_index",
- Type: output.HTMLFormat,
- Addends: "page/3"}, "/page/3/index.html"},
- {
- "Paginated Taxonomy list", targetPathDescriptor{
+ Type: output.HTMLFormat}, "/sect1/index.html"},
+ {"HTML taxonomy list", targetPathDescriptor{
Kind: KindTaxonomy,
- BaseName: "_index",
Sections: []string{"tags", "hugo"},
- Type: output.HTMLFormat,
- Addends: "page/3"}, "/tags/hugo/page/3/index.html"},
- {
- "Regular page with addend", targetPathDescriptor{
- Kind: KindPage,
- Dir: "/a/b",
- BaseName: "mypage",
- Addends: "c/d/e",
- Type: output.HTMLFormat}, "/a/b/mypage/c/d/e/index.html"},
- }
+ BaseName: "_index",
+ Type: output.HTMLFormat}, "/tags/hugo/index.html"},
+ {"HTML taxonomy term", targetPathDescriptor{
+ Kind: KindTaxonomy,
+ Sections: []string{"tags"},
+ BaseName: "_index",
+ Type: output.HTMLFormat}, "/tags/index.html"},
+ {
+ "HTML page", targetPathDescriptor{
+ Kind: KindPage,
+ Dir: "/a/b",
+ BaseName: "mypage",
+ Sections: []string{"a"},
+ Type: output.HTMLFormat}, "/a/b/mypage/index.html"},
- for i, test := range tests {
- test.d.PathSpec = pathSpec
- test.d.UglyURLs = uglyURLs
- test.d.LangPrefix = langPrefix
- test.d.Dir = filepath.FromSlash(test.d.Dir)
- isUgly := uglyURLs && !test.d.Type.NoUgly
+ {
+ // Issue #3396
+ "HTML page with index as base", targetPathDescriptor{
+ Kind: KindPage,
+ Dir: "/a/b",
+ BaseName: "index",
+ Sections: []string{"a"},
+ Type: output.HTMLFormat}, "/a/b/index.html"},
- expected := test.expected
+ {
+ "HTML page with special chars", targetPathDescriptor{
+ Kind: KindPage,
+ Dir: "/a/b",
+ BaseName: "My Page!",
+ Type: output.HTMLFormat}, "/a/b/My-Page/index.html"},
+ {"RSS home", targetPathDescriptor{Kind: kindRSS, Type: output.RSSFormat}, "/index.xml"},
+ {"RSS section list", targetPathDescriptor{
+ Kind: kindRSS,
+ Sections: []string{"sect1"},
+ Type: output.RSSFormat}, "/sect1/index.xml"},
+ {
+ "AMP page", targetPathDescriptor{
+ Kind: KindPage,
+ Dir: "/a/b/c",
+ BaseName: "myamp",
+ Type: output.AMPFormat}, "/amp/a/b/c/myamp/index.html"},
+ {
+ "AMP page with URL with suffix", targetPathDescriptor{
+ Kind: KindPage,
+ Dir: "/sect/",
+ BaseName: "mypage",
+ URL: "/some/other/url.xhtml",
+ Type: output.HTMLFormat}, "/some/other/url.xhtml"},
+ {
+ "JSON page with URL without suffix", targetPathDescriptor{
+ Kind: KindPage,
+ Dir: "/sect/",
+ BaseName: "mypage",
+ URL: "/some/other/path/",
+ Type: output.JSONFormat}, "/some/other/path/index.json"},
+ {
+ "JSON page with URL without suffix and no trailing slash", targetPathDescriptor{
+ Kind: KindPage,
+ Dir: "/sect/",
+ BaseName: "mypage",
+ URL: "/some/other/path",
+ Type: output.JSONFormat}, "/some/other/path/index.json"},
+ {
+ "HTML page with expanded permalink", targetPathDescriptor{
+ Kind: KindPage,
+ Dir: "/a/b",
+ BaseName: "mypage",
+ ExpandedPermalink: "/2017/10/my-title",
+ Type: output.HTMLFormat}, "/2017/10/my-title/index.html"},
+ {
+ "Paginated HTML home", targetPathDescriptor{
+ Kind: KindHome,
+ BaseName: "_index",
+ Type: output.HTMLFormat,
+ Addends: "page/3"}, "/page/3/index.html"},
+ {
+ "Paginated Taxonomy list", targetPathDescriptor{
+ Kind: KindTaxonomy,
+ BaseName: "_index",
+ Sections: []string{"tags", "hugo"},
+ Type: output.HTMLFormat,
+ Addends: "page/3"}, "/tags/hugo/page/3/index.html"},
+ {
+ "Regular page with addend", targetPathDescriptor{
+ Kind: KindPage,
+ Dir: "/a/b",
+ BaseName: "mypage",
+ Addends: "c/d/e",
+ Type: output.HTMLFormat}, "/a/b/mypage/c/d/e/index.html"},
+ }
- // TODO(bep) simplify
- if test.d.Kind == KindPage && test.d.BaseName == test.d.Type.BaseName {
+ for i, test := range tests {
+ test.d.PathSpec = pathSpec
+ test.d.UglyURLs = uglyURLs
+ test.d.LangPrefix = langPrefix
+ test.d.IsMultihost = multiHost
+ test.d.Dir = filepath.FromSlash(test.d.Dir)
+ isUgly := uglyURLs && !test.d.Type.NoUgly
- } else if test.d.Kind == KindHome && test.d.Type.Path != "" {
- } else if (!strings.HasPrefix(expected, "/index") || test.d.Addends != "") && test.d.URL == "" && isUgly {
- expected = strings.Replace(expected,
- "/"+test.d.Type.BaseName+"."+test.d.Type.MediaType.Suffix,
- "."+test.d.Type.MediaType.Suffix, -1)
- }
+ expected := test.expected
- if test.d.LangPrefix != "" && !(test.d.Kind == KindPage && test.d.URL != "") {
- expected = "/" + test.d.LangPrefix + expected
- }
+ // TODO(bep) simplify
+ if test.d.Kind == KindPage && test.d.BaseName == test.d.Type.BaseName {
- expected = filepath.FromSlash(expected)
+ } else if test.d.Kind == KindHome && test.d.Type.Path != "" {
+ } else if (!strings.HasPrefix(expected, "/index") || test.d.Addends != "") && test.d.URL == "" && isUgly {
+ expected = strings.Replace(expected,
+ "/"+test.d.Type.BaseName+"."+test.d.Type.MediaType.Suffix,
+ "."+test.d.Type.MediaType.Suffix, -1)
+ }
- pagePath := createTargetPath(test.d)
+ if test.d.LangPrefix != "" && !(test.d.Kind == KindPage && test.d.URL != "") {
+ expected = "/" + test.d.LangPrefix + expected
+ } else if multiHost && test.d.LangPrefix != "" && test.d.URL != "" {
+ expected = "/" + test.d.LangPrefix + expected
+ }
- if pagePath != expected {
- t.Fatalf("[%d] [%s] targetPath expected %q, got: %q", i, test.name, expected, pagePath)
+ expected = filepath.FromSlash(expected)
+
+ pagePath := createTargetPath(test.d)
+
+ if pagePath != expected {
+ t.Fatalf("[%d] [%s] targetPath expected %q, got: %q", i, test.name, expected, pagePath)
+ }
}
- }
- })
+ })
+ }
}
}
}
--- a/hugolib/site_render.go
+++ b/hugolib/site_render.go
@@ -16,6 +16,7 @@
import (
"fmt"
"path"
+ "strings"
"sync"
"github.com/gohugoio/hugo/helpers"
@@ -378,6 +379,13 @@
if f.Path != "" {
// Make sure AMP and similar doesn't clash with regular aliases.
a = path.Join(a, f.Path)
+ }
+
+ lang := p.Lang()
+
+ if s.owner.multihost && !strings.HasPrefix(a, "/"+lang) {
+ // These need to be in its language root.
+ a = path.Join(lang, a)
}
if err := s.writeDestAlias(a, plink, p); err != nil {