# Internationalization

As seen on Admin section, for all internationalization support, Vuetify Admin will use Vue I18n (opens new window). It's a module that will use key-value based JSON file for each locale. This package also support singular/plural format as well as advanced specialized locale format for numbers, currencies and dates.

# Vue I18n

You can just simply add it to your existing Vue CLI project by vue add i18n. It will generate for you the next file :

src/i18n.js

import Vue from "vue";
import VueI18n from "vue-i18n";

Vue.use(VueI18n);

//...locales auto loading...

export default new VueI18n({
  locale: process.env.VUE_APP_I18N_LOCALE || "en",
  fallbackLocale: process.env.VUE_APP_I18N_FALLBACK_LOCALE || "en",
  messages: loadLocaleMessages(),
});
1
2
3
4
5
6
7
8
9
10
11
12

DEFAULT LOCALE

Set locale config at navigator.language.substr(0, 2) if you want dynamically take user browser language.

All locales will be stored inside locales directory by default, with one JSON file by language. Here will be stored notably all localized resources name and property labels under a specific format.

# UI

ui

Inject the Vue I18n instance into VA by simply importing the previous file. Finally load manually from VA the locales you want to support and include on your final JS admin library bundle.

src/plugins/admin.js

//...

// UI locales your want to support
import { en, fr } from "vuetify-admin/src/locales";

// Vue I18n instance
import i18n from "@/i18n";

//...

export default new VuetifyAdmin({
  //...
  i18n,
  locales: { en, fr },
  //...
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

All localized UI labels of Vuetify Admin will be injected into specific va i18n namespace in order to avoid any conflict with your own custom locales.

DEFAULT LOCALE

VA will take the default locale of Vue I18n, as set above. If no suited locale found for current user, Vue I18n will fallback to a supported locale.

SUPPORTED LOCALES

Actually only enand fr are provided into core.
But you can easily create your own based on this model (opens new window).

# Vuetify

VA locales on itself isn't enough for full UI localization support. As it uses your existing Vuetify plugin for internal components, you must precise supported locales for Vuetify as well as documented here (opens new window).

src/plugins/vuetify.js

import Vuetify from "vuetify/lib";
import en from "vuetify/es5/locale/en";
import fr from "vuetify/es5/locale/fr";
//...

export default new Vuetify({
  lang: {
    locales: { en, fr },
    current: process.env.VUE_APP_I18N_LOCALE || "en",
  },
  //...
});
1
2
3
4
5
6
7
8
9
10
11
12

# Resources

Until there, all default UI labels from VA should be correctly localized. Furthermore, you can use your own custom locales on any custom pages thanks to Vue I18n. But what about resources name as well as all resource property labels ? It will be so boring to use the $t function from Vue I18n everywhere on CRUD pages by setting labels on all components...

i18n

In order to minimize this cataclysmic boilerplate, VA will try to guess the target translation key from the name of resource or property, by following a simple naming convention. VA even supports localized enums that can be used for all choices-based field or input component as select, radio button, etc.

All localized resource specific labels must be added on your own i18n json locale, that is src/locales/{locale}.json by default, under a main resources key. Each translation key under resources must match with a valid resource names set on src/resources/index.js file. Then you can put there 3 supported keys :

Type Description
name The name of resource with singular and plural format, notably used on every page titles and some context messages.
titles Localized titles for every CRUD actions. Valid child keys are list, show, create or edit.
fields Localized labels for each resource property.
enums Localized enums for resource property, each enum is an array of key-value pair, where the key must correspond to a valid value of targeted property.

Here is the naming translation keys format you must respect for each type of resource label :

Type I18n key path format Example for monsters
name resources.{resource}.name resources.monsters.name
titles resources.{resource}.titles resources.monsters.titles
fields resources.{resource}.fields.{source} resources.monsters.fields.description
enums resources.{resource}.enums.{source}.{value} resources.monsters.enums.category

Here an FR sample :

src/locales/fr.json

{
  //...
  "resources": {
    "users": {
      "name": "Utilisateur | Utilisateurs",
      "titles": {
        "list": "Liste des utilisateurs",
        "show": "Détail de l'utilisateur {name}",
        "create": "Créer un nouvel utilisateur",
        "edit": "Editer l'utilisateur {name}"
      },
      "fields": {
        "id": "ID",
        "name": "Nom",
        "email": "Email",
        "password": "Mot de passe",
        "password_confirmation": "Confirmation du Mot de passe",
        "active": "Actif",
        "roles": "Rôles",
        "created_at": "Date de création",
        "updated_at": "Date de modification"
      },
      "enums": {
        "roles": {
          "admin": "Admin",
          "editor": "Editeur",
          "author": "Auteur"
        }
      }
    },
    "monsters": {
      "name": "Monstre | Monstres",
      "fields": {
        "name": "Nom",
        "level": "Niveau",
        "category": "Catégorie",
        "publication_date": "Date",
        "published_before": "Publié avant",
        "published_after": "Publié après"
      },
      "enums": {
        "category": {
          "history": "Histoire",
          "novel": "Roman",
          "comics": "BD"
        }
      }
    }
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50

SINGULAR AND PLURAL

Your resource name should have both singular and plural formats separated by a pipe. VA will choose the right format according to context.

APPLY IT BY DEFAULT

You should use this way to do all the time, even if you have no intention to support multiple locales. It considerably reduces boilerplate and this is the default behavior for code generators.

ENUMS

In order to have functional localized choices for select or radio components, your enum key must be named the same as the source prop for this component.

PAGE TITLES

This specific key is optional and mainly used for edge cases localization management with full control. By default, VA will make the following title format : {action} {resource} (ex. List of users), action is the localized name of CRUD action and resource the localized name of resource.

But sometimes you want more by adding a specific resource property for show and edit action for better identification. This is done by simply adding your property name inside brackets in localized label. For example Edit user {name} #{id}, the name placeholder will be replaced by the value of name user resource property.

OVERRIDE

This is just a convention, all of this default behavior is easily replaceable on each component by simply explicitly set the label property by your custom string. Same for enums, every select or radio components have a choices property that will override the enum seeking default behavior.

HUMANIZED

By default, if no traduction key is found on targeted locale, VA will try to humanize the label property from the given source. For example, a publication_date source will be translated to Publication date.

FREE PROPERTIES

Inside fields, you can add any key-value you want, even those that's not real property field resource. You can for example add there any specific advanced label filters or any other resource related labels. This the case of above published_before and published_after keys.

# Date and number format

For localized number and date field resource values, you will probably use the DateField and the NumberField. This components will use specific Vue I18n functions under the hood :

Each of this fields use a specific format props that must take a valid named format option from Vue I18n plugin. To define this options, follow the above plugin documentation. For example you can create a dedicated src/plugin/i18n.js (already provided by Vue CLI Plugin), initialize all option here and import it from src/main.js :

src/plugin/i18n.js








 




 












 





 





import i18n from "@/i18n";

/**
 * Date format
 */
["en", "fr"].forEach((locale) => {
  i18n.setDateTimeFormat(locale, {
    short: {
      year: "numeric",
      month: "short",
      day: "numeric",
    },
    long: {
      year: "numeric",
      month: "long",
      day: "numeric",
      weekday: "long",
    },
  });
});

/**
 * Number format
 */
i18n.setNumberFormat("en", {
  currency: {
    style: "currency",
    currency: "USD",
  },
});
i18n.setNumberFormat("fr", {
  currency: {
    style: "currency",
    currency: "EUR",
  },
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

As you can see, all formats are defined by a key name that you will use for each adapted field component. For both examples :

  • DateField : <date-field source="publication_date" format="short"></date-field>
  • NumberField : <number-field source="price" format="currency"></number-field>

# Resource translation

Now it will be cool if we could get the translated fields value as well. Thankfully, Vuetify Admin also support this ! This is done by the presence of a contextualized locale selector on Show, Create and Edit pages that will update all translatable fields.

translation

By default this selector takes current UI locale. On locale change, VA will recall getOne method of your data provider with a specific locale parameter passed to the second params argument as explained here. In case of resource saving, this locale parameter will be sent as well on create and edit data provider methods, which allows you to save on targeted locale on backend side.

EDIT PAGE

From user point of view, be sure to select targeted locale at first in case of edition as the inputs will be reset.

BACKEND

The main work will be on server side of course but you can quickly done that if you use the official Laravel Admin (opens new window) composer package, which uses Spatie Translatable (opens new window) under the hood (JSON based storage for translations). See the dedicated Laravel guide section for how it works. Here we talk about client side only.

In order to haver this locale selector appear, you must first pass the list of supported locales for translation :

src/plugins/admin.js

//...
import i18n from "@/i18n";

export default new VuetifyAdmin({
  //...
  translations: ["en", "fr"],
  //...
});
1
2
3
4
5
6
7
8

Each value correspond to the value sent to your data provider. For label, Vuetify Admin looks for a Vue I18n message key on this format translations.{locale}.

Finally, you have to enable translation by resource inside src/resources/index.js file by just setting the translatable property to true and you're done !