diff --git a/presenter/.env.dist b/presenter/.env.dist index c70cbf337a..155d848885 100644 --- a/presenter/.env.dist +++ b/presenter/.env.dist @@ -16,5 +16,3 @@ PUBLIC_ENV__ENDPOINTS__GRAPHQL_URI=http://localhost:4000/ # META PUBLIC_ENV__META__BASE_URL="http://localhost:3000" PUBLIC_ENV__META__DEFAULT_AUTHOR="DreamMall Verlag GbR" -PUBLIC_ENV__META__DEFAULT_DESCRIPTION="Deine Reichweite Erweitern Alle Möglichkeiten Miteinander Ausschöpfen Lebensqualität Leben" -PUBLIC_ENV__META__DEFAULT_TITLE="DreamMall" diff --git a/presenter/renderer/+config.ts b/presenter/renderer/+config.ts index ceabba4d10..8211b38b43 100644 --- a/presenter/renderer/+config.ts +++ b/presenter/renderer/+config.ts @@ -2,7 +2,7 @@ export default { clientRouting: true, prefetchStaticAssets: 'viewport', - passToClient: ['pageProps', /* 'urlPathname', */ 'routeParams'], + passToClient: ['pageProps', /* 'urlPathname', */ 'routeParams', 'locale'], meta: { title: { // Make the value of `title` available on both the server- and client-side diff --git a/presenter/renderer/+onBeforeRoute.ts b/presenter/renderer/+onBeforeRoute.ts new file mode 100644 index 0000000000..ee2308d4fe --- /dev/null +++ b/presenter/renderer/+onBeforeRoute.ts @@ -0,0 +1,16 @@ +import { PageContext } from 'vike/types' + +import { extractLocale } from '#src/locales' + +export function onBeforeRoute(pageContext: PageContext) { + const { urlWithoutLocale, locale } = extractLocale(pageContext.urlPathname) + + return { + pageContext: { + // Make `locale` available as `pageContext.locale` + locale, + // Vike's router will use pageContext.urlLogical instead of pageContext.urlOriginal + urlLogical: urlWithoutLocale, + }, + } +} diff --git a/presenter/renderer/+onPrerenderStart.ts b/presenter/renderer/+onPrerenderStart.ts new file mode 100644 index 0000000000..869bb2a2e6 --- /dev/null +++ b/presenter/renderer/+onPrerenderStart.ts @@ -0,0 +1,32 @@ +import { PageContextServer } from 'vike/types' + +import { locales } from '#src/locales' + +export { onPrerenderStart } + +function onPrerenderStart(prerenderContext: { pageContexts: PageContextServer[] }): { + prerenderContext: { + pageContexts: PageContextServer[] + } +} { + const storePageContexts: PageContextServer[] = [] + prerenderContext.pageContexts.forEach((pageContext) => { + // Duplicate pageContext for each locale + locales.forEach((locale) => { + // Localize URL + let { urlOriginal } = pageContext + urlOriginal = `/${locale}${urlOriginal}` + storePageContexts.push({ + ...pageContext, + urlOriginal, + // Set pageContext.locale + locale, + }) + }) + }) + return { + prerenderContext: { + pageContexts: storePageContexts, + }, + } +} diff --git a/presenter/renderer/app.ts b/presenter/renderer/app.ts index 4362b36d81..e312f4bdd8 100644 --- a/presenter/renderer/app.ts +++ b/presenter/renderer/app.ts @@ -9,6 +9,7 @@ import { createApolloClient } from '#plugins/apollo' import i18n from '#plugins/i18n' import pinia from '#plugins/pinia' import CreateVuetify from '#plugins/vuetify' +import { locales } from '#src/locales' import AuthService from '#src/services/AuthService' import { useAuthStore } from '#stores/authStore' @@ -25,6 +26,7 @@ function createApp(pageContext: PageContext, isClient = true) { data: () => ({ Page: markRaw(pageContext.Page), pageProps: markRaw(pageContext.pageProps || {}), + locale: markRaw(pageContext.locale || {}), isClient, }), created() { @@ -64,6 +66,7 @@ function createApp(pageContext: PageContext, isClient = true) { Object.assign(pageContextReactive, pageContext) rootComponent.Page = markRaw(pageContext.Page) rootComponent.pageProps = markRaw(pageContext.pageProps || {}) + rootComponent.locale = markRaw(pageContext.locale || {}) }, }) @@ -71,6 +74,10 @@ function createApp(pageContext: PageContext, isClient = true) { setPageContext(app, pageContextReactive) + if (pageContext.locale && locales.includes(pageContext.locale)) { + i18n.global.locale.value = pageContext.locale + } + return { app, i18n } } diff --git a/presenter/renderer/plugins/i18n.ts b/presenter/renderer/plugins/i18n.ts index e929463d13..2a70d255eb 100644 --- a/presenter/renderer/plugins/i18n.ts +++ b/presenter/renderer/plugins/i18n.ts @@ -1,14 +1,15 @@ import { createI18n } from 'vue-i18n' import { de as vuetifyDe, en as vuetifyEn } from 'vuetify/locale' +import { localeDefault, fallbackLocale } from '#src/locales' import de from '#src/locales/de.json' import en from '#src/locales/en.json' export default createI18n({ legacy: false, // Vuetify does not support the legacy mode of vue-i18n globalInjection: true, - locale: 'de', - fallbackLocale: 'en', + locale: localeDefault, + fallbackLocale, messages: { de: { $vuetify: vuetifyDe, diff --git a/presenter/renderer/utils.ts b/presenter/renderer/utils.ts index 72833d5e31..b42bb38f76 100644 --- a/presenter/renderer/utils.ts +++ b/presenter/renderer/utils.ts @@ -1,19 +1,19 @@ import { PageContext } from 'vike/types' -import { META } from '#src/env' +import i18n from '#plugins/i18n' function getTitle(pageContext: PageContext) { // The value exported by /pages/**/+title.js is available at pageContext.config.title const val = pageContext.config.title if (typeof val === 'string') return val if (typeof val === 'function') return String(val(pageContext)) - return META.DEFAULT_TITLE + return i18n.global.t('meta.defaultTitle') } function getDescription(pageContext: PageContext) { const val = pageContext.config.description if (typeof val === 'string') return val if (typeof val === 'function') return val(pageContext) - return META.DEFAULT_DESCRIPTION + return i18n.global.t('meta.defaultDescription') } export { getTitle, getDescription } diff --git a/presenter/scripts/tests/mock.vikePageContext.ts b/presenter/scripts/tests/mock.vikePageContext.ts index c9592de8e0..b52d8932a8 100644 --- a/presenter/scripts/tests/mock.vikePageContext.ts +++ b/presenter/scripts/tests/mock.vikePageContext.ts @@ -9,5 +9,6 @@ config.global.provide = { routeParams: { code: 'my-code', }, + locale: 'de', }, } diff --git a/presenter/src/components/language/LanguageSelector.test.ts b/presenter/src/components/language/LanguageSelector.test.ts index 5f1ca52848..788865856f 100644 --- a/presenter/src/components/language/LanguageSelector.test.ts +++ b/presenter/src/components/language/LanguageSelector.test.ts @@ -1,6 +1,8 @@ import { mount } from '@vue/test-utils' import { describe, it, expect, beforeEach } from 'vitest' +import i18n from '#plugins/i18n' + import LanguageSelector from './LanguageSelector.vue' describe('LanguageSelector', () => { @@ -10,12 +12,24 @@ describe('LanguageSelector', () => { }) } let wrapper: ReturnType + let vSelect: ReturnType beforeEach(() => { wrapper = Wrapper() + vSelect = wrapper.findComponent({ name: 'v-select' }) }) it('renders', () => { expect(wrapper.element).toMatchSnapshot() }) + + describe('switch locale', () => { + beforeEach(async () => { + await vSelect.setValue('en') + }) + + it('to en', () => { + expect(i18n.global.locale.value).toBe('en') + }) + }) }) diff --git a/presenter/src/components/language/LanguageSelector.vue b/presenter/src/components/language/LanguageSelector.vue index 07fdbfb0cb..557aa671de 100644 --- a/presenter/src/components/language/LanguageSelector.vue +++ b/presenter/src/components/language/LanguageSelector.vue @@ -29,11 +29,9 @@