Comment internationaliser notre application
Prérequis
Afin de pouvoir suivre ce guide, il faut préalablement avoir intégré un système d’onglets.
@nuxtjs/i18n
Comment configurer Recommandation
Si vous n’êtes pas familier avec la configuration et l’utilisation de @nuxtjs/i18n
, il est fortement conseillé de
consulter la documentation associée disponible ici.
Modifier le fichier de configuration nuxt.config.js
pour ajouter la configuration du plugin @nuxtjs/i18n
:
export default {
// Disable server-side rendering: https://go.nuxtjs.dev/ssr-mode
ssr: false,
// Target: https://go.nuxtjs.dev/config-target
target: "static",
components: true,
css: ["@/assets/css/bootstrap.scss", "@/assets/css/kendo.scss", "@/assets/css/main.scss"],
modules: ["@nuxtjs/proxy", "@nuxtjs/i18n"],
proxy: {
"/locale/catalog.json": {
target: "http://localhost:8080",
},
"/api/v2/**": {
target: "http://localhost:8080",
},
},
i18n: {
locales: [
{ code: "en", file: "en.js" },
{ code: "fr", file: "fr.js" },
],
strategy: "no_prefix",
defaultLocale: "fr",
langDir: "~/locales/",
},
};
Créer le répertoire locales
à la racine du projet et créer les fichiers locales/fr.js
et locales/en.js
. Ces
fichiers contiendront les traductions pour chaque langue de l’application.
mkdir locales && touch locales/fr.js locales/en.js
Préparer le store pour l’internationalisation
Afin de garder une valeur persistante, la langue de l’application sera stockée dans le store Vue
inclus avec Nuxt.js
Recommandation
Si vous n’êtes pas familier avec le concept de Vuex
et de store
, il est fortement recommandé de lire la
documentation associée disponible ici.
Il est également recommandé de consulter la documentation d’utilisation du store
avec Nuxt.js
disponible ici.
Créer le fichier store/app.js
:
touch store/app.js
import axios from "axios";
import Vue from "vue";
export const state = () => ({
locale: "fr",
});
export const mutations = {
setLocale(state, locale) {
if (["fr", "en"].includes(locale)) {
state.locale = locale;
}
},
};
export const getters = {
getLocale: (state) => state.locale,
};
export const actions = {
changeLocale({ commit }, locale) {
// On change d’abord la langue d’Anakeen Platform 4
return axios
.post("/api/v2/restauratec/changeLocale", { locale })
.then((res) => {
// En cas de succès
const locale = res.data.data.locale;
this.$i18n.setLocale(locale); // La langue est modifiée côté client
Vue.$_globalI18n.setLocale(locale); // La langue est modifiée côté client
commit("setLocale", locale); // La langue est stockée dans le store
})
.catch((err) => {
// En cas d’échec
const locale = "fr"; // La langue par défaut est le français
Vue.$_globalI18n.setLocale(locale); // La langue est modifiée côté client
commit("setLocale", locale); // La langue est stockée dans le store
});
},
};
Utiliser l’internationalisation dans l’application
Nous allons utiliser l’internationalisation pour traduire les intitulés des sections. Nous allons également ajouter un bouton dans la barre de navigation pour basculer la langue de français à anglais.
Modifier le fichier layouts/default.vue
:
<template>
<div class="restauratec-main">
<div class="restauratec-header">
<div class="restauratec-header-nav-button restauratec-header-plat btn btn-outline-primary">
<NuxtLink :to="localePath('/plat')">{{ $tc("plat", 2) }}</NuxtLink>
</div>
<div class="restauratec-header-nav-button restauratec-header-boisson btn btn-outline-primary">
<NuxtLink :to="localePath('/boisson')">{{ $tc("boisson", 2) }}</NuxtLink>
</div>
<div class="restauratec-header-nav-button restauratec-header-menu btn btn-outline-primary">
<NuxtLink :to="localePath('/menu')">{{ $tc("menu", 2) }}</NuxtLink>
</div>
<div class="restauratec-header-switch custom-control custom-switch">
<k-switch class="custom-control-input" id="langSwitch" v-model="checked" :default-checked="true" />
<label class="custom-control-label" for="langSwitch">{{ $t("lang") }}</label>
</div>
</div>
<div class="restauratec-body">
<Nuxt />
</div>
</div>
</template>
<script>
import { Switch } from "@progress/kendo-vue-inputs";
export default {
computed: {
checked: {
get: function () {
return this.$store.getters["app/getLocale"] === "fr";
},
set(checked) {
let locale = "en";
if (checked) {
locale = "fr";
}
this.setLocale(locale);
},
},
},
components: {
"k-switch": Switch,
},
methods: {
setLocale(locale) {
this.$store.dispatch("app/changeLocale", locale);
},
},
};
</script>
<style lang="scss">
.k-switch-on .k-switch-track {
border-color: #8ae234;
background-color: #8ae234;
}
.k-switch-md .k-switch-track {
width: 40px;
height: 18px;
}
.k-switch-md .k-switch-thumb {
width: 14px;
height: 14px;
}
</style>
Modifier également le fichier de style assets/css/main.scss
:
$primary: #8ae234;
@import "~@anakeen/user-interfaces/components/scss/AnkSmartElement.scss";
@import "~@anakeen/user-interfaces/components/scss/SmartElementGrid.scss";
body {
height: 100vh;
#__nuxt {
height: 100%;
#__layout {
height: 100%;
.restauratec-main {
height: 100%;
.restauratec-header {
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
height: 3.5rem;
.restauratec-header-nav-button {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
.nuxt-link-active {
color: $primary;
&:hover {
color: black;
}
}
a {
width: 100%;
height: 100%;
text-decoration: auto;
text-align: center;
color: black;
font-weight: bold;
font-size: 1.5rem;
}
}
.restauratec-header-switch {
width: 8rem;
height: 100%;
flex: 1;
display: flex;
align-items: center;
padding: 0 3.5rem;
border-bottom: 1px solid;
border-bottom-color: $primary;
font-weight: bold;
}
}
.restauratec-body {
width: 100%;
height: 100%;
}
}
}
}
}
Modifier la langue d’Anakeen Platform 4
Au changement de langue sur notre application Nuxt.js
on souhaite modifier également la langue d’Anakeen Platform 4.
Pour cela, nous allons créer une route.
Recommandation
Si vous n’êtes pas familier avec l’utilisation des routes Anakeen Platform 4, vous pouvez consulter la documentation associée disponible ici.
Modifier le fichier src/vendor/Cogip/Restauratec/Config/110-RestauratecRoutes.xml
:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<sde:config xmlns:sde="https://platform.anakeen.com/4/schemas/sde/1.0">
<sde:routes namespace="Cogip">
<sde:route name="RestauratecMain">
<sde:callable>Cogip\Restauratec\Routes\Main</sde:callable>
<sde:method>GET</sde:method>
<sde:pattern>/Restauratec/main</sde:pattern>
<sde:description>A route example for Restauratec</sde:description>
</sde:route>
<sde:route name="changeLocale">
<sde:callable>Cogip\Restauratec\Routes\ChangeLocale</sde:callable>
<sde:method>POST</sde:method>
<sde:pattern>/api/v2/restauratec/changeLocale</sde:pattern>
<sde:description>Change the locale of the application</sde:description>
</sde:route>
</sde:routes>
<sde:accesses namespace="Cogip"/>
</sde:config>
Créer la classe PHP appelée par la route src/vendor/Cogip/Restauratec/Routes/ChangeLocale.php
:
touch src/vendor/Cogip/Restauratec/Routes/ChangeLocale.php
<?php
namespace Cogip\Restauratec\Routes;
use Anakeen\Core\ContextManager;
use Anakeen\Exception;
use Anakeen\Router\ApiV2Response;
use Anakeen\Core\Internal\ContextParameterManager;
/**
* Example route
*
* @note Used by route : POST /api/v2/restauratec/changeLocale
*/
class ChangeLocale
{
/**
* @param \Slim\Http\Request $request
* @param \Slim\Http\Response $response
* @param $args
* @return mixed
*/
public function __invoke(\Slim\Http\Request $request, \Slim\Http\Response $response, $args)
{
$localeParam = $request->getParam("locale");
$locale = $this->completeLanguage($localeParam);
if (empty($locale)) {
throw new Exception(sprintf("Locale %s is not defined. Must be 'en' or 'fr'", $localeParam));
}
ContextParameterManager::setValue(\Anakeen\Core\Settings::NsSde, "CORE_LANG", $locale);
return ApiV2Response::withData($response, [ "locale" => $localeParam]);
}
protected function completeLanguage($lang)
{
$locale = '';
switch ($lang) {
case "fr":
$locale = "fr_FR";
break;
case "en":
$locale = "en_US";
break;
default:
break;
}
return $locale;
}
}
Traduire les actions de la grille
Modifier le fichier components/RestauratecSection.vue
:
<template>
<div class="restauratec-section">
<ank-tabs
v-model="selectedTab"
ref="ankTabs"
@tabRemove="onTabRemove"
@tabClick="onTabClick"
@tabAdd="onTabAdd"
:addable="!isCreationTabOpened"
>
<ank-tab tabId="grid" label="Smart Elements">
<div class="restauratec-grid">
<ank-se-grid
:collection="gridConfig.collection"
:columns="gridConfig.columns"
:actions="gridActions"
@rowActionClick="onRowActionClick"
:key="`grid_${delayedLocale}`"
/>
</div>
</ank-tab>
<ank-smart-tab
v-for="(tab, index) in tabs"
:identifier="tab.initid"
:tabId="tab.tabId"
:key="tab.tabId"
:viewId="tab.viewId"
closable
/>
</ank-tabs>
</div>
</template>
<script>
import Vue from "vue";
import AnkTabs from "@anakeen/user-interfaces/components/lib/AnkTabs.esm";
import AnkSmartTab from "@anakeen/user-interfaces/components/lib/AnkSmartElementTab.esm";
import AnkTab from "@anakeen/user-interfaces/components/lib/AnkTab.esm";
import AnkSmartElementGrid from "@anakeen/user-interfaces/components/lib/AnkSmartElementGrid.esm";
import setup from "@anakeen/user-interfaces/components/lib/setup.esm";
Vue.use(setup);
export default {
components: {
"ank-se-grid": () =>
new Promise((resolve) => {
Vue.$_globalI18n.recordCatalog().then(() => {
resolve(AnkSmartElementGrid);
});
}),
AnkTabs,
AnkSmartTab: () => AnkSmartTab,
AnkTab,
},
props: ["section", "gridConfig"],
computed: {
selectedTab: {
get: function () {
return this.$route.params.tab ? this.$route.params.tab : "grid";
},
set(tab) {
this.$router.push(`/${this.section}/${tab}`);
},
},
tabs() {
return this.$store.getters[`${this.section}/getTabs`];
},
isCreationTabOpened() {
return this.tabs.filter((tab) => tab.tabId === "creation").length > 0;
},
locale() {
return this.$store.getters["app/getLocale"];
},
gridActions() {
return [
{
action: "openSETab",
title: this.$t("consult"),
iconClass: "fa fa-eye",
},
];
},
},
data() {
return {
delayedLocale: this.locale,
};
},
methods: {
onRowActionClick(e) {
if (e.data.type === "openSETab") {
e.preventDefault();
const initid = e.data.row.properties.initid.toString();
const tab = {
initid,
tabId: initid,
viewId: "!defaultConsultation",
};
this.addTab(tab);
this.selectTab(tab.tabId);
}
},
addTab(tab) {
this.$store.commit(`${this.section}/pushTab`, tab);
},
onTabRemove(tabId) {
this.removeTab(tabId);
const nextTabId = this.tabs.length ? this.tabs[this.tabs.length - 1].tabId : "grid";
this.selectTab(nextTabId);
},
removeTab(tabId) {
this.$store.commit(`${this.section}/removeTab`, tabId);
},
onTabClick(e) {
this.selectTab(e.tabId);
},
selectTab(tabId) {
this.selectedTab = tabId;
},
onTabAdd() {
const tab = {
initid: this.gridConfig.collection,
tabId: "creation",
viewId: "!defaultCreation",
};
this.addTab(tab);
this.selectTab(tab.tabId);
},
},
watch: {
locale(val) {
this.$nextTick(() => {
this.delayedLocale = val;
});
},
},
};
</script>
<style lang="scss">
.restauratec-section {
display: flex;
flex-direction: column;
align-items: center;
.ank-tabs {
width: 100%;
.ank-tab-pane {
display: flex;
flex-direction: column;
align-items: center;
.restauratec-grid {
height: 39rem;
width: 80%;
margin-top: 5rem;
border: 1px solid;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
}
}
}
</style>
Définir les traductions
Les traductions sont définies dans les fichiers :
locales/fr.js
:
export default {
plat: "Plat | Plats",
boisson: "Boisson | Boissons",
menu: "Menu | Menus",
lang: "Français",
consult: "Consulter",
};
locales/en.js
:
export default {
plat: "Dish | Dishes",
boisson: "Beverage | Beverages",
menu: "Menu | Menus",
lang: "English",
consult: "View",
};
Tester l’internationalisation
Réinstaller l’application pour prendre en compte la nouvelle route :
make reinstall
Lancez le serveur Anakeen Platform 4 :
make env-start
Puis lancez le serveur de développement :
npm run dev
Vous pouvez voir l’internationalisation sous chaque section, par exemple http://localhost:3000/plat
: