App Internationalization with Quasar Framework

Nafaa Boutefer
7 min readMar 17, 2019

--

If you’re building an application using the Quasar-framework, and your users are of different cultures and languages, you probably need to offer multiple translations for the UI. To do that you need internationalization.

Internationalization is the process of making an application adapt to different languages.

If this process looks daunting and boring for you, fear not. This process is super easy with Quasar framework and VueJs internationalization plugins. The defacto plugin in the Vue world is Vue-i18n, it makes it pretty straightforward and Quasar just takes it to another level.

In this article, I will explain how to use Quasar language packs and Vue-i18n for your app internationalization.

Quasar language packs

Quasar comes with a set of language packs for a long list of languages. They provide standard translations for labels of the Quasar components. If you’re using some Quasar components that have labels like ok, Cancel , Update you don’t need to translate them again, you have translations out of the box in those language packs. You can even use those translations in your own code.

QTable Pagination translated by Quasar Language Packs

RTL languages support

Quasar supports RTL languages (Arabic, Hebrew, Farsi…) out of the box, with a single configuration flag you get your UI direction flipped with no additional effort from your side.

The only thing that you need to do is to set rtl: truein the build section in quasar.conf.js file like this:

{
build: {
rtl: true
}
}

With this, Quasar will add an attribute dir="rtl" to the html tag and generate CSS rules that inverse every direction property, what is set to left becomes right and vice-versa. The side effect of this is that the stylesheets size will increase a little.

.some-class {
margin-top: 10px;
margin-right: 10px;
padding-left: 3px;
border-right: 1px solid green
border-left: 2px solid red
}

becomes

[dir=rtl] .some-class {
margin-top: 10px;
margin-left: 10px;
padding-right: 3px;
border-left: 1px solid green
border-right: 2px solid red
}

Likewise, we can set the default language pack in the framework section of the qusar.conf.js file.

{
framework: {
lang: 'ar' // or whatever
}
}

With this set, the Quasar components like QTable will be in Arabic at the start. This won’t affect your app components directly, we will see later how to use this.

Where does Vue-i18n fit?

For your own code, you will need to use one of the Vue plugins for internationalization, like Vue-i18n which we’ll be using in this article.

The example application we’ll be working on is a simple one that has one page, Products that contains a QTable with pagination.

Before we continue, we need to generate the app using the quasar-cli

If you don’t have quasar-cli installed, go ahead and install it.

quasar-cli create my-app -b dev

-b dev is to tell the quasar-cli to use the beta version, you might not need to specify it if the final 1.0 version is out when you read this.

and we should make sure to select Vue-i18n when we are prompted to.

If you choose that, quasar-cli will add vue-i18n package to package.json, and create an i18n folder for the translations and ai18n.js boot file in the boot folder.

src folder

Quasar-1.0-beta introduced what’s called Boot files. These are used like initializers that Quasar would run to do some setup before the Vue root instance is instantiated. They are useful for situations when you want to initialize a library, interfere with Vue Router, inject Vue prototype or inject the root instance of the Vue app.

In the boot file Vue is set to use the Vue-i18n plugin. The default and fallback locales are set to en-us and the application translation messages are imported and fed to Vue-i18n instance to use them.

boot/i18n.jsimport VueI18n from 'vue-i18n'
import messages from 'src/i18n'
export default async ({ app, Vue }) => {
Vue.use(VueI18n)
// Set i18n instance on app
app.i18n = new VueI18n({
locale: 'en-us',
fallbackLocale: 'en-us',
messages
})
}

The generated file i18n/en-us/index.js would contain some example messages.

// This is just an example,
// so you can safely delete all default props below
export default {
failed: 'Action failed',
success: 'Action was successful'
}

Like all the boot files, the default export should be a function that accepts an object. Quasar will call this function on startup with an object containing, app as the object used to instanciate the root Vue application instance, router as the Vue-Router instance and store as the Vuex store instance and just for convininece the Vue constructor.

NOTE: the default locale set in the boot file should be in sync with that of the Quasar language pack. A DRY solution for that could be:

boot/i18n.jsimport { Quasar } from 'quasar'
import VueI18n from 'vue-i18n'
import messages from 'src/i18n'
const defaultLocale = Quasar.lang.isoNameexport default async ({ app, Vue }) => {
Vue.use(VueI18n)
// Set i18n instance on app
app.i18n = new VueI18n({
locale: defaultLocale,
fallbackLocale: defaultLocale,
messages
})
}

Now you need to change it in one place only, the quasar.conf.js file.

Application language packs

At this stage, we’re ready to create the application’s own language packs for all the languages that we need to support and for all the text that we want to translate. Those language packs will be used by Vue-i18n for translations.

In our example, we will use two other languages one ltr (French) and another rtl (Arabic) to see how Quasar handles that.

So we should add new folders in the i18n folder for each of the languages.

i18n folder
//i18n/en-us/index.jsexport default {
failed: 'Action failed',
success: 'Action was successful',
mainMenu: {
products: 'Products'
},
products: {
name: 'Name',
price: 'Price',
quantity: 'Quantity'
}
}
//i18n/fr/index.jsexport default {
failed: "L'operation a échoué",
success: "L'opération a réussi",
mainMenu: {
products: 'Produits'
},
products: {
name: 'Produit',
price: 'Prix',
quantity: 'Quantité'
}
}
//i18n/ar/index.jsexport default {
failed: 'العملية فشلت',
success: 'العملية تمت بنجاح',
mainMenu: {
products: 'قائمة المنتجات'
},
products: {
name: 'إسم المنتج',
price: 'الثمن',
quantity: 'الكمية'
}
}

Then we import them in the i18n/index.js file.

import enUS from './en-us'
import ar from './ar'
import fr from './fr'
export default {
ar,
'en-us': enUS,
fr
}

With this, all the imported translations will be loaded with the application when it starts. In our example app, we do not have too many languages and the translations are very small, so loading them synchronously with the app would not have any performance impact.

In the case of big applications that support too many languages and have hundreds or thousands of messages, it won’t make any sense to load all the translations while the user would only need one or two. For that, we will see how to load the translations asynchronously.

Change the locale at runtime

Now that the translations are loaded, we will add a toggle button to the toolbar for the user to be able to change the application locale.

the toggle button on the toolbar

first, we add the toggle button HTML to the layout file.

<q-toolbar>
<q-btn
flat
dense
round
@click="leftDrawerOpen = !leftDrawerOpen"
aria-label="Menu">
<q-icon name="menu" />
</q-btn>

<q-toolbar-title>
Quasar App
</q-toolbar-title>

<q-space/>
<q-btn-toggle
flat
color="white"
toggle-color="yellow"
v-model='locale'
@input="setLocale"
:options="[{ label: 'Ar', value: 'ar'},
{ label: 'En', value: 'en-us'},
{ label: 'Fr', value: 'fr'}]" />
</q-toolbar>

and set the locale model initial value to the default quasar locale.

data () {
return {
locale: this.$q.lang.isoName
}
}

then the setLocale method

methods: {
setLocale (locale) {
// set the Vue-i18n locale
this.$i18n.locale = locale
// load the Quasar language pack dynamically import(`quasar/lang/${locale}`).then(({ default: messages }) => {
this.$q.lang.set(messages)
})
}
}

When the user clicks on a language button, we set the locale of the global $i18n instance, then we dynamically import and set the corresponding quasar language pack.

User changing the locale of the UI

You can see that if you run

quasar dev

and select a different language.

Load the Vue-i18n language packs dynamically at runtime

As we said before, when the app language packs are big, loading all of them synchronously might be just overkill. So we should just switch to loading them on-demand when the user selects the locale he wants.

setLocale (locale) {
import(`quasar/lang/${locale}`).then(({ default: messages }) => {
this.$q.lang.set(messages)
})
import(`src/i18n/${locale}`).then(({ default: messages}) => {
this.$i18n.locale = locale
this.$i18n.setLocaleMessage(locale, messages)
})
}

With this, Webpack will load the language pack only once and cache it for future use.

Get the code:

The code is available on github.

Conclusion:

If your application is used by customers all over the world and for better user experience, you need to provide it translated into multiple languages. That’s what internationalization is about. In this article, we saw how easy is that with Quasar-Framework and Vue-i18n package.

I hope you’ve enjoyed it. Thanks for reading!

--

--