Add Translations and AllTranslations methods to Page

Will revisit Node later.
This commit is contained in:
Bjørn Erik Pedersen 2016-07-25 22:22:09 +02:00
parent 06d12ab895
commit c4e7c37055
8 changed files with 136 additions and 29 deletions

View file

@ -33,6 +33,7 @@ func readMultilingualConfiguration() error {
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 @@ func toSortedLanguages(l map[string]interface{}) (hugolib.Languages, error) {
language.SetParam(loki, v)
}
langs = append(langs, language)
langs[i] = language
i++
}
sort.Sort(langs)

View file

@ -3,6 +3,7 @@ package hugolib
import (
"sync"
"sort"
"strings"
"github.com/spf13/cast"
@ -23,14 +24,38 @@ func NewLanguage(lang string) *Language {
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{} {
@ -73,15 +98,14 @@ func (s *Site) SetMultilingualConfig(currentLang *Language, languages Languages)
// 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 {

View file

@ -14,10 +14,11 @@
package hugolib
import (
"github.com/spf13/cast"
"html/template"
"sync"
"time"
"github.com/spf13/cast"
)
type Node struct {

View file

@ -61,10 +61,11 @@ type Page struct {
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 @@ func newPage(filename string) *Page {
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,10 +467,30 @@ func (p *Page) Extension() string {
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 {
if len(p.linkTitle) > 0 {
return p.linkTitle

View file

@ -56,6 +56,19 @@ var defaultPageSort = func(p1, p2 *Page) bool {
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] }
@ -212,6 +225,20 @@ func (p Pages) ByLength() Pages {
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
}
// Reverse reverses the order in Pages and returns a copy.
//
// Adjacent invocactions on the same receiver will return a cached result.

View file

@ -744,10 +744,10 @@ func (s *Site) setupTranslations() {
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 @@ func (s *Site) renderAndWriteXML(name string, dest string, d interface{}, layout
err := s.render(name, d, renderBuffer, layouts...)
if err != nil {
return err
}
outBuffer := bp.GetBuffer()
defer bp.PutBuffer(outBuffer)
@ -2030,11 +2034,8 @@ func (s *Site) renderAndWriteXML(name string, dest string, d interface{}, layout
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 @@ func (s *Site) renderAndWritePage(name string, dest string, d interface{}, layou
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 @@ func (s *Site) renderAndWritePage(name string, dest string, d interface{}, layou
}
if err == nil {
if err = s.writeDestPage(dest, pageTarget, outBuffer); err != nil {
return err
}
@ -2122,6 +2134,7 @@ func (s *Site) render(name string, d interface{}, w io.Writer, layouts ...string
}
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) findFirstLayout(layouts ...string) (string, bool) {
}
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)

View file

@ -1399,12 +1399,6 @@ NOTE: should use the "permalinks" configuration with :filename
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 @@ NOTE: should use the "permalinks" configuration with :filename
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 @@ NOTE: should use the "permalinks" configuration with :filename
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 @@ NOTE: should use the "permalinks" configuration with :filename
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()

View file

@ -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 @@ func pagesToTranslationsMap(pages []*Page) map[string]Translations {
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 @@ func assignTranslationsToPages(allTranslations map[string]Translations, pages []
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)
}
}