Mostovenko Alexander

@MostovenkoA

Localization in javascript with c-3po

Project was renamed to ttag. Follow the new doc — https://ttag.js.org/. The name was changed due to the possible legal infringement. (look at this issue for the details)

Hi everyone!

This article is about new javascript localization tool — c-3po. We have been using c-3po for nearly a year in production and are happy with it. c-3po was designed to provide an intelligent and reliable translation workflow on top of GNU gettext format. In general, c-3po is a library plus a set of tools that will allow you to localize your project with minimal effort.

Fear question: “Why yet another one localization library?”. There are a couple of mature solutions for the localization that you can be happy with, but the main reasons why we decided to build our own were:

  • We didn’t want to use sprintf formatting for strings. es6 introduced template strings, we just wanted to use them for the string formatting.
  • We were looking for the intelligent tool that can extract translation strings from the sources (js, jsx) and will be able to add some kind of validation for the extracted strings.
  • We were searching for the solution that will allow us to precompile translations on a build step and on script execution also.
  • Framework agnostic solution, that can be integrated almost in any javascript framework and can be used with any build tool.
  • Wanted to ensure that all strings are translated during CI builds.

Welcome, c-3po!

Here are some examples of how this library can be used:

Plural forms support:

More details about why we should use the t tag for the first argument with msgid are here.

Contexts support:

.po files

According to the GNU gettext format, all translations are placed inside .po files. Each locale has it’s separate .po file and all translations are added there. The c-3po ecosystem provides reliable toolset that can create and update those .po files.

So, somehow we must parse our source code and extract all strings that are wrapped with c-3po tags and functions. For that purpose, we created babel-plugin-c-3po that works well with javascript AST. As a result, it can be used everywhere where babel works (jsx, ts, tsx, React Native e.t.c). There is a separate documentation page for the plugin options here. Just to reduce some boilerplate work we created c-3po-cli, that works on top of that plugin.

npm install -g c-3po will add the c-3po command to your environment, which will be used in the examples below.

.po files creation

Let’s imagine that we have hello.js file and want to localize it to the Ukrainian language.

To get started, you need to setup .po file for the Ukrainian language.

c-3po init uk uk.po
uk is the ISO code for the Ukrainian language. (all supported codes can be found here)

init command will create empty po file with the minimal set of the required headers.

Extracting and updating translations to the .po file

To extract all tagged strings you need to execute one simple command:

c-3po update uk.po hello.js

After that our Hello ${ name } string must appear in the uk.po file:

#: hello.js:3
msgid "Hello ${ name }"
msgstr "
update command will add new strings and will delete those that are not present in the sources. If your workflow requires .pot files — you can use extract and merge commands.

Building localized files

If you can afford to build a separate bundle for every language, it is recommended to do so, as it will increase client performance (no extra parsing and replacing on a client + smaller bundles).

c-3po replace uk.po hello-uk.js hello.js

This command will create a localized version of the original file hello-uk.js with all translations applied from uk.po.

Applying translations at runtime

Another option is that you can apply appropriate .po file on a script execution.

Here is how you can achieve this for our simple hello.js:

You can also build your workflow with webpack and po-gettext-loader and import appropriate .po with dynamic imports.

With this setup, every change in a .po file will trigger the webpack build. You can read more about different setups with webpack here.

Translations validation and CI

This command will throw if there are some untranslated strings or some invalid translations wrapped with tags:

c-3po check uk.po hello.js

More details on validation — https://c-3po.js.org/validation.html

What’s next?

Still, we are working on improving translation process and going to add new features to the library and tools.

  • Simplify webpack integration.
  • Simplify translations setup.
  • Typescript.
  • More docs and examples.

Current translation process requires quite a bit of boilerplate that we can reduce, and we are going to fix that. Any feedback will be appreciated, PR’s are welcome!

More links

More by Mostovenko Alexander

Topics of interest

More Related Stories