Lokalise illustration for beego framework

Beego framework tutorial: step by step with i18n examples

Sometime back we explored how a rising star of a language, namely, Go/Golang supports internationalization (i18n). But, given that you’re here, looks like you (or your organization) have taken things one step further by using Beego—one popular Go web framework—to smoothen out your web applications! However, while the importance of localization stays just the same, this begs the need to learn to approach i18n internationalization the Beego way.

Software internationalization is essential to creating flexible applications that can be easily adapted for various markets.

Hence, in this tutorial, let us take a look at how Beego makes Go l10n/i18n a bit easier, and quite more feature-packed.

We will cover the following topics with example in this tutorial:

  • Beego framework i18n/l10n (internationalization/localization).
  • Step-by-step guide from creating a Beego web app to internationalizing it.
  • Adding and managing locale files holding localization for multiple locales.
  • Using the Beego i18n module for internationalization purposes.
  • Localizing through RESTful HTTP requests.
  • Handling code duplication using Prepare function and implementing a base controller.
  • Date and time formatting through Beego built-in template functions.
  • Supporting section separation in localization using sections in INI.

    Assumptions

    Basic knowledge of:

    • Golang (Go)
    • REST/MVC Architectures

    Prerequisites

    A local environment set up with:

    • Go 1.11 or higher
    • Bee tool
    • Golang supported IDE
    • Any API Client (e.g.: Postman)

    Note: Mentioned Go version or greater is required for module support. Since we will be using Go modules, we would not require to install Beego to our system.

    Environment

    I will be using the following environment for my development purposes:

    • Go 1.16.5 windows/amd64
    • Bee tool v2.0.2
    • GoLang 2020.1 Build 201.6668.125
    • Postman 8.6.1

    The source code is available on GitHub.

    Basic Beego i18n project setup

    First things first, let’s create a simple Beego web project which we can use for our internationalization trickery later on.

    Bee tool allows us to do exactly this using a single-line command. Let’s open a Command Prompt inside any directory we prefer and enter the following:

    bee new BeegoI18n

    This would create a “BeegoI18n” RESTful MVC web project as a Go module along with an example MVC implementation.

    Secondly, let’s run a convenient tidy command Go developers have provided us to make sure our Go module holds all the dependencies it needs:

    go mod tidy

    That’s it! A basic Beego project (with all the RESTful MVC-related folders and files inside it) is already on our hands.

    Test it out

    Just to check if everything’s working just fine, let’s run our BeegoI18n project using a simple bee run command. We should now see our console printing it started the BeegoI18n server on http://localhost:8080.

    Add locale files

    How could our BeegoI18n project plan to internationalize if all its content only comprises a single default language of English?

    So, as our first step into i18n, let’s add a few locale files to our BeegoI18n project; each locale file we add would hold the same keys, but the values would bear the relevant localization for each locale.

    Firstly, let us add a locale file holding l10n values for the English locale. Let’s open our BeegoI18n project inside our IDE and add an en-US.ini file inside the project’s conf directory:

    welcome = Welcome!

    Secondly, let’s follow the same procedure to add an fr-FR.ini file holding its French locale counterparts:

    welcome = Bienvenue!

    Load localization

    First up, let’s open the “app.conf” file inside our BeegoI18n project and add a line as follows:

    langs = en-US|fr-FR

    This configuration holds the languages our application supports as bar-separated values.

    Now, it’s time to introduce Beego’s very own i18n module to our project! So secondly, let us add the Beego i18n package to our BeegoI18n Go module by running this command on the IDE console:

    go get github.com/beego/i18n

    Then, let’s ask our Go application to process the langs property we added inside “app.conf” each time the server runs, and load the provided languages along with the relevant localization onto the running app. So thirdly, let us head over to the routers/router.go file in our BeegoI18n project and insert the following code inside its init function:

    langs, err := beego.AppConfig.String("langs")  // 1
    if err != nil {  // 2
      fmt.Println("Failed to load languages from the app.conf")
      return
    }
    
    langsArr := strings.Split(langs, "|")  // 3
    
    for _, lang := range langsArr {  // 4
      if err := i18n.SetMessage(lang, "conf/"+lang+".ini"); err != nil {  // 5
        fmt.Println("Failed to set message file for l10n")
        return
      }
    }
    1. langs configuration inside the “app.conf” file is loaded to a langs string variable.
    2. Print an error message on the IDE console if an error occurred while loading configuration on step 1.
    3. Split langs string variable into substrings separated by the bar symbol (|); returned substrings are saved as a slice in langArr variable.
    4. langsArr slice is iterated holding each iteration’s value inside a lang variable.
    5. Per each iteration, the language currently in lang is passed along with the relevant locale INI file over to i18n.SetMessage function. This would let our application know which languages it supports, and which locale files to look into for each locale. If an error occurred while calling the i18n.SetMessage function, an error message is printed out to the IDE console.

    Enter Beego i18n

    Alright! We sorted out our locale files-related endeavors. Now, let’s find out how to use them in our BeegoI18n application.

    Initial setup

    Just to avoid complications and confusion, how about we leave the default RESTful MVC implementations on our BeegoI18n project alone and create our own MVC operations to handle i18n?

    Firstly, let us head over to the routers/router.go file in our BeegoI18n project. Now, let’s introduce a new HTTP route to our project by adding the following line inside its init function:

    beego.Router("/welcome", &controllers.WelcomeController{})

    This registers a router address with a /welcome URI and assigns a WelcomeController struct to handle its requests.

    Secondly, let’s create this missing WelcomeController inside our BeegoI18n project. Let us make a new “welcome.go” file inside the “controllers” directory and fill it like this:

    type WelcomeController struct {
      beego.Controller  // 1
      i18n.Locale  // 2
    }
    
    1. Add an anonymous field of Beego web.Controller inside the WelcomeController struct. This would embed Beego’s base controller to the WelcomeController struct letting it gain access to the base controller’s RESTful HTTP/MVC operations.
    2. Add an anonymous field of i18n.Locale to the WelcomeController struct. With this embedding, our WelcomeController would acquire the ability to process locale operations of the current request.

    Now, our BeegoI18n project is ready to get localized. Let’s find out how we can use different methods to achieve our localization.

    Using URL arguments

    Let’s see how we can pass our desired locale through an HTTP parameter.

    Firstly, let’s open up the welcome.go file Inside our BeegoI18n project and add a new Get function:

    func (welcomeController *WelcomeController) Get() {  // 1
      welcomeController.Data["langTemplateKey"] = welcomeController.GetString("lang")  // 2
      welcomeController.TplName = "welcome.tpl"  // 3
    }
    1. Create a Get function overriding the Get function in Beego web.Controller.
    2. Use Beego web.Controller.GetString function to obtain the value for parameter key "lang" from the GET request. The received value is put on the Beego web.Controller’s Data map with a key of "langTemplateKey". The View template would retrieve and use this language value later on when rendering.
    3. Set the name of the template to render as “welcome.tpl”. Now, Beego would make sure to find the provided template file under our BeegoI18n project’s viewpath, and render it along with the Data map values.

    Note: No parameter validation was performed on step 2 to keep to the scope of the article.

    Secondly, let us register a Tr function provided in the i18n package as a template function. Let’s head over to the main.go file in our BeegoI18n project and add the below-mentioned highlighted code inside its main function:

    func main() {
      beego.AddFuncMap("i18n", i18n.Tr)
      beego.Run()
    }

    Important Note: Make sure to place this line before the beego.Run function is executed; otherwise, the app would start without registering the i18n function!

    Beego web.AddFuncMap function call adds a map record with a key of “i18n” and a value of the i18n.Tr function itself which would later be accessible to the template.

    Thirdly, let’s create a “welcome.tpl” template View file inside our BeegoI18n project’s “view” directory, and add a simple line to it:

    {{i18n .langTemplateKey "welcome"}}

    This line would cause the passed in i18n.Tr function (abbreviated as a template function named i18n) to be called passing the “langTemplateKey” Data map value holding the required l10n language and the “welcome” string holding the locale file key required to be localized.

    Test it out

    Let’s run our BeegoI18n app server and use our API client app to make a GET request to the “http://localhost:8080/welcome” domain. Let us not forget to pass a "lang" parameter along with it holding each locale our application supports:

    In English (en-US) locale:

    In French (fr-FR) locale:

    As you can see, we could successfully localize the “welcome” resource value to multiple languages using HTTP request URL arguments.

    Using Accept-Language header

    Beego also lets us send our locale choice simply by setting an “Accept-Language” header in our HTTP request.

    Firstly, let’s navigate to our BeegoI18n project’s welcome.go file and replace its Get function with the following:

    func (welcomeController *WelcomeController) Get() {
      welcomeController.Data["langTemplateKey"] = welcomeController.Ctx.Request.Header.Get("Accept-Language")  // 1
      welcomeController.TplName = "welcome.tpl"  // 2
    }
    1. Change the "langTemplateKey" value on the Beego web.Controller’s Data map to the “Accept-Language” header value extracted from the GET request.
    2. Set the name of the template to render as “welcome.tpl”.

    Note: No header value validation was performed on step 1 to keep to the scope of the article.

    Test it out

    Let us run our BeegoI18n application server and use our API client app to make a GET request to the “http://localhost:8080/welcome” domain. This time, instead of a parameter, let’s pass an “Accept-Language” header holding our l10n preference:

    In English (en-US) locale:

    In French (fr-FR) locale:

    Evidently, our internationalized BeegoI18n app could just as easily localize the “welcome” resource to multiple localization using an “Accept-Language” header as well.

    Using cookies

    In both the methods we discussed earlier, we had to send our language preference embedded inside each HTTP request. But, guess what? Beego additionally allows us to save the language choice as a cookie in our—well.. technically our clients’ or customers’—browsers. This way, we can set Beego to retrieve this cookie for its l10n decisions, instead of expecting us to send our language choice each and every time we make a request.

    Firstly, let’s open our BeegoI18n application’s welcome.go file and add an i18nCookieSet boolean variable within it:

    var i18nCookieSet = false
    

    i18nCookieSet is simply a flag that indicates if a cookie declaring i18n related preferences has already been set or not.

    Secondly, let’s move inside the Get function in our welcome.go file and replace its content with this code snippet:

    func (welcomeController *WelcomeController) Get() {
      if !i18nCookieSet {
        welcomeController.Ctx.SetCookie("lang_choice", "fr-FR")  // 1
        i18nCookieSet = true  // 2
        welcomeController.Ctx.Output.Body([]byte("i18n cookie successfully set!"))  // 3
      } else {
        welcomeController.Data["langTemplateKey"] = welcomeController.Ctx.GetCookie("lang_choice")  // 4
      }
      welcomeController.TplName = "welcome.tpl"  // 5
    }
    1. If a cookie indicating i18n preferences isn’t set, use Context.SetCookie function to set a “lang_choice” cookie inside the client’s browser. This cookie would hold an l10n choice of the French locale.
    2. Mark the cookie indicating i18n preferences has been set by setting the i18nCookieSet boolean flag to true.
    3. Directly output to the browser with a success message.
    4. If a cookie indicating i18n preferences is already set, fetch the “lang_choice” cookie from the client’s browser using Context.GetCookie function. The acquired cookie value is put on the WelcomeController.Data map with a “langTemplateKey” key.
    5. Set the name of the template to render as “welcome.tpl”.

    Test it out

    Before sending the request, let us open up our API client app and make sure no cookies have been set at the moment:

    Note: You can do this in Postman by clicking the “Cookies” button right under the “Send” button.

    Now, let’s send a GET request to the “http://localhost:8080/welcome” domain. But, note that this time we would only send a plain GET request; with no parameters attached and no headers modified:

    In GET request response:

    In API client app cookies dialog:

    Then, let’s send the same GET request to “http://localhost:8080/welcome”. Now, we shall see a “welcome” resource nicely localized to the French locale just as we set in our cookie!

    We can resend the same request as many times as we’d fancy, but as long as the cookie lives, our Beego app would output the same localized response each time.

    Some Beego i18n extras

    So, we discovered all the essentials required to internationalize our Beego web application. But, before you begone to Beego-ing, why not learn a few more tricks in Beego i18n?

    How Beego helps to avoid code duplication

    Earlier, we created a WelcomeController struct of which we only overrode a single Get function of Beego web.Controller. Hence, we encountered no code duplication. Let’s find out a few occasions these duplication can occur and how we can overcome those.

    Prepare function

    Imagine a government top-secret agent happened to fall in love with our BeegoI18n app–a bit of an overkill, but a man can dream, right?. Nevertheless, he complained that whenever he sends his i18n language preference as a GET request URL parameter, it’s undeniably visible for any passers-by and/or any intruders to his network, which is obviously not acceptable for his line of work. Ergo emerges the need for a POST method endpoint for the same “http://localhost:8080/welcome” endpoint on our BeegoI18n app.

    Set up POST API endpoint for “/welcome” route

    Let’s head over to the welcome.go file in our BeegoI18n app and add a POST function:

    func (welcomeController *WelcomeController) Post() {  // 1
      welcomeController.Data["langTemplateKey"] = welcomeController.GetString("lang")  // 2
      welcomeController.TplName = "welcome.tpl"  // 3
    }
    1. Create a Post function overriding the Post function in Beego web.Controller.
    2. Use Beego web.Controller.GetString function to obtain the value for parameter key “lang” from the POST request. The received value is put on the Beego web.Controller’s Data map with a key of “langTemplateKey”. The View template would retrieve and use this language value later on when rendering.
    3. Set the name of the template to render as “welcome.tpl”.

    Just to test if it works as expected, let’s run our BeegoI18n server and send a POST request to the “http://localhost:8080/welcome” endpoint. And, to keep our top-secret agent happy, let us set the i18n language preference not as a URL parameter argument, but inside the POST request body with a ‘URL encoded form’ or ‘x-www-form-urlencoded’ type:

    As you might have noticed, this code is exactly the same as the Get method we coded when we initially learned how to localize using URL arguments. Except, of course, it’s a Post method definition this time instead of Get. So, in other words, we have met some code duplication within the same Beego controller.

    Beego developers have identified this issue and provided us with a convenient web.Controller.Prepare function to handle this. Once we override this Prepare function in our controller, Beego will make sure to always run the code inside it after the init function is executed but before any other request function is executed. Let’s see how we can use this behavior to our advantage!

    Firstly, let’s open the welcome.go file in our BeegoI18n app and add a Prepare function holding the duplicate code within both Get and Post functions:

    func (welcomeController *WelcomeController) Prepare() {
      welcomeController.Data["langTemplateKey"] = welcomeController.GetString("lang")
      welcomeController.TplName = "welcome.tpl"
    }

    Note: The highlighted Prepare function overrides the Prepare function in Beego web.Controller.

    Secondly, let’s remove both of those ugly duplicate code from Get and Post functions leaving them as two empty functions:

    func (welcomeController *WelcomeController) Get() {}
    func (welcomeController *WelcomeController) Post() {}
    Test it out

    That’s it! Testing our BeegoI18n app’s “http://localhost:8080/welcome” endpoint on both GET and POST REST methods would get us the localized response!

    Base controller

    Let’s assume we planned to extend our BeegoI18n application to provide multiple domain endpoints.

    So, let us go ahead and implement a new domain on URL “http://localhost:8080/thanks”; this endpoint would show a localized value thanking our clients for using our BeegoI18n server.

    Note: I will be skipping the code explanations for this section since they’d be identical to the initial explanations given when initiating the welcome.go file. Please refer to the ‘Using URL arguments’ section for any clarifications.

    Firstly, let us add relevant resources inside our locale files inside the BeegoI18n project’s “conf” directory:

    In en-US.ini:
    .
    thanks = Thank you for visiting us!
    In fr-FR.ini:
    .
    thanks = Merci de votre visite!

    Secondly, let’s open the routers/router.go file and add our new route inside its init function:

    .
    beego.Router("/thanks", &controllers.ThanksController{})

    Thirdly, it’s time to add the missing ThanksController by adding a thanks.go file to our BeegoI18n project’s “controllers” directory just like we did with the WelcomeController:

    type ThanksController struct {
      beego.Controller
      i18n.Locale
    }

    In the previous section, we learned how to avoid duplicate code within the same Beego controller. Hence, let’s put that knowledge to use and directly add a Prepare function to our thanks.go file along with empty Get and Post functions:

    func (thanksController *ThanksController) Prepare() {
      thanksController.Data["langTemplateKey"] = thanksController.GetString("lang")
      thanksController.TplName = "thanks.tpl"
    }
    
    func (thanksController *ThanksController) Get() {}
    func (thanksController *ThanksController) Post() {}

    Finally, let’s add the missing “thanks.tpl” template file within our BeegoI18n project’s “views” folder:

    {{i18n .langTemplateKey "thanks"}}

    Running our BeegoI18n server and testing out the “http://localhost:8080/thanks” domain on both GET and POST methods and both locales would give us the expected results. But, wasn’t it such a drag with so much boilerplate and duplicate code just to add a new domain?

    If only we could have a parent controller holding all this common code inside it, right? Well, although there’s no OOP inheritance support in Go per se, we could definitely mimic it using a base Go file that holds all the common code and all other controllers would embed! Let’s see how in the next section.

    Introduce base controller

    Firstly, let’s add a base.go file inside our BeegoI18n project’s “controllers” directory:

    type BaseController struct {  // 1
      beego.Controller
      i18n.Locale
    }
    
    type ChildPrepareHolder interface {  // 2
      ChildPrepare()
    }
    
    func (baseController *BaseController) Prepare() {  // 3
      baseController.Data["langTemplateKey"] = baseController.GetString("lang")  // 4
    
      if app, ok := baseController.AppController.(ChildPrepareHolder); ok {  // 5
        app.ChildPrepare()
      }
    }
    1. BaseController struct holds both Beego web.Controller and i18n.Locale which other controllers can later embed through BaseController.
    2. ChildPrepareHolder interface declared. Later on, other controllers can implement the interface making it possible for this BaseController to call a ChildPrepare function in other controllers.
    3. Prepare function on the BaseController which would be called by requests to all other controllers. Hence, this function can act as a common Prepare function to all other controllers.
    4. Use Beego web.Controller.GetString function to obtain the value for parameter key “lang” from the POST request. The received value is put on the Beego web.Controller’s Data map with a key of “langTemplateKey”. This is a common line within the Prepare functions of all other controllers.
    5. baseController.AppController holds the currently executing controller. Therefore, Go type assertion is used to check if the executing controller is of type ChildPrepareHolder (implements ChildPrepareHolder interface) and if it is, retrieves its value to an app variable. Later, ChildPrepareHolder.ChildPrepare interface function is called through the app variable, which fundamentally calls the currently executing controller’s ChildPrepare implementation.

    Secondly, let’s head over to the controllers/welcome.go file and make the following changes:

    type WelcomeController struct {
      BaseController  // 1
    }
    
    func (welcomeController *WelcomeController) ChildPrepare() {  // 2
      welcomeController.TplName = "welcome.tpl"  // 3
    }
    1. Instead of embedding Beego web.Controller and i18n.Locale, simply the BaseController is embedded which itself embeds web.Controller and i18n.Locale.
    2. Refactor the Prepare function and rename it as ChildPrepare to have the WelcomeController implicitly implement the ChildPrepareHolder interface.
    3. Only the code unique to WelcomeController is put in its ChildPrepare function (which is called by the BaseController after it’s done executing the common logic).

    Thirdly, let’s make similar changes on controllers/thanks.go file as well:

    type ThanksController struct {
      BaseController
    }
    
    func (thanksController *ThanksController) ChildPrepare() {
      thanksController.TplName = "thanks.tpl"
    }
    Test it out

    That’s all it takes! Testing our BeegoI18n app’s “http://localhost:8080/welcome” and “http://localhost:8080/thanks” endpoints on both GET and POST methods and both locales would give us the expected localized responses! And, this time, our code is as clean as it can be!

    Beego date and time i18n

    If you’re planning to develop (or already developing) a Beego web application facing your customers, sooner or later you’re going to have to deal with dates and times.

    We can use Beego’s built-in template functions to easily handle date and time-related concerns in our app’s templates themselves. Let’s find out how, shall we?

    First off, let us quickly set up a new REST API route on “http://localhost:8080/datetime” to our BeegoI18n project.

    Set up “/datetime” REST API route

    Firstly, let’s head over to the router.go file and add a new “/datetime” route inside the init method:

    beego.Router("/datetime", &controllers.DatetimeController{})

    Secondly, let’s create this missing DatetimeController inside our BeegoI18n project. Let us make a new “datetime.go” file inside the “controllers” directory and fill it like this:

    type DatetimeController struct {  // 1
      beego.Controller
      i18n.Locale
    }
    
    func (datetimeController *DatetimeController) Get() {
      datetimeController.Data["DateTimeKey"] = time.Now()  // 2
      datetimeController.TplName = "datetime.tpl"  // 3
    }
    1. Create a DatetimeController struct embedding Beego web.Controller and i18n.Locale.
    2. The current local time is received using Go built-in Time.Now() function. This obtained value is put on the Beego web.Controller’s Data map with a key of “currentDateTimeKey”.
    3. Set the name of the template to render as “datetime.tpl”.

    Note: More details regarding Go built-in Time package can be seen on the ‘Date and time’ section of our Go internationalization article.

    Thirdly, let us register a Date function (provided as a Beego built-in template function) that formats a given Time to a provided format. Let’s head over to the main.go file in our BeegoI18n project and add the below-mentioned highlighted code inside its main function:

    func main() {
      .
      beego.AddFuncMap("datetimefmt", beego.Date)
      beego.Run()
    }

    Important Note: Make sure to place this line before the beego.Run function is executed; otherwise, the app would start without registering the date function!

    Beego web.AddFuncMap function call adds a map record with a key of “datetimefmt” and a value of the beego.Date function itself which would later be accessible to the template.

    Finally, let’s create a “datetime.tpl” template View file inside our BeegoI18n project’s “view” directory, and add a simple line to it:

    {{datetimefmt .currentDateTimeKey "Y-m-d H:i:s"}}

    This line would cause the passed in Beego Date function (abbreviated as a template function named datetimefmt) to be called. The date-time value on currentDateTimeKey and a date-time format string it needs to format as are passed in when calling this datetimefmt function.

    Note: According to Beego, the Date function uses PHP date-time syntax.

    Test it out

    We’re all set! Running our BeegoI18n server and heading to “http://localhost:8080/datetime” should give us the current date and time formatted in the format we provided:

    Section separation of localization

    Sometimes, there can be instances we’d need to display the same localization value on one page of our app slightly differently on another page. For example, assume we thought of adding a thanks message on our “/welcome” domain as well. But, we need it not to hold the same generic “Thank you for visiting us!” value, but rather a value showing gratification for visiting our server. But, all in all, it would still be a thanking message. So, it’d be quite repetitive to introduce another key to our locale files, right?

    Beego supports the use of sections in INI that could be pretty useful to overcome this. Let us go ahead and see how we can implement section-based i18n value separation on our Beego app!

    Firstly, let’s open our locale files inside our BeegoI18n project’s “conf” directory and add the highlighted changes to it:

    In en-US.ini:

    welcome = Welcome!
    thanks = Thank you for visiting us!

    [main]

    thanks = Thanks for visiting our server!

    In fr-FR.ini:

    welcome = Bienvenue!
    thanks = Merci de votre visite!

    [main]

    thanks = Merci d`avoir visité notre serveur!

    Hereupon, we have two values on each locale file for the same key. But, for the second key on each, they’re separated by a “[main]” heading.

    Secondly, let us head over to the welcome.tpl file within the “views” folder and add a line below the existing one:

    .
    {{i18n .langTemplateKey "main.thanks"}}

    Now, the i18n template function—which implicitly executes the Tr function—would be called with an i18n key prefixed by the section name. And, as we can clarify through a sneak peek into the Tr function’s source code itself, this i18n function call extracts the section and passes it on as a separate parameter to the Get function.

    Test it out

    Let’s run our BeegoI18n server and send GET requests to both “http://localhost:8080/welcome” and “http://localhost:8080/thanks” domains:

    On http://localhost:8080/welcome domain

    On http://localhost:8080/thanks domain

    As we can observe, although both templates accessed a key of “thanks” from the locale files, the “/welcome” domain retrieved the value from the “main” section while the “/thanks” domain obtained the usual value.

    Localize with Lokalise

    I think it’s time to pat yourself on the back since as we speak you and/or your team are challenging the status quo! From choosing a quite unripe language Go for your app development, all the way to using the Beego framework beyond Go built-in HTTP facilities to write your RESTful web application, over to putting in extra time to internationalize your web service instead of counting on all your clients to speak English, and utilizing translation management system to efficiently handle your multilingual content, surely you must have passed a great number of your competitors already!

    But, why not be a bit less hard on yourself since when it comes to Beego i18n, there’s a much easier, 1000x faster, and much more convenient way just hiding in plain sight?

    Meet Lokalise, the translation management system that takes care of all your Beego app’s internationalization wants and needs. With features like:

    • Easy integration with various other services
    • Collaborative translations
    • Quality assurance tools for translations
    • Easy management of your translations through a central dashboard
    • Plus, loads of others

    Lokalise will make your life a whole lot easier by letting you expand your Beego i18n-powered app to all the locales you’ll ever plan to reach.

    Start with Lokalise in just a few steps:

    • Sign up for a free trial (no credit card information required).
    • Log in to your account.
    • Create a new project under any name you like.
    • Upload your translation files and edit them as required.

    That’s all it takes! You have already completed the baby steps toward Lokalise-ing your Beego web application. See the Getting Started section for a collection of articles that will provide all the help you’ll need to kick-start the Lokalise journey. Also, refer to Lokalise API Documentation for a complete list of REST commands you can call on your Lokalise internationalization project.

    Conclusion

    In this tutorial, we took a step-by-step dive into localizing a Beego RESTful MVC web application into multiple languages. We explored how to create a basic Beego MVC project using the Bee tool and add locale files holding language resources in multiple languages to it. Afterward, we deduced ways to carry out Beego i18n using URL arguments, Accept-Language headers, and cookies.

    Moreover, we learned procedures to avoid code duplication in our Beego web applications, i.e., Prepare function, base controller, and formatting date and time utilizing Beego built-in template functions. Further, we looked at separating localization into sections through Beego-supported INI features.

    And thereupon, it’s time for me to begone so you can start your Beego-ing. Drop me a line if you have any questions, and don’t hesitate to leave a comment.

    Till we meet again, do mind getting both shots of those COVID-19 vaccines, so you may safely live on to (hopefully) accidentally or even (deceitfully) intentionally code some digital bugs for those QA guys to catch!

    Further reading

    Related articles
    Stop wasting time with manual localization tasks. 

    Launch global products days from now.