As I improve my knowledge and framework for a Go based web service I am building, I continue to go back and enhance my Beego Sample App. Something I just added recently was providing localized messages for validation errors. I was fortunate to find Nick Snyder's go-i18n package. Nick's package made it easy to support multiple languages for the Go web service I am writing.
The go-i18n package is simple to use and you can use it to read files or strings that contain all the messages you want to localize. It has some nice features including variable substitution and support for handling plurals for each individual locale. Nick has documentation for his package, so I am going to show you how I abstracted and integrated go-i18n into the Beego sample app.
I decided I didn't want to use files to store the messages, but create raw string literal variables. The less I had to worry about managing external resources the better. With that being said, I built a simple package that abstracted the support I needed. Luckily go-i18n supports passing in a string that can contain the JSON document with the message data:
I am just using simple messages right now, but as you can see, the variable En_US is defined and assigned a JSON document with the messages I need localized. The go-i18n package also lets you define messages like this:
In this sample, the translation has one message for the singular case and one for the plural case. There is also support for using variable substitution thanks to template support.
Here is the localize package that provides support for the web service:
The Init function creates the default locale for the application. Currently the Beego Sample App only supports English for the United States. Eventually, we can add cases for the other locales. Obviously this can all be done through configuration in the future.
The Init function uses the LoadJSON function to load the go-i18n datastore with the internal messages for the default locale. Later on we can use the LoadJSON function again to load more JSON documents for the same or different locales.
The Init function also uses the NewTranslation function to obtain a new i18n.TranslateFunc object for the default locale. This object is used to retrieve messages from the go-i18n datastore. If we have a scenario where the default locale is not valid, we can use the NewTranslation function at any time to obtain an object for the locale we need.
To see how I integrated the go-i18n package into the sample app, we need to look at the controller:
As discussed in my previous post about the Beego Sample App, we define a struct with tags that are used by the Beego validation module. I added support for defining the error to be returned when validation fails, by providing a new tag called error. In this case the error tag contains the id of the localized message we want to return. The ParseAndValidate function will handle the rest:
When the Beego validation module finds a problem, then the real work begins. The function uses reflection to find the error tag on any of the fields in the param struct. If an error tag is found, the id of the localized message is stored along with the field name. Then the function ranges over all the errors that the Beego validation module found and if an error tag existed for that field, we use the id to retrieve the localized message.
If we run the run_endpoint_test.sh shell script, which can be found in the zscripts folder, we can see the localized message returned in the last test:
The last test is designed to validate the localized message is returned.
The Beego framework has been great for developing my Go web service. It has the right amount of framework and modules, like the validation module, when you need it. The ability to bring in a package like go-i18n and integrate it so easily is another big win for Beego.
If you are in need for localizing your Go application, take a look at go-i18n and see if it can work for you.