Skip to content

x/text/message: documentation for i18n HTML template example? #39954

@raspi

Description

@raspi

Hi,

I would like to see an example for translated html/template with x/text/message.

Here's my current attempt with two different calling styles (free to use):

package main

import (
	"bytes"
	"fmt"
	"golang.org/x/text/language"
	"golang.org/x/text/message"
	"golang.org/x/text/message/catalog"
	"html/template"
)

type TrPage struct {
	contents string
	trcat    catalog.Catalog
}

type TrTemplate struct {
	funcs template.FuncMap
	base  string            // Base template as string
	pages map[string]TrPage // Pages which uses base template
}

func New(base string, funcs template.FuncMap) (TrTemplate, error) {
	return TrTemplate{
		base:  `{{define "base"}}` + base + `{{end}}`,
		pages: make(map[string]TrPage),
		funcs: funcs,
	}, nil
}

func (t *TrTemplate) AddPage(name string, template string, translations catalog.Catalog) error {
	tp := TrPage{
		contents: `{{define "content"}}` + template + `{{end}}`,
		trcat:    translations,
	}

	t.pages[name] = tp
	return nil
}

func (t *TrTemplate) Render(templatename string, language language.Tag, data interface{}) (out string, err error) {
	var tmp bytes.Buffer

	tpl := template.New(``)
	tpl.Funcs(t.funcs)
	tpl.Funcs(template.FuncMap{
		// Translate inside template
		`T`: func(s string, a ...interface{}) template.HTML {
			pr := message.NewPrinter(language, message.Catalog(t.pages[templatename].trcat))
			return template.HTML(pr.Sprintf(s, a))
		},
	})

	_, err = tpl.Parse(t.base)
	if err != nil {
		return ``, err
	}

	_, err = tpl.Parse(t.pages[templatename].contents)
	if err != nil {
		return ``, err
	}

	err = tpl.ExecuteTemplate(&tmp, `base`, data)
	if err != nil {
		return ``, err
	}

	return tmp.String(), nil
}

type myBaseStruct struct {
	Title    string // Base title
	Language string
	C        interface{} // per-page content variables
}

type myAboutPageStruct struct {
	User string
	Msg  string
}

func main() {
	// Common functions for templates (for example CSRF generation)
	funcs := template.FuncMap{
	}

	basetpl, err := New(baseHTML, funcs)
	if err != nil {
		panic(err)
	}

	// Translate template to this language
	useLanguage := language.Finnish
	//useLanguage := language.English

	// Front page
	frontpageCat := catalog.NewBuilder(
		catalog.Fallback(useLanguage),
	)

	basetpl.AddPage(`frontpage`, frontpageHTML, frontpageCat)

	// About page
	aboutCat := catalog.NewBuilder(
		catalog.Fallback(useLanguage),
	)

	aboutCat.SetString(language.Finnish, `about_page_user`, `Tietoa käyttäjästä %s`)
	aboutCat.SetString(language.English, `about_page_user`, `Information about user %s`)

	basetpl.AddPage(`about`, aboutHTML, aboutCat)

	printer := message.NewPrinter(useLanguage, message.Catalog(aboutCat))

	out, err := basetpl.Render(`about`, useLanguage, myBaseStruct{
		Title:    `yay title`,
		Language: useLanguage.String(),
		C: myAboutPageStruct{
			// Style 1
			User: `test user`,
			// Style 2
			Msg: printer.Sprintf(`about_page_user`, `test`),
		},
	})
	if err != nil {
		panic(err)
	}

	fmt.Print(out)

}

var baseHTML = `
<!DOCTYPE html>
<html lang="{{.Language}}">
<head>
    <meta charset="UTF-8">
    <title>{{.Title}}</title>
</head>
<body>
This is base
Content:
{{template "content" .C}}

</body>
</html>
`

var aboutHTML = `
<div>
    <!-- Style 1 -->
    {{T "about_page_user" "{{.User}}" }}

    <!-- Style 2 -->
    {{.Msg}}
</div>
`

var frontpageHTML = `
<div>
    This is frontpage
</div>
`

Which calling style is recommended or is there third option?

Style 1 also doesn't evaluate {{.User}} to test user (I don't know how).

I would like to see style 1 to be used.

Also the parser for html/template is hidden as internal so you can't build nice automated translated token gatherer script for these kind of tasks to find all T calling functions and dump those to a translation file. Are there plans to open it up?

I would also like to see example for when you have to add some HTML to a translation such as:

someCatalog.SetString(language.Finnish, `about_page_user`, `Tietoa käyttäjästä %s`)

and %s is for example <a href="/foo">{{.User}}</a>.

Metadata

Metadata

Assignees

No one assigned

    Labels

    DocumentationIssues describing a change to documentation.NeedsInvestigationSomeone must examine and confirm this is a valid issue and not a duplicate of an existing one.

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions