Skip to content
This repository has been archived by the owner on Feb 24, 2024. It is now read-only.

Commit

Permalink
Merge pull request #763 from gobuffalo/simplify-i18n
Browse files Browse the repository at this point in the history
Simplify i18n
  • Loading branch information
markbates authored Nov 19, 2017
2 parents 65de218 + 626b077 commit ea3de19
Show file tree
Hide file tree
Showing 6 changed files with 98 additions and 46 deletions.
91 changes: 48 additions & 43 deletions middleware/i18n/i18n.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,8 @@ type Translator struct {
// default is "lang"
SessionName string
// HelperName - name of the view helper. default is "t"
HelperName string
// HelperNamePlural - name of the view plural helper. default is "tp"
HelperNamePlural string
LanguageFinder LanguageFinder
HelperName string
LanguageFinder LanguageFinder
}

// Load translations from the t.Box.
Expand All @@ -59,13 +57,12 @@ func (t *Translator) AddTranslation(lang *language.Language, translations ...tra
// also call t.Load() and load the translations from disk.
func New(box packr.Box, language string) (*Translator, error) {
t := &Translator{
Box: box,
DefaultLanguage: language,
CookieName: "lang",
SessionName: "lang",
HelperName: "t",
HelperNamePlural: "tp",
LanguageFinder: defaultLanguageFinder,
Box: box,
DefaultLanguage: language,
CookieName: "lang",
SessionName: "lang",
HelperName: "t",
LanguageFinder: defaultLanguageFinder,
}
return t, t.Load()
}
Expand All @@ -74,6 +71,7 @@ func New(box packr.Box, language string) (*Translator, error) {
// selected. By default languages are loaded in the following order:
//
// Cookie - "lang"
// Session - "lang"
// Header - "Accept-Language"
// Default - "en-US"
//
Expand All @@ -91,45 +89,52 @@ func (t *Translator) Middleware() buffalo.MiddlewareFunc {
}
}

// set languages in context, if not set yet
if langs := c.Value("languages"); langs == nil {
c.Set("languages", t.LanguageFinder(t, c))
}

// set translator
if T := c.Value("T"); T == nil {
langs := c.Value("languages").([]string)
T, err := i18n.Tfunc(langs[0], langs[1:]...)
if err != nil {
return err
}
c.Set("T", T)
}

// set up the helper function for the views:
c.Set(t.HelperName, func(s string) (string, error) {
return t.Translate(c, s)
})
c.Set(t.HelperNamePlural, func(s string, i interface{}) (string, error) {
return t.TranslatePlural(c, s, i)
c.Set(t.HelperName, func(s string, i ...interface{}) string {
return t.Translate(c, s, i...)
})
return next(c)
}
}
}

// Translate translates a string given a Context
// s is the translation ID
func (t *Translator) Translate(c buffalo.Context, s string) (string, error) {
if langs := c.Value("languages"); langs == nil {
c.Set("languages", t.LanguageFinder(t, c))
}
langs := c.Value("languages").([]string)
T, err := i18n.Tfunc(langs[0], langs[1:]...)
if err != nil {
return "", err
}
return T(s, c.Data()), nil
}

// TranslatePlural is the plural version of Translate
// s is the translation ID
// i must be an integer type (int, int8, int16, int32, int64) or a float formatted as a string (e.g. "123.45")
func (t *Translator) TranslatePlural(c buffalo.Context, s string, i interface{}) (string, error) {
if langs := c.Value("languages"); langs == nil {
c.Set("languages", t.LanguageFinder(t, c))
}
langs := c.Value("languages").([]string)
T, err := i18n.Tfunc(langs[0], langs[1:]...)
if err != nil {
return "", err
}
return T(s, i, c.Data()), nil
// Translate returns the translation of the string identified by translationID.
//
// See https://github.com/nicksnyder/go-i18n
//
// If there is no translation for translationID, then the translationID itself is returned.
// This makes it easy to identify missing translations in your app.
//
// If translationID is a non-plural form, then the first variadic argument may be a map[string]interface{}
// or struct that contains template data.
//
// If translationID is a plural form, the function accepts two parameter signatures
// 1. T(count int, data struct{})
// The first variadic argument must be an integer type
// (int, int8, int16, int32, int64) or a float formatted as a string (e.g. "123.45").
// The second variadic argument may be a map[string]interface{} or struct{} that contains template data.
// 2. T(data struct{})
// data must be a struct{} or map[string]interface{} that contains a Count field and the template data,
// Count field must be an integer type (int, int8, int16, int32, int64)
// or a float formatted as a string (e.g. "123.45").
func (t *Translator) Translate(c buffalo.Context, translationID string, args ...interface{}) string {
T := c.Value("T").(i18n.TranslateFunc)
return T(translationID, args...)
}

func defaultLanguageFinder(t *Translator, c buffalo.Context) []string {
Expand Down
33 changes: 32 additions & 1 deletion middleware/i18n/i18n_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ import (
"github.com/stretchr/testify/require"
)

type User struct {
FirstName string
LastName string
}

func app() *buffalo.App {
app := buffalo.New(buffalo.Options{})

Expand All @@ -30,6 +35,13 @@ func app() *buffalo.App {
app.GET("/plural", func(c buffalo.Context) error {
return c.Render(200, r.HTML("plural.html"))
})
app.GET("/format", func(c buffalo.Context) error {
usersList := make([]User, 0)
usersList = append(usersList, User{"Mark", "Bates"})
usersList = append(usersList, User{"Chuck", "Berry"})
c.Set("Users", usersList)
return c.Render(200, r.HTML("format.html"))
})
return app
}

Expand Down Expand Up @@ -69,4 +81,23 @@ func Test_i18n_plural_fr(t *testing.T) {
req.Headers["Accept-Language"] = "fr-fr"
res := req.Get()
r.Equal("Bonjour, tout seul !\nBonjour, 5 personnes !\n", res.Body.String())
}
}

func Test_i18n_format(t *testing.T) {
r := require.New(t)

w := willie.New(app())
res := w.Request("/format").Get()
r.Equal("Hello Mark!\n\n\t* Mr. Mark Bates\n\n\t* Mr. Chuck Berry\n", res.Body.String())
}

func Test_i18n_format_fr(t *testing.T) {
r := require.New(t)

w := willie.New(app())
req := w.Request("/format")
// Set language as "french"
req.Headers["Accept-Language"] = "fr-fr"
res := req.Get()
r.Equal("Bonjour Mark !\n\n\t* M. Mark Bates\n\n\t* M. Chuck Berry\n", res.Body.String())
}
6 changes: 6 additions & 0 deletions middleware/i18n/locales/test.en-us.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,9 @@
translation:
one: "Hello, alone!"
other: "Hello, {{.Count}} people!"

- id: test-format
translation: "Hello {{.Name}}!"

- id: test-format-loop
translation: "Mr. {{.FirstName}} {{.LastName}}"
6 changes: 6 additions & 0 deletions middleware/i18n/locales/test.fr-fr.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,9 @@
translation:
one: "Bonjour, tout seul !"
other: "Bonjour, {{.Count}} personnes !"

- id: test-format
translation: "Bonjour {{.Name}} !"

- id: test-format-loop
translation: "M. {{.FirstName}} {{.LastName}}"
4 changes: 4 additions & 0 deletions middleware/i18n/templates/format.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<%= t("test-format", {Name: "Mark"}) %>
<%= for (u) in Users { %>
* <%= t("test-format-loop", u) %>
<% } %>
4 changes: 2 additions & 2 deletions middleware/i18n/templates/plural.html
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
<%= tp("greeting-plural", 1) %>
<%= tp("greeting-plural", 5) %>
<%= t("greeting-plural", 1) %>
<%= t("greeting-plural", 5) %>

0 comments on commit ea3de19

Please sign in to comment.