Add language merge support for Pages in resource.Resources
authorBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Thu, 19 Apr 2018 07:02:18 +0000 (09:02 +0200)
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Thu, 19 Apr 2018 14:23:00 +0000 (16:23 +0200)
Fixes #4644

hugolib/pages_language_merge_test.go
resource/resource.go

index 3b55a6288d5a79122abe2de52fa5f440f851417d..b7c78836c897c9b4079a0089256e08a98bb162a8 100644 (file)
@@ -17,6 +17,7 @@ import (
        "fmt"
        "testing"
 
+       "github.com/gohugoio/hugo/resource"
        "github.com/stretchr/testify/require"
 )
 
@@ -35,16 +36,16 @@ func TestMergeLanguages(t *testing.T) {
        frSite := h.Sites[1]
        nnSite := h.Sites[2]
 
-       assert.Equal(30, len(enSite.RegularPages))
+       assert.Equal(31, len(enSite.RegularPages))
        assert.Equal(6, len(frSite.RegularPages))
-       assert.Equal(11, len(nnSite.RegularPages))
+       assert.Equal(12, len(nnSite.RegularPages))
 
        for i := 0; i < 2; i++ {
                mergedNN := nnSite.RegularPages.MergeByLanguage(enSite.RegularPages)
-               assert.Equal(30, len(mergedNN))
-               for i := 1; i <= 30; i++ {
+               assert.Equal(31, len(mergedNN))
+               for i := 1; i <= 31; i++ {
                        expectedLang := "en"
-                       if i == 2 || i%3 == 0 {
+                       if i == 2 || i%3 == 0 || i == 31 {
                                expectedLang = "nn"
                        }
                        p := mergedNN[i-1]
@@ -53,8 +54,8 @@ func TestMergeLanguages(t *testing.T) {
        }
 
        mergedFR := frSite.RegularPages.MergeByLanguage(enSite.RegularPages)
-       assert.Equal(30, len(mergedFR))
-       for i := 1; i <= 30; i++ {
+       assert.Equal(31, len(mergedFR))
+       for i := 1; i <= 31; i++ {
                expectedLang := "en"
                if i%5 == 0 {
                        expectedLang = "fr"
@@ -67,6 +68,17 @@ func TestMergeLanguages(t *testing.T) {
        assert.Equal(4, len(firstNN.Sites()))
        assert.Equal("en", firstNN.Sites().First().Language.Lang)
 
+       nnBundle := nnSite.getPage("page", "bundle")
+       enBundle := enSite.getPage("page", "bundle")
+
+       assert.Equal(6, len(enBundle.Resources))
+       assert.Equal(2, len(nnBundle.Resources))
+
+       var ri interface{} = nnBundle.Resources
+
+       // This looks less ugly in the templates ...
+       mergedNNResources := ri.(resource.ResourcesLanguageMerger).MergeByLanguage(enBundle.Resources)
+       assert.Equal(6, len(mergedNNResources))
 }
 
 func TestMergeLanguagesTemplate(t *testing.T) {
@@ -79,10 +91,16 @@ func TestMergeLanguagesTemplate(t *testing.T) {
 {{ if eq .Lang "nn" }}:
 {{ $enSite := index .Sites 0 }}
 {{ $frSite := index .Sites 1 }}
+{{ $nnBundle := .Site.GetPage "page" "bundle" }}
+{{ $enBundle := $enSite.GetPage "page" "bundle" }}
 {{ .Scratch.Set "pages" ($pages | lang.Merge $frSite.RegularPages| lang.Merge $enSite.RegularPages) }}
+{{ .Scratch.Set "pages2" (sort ($nnBundle.Resources | lang.Merge $enBundle.Resources) "Title") }}
 {{ end }}
 {{ $pages := .Scratch.Get "pages" }}
-{{ range $i, $p := $pages }}{{ add $i 1 }}: {{ .Path }} {{ .Lang }} | {{ end }}
+{{ $pages2 := .Scratch.Get "pages2" }}
+Pages1: {{ range $i, $p := $pages }}{{ add $i 1 }}: {{ .Path }} {{ .Lang }} | {{ end }}
+Pages2: {{ range $i, $p := $pages2 }}{{ add $i 1 }}: {{ .Title }} {{ .Lang }} | {{ end }}
+
 `,
                "shortcodes/shortcode.html", "MyShort",
                "shortcodes/lingo.html", "MyLingo",
@@ -91,7 +109,8 @@ func TestMergeLanguagesTemplate(t *testing.T) {
        b.CreateSites()
        b.Build(BuildCfg{})
 
-       b.AssertFileContent("public/nn/index.html", "p1.md en | 2: p2.nn.md nn | 3: p3.nn.md nn | 4: p4.md en | 5: p5.fr.md fr | 6: p6.nn.md nn | 7: p7.md en | 8: p8.md en | 9: p9.nn.md nn | 10: p10.fr.md fr | 11: p11.md en | 12: p12.nn.md nn | 13: p13.md en | 14: p14.md en | 15: p15.nn.md nn")
+       b.AssertFileContent("public/nn/index.html", "Pages1: 1: p1.md en | 2: p2.nn.md nn | 3: p3.nn.md nn | 4: p4.md en | 5: p5.fr.md fr | 6: p6.nn.md nn | 7: p7.md en | 8: p8.md en | 9: p9.nn.md nn | 10: p10.fr.md fr | 11: p11.md en | 12: p12.nn.md nn | 13: p13.md en | 14: p14.md en | 15: p15.nn.md nn")
+       b.AssertFileContent("public/nn/index.html", "Pages2: 1: doc100 en | 2: doc101 nn | 3: doc102 nn | 4: doc103 en | 5: doc104 en | 6: doc105 en")
 }
 
 func newTestSiteForLanguageMerge(t testing.TB, count int) *sitesBuilder {
@@ -126,6 +145,18 @@ date: "2018-02-28"
                }
        }
 
+       // See https://github.com/gohugoio/hugo/issues/4644
+       // Add a bundles
+       j := 100
+       contentPairs = append(contentPairs, []string{"bundle/index.md", fmt.Sprintf(contentTemplate, j, j)}...)
+       for i := 0; i < 6; i++ {
+               contentPairs = append(contentPairs, []string{fmt.Sprintf("bundle/pb%d.md", i), fmt.Sprintf(contentTemplate, i+j, i+j)}...)
+       }
+       contentPairs = append(contentPairs, []string{"bundle/index.nn.md", fmt.Sprintf(contentTemplate, j, j)}...)
+       for i := 1; i < 3; i++ {
+               contentPairs = append(contentPairs, []string{fmt.Sprintf("bundle/pb%d.nn.md", i), fmt.Sprintf(contentTemplate, i+j, i+j)}...)
+       }
+
        builder.WithContent(contentPairs...)
        return builder
 }
index 12e1160cfe71b662019f658f28a0073fcca68e77..e92706803ee92b96b6664e35cbe842bb8cd7bc26 100644 (file)
@@ -34,10 +34,11 @@ import (
 )
 
 var (
-       _ Resource     = (*genericResource)(nil)
-       _ metaAssigner = (*genericResource)(nil)
-       _ Source       = (*genericResource)(nil)
-       _ Cloner       = (*genericResource)(nil)
+       _ Resource                = (*genericResource)(nil)
+       _ metaAssigner            = (*genericResource)(nil)
+       _ Source                  = (*genericResource)(nil)
+       _ Cloner                  = (*genericResource)(nil)
+       _ ResourcesLanguageMerger = (*Resources)(nil)
 )
 
 const DefaultResourceType = "unknown"
@@ -97,6 +98,16 @@ type Resource interface {
        Content() (interface{}, error)
 }
 
+type ResourcesLanguageMerger interface {
+       MergeByLanguage(other Resources) Resources
+       // Needed for integration with the tpl package.
+       MergeByLanguageInterface(other interface{}) (interface{}, error)
+}
+
+type translatedResource interface {
+       TranslationKey() string
+}
+
 // Resources represents a slice of resources, which can be a mix of different types.
 // I.e. both pages and images etc.
 type Resources []Resource
@@ -222,6 +233,36 @@ func getGlob(pattern string) (glob.Glob, error) {
 
 }
 
+// MergeByLanguage adds missing translations in r1 from r2.
+func (r1 Resources) MergeByLanguage(r2 Resources) Resources {
+       result := append(Resources(nil), r1...)
+       m := make(map[string]bool)
+       for _, r := range r1 {
+               if translated, ok := r.(translatedResource); ok {
+                       m[translated.TranslationKey()] = true
+               }
+       }
+
+       for _, r := range r2 {
+               if translated, ok := r.(translatedResource); ok {
+                       if _, found := m[translated.TranslationKey()]; !found {
+                               result = append(result, r)
+                       }
+               }
+       }
+       return result
+}
+
+// MergeByLanguageInterface is the generic version of MergeByLanguage. It
+// is here just so it can be called from the tpl package.
+func (r1 Resources) MergeByLanguageInterface(in interface{}) (interface{}, error) {
+       r2, ok := in.(Resources)
+       if !ok {
+               return nil, fmt.Errorf("%T cannot be merged by language", in)
+       }
+       return r1.MergeByLanguage(r2), nil
+}
+
 type Spec struct {
        *helpers.PathSpec