Multi-language single page applications

Introduction

When we are developing applications, one of the challenges is to manage several languages. In particular, I am dealing with this matter in a personal project, which is being developed using vue.js. (https://vuejs.org/), so this post is focused on vue.js, but it could be used by other technologies.

In order to maintain your language translations, several aspects are desirable:

  • Easy to use. For example, if I am writing html, one tag or class should be enough to say that I want to translate a given literal.
  • Easy to maintain. When we are writing code, we don't want to care about translations or sometimes even we are not allowed to choose a particular, maybe because it is a decision of a different department or a professional translator.
  • Available for multiple coding languages. For example, if we are developing with vue.js, we should consider html, javascript or vue files. If we migrate our application to a different technology (like Angular), our translations should work with that technology too.
  • Plural support: sometimes, we show the number of items of a list, and the translations could change depending on the number of items. Our translation manager should be able to do this easily.

Gettext is one of the most popular internationalization and localization (i18n) systems, which is designed to minimize the impact of internationalization on program sources, keeping this impact as small and hardly noticeable as possible. Internationalization has better chances of succeeding if it is very light weighted. https://www.gnu.org/software/gettext/

One of the biggest advantages of using gettext is the fact that there are a lot of frameworks to use it in most of technologies. In the particular case of vue.js, we have the npm package vue-gettext to make easy the usage of gettext. (https://github.com/Polyconseil/vue-gettext)

To install vue-gettext we open a cmd where our package.json is located and we type:

       npm install vue-gettext

Extracting translations from your code

In order to generate translation files, vue-gettext depends on easygettext, which at the same time depends on two packages:
  • gettext-extract to extract annotated strings from template files and produce a .pot (Portable Object Template) file.
  • gettext-compile to produce the sanitized JSON version of a .po file.
In spite of the fact that vue-gettext tries to simplify the translations extraction, I prefer using directly the package gettext-extract (https://www.npmjs.com/package/gettext-extract), since you can use the file .gettext.json to define the rules to extract your translations.

In the JSON below, we can see a simple example of .gettext.json, where we are going to extract translation expressions in javascript and html files, which are the most common files in vue projects.


{
  "js": {

    "parsers": [
      {
        "expression": "gettext",
        "arguments": {
          "text": 0
        }
      },
      {
        "expression": "ngettext",
        "arguments": {
          "text": 0,
          "textPlural": 1
        }
      },
      {
        "expression": "pgettext",
        "arguments": {
          "context": 0,
          "text": 1
        }
      }
    ],
    "glob": {
      "pattern": "src/**/*.js"
    }
  },
  "html": {
    "parsers": [
      {
        "element": "[v-translate]",
        "attributes": {
          "textPlural": "translate-plural",
          "context": "translate-context"
        }
      },
      {
        "attribute": "translate-text",
        "attributes": {
          "textPlural": "translate-plural",
          "context": "translate-context"
        }
      }
    ],
    "glob": {
      "pattern": "src/**/*.vue"
    }
  },
  "headers": {
    "Language": ""
  },
  "output": "translations/dictionary.pot"
}
}

For javascript, the extractor will search for the following expressions:

  • gettext: simple translations
  • ngettext: plural translations
  • pgettext: translation with context (for example if we have the same key for different parts of the application, the context might differ). 

For html, there are two possibilities, the element v-translate or the attribute translate-text. One example to use translations in html is:

        <span v-translate>Welcome</span>

Steps to use translations extraction

  • Generate your rules for extraction in .gettext.json and place in the same folder as you package.json
  • Install the package gettext-extract: 
    • npm install gettext-extract --save-dev
  • Write your code using the translation rules
  • In package.json file add the following script:     
    • "gettext-extract": "gettext-extract"
  • Extract your translations and generate your template dictionary.pot with the command: 
    • npm run gettext-extract

Managing languages


Once we have generated the templete .pot file, we need to create or update the different languages that we will support.

PoEdit

To create po files from pot templates, we can use poedit, which is a free multi-platform desktop application. https://poedit.net/


 With pro edition, we will have some extra features, as for example automatic suggestions for translation.

PoEditor

Another alternative is PoEditor (https://poeditor.com), which offers us an online application to manage our translations with a very well designed interface.



In a free account, you can manage only 1000 strings. But this is a utterly powerful application, since it can be integrated with other applications like GitHub, VSTS, Bitbucket, etc.

Now, from our .po files, we need to merge them into one JSON file, in order to support multiple languages in our vue.js application. To carry out this, we need to add to our package.json file the following script, considering that we had two translation files es.po and en.po:

    "gettext-compile": "gettext-compile --output ./translations/translations.json ./translations/es.po ./translations/en.po"

Now, as always, we execute the command:

    npm run gettext-compile

As a result, we will obtain the file translations.json, which can be used by our application vue.js.

Using translations in vue.js applications

To use translation in our vue.js application, we only need to add a simple configuration. In main.js (or our entry point of our application) we must add the following code, where we configure spanish as a default language:


import GetTextPlugin from 'vue-gettext'

import translations from './../translations/translations.json'



Vue.use(GetTextPlugin, {
  availableLanguages: {
    en: 'British English',
    es: 'Español'
  },
  defaultLanguage: 'es',
  languageVmMixin: {
    computed: {
      currentKebabCase: function () {
        return this.current.toLowerCase().replace('_', '-')
      }
    }
  },
  translations: translations,
  silent: true
})


And now our application is already configured to support multi-language texts.

I hope you could find this post helpful.

Happy coding.

P.S. Sorry for my English in advance. I am sure I made mistakes because it is not my mother tongue, but I prefer to use English in order to make this information useful for more people.

Comments

Popular posts from this blog

Azure DevOps: Deploy your SPA on AWS S3 bucket

Why you should migrate your old csproj to SDK format

Writing unit tests faster