CloudyKit / jet

Jet template engine
Apache License 2.0
1.23k stars 103 forks source link

Add internationalization support #3

Open jhsx opened 8 years ago

jhsx commented 8 years ago

Support for internationalization can be done by adding a new token type in the lexer, and an evaluator that would call the translator.Translate passed to the template.ExecuteI18n.

Also add a builtin function trans, a type Translator interface{ Translate(v string,i ...interface{}) error }

hao1118 commented 7 years ago

I do internationalization in this way: //in handler or add i18n to global functions m := jet.VarMap{} m.Set("i18n", GetText) //func GetText(locale,str string)string{...} Render(ctx, "public/home", m, data) //ctx=*fasthttp.RequestCtx, I use fasthttp and jet template, so fast ;-) //in template {{i18n(user.Locale,"String to translate")}}

annismckenzie commented 7 years ago

Yep, doing it the same way. But it has issues when you're trying to add pluralization because all the libraries out there are using Golang templates under the hood which results in multiple evaluations of template parts. Let's just wait on @jhsx on what he has in mind. :)

nkev commented 7 years ago

@hao1118 How do you use jet templating engine to render to fasthttp? fasthttp does not have response.Writer... I tried jetView.Execute(fasthttp.Response.BodyWriter(), nil, c) but that renders only body section as string.

annismckenzie commented 7 years ago

@nkev: you can't pass fasthttp.Response.BodyWriter(). For one, it doesn't belong to an instantiated object/context. It also doesn't belong to a request. Looking at the example at https://github.com/valyala/fasthttp#switching-from-nethttp-to-fasthttp (slightly edited for brevity):

  type MyHandler struct {
    foobar string
  }

  // request handler in net/http style, i.e. method bound to MyHandler struct.
  func (h *MyHandler) HandleFastHTTP(ctx *fasthttp.RequestCtx) {
    t, _ := jetView.GetTemplate("some_template.jet")
    t.Execute(ctx, map[string]interface{}, nil)
  }

  // pass bound struct method to fasthttp
  myHandler := &MyHandler{foobar: "foobar"}
  fasthttp.ListenAndServe(":8080", myHandler.HandleFastHTTP)

Let's unpack this: fasthttp's request context already implements the io.Writer interface (see https://github.com/valyala/fasthttp/blob/b43280dfe8ade44056e0179593f8ab30f82a7f47/server.go#L1002) so you can just pass the context to the template's Execute function.

Here's a pointer to the relevant documentation in the wiki: https://github.com/CloudyKit/jet/wiki/Rendering-templates.

If you need help, we're on Gitter: https://gitter.im/CloudyKit/jet. :)

nkev commented 7 years ago

@annismckenzie Thank you for taking the time to write the detailed response. Much appreciated!

annismckenzie commented 7 years ago

Happy to help!

hao1118 commented 7 years ago

hi @nkev, here is my render function:

https://github.com/hao1118/fasthttp-rendering-jet-template

nkev commented 7 years ago

Wow! Including gzip, minification and caching... that's almost a framework, thank you!

hao1118 commented 7 years ago

ya, almost a framework if having session and database modules. I use "github.com/fasthttp-contrib/sessions" and mongodb "gopkg.in/mgo.v2".

func RenderCache should add support for no-gzip clients(unzip gzipped cache data).

annismckenzie commented 7 years ago

Guys, while I appreciate you exchanging code and ideas I'd suggest moving this to the Gitter chat room because it has nothing to do with this issue. Agreed? :)

hao1118 commented 7 years ago

@annismckenzie : I just moved the code to my own github page ;-)

Dynom commented 3 years ago

A bit of an old topic, but I figured that since it has a relevant solution and since it's still open, it still makes sense to add it here.

I'm wondering if the Translator interface can be changed, currently it's:

type Translator interface {
    Msg(key, defaultValue string) string
    Trans(format, defaultFormat string, v ...interface{}) string
}

I'm not sure what Msg() should do, but Trans() is a pretty common API that is shared by go-i18n:

type TranslateFunc func(translationID string, args ...interface{}) string

Currently the translator is accepted, but never used, which sounds like that it's safe to change.

func (t *Template) ExecuteI18N(translator Translator, w io.Writer, variables VarMap, data interface{}) (err error) {

    // ..    
    st.translator = translator
    // ..           
}

The reason for my request is that I want to influence the function responsible for translation while passing it through to Execute(), e.g.:

// ..

T, err := svc.tr.Tfunc(locale, formal, user.RegionSettings)
if err != nil {
    return false, err
}

err = tpl.ExecuteI18N(T, &writer, nil, nil)
// ..

This way we can keep the templates nice and clean:

{{ T: "my.awesome.key" }}

My current work-around is:

tpl.Execute(html, jet.VarMap{"T": reflect.ValueOf(T)}, nil)

With the template:

{{ T("my.awesome.key") }}