How to keep track of your Angular i18n translations with i18n-ally

In our previous blog post on i18n, we had a look at how to approach Angular internationalization (i18n) in 2022. There we learned, what internationalization is and how it can be implemented with the native Angular localization library. However, while this is great, it is only the first part of the task. Mainly, because implementing i18n is about providing the infrastructure to perform localization or in other words to translate your application’s content, but not about performing the actual translation.

Therefore, we lack the second part, which is managing the translated content. Of course, this sounds easy at first. We have our human-readable Json file with a flat key-value structure, consisting of translation IDs and the corresponding translation. What could be so hard about managing a simple file like that? I mean you add a new entry to the translation file or update some string and be done with it.

Well, at first nothing is hard about that. But when your application and the number of translations is growing, problems start to arise. Soon, you’ll start to see errors in the console, which complain about missing translations. You’ll start asking yourself, are these translations still used or are they outdated, and did you translate this caption into Spanish or not? Who knows? Unfortunately, your customer will soon. If this sounds familiar to you, keep reading.

Contents

Learnings

  • Overview of problems that arise when translation files grow
  • What is the i18n-ally extension
  • How to use i18n-ally with Angular i18n
  • How does i18n-ally make your life as a developer easier

Keeping track of translations is hard

As described in the introduction keeping track of translation is a task that starts easy and becomes more painful over time. At least if you are not working in some large company in which professional translators that use specialized software do this for you.

For example, the official Angular localize package, which is maintained by the Angular team had a bad reputation because it was tailored for the needs of Google, a large company that uses professional translators to perform localization. They mostly use translation files in the format XLIFF, which is standardized, but hard to read and manage without specialized software. By now Angular localize supports a developer-friendly Json file format for translations. This means developers without specialized translation software can handle the translation files. But this does not solve the task of performing and managing translations.

Especially the task of managing translations starts easy because you only add a new line to your Json file, and you’re finished. But when the software grows, and more translations are added or when existing translations should be updated, and even worse, when new languages are added, things start to get ugly. To prevent duplication and missing translations in production code, you need a way to manage translations. To break it down, you’ll have to ensure the following:

  1. Make sure all translation IDs have a corresponding translation
  2. Make sure there is a translation for every language that is supported
  3. Make sure translations are still used in the application to prevent an ever-growing translation file
  4. Minimize duplications of existing translations

While doing this manually is easy, when your translation files are small, this becomes unbearable with hundreds or thousands of translation IDs and strings. Luckily, there is a solution.

Meet i18n-ally

When you have troubles with managing translations i18n-ally by Lokalise comes to the rescue. It is an extension for VS Code and describes itself as an “All in one i18n extension for VS Code”. Its primary features are:

  • Inline Annotations (shows the translation instead of a cryptic translation key)
  • Hover and Direct Actions (goodbye to searching translations by hand)
  • Manage All Translations in One Place (i.e. the i18n-ally tab in VS Code sidebar)
  • Editor UI & Review System (helps you to improve translations)
  • Extract Translations from Code (remove magic strings)
  • Report Missing Translations (scans all your templates and code for i18n IDs in use)
  • Machine Translation (great if you want to provide basic translations)
  • Annotations for JSON and YAML (add a meaningful description to your translations)

Even if you don’t think you need all these features, most of them are incredibly helpful, after you invested some time in exploring them. So what does working with i18n-ally look like? The following screenshots show two of my favorite i18n-ally features, namely the usage and the progress report:

The usage report helps you to identify missing or outdated translation keys in a fast and reliable way. This is also great to spot typos in translation keys because you will have an unused and a missing translation key at the same time. As you can see in the usage report above, we have a typo in the start page route label i18n key. By double clicking on “app.component.html”, we can directly jump to the issue and correct the typo. Without i18n-ally this would have been hard to spot and more cumbersome to fix.

The progress report, on the other hand, is great to spot missing translations in other languages and even shows change requests for translations. In the example above, Spanish was added as a new language we had to support. However, while translation IDs were added to the Spanish translation file, the translations are empty. This is shown via the “Empty” flag. Another issue that can be easily spotted with the progress report is missing translation IDs. This could happen when you add a new translation but forget to add the id to all existing translation files or just forget to add it to one of the languages.

However, this shouldn’t be confused with the usage report. One issue is translation IDs that are missing or unused for all languages you support, but another issue is translation IDs or translations that are missing for just some languages. In our example, we did forget to add the new translation id we created while adding support for Spanish to the existing English translation file. Luckily, with the progress report, we can easily spot the error and fix it with the quick actions shown when clicking on the translation id.

Intriguing right? But unfortunately, there is a problem we must solve first.

How to use i18n-ally with Angular localize

Now, after reading through the feature list of i18n-ally, you decide to try i18n-ally as it would solve most of your problems and make your life as a developer easier. But when you explore the list of supported frameworks, you’ll see that there is no support for the official Angular localize library. Wait, how can that be? Why is it presented as the solution for your translation problems, when there is no support for the library the first part of this guide recommended?

While it is interesting, that the official Angular i18n solution is not supported, but less popular i18n solutions are, there is a way to solve the issue. i18n-ally has a nifty feature that allows you to define a configuration for custom frameworks, which is loaded from the projects /.vscode directory. This is a great and unintrusive way for developers to use their framework of choice without the need for i18n-ally to support endless variants of i18n frameworks.

Now the following shows the part of the configuration which is necessary to detect i18n tags in component templates and $localize strings in code. See the full example on GitHub.

usageMatchRegex:
  # Matches Angular native i18n tags, 
  # the regex must capture the key introductionHeader in the following examples
  # Example for first regex:
  # <h1 i18n="An introduction header for this sample@@introductionHeader">Hello i18n!</h1>
  # Example for second regex:
  # $localize`:An introduction header for this sample@@introductionHeader:Hello i18n!`
  - "(?:i18n)[-\\w]*?[\\=]['\"].*?[@]{2}([\\w\\s\\.\\-]+?)['\"]"
  - "(?:\\$localize)\\s*?[`][\\:].*?[@]{2}([\\w\\s\\.\\-]+?)[:]"

Of course, the regex was a bit tricky to get right at first, but it’s no black magic either. The remarkable thing about this approach of configuration is, that we can leverage i18n-ally even if we switch to Vue.js or React or some other exotic framework. The only thing we must do is write some more or less complex regex.

Welcome to the bright side of translations

So, for the future, this means goodbye to manually managing translation files, dead translation keys, and missing translations. No matter if you prefer Angular localize or Transloco or some completely different framework. Welcome to the bright side of translations.

Inline actions

While the usage and progress report alone is reason enough to use i18n-ally, there is more. Did you ever find yourself coding and in the need to provide a translation for the translation id you just created? Look no more, direct actions when hovering over translation IDs in the code have you covered. From there you can simply add or edit a translation for a translation id without leaving your code or switching files. Furthermore, you can leave comments on the translation, jump to the definition of the translation, i.e. the translation file, and even perform a machine translation via a provider such as Google Translate. Try it out yourself.

Inline auto translations

In the image showing the inline actions, we saw a missing translation for the app title in Spanish. Now, if you don’t speak Spanish but want to provide at least some translation instead of nothing, you can leverage the auto-translate feature of i18n-ally. A click on the globe icon performs the translation and updates the translation file with it. You see the result in the image above. This translation might be slightly wrong but is better than a blank screen and can be improved by a Spanish speaker in the future, which brings us to the next feature.

i18n-ally editor and review system

Now, if at some later point somebody sees the translation and wants to propose an improved translation, the i18n-ally editor and review system can be helpful. As you can see in the image above, you can add a description to the translation, review existing translations, make proposals for an improved translation, and even discuss them. All this metadata is stored in the i18n-ally-reviews.yml file and can be committed into git to be under source control. Therefore, the metadata added with i18n-ally stays in sync with your code and stays under your control. The discussion from above with the added description is stored in a format as in the following image:

i18n-ally-reviews.yml

So, what do you think? Does i18n-ally hold up to its promise to be an “All in one i18n extension for VS Code”? For me it does. So far it did cover all requirements I had when being tasked with implementing and maintaining i18n in a project.

Conclusion

As with most things, i18n-ally isn’t the holy grail, but it’s amazing how a simple Visual Studio Code Extension, based solely on local files and configuration, can simplify your life as a developer. Even with the hurdle of writing some regex to support the i18n framework of your choice, it’s still worth it to invest the time. Especially, when you must develop and support a large application. Of course, if you only have 10 translations that don’t change often, you won’t be impressed by this tool, but even then, it can be useful. However, as soon as you start to experience the pains of a growing translation file or work with multiple people, you will start to see the real benefit:

No more tedious managing tasks, unused or outdated translations, and most important no more missing translations in shipped code. Yep, they are a real pain!