You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
136 lines
4.4 KiB
136 lines
4.4 KiB
3 years ago
|
# i18n Example
|
||
|
This project is an demo for i18n usage.
|
||
|
We integrated [go-i18n](https://github.com/nicksnyder/go-i18n) into our project for localization.
|
||
|
|
||
|
We start with the project generate with `kratos-layout`, you could use `kratos new` to generate it.
|
||
|
|
||
|
The following steps are applied.
|
||
|
## Step 1: install
|
||
|
Install the cli tool `goi18n` and the package.
|
||
|
|
||
|
```bash
|
||
|
go get -u github.com/nicksnyder/go-i18n/v2/goi18n
|
||
|
go get -u github.com/nicksnyder/go-i18n
|
||
|
```
|
||
|
|
||
|
## Step 2: implement and register the middleware
|
||
|
There's a middleware in `internal/pkg/middleware/localize`,
|
||
|
we implement this middleware, and register it into our http server in `internal/server/http.go`.
|
||
|
We init the bundle and load our translation file(we will generate it later).
|
||
|
For convenience, we hard-coded the translation file path here, you should avoid it in your project :)
|
||
|
|
||
|
Also the middleware will extract `accept-language` header
|
||
|
from our request, then set the correct `localizer` to the context.
|
||
|
In our service request handler, we can use the `FromContext` method to get this `localizer` for localization.
|
||
|
|
||
|
This middleware is so simple that we can show it as following:
|
||
|
```go
|
||
|
package localize
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
"github.com/BurntSushi/toml"
|
||
|
"github.com/nicksnyder/go-i18n/v2/i18n"
|
||
|
"golang.org/x/text/language"
|
||
|
|
||
|
"github.com/go-kratos/kratos/v2/middleware"
|
||
|
"github.com/go-kratos/kratos/v2/transport"
|
||
|
)
|
||
|
|
||
|
type localizerKey struct{}
|
||
|
|
||
|
func I18N() middleware.Middleware {
|
||
|
bundle := i18n.NewBundle(language.English)
|
||
|
bundle.RegisterUnmarshalFunc("toml", toml.Unmarshal)
|
||
|
bundle.MustLoadMessageFile("../../active.zh.toml")
|
||
|
|
||
|
return func(handler middleware.Handler) middleware.Handler {
|
||
|
return func(ctx context.Context, req interface{}) (reply interface{}, err error) {
|
||
|
if tr, ok := transport.FromServerContext(ctx); ok {
|
||
|
accept := tr.Header().Get("accept-language")
|
||
|
println(accept)
|
||
|
localizer := i18n.NewLocalizer(bundle, accept)
|
||
|
ctx = context.WithValue(ctx, localizerKey{}, localizer)
|
||
|
}
|
||
|
return handler(ctx, req)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func FromContext(ctx context.Context) *i18n.Localizer {
|
||
|
return ctx.Value(localizerKey{}).(*i18n.Localizer)
|
||
|
}
|
||
|
```
|
||
|
|
||
|
## Step 3:
|
||
|
Write our request handler code.
|
||
|
In `internal/service/greeter.go`, we use `localize.FromContext(ctx)` to get the localizer, and write the string for localizing.
|
||
|
You should write your message with golang template syntax.
|
||
|
Notice that both `One` and `Other` fields must be filled or you will get an panic on translation file generation with `goi18n` tool.
|
||
|
|
||
|
```go
|
||
|
func (s *GreeterService) SayHello(ctx context.Context, in *v1.HelloRequest) (*v1.HelloReply, error) {
|
||
|
s.log.WithContext(ctx).Infof("SayHello Received: %v", in.GetName())
|
||
|
|
||
|
if in.GetName() == "error" {
|
||
|
return nil, v1.ErrorUserNotFound("user not found: %s", in.GetName())
|
||
|
}
|
||
|
localizer := localize.FromContext(ctx)
|
||
|
helloMsg, err := localizer.Localize(&i18n.LocalizeConfig{
|
||
|
DefaultMessage: &i18n.Message{
|
||
|
Description: "sayhello",
|
||
|
ID: "sayHello",
|
||
|
One: "Hello {{.Name}}",
|
||
|
Other: "Hello {{.Name}}",
|
||
|
},
|
||
|
TemplateData: map[string]interface{}{
|
||
|
"Name": in.Name,
|
||
|
},
|
||
|
})
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
return &v1.HelloReply{Message: helloMsg}, nil
|
||
|
}
|
||
|
```
|
||
|
|
||
|
## Step 3: Generate and translate
|
||
|
|
||
|
In the root of this project, generate `active.en.toml` with
|
||
|
```bash
|
||
|
goi18n extract
|
||
|
```
|
||
|
The string which should be translated will be extracted from your code, and write into `active.en.toml`
|
||
|
You should create the empty target language file:
|
||
|
```bash
|
||
|
touch tranlate.zh.toml
|
||
|
```
|
||
|
|
||
|
Then fill the translate file:
|
||
|
```bash
|
||
|
goi18n merge active.en.toml translate.zh.toml
|
||
|
```
|
||
|
|
||
|
You should edit the `translate.zh.toml` to finish the translation work. We translate `Hello` to `你好` in Chinese.
|
||
|
After that, you should rename this file to `active.zh.toml`
|
||
|
And this file is the translation file that we load in the Step 2.
|
||
|
You could also embed these translation files into your binaries for easier deployment.
|
||
|
|
||
|
## Step 4: Run
|
||
|
Go to `cmd/i18n/`, and run `go run .` to start the service.
|
||
|
|
||
|
You could try with curl with `Accept-Language` header
|
||
|
```bash
|
||
|
curl "http://localhost:8000/helloworld/eric" \
|
||
|
-H 'Accept-Language: zh-CN'
|
||
|
```
|
||
|
Will get the Chinese result `{"message":"你好 eric"}`
|
||
|
|
||
|
And if no header:
|
||
|
```
|
||
|
curl "http://localhost:8000/helloworld/eric"
|
||
|
```
|
||
|
Will get the default English result `{"message":"Hello eric"}`
|
||
|
|
||
|
## Reference
|
||
|
* [go-i18n](https://github.com/nicksnyder/go-i18n) You could refer to this repository for more detailed document.
|