Why donate
API Explorer
App Internationalization (i18n)

Internationalization is a design process that ensures a product (a website or application) can be adapted to various languages and regions without requiring engineering changes to the source code. Think of internationalization as readiness for localization.

TIP

The recommended package for handling website/app is vue-i18n. This package should be added through a @quasar/app-vite Boot File or a @quasar/app-webpack Boot File. On the Boot File documentation page you can see a specific example for plugging in vue-i18n.

WARNING

Quasar documentation assumes you are already familiar with vue-i18n. Below it’s described only the basics of how to make use of it in a Quasar CLI project. For the full list of its features please visit the Vue I18n documentation.

Setup manually

If you missed enabling i18n during yarn create quasar (or npm init quasar or the pnpm or Bun equivalent) wizard, here is how you can set it up manually.

  1. Install the vue-i18n dependency into your app.

$ yarn add vue-i18n@next
  1. Create a file src/boot/i18n.js with following content:
import { createI18n } from 'vue-i18n'
import messages from 'src/i18n'

export default ({ app }) => {
  // Create I18n instance
  const i18n = createI18n({
    locale: 'en-US',
    legacy: false, // comment this out if not using Composition API
    messages
  })

  // Tell app to use the I18n instance
  app.use(i18n)
}
  1. Create a folder (/src/i18n/) in your app which will hold the definitions for each language that you’ll support. Example: src/i18n. Notice the “import messages from ‘src/i18n’” from step 2. This is step where you write the content that gets imported.

  2. Now reference this file in quasar.config one in the boot section:

/quasar.config file

return {
  boot: [
    // ...
    'i18n'
  ],

  // ...
}

Now you are ready to use it in your pages.

Setting up Translation Blocks in your SFCs

If we want to add support to the <i18n> tag inside a SFC (single file component) in a Quasar CLI project then we need to modify the existing configuration.

We first install the @intlify/vue-i18n-loader package:


$ yarn add --dev @intlify/vue-i18n-loader

We then edit the quasar.config file at the root of our project. We have to include the following:

/quasar.config file

const path = require('node:path')

build: {
  chainWebpack: chain => {
    chain.module
      .rule('i18n-resource')
        .test(/\.(json5?|ya?ml)$/)
          .include.add(path.resolve(__dirname, './src/i18n'))
          .end()
        .type('javascript/auto')
        .use('i18n-resource')
          .loader('@intlify/vue-i18n-loader')
    chain.module
      .rule('i18n')
        .resourceQuery(/blockType=i18n/)
        .type('javascript/auto')
        .use('i18n')
          .loader('@intlify/vue-i18n-loader')
  }
}

How to use

Here is an example displaying the main use cases:

<template>
  <q-page>
    <!-- text interpolation, reactive -->
    {{ $t('hello') }}

    <!-- prop/attr binding, reactive -->
    <q-btn :label="$t('hello')" />

    <!-- v-html directive usage -->
    <span v-html="content"></span>
  </q-page>
</template>

<script setup>
// Composition API variant
import { computed } from 'vue'
import { useI18n } from 'vue-i18n'

const { t } = useI18n()

// bound to a static variable, non-reactive
// const staticContent = t('hello')
// bound to a reactive variable, but one-time assignment, locale changes will not update the value
// const reactiveStaticContent = ref(t('hello'))

// bound to a reactive variable, locale changes will reflect the value
const content = computed(() => t('hello'))

function notify() {
  Notify.create({
    type: 'positive',
    message: t('hello')
  })
}
</script>
<script>
// Options API variant
export default {
  data() {
    return {
      // bound to a reactive variable, but one-time assignment, locale changes will not update the value
      content: this.$t('hello')
    }
  }
}
</script>

Add new language

Let’s say you want to add new German language.

  1. Create the new file src/i18n/de/index.js and copy there the content of the file src/i18n/en-US/index.js then make changes to the language strings.
  2. Now change src/i18n/index.js and add the new de language there.
import enUS from './en-US'
import de from './de'

export default {
  'en-US': enUS,
  'de': de
}

Create language switcher

Some Vue file

<template>
  <!-- ...... -->
  <q-select
    v-model="locale"
    :options="localeOptions"
    label="Quasar Language"
    dense
    borderless
    emit-value
    map-options
    options-dense
    style="min-width: 150px"
  />
  <!-- ...... -->
</template>

<script>
import { useI18n } from 'vue-i18n'

export default {
  setup () {
    const { locale } = useI18n({ useScope: 'global' })

    return {
      locale,
      localeOptions: [
        { value: 'en-US', label: 'English' },
        { value: 'de', label: 'German' }
      ]
    }
  }
}
</script>

UPPERCASE

Many languages, such as Greek, German and Dutch have non-intuitive rules for uppercase display, and there is an edge case that you should be aware of:

QBtn component will use the CSS text-transform: uppercase rule to automatically turn its label into all-caps. According to the MDN webdocs, “The language is defined by the lang HTML attribute or the xml:lang XML attribute.” Unfortunately, this has spotty implementation across browsers, and the 2017 ISO standard for the uppercase German eszett ß has not really entered the canon. At the moment you have two options:

  1. use the prop no-caps in your label and write the string as it should appear
  2. use the prop no-caps in your label and rewrite the string with toLocaleUpperCase by using the locale as detected by $q.lang.getLocale()

Detecting Locale

There’s also a method to determine user locale which is supplied by Quasar out of the box:

// outside of a Vue file
import { Lang } from 'quasar'
Lang.getLocale() // returns a string

// inside of a Vue file
import { useQuasar } from 'quasar'

setup () {
  const $q = useQuasar()
  $q.lang.getLocale() // returns a string
}

WARNING

If you use Quasar’s set method ($q.lang.set()), this will not be reflected by Quasar’s getLocale above. The reason for this is that getLocale() will always return the users locale (based on browser settings). The set() method refers to Quasars internal locale setting which is used to determine which language file to use. If you would like to see which language has been set using set() you can use $q.lang.isoName.