i18n for models with fallback
This commit is contained in:
parent
1b180f07cf
commit
1f201326ee
16 changed files with 152 additions and 71 deletions
18
app.vue
18
app.vue
|
|
@ -42,7 +42,7 @@ import { defineComponent } from "vue";
|
|||
import type { RouteLocationNormalizedLoaded } from "vue-router";
|
||||
import ToolboxHelper from "./classes/ToolboxHelper";
|
||||
import { useAppStore } from "~/stores/useAppStore";
|
||||
import data from "data/test.json";
|
||||
// import data from "data/test.json";
|
||||
|
||||
export default defineComponent({
|
||||
name: "IndexPage",
|
||||
|
|
@ -54,7 +54,7 @@ export default defineComponent({
|
|||
// adminModalId: string;
|
||||
// modal: Modal;
|
||||
// adminModal: Modal;
|
||||
data: typeof data;
|
||||
// data: typeof data;
|
||||
// selectedItem: Item | null;
|
||||
// konami: KonamiCode;
|
||||
// contacts: Array<Contact>;
|
||||
|
|
@ -65,7 +65,7 @@ export default defineComponent({
|
|||
route: useRoute(),
|
||||
// modalId: "productModal",
|
||||
// adminModalId: "adminModal",
|
||||
data,
|
||||
// data,
|
||||
// selectedItem: null,
|
||||
// modal: {} as Modal,
|
||||
// adminModal: {} as Modal,
|
||||
|
|
@ -97,11 +97,11 @@ export default defineComponent({
|
|||
},
|
||||
mounted() {
|
||||
// * Make sure array does not start using 0 index
|
||||
const items: typeof data.items = [];
|
||||
this.data.items.forEach((item, itemIndex) => {
|
||||
items[itemIndex + 1] = item;
|
||||
});
|
||||
this.data.items = items;
|
||||
// const items: typeof data.items = [];
|
||||
// this.data.items.forEach((item, itemIndex) => {
|
||||
// items[itemIndex + 1] = item;
|
||||
// });
|
||||
// this.data.items = items;
|
||||
// * Init contacts (Fetch form local storage or new)
|
||||
// const serializedContacts = window.localStorage.getItem("contacts");
|
||||
// this.contacts = !serializedContacts ? new Array<Contact>() : JSON.parse(serializedContacts);
|
||||
|
|
@ -121,7 +121,7 @@ export default defineComponent({
|
|||
|
||||
// * INIT STATES
|
||||
window.ipcRendererObject.getJsonData().then((dataJson) => {
|
||||
useAppStore().setupAppData(dataJson);
|
||||
useAppStore().setupAppData(dataJson, this.$i18n.locale, String(this.$i18n.fallbackLocale));
|
||||
this.loading = false;
|
||||
this.setTimeout();
|
||||
dataJson.fonts.forEach(font => this.injectFontFace(font.font_name, font.font));
|
||||
|
|
|
|||
|
|
@ -4,14 +4,36 @@ export default class AppState {
|
|||
/** Json data as exported from zip and compliant with schemas */
|
||||
private jsonData: TypeApp;
|
||||
|
||||
constructor(jsonData: TypeApp) {
|
||||
/** Current App locale */
|
||||
private locale: string;
|
||||
/** Fallback App locale */
|
||||
private fallbackLocale: string;
|
||||
|
||||
constructor(jsonData: TypeApp, locale: string, fallbackLocale: string) {
|
||||
this.jsonData = jsonData;
|
||||
this.locale = locale;
|
||||
this.fallbackLocale = fallbackLocale;
|
||||
}
|
||||
|
||||
public settings(): TypeSettings {
|
||||
return this.jsonData.settings;
|
||||
}
|
||||
|
||||
public switchLocale(locale: string): void {
|
||||
this.locale = locale;
|
||||
}
|
||||
|
||||
public geti18N() {
|
||||
return {
|
||||
locale: this.locale,
|
||||
fallbackLocale: this.fallbackLocale,
|
||||
};
|
||||
}
|
||||
|
||||
public getFallbackLocale(): string {
|
||||
return this.fallbackLocale;
|
||||
}
|
||||
|
||||
// * --- BRANDS
|
||||
|
||||
public brands(): Array<TypeBrand> {
|
||||
|
|
@ -19,7 +41,7 @@ export default class AppState {
|
|||
}
|
||||
|
||||
public brand(slug:string): TypeBrand|undefined {
|
||||
return this.jsonData.items.find(brand => brand.slug === slug);
|
||||
return this.jsonData.items.find(brand => brand.slug[this.locale] === slug);
|
||||
}
|
||||
|
||||
public brandFromRange(range:TypeRange): TypeBrand {
|
||||
|
|
@ -48,7 +70,7 @@ export default class AppState {
|
|||
}
|
||||
|
||||
public range(slug:string): TypeRange|undefined {
|
||||
return this.ranges().find(range => range.slug === slug);
|
||||
return this.ranges().find(range => range.slug[this.locale] === slug);
|
||||
}
|
||||
|
||||
// * --- END RANGES
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ export default class ToolboxHelper {
|
|||
}
|
||||
|
||||
public static trans(text: string, params: Record<string,string> = {}, localeToUse: string|null = null): string {
|
||||
const { t } = useI18n();
|
||||
const { t } = useI18n({ useScope: "global"});
|
||||
if(localeToUse) {
|
||||
return t(text, params, {
|
||||
locale: localeToUse,
|
||||
|
|
@ -40,4 +40,15 @@ export default class ToolboxHelper {
|
|||
}
|
||||
return t(text, params);
|
||||
}
|
||||
|
||||
public static getTranslatableField(model: TypeBrand | TypeRange | TypeProduct, field: "name" | "slug" | "description"): string {
|
||||
const { locale, fallbackLocale } = useAppStore().getI18n();
|
||||
const i18nField: Typei18nField | null = (model[field as keyof typeof model] ?? null) as Typei18nField | null;
|
||||
|
||||
if (!i18nField) {
|
||||
throw new Error(`getTranslatableField ${field} is not part of ${model}`);
|
||||
}
|
||||
|
||||
return i18nField[locale] !== undefined ? i18nField[locale] : i18nField[fallbackLocale];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
<button
|
||||
class="rounded-pill btn btn-primary px-4 py-1"
|
||||
:disabled="previousRange === null"
|
||||
:title="`Voir les produits de la gamme ${previousRange?.name}`"
|
||||
:title="previousRange ? t('view_range_products', {'range_name': transField(previousRange, 'name')}) : ''"
|
||||
data-bs-toggle="tooltip"
|
||||
@click="gotoRange(previousRange)"
|
||||
>
|
||||
|
|
@ -15,7 +15,7 @@
|
|||
<div class="col home text-center px-3">
|
||||
<button
|
||||
class="rounded-pill btn btn-primary px-4 py-1"
|
||||
title="Voir les gammes"
|
||||
:title="activeBrand ? t('view_brand_ranges', {'brand_name': transField(activeBrand, 'name')}) : ''"
|
||||
data-bs-toggle="tooltip"
|
||||
@click="gotoBrand(activeBrand)"
|
||||
>
|
||||
|
|
@ -26,7 +26,7 @@
|
|||
<button
|
||||
class="rounded-pill btn btn-primary px-4 py-1"
|
||||
:disabled="nextRange === null"
|
||||
:title="`Voir les produits de la gamme ${nextRange?.name}`"
|
||||
:title="nextRange ? t('view_range_products', {'range_name': transField(nextRange, 'name')}) : ''"
|
||||
data-bs-toggle="tooltip"
|
||||
@click="gotoRange(nextRange)"
|
||||
>
|
||||
|
|
@ -41,11 +41,13 @@
|
|||
// eslint-disable-next-line import/named
|
||||
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
|
||||
import { defineComponent } from "vue";
|
||||
import ToolboxHelper from "~/classes/ToolboxHelper";
|
||||
|
||||
export default defineComponent({
|
||||
name: "NavigationMenu",
|
||||
components: { FontAwesomeIcon },
|
||||
data(): {
|
||||
locale: string;
|
||||
brands: Array<TypeRange>;
|
||||
nextRange: TypeRange | null;
|
||||
previousRange: TypeRange | null;
|
||||
|
|
@ -53,6 +55,7 @@ export default defineComponent({
|
|||
activeBrand: TypeBrand | null;
|
||||
} {
|
||||
return {
|
||||
locale: "",
|
||||
brands: [],
|
||||
nextRange: null,
|
||||
previousRange: null,
|
||||
|
|
@ -67,8 +70,16 @@ export default defineComponent({
|
|||
},
|
||||
mounted() {
|
||||
this.refreshData();
|
||||
const { locale } = useAppStore().getI18n();
|
||||
this.locale = locale;
|
||||
},
|
||||
methods: {
|
||||
t(text: string, params: Record<string,string> = {}, localeToUse: string|null = null): string {
|
||||
return ToolboxHelper.trans(text, params, localeToUse);
|
||||
},
|
||||
transField(model: TypeBrand | TypeRange | TypeProduct, field: "name" | "slug" | "description") {
|
||||
return ToolboxHelper.getTranslatableField(model, field);
|
||||
},
|
||||
refreshData() {
|
||||
this.activeBrand = useAppStore().activeBrand;
|
||||
this.activeRange = useAppStore().activeRange;
|
||||
|
|
@ -80,14 +91,14 @@ export default defineComponent({
|
|||
return;
|
||||
}
|
||||
useAppStore().setActiveRange(null);
|
||||
navigateTo(useLocaleRoute()({"name": "brands-slug", "params": {"slug": activeBrand.slug}}));
|
||||
navigateTo(useLocaleRoute()({"name": "brands-slug", "params": {"slug": activeBrand.slug[this.locale]}}));
|
||||
},
|
||||
gotoRange(range: TypeRange|null) {
|
||||
if(!range) {
|
||||
return;
|
||||
}
|
||||
useAppStore().setActiveRange(range);
|
||||
navigateTo(useLocaleRoute()({"name": "ranges-slug", "params": {"slug": range.slug}}));
|
||||
navigateTo(useLocaleRoute()({"name": "ranges-slug", "params": {"slug": range.slug[this.locale]}}));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -40,14 +40,14 @@
|
|||
class="swiper-slide"
|
||||
:to="`/brands/${brand.slug}`"
|
||||
data-bs-toggle="tooltip"
|
||||
:title="`Voir les gammes de la marque ${brand.name}`"
|
||||
:title="`Voir les gammes de la marque ${transField(brand, 'name')}`"
|
||||
@click.prevent="gotoBrand(brand)"
|
||||
>
|
||||
<img
|
||||
class="img-fluid"
|
||||
:src="`/data/${brand.picture}`"
|
||||
:alt="`Marque ${brand.name}`"
|
||||
:title="`Le logo de la marque ${brand.name}`"
|
||||
:alt="`Marque ${transField(brand, 'name')}`"
|
||||
:title="`Le logo de la marque ${transField(brand, 'name')}`"
|
||||
data-bs-toggle="tooltip"
|
||||
>
|
||||
</NuxtLinkLocale>
|
||||
|
|
@ -87,6 +87,7 @@ export default defineComponent({
|
|||
name: "AppFooter",
|
||||
components: {Swiper, SwiperSlide},
|
||||
data(): {
|
||||
locale: string;
|
||||
versions: typeof window.versions;
|
||||
appInfo: typeof appInfo;
|
||||
route: RouteLocationNormalizedLoaded;
|
||||
|
|
@ -97,6 +98,7 @@ export default defineComponent({
|
|||
}>;
|
||||
} {
|
||||
return {
|
||||
locale: "",
|
||||
route: useRoute(),
|
||||
versions: window.versions,
|
||||
appInfo: {
|
||||
|
|
@ -123,17 +125,22 @@ export default defineComponent({
|
|||
window.ipcRendererObject.getAppInfo().then((appInfo) => {this.appInfo = appInfo;});
|
||||
this.brands = useAppStore().data.brands();
|
||||
this.activeBrand = useAppStore().activeBrand;
|
||||
const { locale } = useAppStore().getI18n();
|
||||
this.locale = locale;
|
||||
},
|
||||
methods: {
|
||||
t(text: string, params: Record<string,string> = {}, localeToUse: string|null = null): string {
|
||||
return ToolboxHelper.trans(text, params, localeToUse);
|
||||
},
|
||||
transField(model: TypeBrand | TypeRange | TypeProduct, field: "name" | "slug" | "description") {
|
||||
return ToolboxHelper.getTranslatableField(model, field);
|
||||
},
|
||||
getContrastYIQ(hexcolor: string): string {
|
||||
return ToolboxHelper.getContrastYIQ(hexcolor);
|
||||
},
|
||||
gotoBrand(brand: TypeBrand) {
|
||||
useAppStore().setActiveBrand(brand);
|
||||
navigateTo(useLocaleRoute()({"name": "brands-slug", "params": {"slug": brand.slug}}));
|
||||
navigateTo(useLocaleRoute()({"name": "brands-slug", "params": {"slug": this.transField(brand, "slug")}}));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -15,19 +15,19 @@
|
|||
}"
|
||||
>
|
||||
<NuxtLinkLocale
|
||||
:to="`/brands/${activeBrand.slug}`"
|
||||
:to="`/brands/${transField(activeBrand, 'slug')}`"
|
||||
:class="{
|
||||
'd-inline-block py-3 px-2 text-center': true,
|
||||
'flex-grow-1': !activeRange
|
||||
}"
|
||||
data-bs-toggle="tooltip"
|
||||
:title="t('view_brand_ranges', {'brand_name': activeBrand.name})"
|
||||
:title="t('view_brand_ranges', {'brand_name': transField(activeBrand, 'name')})"
|
||||
>
|
||||
<img
|
||||
class="img-fluid main-logo"
|
||||
:src="`/data/${activeBrand.picture}`"
|
||||
:alt="`Marque ${activeBrand.name}`"
|
||||
:title="t('brands_logo', {'brand_name': activeBrand.name})"
|
||||
:alt="`Marque ${transField(activeBrand, 'name')}`"
|
||||
:title="t('brands_logo', {'brand_name': transField(activeBrand, 'name')})"
|
||||
>
|
||||
</NuxtLinkLocale>
|
||||
<div v-if="activeRange" class="flex-grow-1 text-center">
|
||||
|
|
@ -42,7 +42,7 @@
|
|||
'text-shadow': `0 0 0.2rem ${toRGBA(getContrastYIQ(activeRange.color), 0.8)}`
|
||||
}"
|
||||
>
|
||||
{{ activeRange.name }}
|
||||
{{ transField(activeRange, 'name') }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -75,7 +75,11 @@
|
|||
<button
|
||||
v-for="(localeObject,localeIndex) of locales"
|
||||
:key="localeIndex"
|
||||
class="btn btn-link px-2 shadow"
|
||||
:class="{
|
||||
'btn px-2 shadow': true,
|
||||
'btn-link': locale === localeObject.iso,
|
||||
'btn-warning': locale !== localeObject.iso,
|
||||
}"
|
||||
:title="localeObject.label"
|
||||
data-bs-toggle="tooltip"
|
||||
@click.prevent="switchLocale(localeObject)"
|
||||
|
|
@ -97,7 +101,7 @@ import ToolboxHelper from "~/classes/ToolboxHelper";
|
|||
import { useAppStore } from "~/stores/useAppStore";
|
||||
import bsTooltips from "~/vueModules/bsTooltips";
|
||||
|
||||
type Locale = {
|
||||
type LocaleParams = {
|
||||
iso: string,
|
||||
flag: string,
|
||||
label: string,
|
||||
|
|
@ -108,8 +112,8 @@ export default defineComponent({
|
|||
data(): {
|
||||
versions: typeof window.versions;
|
||||
settings: TypeSettings;
|
||||
locales: Array<Locale>,
|
||||
locale: string|null;
|
||||
locales: Array<LocaleParams>,
|
||||
locale: string;
|
||||
route: RouteLocationNormalizedLoaded;
|
||||
activeBrand: TypeBrand|null;
|
||||
activeRange: TypeRange|null;
|
||||
|
|
@ -118,7 +122,7 @@ export default defineComponent({
|
|||
versions: window.versions,
|
||||
settings: {} as TypeSettings,
|
||||
locales: [],
|
||||
locale: null,
|
||||
locale: "",
|
||||
route: useRoute(),
|
||||
activeBrand: null,
|
||||
activeRange: null,
|
||||
|
|
@ -133,13 +137,15 @@ export default defineComponent({
|
|||
}
|
||||
this.activeBrand = useAppStore().activeBrand;
|
||||
this.activeRange = useAppStore().activeRange;
|
||||
const { locale } = useAppStore().getI18n();
|
||||
this.locale = locale;
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.$nextTick(() => bsTooltips.methods.initTooltips());
|
||||
this.settings = useAppStore().data.settings();
|
||||
this.activeBrand = useAppStore().activeBrand;
|
||||
const { locale, availableLocales } = useI18n();
|
||||
const { locale, availableLocales } = useI18n({ useScope: "global"});
|
||||
this.locale = locale.value;
|
||||
this.locales = availableLocales.map(localeStr => {
|
||||
return {
|
||||
|
|
@ -153,10 +159,14 @@ export default defineComponent({
|
|||
t(text: string, params: Record<string,string> = {}, localeToUse: string|null = null): string {
|
||||
return ToolboxHelper.trans(text, params, localeToUse);
|
||||
},
|
||||
switchLocale(locale:Locale) {
|
||||
transField(model: TypeBrand | TypeRange | TypeProduct, field: "name" | "slug" | "description") {
|
||||
return ToolboxHelper.getTranslatableField(model, field);
|
||||
},
|
||||
switchLocale(localeToSwitch:LocaleParams) {
|
||||
const switchLocalePath = useSwitchLocalePath();
|
||||
Toast.toast(locale.label, ToastTypeEnum.default);
|
||||
navigateTo(switchLocalePath(locale.iso));
|
||||
Toast.toast(localeToSwitch.label, ToastTypeEnum.default);
|
||||
useAppStore().switchLocale(localeToSwitch.iso);
|
||||
navigateTo(switchLocalePath(localeToSwitch.iso));
|
||||
},
|
||||
rangeFont(fontId: number) {
|
||||
const font = useAppStore().getFont(fontId);
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ export default defineI18nConfig(() => ({
|
|||
legacy: false,
|
||||
globalInjection: true,
|
||||
locale: "en",
|
||||
fallbackLocale: "en",
|
||||
fallbackLocale: "fr",
|
||||
messages: {
|
||||
en,
|
||||
fr,
|
||||
|
|
|
|||
18
index.d.ts
vendored
18
index.d.ts
vendored
|
|
@ -5,6 +5,9 @@ export { };
|
|||
|
||||
// * --- MODELS From JSON Schema
|
||||
|
||||
type Locale = string;
|
||||
type i18nField = Record<Locale, string>
|
||||
|
||||
/** Showroom Bo json data format */
|
||||
type AppModel = {
|
||||
/** Version de l'application */
|
||||
|
|
@ -47,9 +50,9 @@ type BrandModel = {
|
|||
/** The unique identifier for a brand */
|
||||
id: number;
|
||||
/** Nom de la marque */
|
||||
name: string;
|
||||
name: i18nField;
|
||||
/** Slug de la marque */
|
||||
slug: string;
|
||||
slug: i18nField;
|
||||
/** Couleur de la marque (hex color) */
|
||||
color: string;
|
||||
/** Logo de la marque, chemin tel que présent dans le zip */
|
||||
|
|
@ -64,9 +67,9 @@ type RangeModel = {
|
|||
/** The unique identifier for a range */
|
||||
id: number;
|
||||
/** Nom de la gamme */
|
||||
name: string;
|
||||
name: i18nField;
|
||||
/** Slug de la gamme */
|
||||
slug: string;
|
||||
slug: i18nField;
|
||||
/** Logo de la gamme, chemin tel que présent dans le zip */
|
||||
picture: string;
|
||||
/** Couleur de la gamme */
|
||||
|
|
@ -89,11 +92,11 @@ type ProductModel = {
|
|||
/** The unique identifier for a product */
|
||||
id: number;
|
||||
/** Nom du produit */
|
||||
name: string;
|
||||
name: i18nField;
|
||||
/** Slug du produit */
|
||||
slug: string;
|
||||
slug: i18nField;
|
||||
/** Description du produit, texte WYSYWYG */
|
||||
description: string;
|
||||
description: i18nField;
|
||||
/** Logo du produit, chemin tel que présent dans le zip */
|
||||
picture: string;
|
||||
/** Clé étrangère de la gamme */
|
||||
|
|
@ -150,6 +153,7 @@ declare global {
|
|||
type TypeProduct = ProductModel;
|
||||
type TypeFont = FontModel;
|
||||
|
||||
type Typei18nField = i18nField;
|
||||
type ToastTypeEnum = ToastType;
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -66,8 +66,8 @@ export default defineNuxtConfig({
|
|||
},
|
||||
|
||||
i18n: {
|
||||
locales: ["en","fr", "nl"],
|
||||
defaultLocale: "en",
|
||||
locales: ["en", "fr", "nl"],
|
||||
defaultLocale: "fr",
|
||||
// * Ajouter aussi la locale dans ce fichier
|
||||
vueI18n: "./i18n.config.ts"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
:class="{
|
||||
'd-inline-block btn position-relative': true,
|
||||
}"
|
||||
:title="t('view_range_products', {'range_name': range.name})"
|
||||
:title="t('view_range_products', {'range_name': transField(range, 'name')})"
|
||||
data-bs-toggle="tooltip"
|
||||
@click.stop="gotoRange(range)"
|
||||
>
|
||||
|
|
@ -22,8 +22,8 @@
|
|||
<img
|
||||
class="img-fluid"
|
||||
:src="`/data/${range.picture}`"
|
||||
:alt="t('ranges_logo', {'range_name': range.name})"
|
||||
:title="t('ranges_logo', {'range_name': range.name})"
|
||||
:alt="t('ranges_logo', {'range_name': transField(range, 'name')})"
|
||||
:title="t('ranges_logo', {'range_name': transField(range, 'name')})"
|
||||
>
|
||||
</div>
|
||||
<span
|
||||
|
|
@ -41,7 +41,7 @@
|
|||
'text-shadow': `0 0 0.2rem ${toRGBA(getContrastYIQ(range.color), 0.8)}`,
|
||||
}"
|
||||
>
|
||||
{{ range.name }}
|
||||
{{ transField(range, 'name') }}
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
|
|
@ -117,6 +117,9 @@ export default defineComponent({
|
|||
t(text: string, params: Record<string,string> = {}, localeToUse: string|null = null): string {
|
||||
return ToolboxHelper.trans(text, params, localeToUse);
|
||||
},
|
||||
transField(model: TypeBrand | TypeRange | TypeProduct, field: "name" | "slug" | "description") {
|
||||
return ToolboxHelper.getTranslatableField(model, field);
|
||||
},
|
||||
titleAnimations(rangeIndex: number) {
|
||||
const animation = this.animations.at(ToolboxHelper.randomInteger(0, this.animations.length -1));
|
||||
const out: Map<string, boolean> = new Map<string, boolean>();
|
||||
|
|
@ -144,7 +147,7 @@ export default defineComponent({
|
|||
},
|
||||
gotoRange(range: TypeRange) {
|
||||
useAppStore().setActiveRange(range);
|
||||
navigateTo(useLocaleRoute()({"name": "ranges-slug", "params": {"slug": range.slug}}));
|
||||
navigateTo(useLocaleRoute()({"name": "ranges-slug", "params": {"slug": this.transField(range, "slug")}}));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -28,11 +28,11 @@
|
|||
:class="{...{'brand-title fw-bold text-capitalize fs-1 animate__animated': true}, ...titleAnimations(brandIndex)}"
|
||||
:style="{ 'color': brand.color }"
|
||||
role="button"
|
||||
:title="t('view_brand_ranges', {'brand_name': brand.name})"
|
||||
:title="t('view_brand_ranges', {'brand_name': transField(brand, 'name')})"
|
||||
data-bs-toggle="tooltip"
|
||||
@click="gotoBrand(brand)"
|
||||
>
|
||||
{{ brand.name }}
|
||||
{{ transField(brand, 'name') }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -46,15 +46,15 @@
|
|||
<div
|
||||
class="d-inline-block"
|
||||
role="button"
|
||||
:title="t('view_brand_ranges', {'brand_name': brand.name})"
|
||||
:title="t('view_brand_ranges', {'brand_name': transField(brand, 'name')})"
|
||||
data-bs-toggle="tooltip"
|
||||
@click="gotoBrand(brand)"
|
||||
>
|
||||
<img
|
||||
class="img-fluid"
|
||||
:src="`/data/${brand.picture}`"
|
||||
:alt="t('brands_logo', {'brand_name': brand.name})"
|
||||
:title="t('brands_logo', {'brand_name': brand.name})"
|
||||
:alt="t('brands_logo', {'brand_name': transField(brand, 'name')})"
|
||||
:title="t('brands_logo', {'brand_name': transField(brand, 'name')})"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -114,6 +114,9 @@ export default defineComponent({
|
|||
t(text: string, params: Record<string,string> = {}, localeToUse: string|null = null): string {
|
||||
return ToolboxHelper.trans(text, params, localeToUse);
|
||||
},
|
||||
transField(model: TypeBrand | TypeRange | TypeProduct, field: "name" | "slug" | "description") {
|
||||
return ToolboxHelper.getTranslatableField(model, field);
|
||||
},
|
||||
setBrandToAnimate(): void {
|
||||
clearTimeout(this.animateTimeout);
|
||||
this.animateIndex = ToolboxHelper.randomInteger(0, this.appState.brands().length -1);
|
||||
|
|
@ -127,7 +130,7 @@ export default defineComponent({
|
|||
},
|
||||
gotoBrand(brand: TypeBrand) {
|
||||
useAppStore().setActiveBrand(brand);
|
||||
navigateTo(useLocaleRoute()({"name": "brands-slug", "params": {"slug": brand.slug}}));
|
||||
navigateTo(useLocaleRoute()({"name": "brands-slug", "params": {"slug": this.transField(brand, "slug")}}));
|
||||
}
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -44,13 +44,13 @@
|
|||
'img-fluid': activeProduct?.id === product.id,
|
||||
}"
|
||||
:src="`/data/${product.picture}`"
|
||||
:alt="t('products_logo', {'product_name': product.name})"
|
||||
:title="t('products_logo', {'product_name': product.name})"
|
||||
:alt="t('products_logo', {'product_name': transField(product, 'name')})"
|
||||
:title="t('products_logo', {'product_name': transField(product, 'name')})"
|
||||
>
|
||||
</div>
|
||||
<Transition>
|
||||
<div v-if="activeProduct?.id === product.id" class="col pt-5 ps-md-4">
|
||||
<div v-sane-html="product.description" class="p-md-3 my-md-5 description" />
|
||||
<div v-sane-html="transField(product, 'description')" class="p-md-3 my-md-5 description" />
|
||||
</div>
|
||||
</Transition>
|
||||
</div>
|
||||
|
|
@ -69,7 +69,7 @@
|
|||
'background-color': activeProduct?.id === product.id ? '' : range.color
|
||||
}"
|
||||
>
|
||||
{{ product.name }}
|
||||
{{ transField(product, 'name') }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -133,6 +133,7 @@ export default defineComponent({
|
|||
return ;
|
||||
}
|
||||
this.range = range;
|
||||
|
||||
// * Pour que ces putains de titres label aient la meme hauteur.
|
||||
this.$nextTick(() => {
|
||||
const spanList = (this.$refs.rangeList as HTMLDivElement).querySelectorAll(".product-title") as NodeListOf<HTMLSpanElement>;
|
||||
|
|
@ -152,6 +153,9 @@ export default defineComponent({
|
|||
t(text: string, params: Record<string,string> = {}, localeToUse: string|null = null): string {
|
||||
return ToolboxHelper.trans(text, params, localeToUse);
|
||||
},
|
||||
transField(model: TypeBrand | TypeRange | TypeProduct, field: "name" | "slug" | "description") {
|
||||
return ToolboxHelper.getTranslatableField(model, field);
|
||||
},
|
||||
getContrastYIQ(hexcolor: string): string {
|
||||
return ToolboxHelper.getContrastYIQ(hexcolor);
|
||||
},
|
||||
|
|
|
|||
|
|
@ -11,11 +11,11 @@
|
|||
},
|
||||
"name": {
|
||||
"description": "Nom de la marque",
|
||||
"type": "string"
|
||||
"type": "object"
|
||||
},
|
||||
"slug": {
|
||||
"description": "Slug de la marque",
|
||||
"type": "string"
|
||||
"type": "object"
|
||||
},
|
||||
"color": {
|
||||
"description": "Couleur de la marque",
|
||||
|
|
|
|||
|
|
@ -11,15 +11,15 @@
|
|||
},
|
||||
"name": {
|
||||
"description": "Nom du produit",
|
||||
"type": "string"
|
||||
"type": "object"
|
||||
},
|
||||
"slug": {
|
||||
"description": "Slug du produit",
|
||||
"type": "string"
|
||||
"type": "object"
|
||||
},
|
||||
"description": {
|
||||
"description": "Description du produit, texte WYSYWYG",
|
||||
"type": "string"
|
||||
"type": "object"
|
||||
},
|
||||
"picture": {
|
||||
"description": "Logo du produit, chemin tel que présent dans le zip",
|
||||
|
|
|
|||
|
|
@ -11,11 +11,11 @@
|
|||
},
|
||||
"name": {
|
||||
"description": "Nom de la gamme",
|
||||
"type": "string"
|
||||
"type": "object"
|
||||
},
|
||||
"slug": {
|
||||
"description": "Slug de la gamme",
|
||||
"type": "string"
|
||||
"type": "object"
|
||||
},
|
||||
"picture": {
|
||||
"description": "Logo de la gamme, chemin tel que présent dans le zip",
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import AppState from "../classes/AppState";
|
|||
|
||||
export const useAppStore = defineStore("appStore", {
|
||||
state: () => ({
|
||||
data: new AppState({} as TypeApp),
|
||||
data: new AppState({} as TypeApp, "fr", "fr"),
|
||||
activeBrand: null,
|
||||
activeRange: null,
|
||||
} as {
|
||||
|
|
@ -11,8 +11,8 @@ export const useAppStore = defineStore("appStore", {
|
|||
activeRange: TypeRange | null;
|
||||
}),
|
||||
actions: {
|
||||
setupAppData(dataJson: TypeApp): void {
|
||||
this.data = new AppState(dataJson);
|
||||
setupAppData(dataJson: TypeApp, locale: string, fallbackLocale: string): void {
|
||||
this.data = new AppState(dataJson, locale, fallbackLocale);
|
||||
},
|
||||
setActiveBrand(brand: TypeBrand|null): void {
|
||||
this.activeBrand = brand;
|
||||
|
|
@ -47,6 +47,12 @@ export const useAppStore = defineStore("appStore", {
|
|||
return null;
|
||||
}
|
||||
return font;
|
||||
},
|
||||
getI18n() {
|
||||
return this.data.geti18N();
|
||||
},
|
||||
switchLocale(locale: string): void {
|
||||
this.data.switchLocale(locale);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue