shithub: hugo

Download patch

ref: c4e7c37055a029a26d87ebeb21614efb3f0b0040
parent: 06d12ab895a83fc8a9f94b23e533b25511bbb6d1
author: Bjørn Erik Pedersen <[email protected]>
date: Mon Jul 25 18:22:09 EDT 2016

Add Translations and AllTranslations methods to Page

Will revisit Node later.

--- a/commands/multilingual.go
+++ b/commands/multilingual.go
@@ -33,6 +33,7 @@
 
 func toSortedLanguages(l map[string]interface{}) (hugolib.Languages, error) {
 	langs := make(hugolib.Languages, len(l))
+	i := 0
 
 	for lang, langConf := range l {
 		langsMap, ok := langConf.(map[string]interface{})
@@ -57,7 +58,8 @@
 			language.SetParam(loki, v)
 		}
 
-		langs = append(langs, language)
+		langs[i] = language
+		i++
 	}
 
 	sort.Sort(langs)
--- a/hugolib/multilingual.go
+++ b/hugolib/multilingual.go
@@ -3,6 +3,7 @@
 import (
 	"sync"
 
+	"sort"
 	"strings"
 
 	"github.com/spf13/cast"
@@ -23,16 +24,40 @@
 
 type Languages []*Language
 
+func NewLanguages(l ...*Language) Languages {
+	languages := make(Languages, len(l))
+	for i := 0; i < len(l); i++ {
+		languages[i] = l[i]
+	}
+	sort.Sort(languages)
+	return languages
+}
+
 func (l Languages) Len() int           { return len(l) }
 func (l Languages) Less(i, j int) bool { return l[i].Weight < l[j].Weight }
 func (l Languages) Swap(i, j int)      { l[i], l[j] = l[j], l[i] }
 
 type Multilingual struct {
-	enabled bool
-
 	Languages Languages
+
+	langMap     map[string]*Language
+	langMapInit sync.Once
 }
 
+func (ml *Multilingual) Language(lang string) *Language {
+	ml.langMapInit.Do(func() {
+		ml.langMap = make(map[string]*Language)
+		for _, l := range ml.Languages {
+			ml.langMap[l.Lang] = l
+		}
+	})
+	return ml.langMap[lang]
+}
+
+func (ml *Multilingual) enabled() bool {
+	return len(ml.Languages) > 0
+}
+
 func (l *Language) Params() map[string]interface{} {
 	l.paramsInit.Do(func() {
 		// Merge with global config.
@@ -73,15 +98,14 @@
 	// TODO(bep) multilingo evaluate
 	viper.Set("CurrentLanguage", currentLang)
 	ml := &Multilingual{
-		enabled:   len(languages) > 0,
 		Languages: languages,
 	}
-	viper.Set("Multilingual", ml.enabled)
+	viper.Set("Multilingual", ml.enabled())
 	s.Multilingual = ml
 }
 
 func (s *Site) multilingualEnabled() bool {
-	return s.Multilingual != nil && s.Multilingual.enabled
+	return s.Multilingual != nil && s.Multilingual.enabled()
 }
 
 func currentLanguageString() string {
--- a/hugolib/node.go
+++ b/hugolib/node.go
@@ -14,10 +14,11 @@
 package hugolib
 
 import (
-	"github.com/spf13/cast"
 	"html/template"
 	"sync"
 	"time"
+
+	"github.com/spf13/cast"
 )
 
 type Node struct {
--- a/hugolib/page.go
+++ b/hugolib/page.go
@@ -61,10 +61,11 @@
 	PublishDate         time.Time
 	ExpiryDate          time.Time
 	Markup              string
-	Translations        Translations
+	translations        Pages
 	extension           string
 	contentType         string
 	lang                string
+	language            *Language
 	renderable          bool
 	Layout              string
 	layoutsCalculated   []string
@@ -305,7 +306,7 @@
 		Source:       Source{File: *source.NewFile(filename)},
 		Node:         Node{Keywords: []string{}, Sitemap: Sitemap{Priority: -1}},
 		Params:       make(map[string]interface{}),
-		Translations: make(Translations),
+		translations: make(Pages, 0),
 	}
 
 	jww.DEBUG.Println("Reading from", page.File.Path())
@@ -466,8 +467,28 @@
 	return viper.GetString("DefaultExtension")
 }
 
+// TODO(bep) multilingo consolidate
+func (p *Page) Language() *Language {
+	return p.language
+}
 func (p *Page) Lang() string {
 	return p.lang
+}
+
+// AllTranslations returns all translations, including the current Page.
+func (p *Page) AllTranslations() Pages {
+	return p.translations
+}
+
+// Translations returns the translations excluding the current Page.
+func (p *Page) Translations() Pages {
+	translations := make(Pages, 0)
+	for _, t := range p.translations {
+		if t != p {
+			translations = append(translations, t)
+		}
+	}
+	return translations
 }
 
 func (p *Page) LinkTitle() string {
--- a/hugolib/pageSort.go
+++ b/hugolib/pageSort.go
@@ -56,6 +56,19 @@
 	return p1.Weight < p2.Weight
 }
 
+var languagePageSort = func(p1, p2 *Page) bool {
+	if p1.language.Weight == p2.language.Weight {
+		if p1.Date.Unix() == p2.Date.Unix() {
+			if p1.LinkTitle() == p2.LinkTitle() {
+				return (p1.FullFilePath() < p2.FullFilePath())
+			}
+			return (p1.LinkTitle() < p2.LinkTitle())
+		}
+		return p1.Date.Unix() > p2.Date.Unix()
+	}
+	return p1.language.Weight < p2.language.Weight
+}
+
 func (ps *pageSorter) Len() int      { return len(ps.pages) }
 func (ps *pageSorter) Swap(i, j int) { ps.pages[i], ps.pages[j] = ps.pages[j], ps.pages[i] }
 
@@ -208,6 +221,20 @@
 	}
 
 	pages, _ := spc.get(key, p, pageBy(length).Sort)
+
+	return pages
+}
+
+// ByLanguage sorts the Pages by the language's Weight.
+//
+// Adjacent invocactions on the same receiver will return a cached result.
+//
+// This may safely be executed  in parallel.
+func (p Pages) ByLanguage() Pages {
+
+	key := "pageSort.ByLanguage"
+
+	pages, _ := spc.get(key, p, pageBy(languagePageSort).Sort)
 
 	return pages
 }
--- a/hugolib/site.go
+++ b/hugolib/site.go
@@ -744,10 +744,10 @@
 
 	currentLang := currentLanguageString()
 
-	allTranslations := pagesToTranslationsMap(s.AllPages)
+	allTranslations := pagesToTranslationsMap(s.Multilingual, s.AllPages)
 	assignTranslationsToPages(allTranslations, s.AllPages)
 
-	var currentLangPages []*Page
+	var currentLangPages Pages
 	for _, p := range s.AllPages {
 		if p.Lang() == "" || strings.HasPrefix(currentLang, p.lang) {
 			currentLangPages = append(currentLangPages, p)
@@ -2014,6 +2014,10 @@
 
 	err := s.render(name, d, renderBuffer, layouts...)
 
+	if err != nil {
+		return err
+	}
+
 	outBuffer := bp.GetBuffer()
 	defer bp.PutBuffer(outBuffer)
 
@@ -2030,11 +2034,8 @@
 	transformer := transform.NewChain(transform.AbsURLInXML)
 	transformer.Apply(outBuffer, renderBuffer, path)
 
-	if err == nil {
-		err = s.writeDestFile(dest, outBuffer)
-	}
+	return s.writeDestFile(dest, outBuffer)
 
-	return err
 }
 
 func (s *Site) renderAndWritePage(name string, dest string, d interface{}, layouts ...string) error {
@@ -2043,6 +2044,16 @@
 
 	err := s.render(name, d, renderBuffer, layouts...)
 
+	if err != nil {
+		return err
+	}
+
+	if renderBuffer.Len() == 0 {
+		if p, ok := d.(*Page); ok {
+			fmt.Println(">>>>", p.Lang(), len(p.Content))
+		}
+	}
+
 	outBuffer := bp.GetBuffer()
 	defer bp.PutBuffer(outBuffer)
 
@@ -2107,6 +2118,7 @@
 	}
 
 	if err == nil {
+
 		if err = s.writeDestPage(dest, pageTarget, outBuffer); err != nil {
 			return err
 		}
@@ -2122,6 +2134,7 @@
 	}
 
 	if err := s.renderThing(d, layout, w); err != nil {
+
 		// Behavior here should be dependent on if running in server or watch mode.
 		distinctErrorLogger.Printf("Error while rendering %s: %v", name, err)
 		if !s.running() && !testMode {
@@ -2145,6 +2158,7 @@
 }
 
 func (s *Site) renderThing(d interface{}, layout string, w io.Writer) error {
+
 	// If the template doesn't exist, then return, but leave the Writer open
 	if templ := s.Tmpl.Lookup(layout); templ != nil {
 		return templ.Execute(w, d)
--- a/hugolib/site_test.go
+++ b/hugolib/site_test.go
@@ -1399,12 +1399,6 @@
 
 	hugofs.InitMemFs()
 
-	s := &Site{
-		Source: &source.InMemorySource{ByteSource: sources},
-		Multilingual: &Multilingual{
-			enabled: true,
-		},
-	}
 	// Multilingual settings
 	viper.Set("Multilingual", true)
 	en := NewLanguage("en")
@@ -1412,6 +1406,14 @@
 	viper.Set("DefaultContentLanguage", "fr")
 	viper.Set("paginate", "2")
 
+	languages := NewLanguages(en, NewLanguage("fr"))
+	s := &Site{
+		Source: &source.InMemorySource{ByteSource: sources},
+		Multilingual: &Multilingual{
+			Languages: languages,
+		},
+	}
+
 	s.prepTemplates()
 	s.initializeSiteInfo()
 
@@ -1425,7 +1427,7 @@
 	permalink, err := doc1en.Permalink()
 	assert.NoError(t, err, "permalink call failed")
 	assert.Equal(t, "http://example.com/blog/en/sect/doc1-slug", permalink, "invalid doc1.en permalink")
-	assert.Len(t, doc1en.Translations, 1, "doc1-en should have one translation, excluding itself")
+	assert.Len(t, doc1en.Translations(), 1, "doc1-en should have one translation, excluding itself")
 
 	doc2 := s.Pages[1]
 	permalink, err = doc2.Permalink()
@@ -1440,19 +1442,20 @@
 
 	assert.Equal(t, doc2.Next, doc3, "doc3 should follow doc2, in .Next")
 
-	doc1fr := doc1en.Translations["fr"]
+	doc1fr := doc1en.Translations()[0]
 	permalink, err = doc1fr.Permalink()
 	assert.NoError(t, err, "permalink call failed")
 	assert.Equal(t, "http://example.com/blog/fr/sect/doc1", permalink, "invalid doc1fr permalink")
 
-	assert.Equal(t, doc1en.Translations["fr"], doc1fr, "doc1-en should have doc1-fr as translation")
-	assert.Equal(t, doc1fr.Translations["en"], doc1en, "doc1-fr should have doc1-en as translation")
+	assert.Equal(t, doc1en.Translations()[0], doc1fr, "doc1-en should have doc1-fr as translation")
+	assert.Equal(t, doc1fr.Translations()[0], doc1en, "doc1-fr should have doc1-en as translation")
+	assert.Equal(t, "fr", doc1fr.Language().Lang)
 
 	doc4 := s.AllPages[4]
 	permalink, err = doc4.Permalink()
 	assert.NoError(t, err, "permalink call failed")
 	assert.Equal(t, "http://example.com/blog/fr/sect/doc4", permalink, "invalid doc4 permalink")
-	assert.Len(t, doc4.Translations, 0, "found translations for doc4")
+	assert.Len(t, doc4.Translations(), 0, "found translations for doc4")
 
 	doc5 := s.AllPages[5]
 	permalink, err = doc5.Permalink()
--- a/hugolib/translations.go
+++ b/hugolib/translations.go
@@ -13,12 +13,16 @@
 
 package hugolib
 
+import (
+	"fmt"
+)
+
 // Translations represent the other translations for a given page. The
 // string here is the language code, as affected by the `post.LANG.md`
 // filename.
 type Translations map[string]*Page
 
-func pagesToTranslationsMap(pages []*Page) map[string]Translations {
+func pagesToTranslationsMap(ml *Multilingual, pages []*Page) map[string]Translations {
 	out := make(map[string]Translations)
 
 	for _, page := range pages {
@@ -34,6 +38,14 @@
 			continue
 		}
 
+		language := ml.Language(pageLang)
+
+		if language == nil {
+			panic(fmt.Sprintf("Page language not found in multilang setup: %s", pageLang))
+		}
+
+		page.language = language
+
 		pageTranslation[pageLang] = page
 		out[base] = pageTranslation
 	}
@@ -49,11 +61,14 @@
 			continue
 		}
 
-		for lang, translatedPage := range trans {
+		// TODO(bep) multilingo remove lang
+		for _, translatedPage := range trans {
 			if translatedPage == page {
 				continue
 			}
-			page.Translations[lang] = translatedPage
+			page.translations = append(page.translations, translatedPage)
 		}
+
+		pageBy(languagePageSort).Sort(page.translations)
 	}
 }