Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
raspi opened this issue Jun 30, 2020 · 1 comment
Open

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

raspi opened this issue Jun 30, 2020 · 1 comment

Comments

@raspi
Copy link

@raspi raspi commented Jun 30, 2020

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>.

@gopherbot gopherbot added this to the Unreleased milestone Jun 30, 2020
@dmitshur
Copy link
Contributor

@dmitshur dmitshur commented Jul 1, 2020

/cc @mpvl per owners.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
3 participants