UI Translations
Explore how to implement UI translations in VueJS applications by using global mixins and reactive variables. Understand the technical steps to manage string translations, create a language switcher, and ensure translations update across components. Discover best practices for translation keys and how to maintain flexibility in multilingual Vue apps.
Most modern web apps with an international audience need to have localized UIs. The most important part of this is string translations. Once we have implemented a second UI language, we can usually add more languages without much technical effort.
We won’t use different languages in code examples in this lesson, but instead, we’ll use an all-uppercase and all-lowercase version of English. This way, the change is visible but still understandable for everyone. The focus of this lesson is on the technical aspects and not the linguistic ones.
Implementing translations as a global mixin
To implement UI translations, we need a way to know which string we need in which language. Furthermore, since every Vue component most likely needs translations in some form or another, we need this approach to be a global one. There are several approaches to global code in Vue—global mixins, state machines (such as Vuex), or a custom plugin. We won’t cover creating a translation interface with these two approaches. Instead, we’ll implement a global mixin.
As we’ve learned already, a mixin is a renderless component with some functionality that can be offered to every component applying the mixin. The most basic renderless component we can create is an empty object. We use the mixins option in a component to apply a mixin.
Global mixins work a bit differently. First, they add functionality to every component the app uses—we don’t need to apply them explicitly. Second, when paired with ref, they allow us to share states between components. We can define a global mixin as illustrated below:
We add a method sayHello() to every component with this global mixin. Unless a component explicitly overwrites the method, all components share this functionality. In addition, we can implement a translate method or t for short. For now, we’ll hardcode the language and all translations in a separate variable outside the mixin itself. We’ll use two languages, up for uppercase and low for lowercase.
In the SPA below, we’ve already implemented a global mixin. This mixin needs to check if the selected language exists and return the correct string. It should fall back to returning the translation key if the language or the translation key doesn’t exist.
<template>
<div id="app">
<h1>{{ t('Hello, World!') }}</h1>
<p>
{{ t('Lorem ipsum dolor sit amet.') }}
</p>
</div>
</template>
Unsure of how to approach this? There’s a possible solution in the hint below:
The fallback to the translation key allows the user to at least see something being rendered instead of the app breaking. If your new audience is in an area where English is a popular second language, they might be able to understand untranslated things too.
Implementing a language switcher
We implemented the language as a lang object in the above example. We share this object between all components, but when we update the language of a single component (via this.lang.value = 'low'), other components won’t notice the change.
Vue offers us the possibility to create reactive variables anywhere we’d like. The ref attribute makes any given object reactive, meaning that a change in one component automatically updates all occurrences everywhere else.
We can use this technique to implement a language switcher for our app. Whenever the language switcher updates this.lang, ref ensures that every other component receives the update. In the SPA below, we’ve implemented the translation mixin already but need a language switch component. It should be usable everywhere and list all possible languages.
<template>
<h1>{{ t('Hello, World!') }}</h1>
</template>
A possible approach can be found in the hint below:
If we want to, we can also add ways to determine the language for the user via navigator.language || navigator.userLanguage and save it in a cookie or local storage. There are also ways to determine the language via the route.
vue-i18n
The problem of internationalization is by no means a new one. There are quite a few ready-made solutions one can install and configure. The standard is vue-i18n. vue-i18n offers many features, such as language detection, number localization, date localization, and pluralization.
Best practices for translation keys
We’ve used the original string as the translation key in the above examples. However, using text as keys is often not the best approach because translations might change in the future, and a translation key change would be necessary. For example, if a button with the text “proceed” should be retranslated to “next,” the key would still be proceed. We, therefore, often use context as translation keys, for example nextButton.
It’s also helpful to nest translation objects and group them by coherent units, such as pages or features. We will probably duplicate some strings with this approach, but it gives us more flexibility to change nuances of the language depending on the context.