Localization

As seen in the Plugins section, Olobase Admin will use Vue I18n for all internationalization support. A key/value based JSON file is used for each locale. Vue I18n also supports advanced formats such as numbers, currencies, and dates, as well as singular/plural formatting.

Vue I18n

The Vuei18n library is loaded from the file below under your current project.

src/i18n/index.js

import { createI18n } from "vue-i18n";
import pluralRules from "./rules/pluralization";
import numberFormats from "./rules/numbers.js";
import datetimeFormats from "./rules/datetime.js";
/**
 * app messages
 */
import _en from "./locales/en.json" assert { type: "json" };
import _tr from "./locales/tr.json" assert { type: "json" };

const i18n = createI18n({
  locale: import.meta.env.VITE_DEFAULT_LOCALE,
  fallbackLocale: import.meta.env.VITE_FALLBACK_LOCALE,
  legacy: false,
  globalInjection: true,
  // forceStringify: false,
  messages: { tr: _tr, en: _en },
  runtimeOnly: false,
  pluralRules,
  numberFormats,
  datetimeFormats,
});
/**
 * import vuetify admin locales
 */
import { en, tr } from "olobase-admin/src/locales";
/**
 * build vuetify admin messages
 */
const vaMessages = { en, tr };
/**
 * load vuetify admin i18n locales
 */
Object.keys(vaMessages).forEach((locale) => {
  i18n.global.mergeLocaleMessage(locale, { va: vaMessages[locale] });
})
export default i18n

Default Locale

The LanguageSwitcher component allows the user to determine the default language value.

src/views/Login.vue

Switch Locale

You can also add the language switching component to your other pages. The following example shows the use of the LanguageSwitcher component on the Login.vue page.

src/i18n/translation.js

import i18n from "@/i18n";
import { nextTick } from "vue";
import store from "../store";

const Trans = {
  /*
  * code shortened for readability
  */
  async switchLanguage(newLocale) {
    Trans.currentLocale = newLocale;
    store.commit('SET_LOCALE', newLocale);
    cookies.set("lang", newLocale); // we user cookies
    document.querySelector("html").setAttribute("lang", newLocale);
  },
  /*
  * code shortened for readability
  */
}

src/views/Login.vue

<template>
  <div>
    <LanguageSwitcher />
  </div>
</template>

src/views/Login.vue

import LanguageSwitcher from "@/components/LanguageSwitcher.vue";

export default {
  components: { LanguageSwitcher },
}

The default locale is saved in the browser's local storage called cookies after the user logs in. If the user visiting the application has previously selected a local language, this value is obtained from cookies, if it cannot be found in cookies, it is obtained from VITE_DEFAULT_LOCALE.

src/i18n/index.js

const i18n = createI18n({
  locale: import.meta.env.VITE_DEFAULT_LOCALE,
  fallbackLocale: import.meta.env.VITE_FALLBACK_LOCALE,
  legacy: false,
  globalInjection: true,
  // forceStringify: false,
  messages: { tr: _tr, en: _en },
  runtimeOnly: false,
  pluralRules,
  numberFormats,
  datetimeFormats,
});
├── src
│   ├── i18n
│   │   ├── locales
│   │   │   ├── en.js
│   │   │   ├── tr.js

Supported Languages

When you want to add or remove a new language from the supported languages, you must also update the VITE_SUPPORTED_LOCALES variable in the src/.env.dev, src/.env.prod files.

VITE_DEFAULT_LOCALE=tr
VITE_FALLBACK_LOCALE=en
VITE_SUPPORTED_LOCALES=en,tr
VITE_API_URL=http://demo.local/api
VITE_LICENSE_KEY=

Vuetify

For full UI localization support, Olobase Admin locales alone are not enough. Since Vuetify is used as a plugin in Olobase Admin, you also need to specify the localization rules for Vuetify i18n.

src/plugins/vuetify.js

// Styles
import "vuetify/styles";

// Translations provided by Vuetify
import { en, tr } from "vuetify/locale";
import Trans from "@/i18n/translation";
const defaultLang = Trans.guessDefaultLocale();

// Composables
import { createVuetify } from "vuetify";

const defaultTheme = {
  dark: false,
  colors: {
    background: "#FFFFFF",
    surface: "#FFFFFF",
    primary: localStorage.getItem("themeColor")
      ? localStorage.getItem("themeColor")
      : "#0a7248",
    secondary: "#eeeeee",
    error: "#ed0505",
    info: "#00CAE3",
    // success: '#4CAF50',
    // warning: '#FB8C00',
  },
};
// Vuetify 
export default createVuetify({
  locale: {
    locale: Trans.supportedLocales.includes(defaultLang) ? defaultLang : import.meta.env.VITE_DEFAULT_LOCALE,
    fallback: "en",
    messages: { tr, en },
  },
  theme: {
    defaultTheme: "defaultTheme",
    themes: {
      defaultTheme,
    },
  },
});

Resources

All default UI labels in Olobase Admin must be localized correctly. Plus, thanks to Vue I18n, you can use your own custom locales on any custom page. But what about the name of the resources and all the resource attribute tags? It can be tedious to use the $t function from Vue I18n all over CRUD pages, settings labels to all components.

To minimize this code, Olobase Admin will try to guess the target translation key from the source or source name by following a simple naming convention. Olobase Admin, selection, radio button etc. It even supports localized enumerations that can be used for any selection-based field or input components, such as. Any localized resource specific tags need to be added to your own i18n json locale, which is src/locales/{locale}.json by default, under the main resources key. Each translation key under Resources must match the valid resource names set in the src/resources/index.js file.

You can then put the following keys in your language settings:

Key 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 follow for each type of weld tag:

Key I18n key path format Example for users module
name resources.{resource}.name resources.users.name
titles resources.{resource}.titles resources.users.titles
fields resources.{resource}.fields.{source} resources.users.fields.name
enums resources.{resource}.enums.{source}.{value} resources.users.enums.roles

Here's an example of a users module and en locale:

src/locales/en.json

{
  //...
  "resources": {
    "users": {
      "name": "User | Users",
      "titles": {
        "list": "List all users",
        "show": "Details of user {name}",
        "create": "Create new user",
        "edit": "Edit user {name}"
      },
      "fields": {
        "id": "ID",
        "name": "Name",
        "email": "Email",
        "password": "Password",
        "password_confirmation": "Password Confirmation",
        "active": "Active",
        "roles": "Roles",
        "createdAt": "Creation Date",
        "updatedAt": "Modification Date"
      },
      "enums": {
        "roles": {
          "admin": "Admin",
          "editor": "Editor",
          "author": "Author"
        }
      }
    }
  }
}

Singular and Plural

Apply by Default

Enumeric Values (enums)

To have functional localized options for select or radio components, your enumeration key must be named the same as the source support for that component.

Page Titles

This private key is optional and is mainly used for edge localization management with full control. By default, Olobase Admin will generate the following header format: {action} {resource} (e.g. User list), where action is the localized name of the CRUD action and resource is the localized name of the resource.

But sometimes you may want more by adding a specific source attribute to the show and edit action for better identification. This is easily done by adding your attribute name in parentheses in the localized tag. For example, edit user {name} #{id}, the name placeholder will be replaced with the value of the name user resource property.

Override

If you want a particular property to exhibit override behavior within a component, you must explicitly specify the property name and value. For example, specifying the label property as follows ensures that the default label value is overridden and the new value takes effect. You can apply this for each component.

<va-select-input
  :label="$t('demo.currencyId')"
  reference="currencies"
  v-model="model.currencyId"
></va-select-input>

Date and Number Format Rules

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

├── src
│   ├── i18n
│   │   ├── rules
│   │   │   ├── datetime.js
│   │   │   ├── numbers.js
  • For date rules, click on this link.
  • For number rules, click on this link

src/i18n/rules/datetime.js

export default {
  en: {
    year: {
      year: "numeric",
    },
    month: {
      month: "short",
    },
    shortFormat: {
      dateStyle: "short",
    },
    longFormat: {
      year: "numeric",
      month: "long",
      day: "numeric",
      weekday: "long",
      hour: "numeric",
      minute: "numeric",
      hour12: false,
    },
  },
  tr: {
    year: {
      year: "numeric",
    },
    month: {
      month: "short",
    },
    shortFormat: {
      dateStyle: "short",
    },
    longFormat: {
      year: "numeric",
      month: "long",
      day: "numeric",
      weekday: "long",
      hour: "numeric",
      minute: "numeric",
      hour12: false,
    },
  },
};

For example, a date rule defined as above is defined in i18n/index.js.

src/i18n/index.js

import { createI18n } from "vue-i18n";
import pluralRules from "./rules/pluralization";
import numberFormats from "./rules/numbers.js";
import datetimeFormats from "./rules/datetime.js";
import _en from "./locales/en.json";
import _tr from "./locales/tr.json";

const i18n = createI18n({
  locale: import.meta.env.VITE_DEFAULT_LOCALE,
  fallbackLocale: import.meta.env.VITE_FALLBACK_LOCALE,
  legacy: false,
  globalInjection: true,
  // forceStringify: false,
  messages: { tr: _tr, en: _en },
  runtimeOnly: false,
  pluralRules,
  numberFormats,
  datetimeFormats,
});

DateField

<date-field source="creationDate" format="short"></date-field>

NumberField

<number-field source="price" format="currency"></number-field>