mirror of
https://github.com/gohugoio/hugo.git
synced 2024-11-07 20:30:36 -05:00
Add Translations and AllTranslations methods to Page
Will revisit Node later.
This commit is contained in:
parent
06d12ab895
commit
c4e7c37055
8 changed files with 136 additions and 29 deletions
|
@ -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)
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -14,10 +14,11 @@
|
|||
package hugolib
|
||||
|
||||
import (
|
||||
"github.com/spf13/cast"
|
||||
"html/template"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/spf13/cast"
|
||||
)
|
||||
|
||||
type Node struct {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue