diff --git a/cookbook/templates/frontend/tandoor.html b/cookbook/templates/frontend/tandoor.html index c2edcc442..7ed82de93 100644 --- a/cookbook/templates/frontend/tandoor.html +++ b/cookbook/templates/frontend/tandoor.html @@ -1,12 +1,15 @@ {% load django_vite %} +{% load i18n %} +{% get_current_language as LANGUAGE_CODE %} + {% load theming_tags %} {% load custom_tags %} {% theme_values request as theme_values %} - + Tandoor diff --git a/vue3/src/apps/tandoor/Tandoor.vue b/vue3/src/apps/tandoor/Tandoor.vue index 17438e476..7861d53aa 100644 --- a/vue3/src/apps/tandoor/Tandoor.vue +++ b/vue3/src/apps/tandoor/Tandoor.vue @@ -34,6 +34,7 @@ + Test: {{$t('No_Results')}} diff --git a/vue3/src/apps/tandoor/main.ts b/vue3/src/apps/tandoor/main.ts index ec7540146..22fca1af0 100644 --- a/vue3/src/apps/tandoor/main.ts +++ b/vue3/src/apps/tandoor/main.ts @@ -1,6 +1,8 @@ import {createApp} from "vue"; import {createRouter, createWebHashHistory} from 'vue-router' import {createPinia} from 'pinia' +import en from '../../locales/en.json' +import de from '../../locales/de.json' // @ts-ignore import App from './Tandoor.vue' @@ -15,6 +17,8 @@ import RecipeEditPage from "@/pages/RecipeEditPage.vue"; import MealPlanPage from "@/pages/MealPlanPage.vue"; import SearchPage from "@/pages/SearchPage.vue"; import TestPage from "@/pages/TestPage.vue"; +import {createI18n} from "vue-i18n"; +import {getLocale, loadLocaleMessages, setI18nLanguage, setupI18n, SUPPORT_LOCALES} from "@/i18n"; const routes = [ {path: '/', component: StartPage, name: 'view_home'}, @@ -33,12 +37,29 @@ const router = createRouter({ routes, }) +let locale = document.querySelector('html')!.getAttribute('lang') +if (locale == null || !SUPPORT_LOCALES.includes(locale)) { + console.log('falling back to en because ', locale, ' is not supported as a locale') + locale = 'en' +} +const localeMessages = await import((`../../locales/${locale}.json`)) +console.log(localeMessages, de) +const i18n = setupI18n({ + legacy: false, + locale: locale, + fallbackLocale: 'en', + messages: { + en, de + } +}) + + const app = createApp(App) app.use(createPinia()) app.use(vuetify) app.use(router) -app.use(luxonPlugin) +app.use(i18n) app.use(mavonEditor) // TODO only use on pages that need it app.mount('#app') diff --git a/vue3/src/components/inputs/ModelSelect.vue b/vue3/src/components/inputs/ModelSelect.vue index b9db0d2cd..a93d114e0 100644 --- a/vue3/src/components/inputs/ModelSelect.vue +++ b/vue3/src/components/inputs/ModelSelect.vue @@ -55,10 +55,14 @@ const props = defineProps({ allowCreate: {type: Boolean, default: false}, + placeholder: {type: String, default: undefined}, + noOptionsText: {type: String, default: undefined}, + noResultsText: {type: String, default: undefined}, + // not verified search_on_load: {type: Boolean, default: false}, - placeholder: {type: String, default: undefined}, + parent_variable: {type: String, default: undefined}, sticky_options: { diff --git a/vue3/src/i18n.ts b/vue3/src/i18n.ts new file mode 100644 index 000000000..458e047cd --- /dev/null +++ b/vue3/src/i18n.ts @@ -0,0 +1,100 @@ +import {nextTick, isRef} from 'vue' +import {createI18n} from 'vue-i18n' + +import type { + I18n, + I18nOptions, + Locale, + VueI18n, + Composer, + I18nMode +} from 'vue-i18n' + +/** + * lazy loading of translation, resources: + * https://vue-i18n.intlify.dev/guide/advanced/lazy.html + * https://github.com/intlify/vue-i18n/blob/master/examples/lazy-loading/vite/src/i18n.ts + */ + +// TODO not sure why/if this is needed, comment out for now and see if anything breaks +export const SUPPORT_LOCALES = getSupportedLocales() + +function getSupportedLocales() { + let supportedLocales: string[] = [] + let localeFiles = import.meta.glob('@/locales/*.json'); + for (const path in localeFiles) { + supportedLocales.push(path.split('/').slice(-1)[0].split('.')[0]); + } + return supportedLocales +} + +function isComposer( + instance: VueI18n | Composer, + mode: I18nMode +): instance is Composer { + return mode === 'composition' && isRef(instance.locale) +} + +export function setupI18n2() { + let locale = document.querySelector('html')!.getAttribute('lang') + if (locale == null || !SUPPORT_LOCALES.includes(locale)) { + locale = 'en' + } + + const i18n = createI18n({locale: locale}) + + + + return i18n +} + +export function getLocale(i18n: I18n): string { + if (isComposer(i18n.global, i18n.mode)) { + return i18n.global.locale.value + } else { + return i18n.global.locale + } +} + +export function setLocale(i18n: I18n, locale: Locale): void { + if (isComposer(i18n.global, i18n.mode)) { + i18n.global.locale.value = locale + } else { + i18n.global.locale = locale + } +} + +export function setupI18n(options: I18nOptions = {locale: 'en'}): I18n { + const i18n = createI18n(options) + setI18nLanguage(i18n, options.locale!) + return i18n +} + +export function setI18nLanguage(i18n: I18n, locale: Locale): void { + setLocale(i18n, locale) + /** + * NOTE: + * If you need to specify the language setting for headers, such as the `fetch` API, set it here. + * The following is an example for axios. + * + * axios.defaults.headers.common['Accept-Language'] = locale + */ + + // should be done by django + // document.querySelector('html')!.setAttribute('lang', locale) +} + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +const getResourceMessages = (r: any) => r.default || r + +export async function loadLocaleMessages(i18n: I18n, locale: Locale) { + // load locale messages + const messages = await import(`./locales/${locale}.json`).then( + getResourceMessages + ) + + // set locale and locale message + i18n.global.setLocaleMessage(locale, messages) + + return nextTick() +} \ No newline at end of file diff --git a/vue3/src/locales b/vue3/src/locales new file mode 120000 index 000000000..16df897e5 --- /dev/null +++ b/vue3/src/locales @@ -0,0 +1 @@ +../../vue/src/locales/ \ No newline at end of file