Skip to content

Commit

Permalink
Merge pull request #335 from dreammall-earth/208-feature-implement-pa…
Browse files Browse the repository at this point in the history
…ge-title-translation-and-vike-language

feat(presenter): make i18n locale extractable from url
  • Loading branch information
Elweyn authored Mar 26, 2024
2 parents 1788f26 + a80a6ed commit d89cb76
Show file tree
Hide file tree
Showing 11 changed files with 105 additions and 9 deletions.
2 changes: 1 addition & 1 deletion presenter/renderer/+config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
16 changes: 16 additions & 0 deletions presenter/renderer/+onBeforeRoute.ts
Original file line number Diff line number Diff line change
@@ -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,
},
}
}
32 changes: 32 additions & 0 deletions presenter/renderer/+onPrerenderStart.ts
Original file line number Diff line number Diff line change
@@ -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,
},
}
}
7 changes: 7 additions & 0 deletions presenter/renderer/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'

Expand All @@ -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() {
Expand Down Expand Up @@ -64,13 +66,18 @@ 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 || {})
},
})

const pageContextReactive = reactive(pageContext)

setPageContext(app, pageContextReactive)

if (pageContext.locale && locales.includes(pageContext.locale)) {
i18n.global.locale.value = pageContext.locale
}

return { app, i18n }
}

Expand Down
5 changes: 3 additions & 2 deletions presenter/renderer/plugins/i18n.ts
Original file line number Diff line number Diff line change
@@ -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,
Expand Down
1 change: 1 addition & 0 deletions presenter/scripts/tests/mock.vikePageContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@ config.global.provide = {
routeParams: {
code: 'my-code',
},
locale: 'de',
},
}
14 changes: 14 additions & 0 deletions presenter/src/components/language/LanguageSelector.test.ts
Original file line number Diff line number Diff line change
@@ -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', () => {
Expand All @@ -10,12 +12,24 @@ describe('LanguageSelector', () => {
})
}
let wrapper: ReturnType<typeof Wrapper>
let vSelect: ReturnType<typeof wrapper.findComponent>

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')
})
})
})
8 changes: 3 additions & 5 deletions presenter/src/components/language/LanguageSelector.vue
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,9 @@
<script lang="ts" setup>
import { ref } from 'vue'
// TODO better place? maybe locales folder?
const languages = ref([
{ locale: 'de', title: 'Deutsch' },
{ locale: 'en', title: 'English' },
])
import { localizedLocale } from '#src/locales'
const languages = ref(localizedLocale)
</script>

<style lang="scss">
Expand Down
25 changes: 25 additions & 0 deletions presenter/src/locales/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
export type LocaleCode = 'de' | 'en'
export const locales: LocaleCode[] = ['de', 'en']
export const localeDefault = 'de'
export const fallbackLocale = 'en'
export const localizedLocale = [
{ locale: 'de', title: 'Deutsch' },
{ locale: 'en', title: 'English' },
]

export function extractLocale(url: string) {
const urlPaths = url.split('/')
let locale: LocaleCode
let urlWithoutLocale
// We remove the URL locale, for example `/de/about` => `/about`
const firstPath = urlPaths[1] as LocaleCode
if (locales.includes(firstPath)) {
locale = firstPath
urlWithoutLocale = '/' + urlPaths.slice(2).join('/')
} else {
locale = localeDefault
urlWithoutLocale = url
}

return { locale, urlWithoutLocale }
}
2 changes: 2 additions & 0 deletions presenter/types/PageContext.d.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { LocaleCode } from '#src/locales'
import { Page } from '#types/Page'
import { PageProps } from '#types/PageProps'

Expand All @@ -11,6 +12,7 @@ declare global {
}
Page: Page
pageProps?: PageProps
locale?: LocaleCode
}
}
}
2 changes: 1 addition & 1 deletion presenter/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const config: UserConfig = {
!isStorybook() && vike({ prerender: true }), // SSR only when storybook is not running
vueI18n({
ssr: true,
include: path.resolve(__dirname, './src/locales/**'),
include: path.resolve(__dirname, './src/locales/**.json'),
jitCompilation: false,
}),
checker({
Expand Down

0 comments on commit d89cb76

Please sign in to comment.