fix: i18n SSR

zio/stable
Anthony Fu 2022-12-28 02:28:17 +01:00
parent d09b4deb52
commit 970b6538e2
5 changed files with 24 additions and 23 deletions

View File

@ -1,13 +1,12 @@
<script setup lang="ts"> <script setup lang="ts">
setupI18n()
setupPageHeader() setupPageHeader()
setupEmojis() setupEmojis()
provideGlobalCommands() provideGlobalCommands()
await setupI18n()
// We want to trigger rerendering the page when account changes // We want to trigger rerendering the page when account changes
const key = computed(() => `${currentUser.value?.server ?? currentServer.value}:${currentUser.value?.account.id || ''}`) const key = computed(() => `${currentUser.value?.server ?? currentServer.value}:${currentUser.value?.account.id || ''}`)
const { params } = useRoute()
</script> </script>
<template> <template>

View File

@ -1,7 +1,7 @@
import { pwaInfo } from 'virtual:pwa-info' import { pwaInfo } from 'virtual:pwa-info'
import type { Link } from '@unhead/schema' import type { Link } from '@unhead/schema'
import type { Directions } from 'vue-i18n-routing' import type { Directions } from 'vue-i18n-routing'
import { APP_NAME, STORAGE_KEY_LANG } from '~/constants' import { APP_NAME, COOKIE_MAX_AGE, STORAGE_KEY_LANG } from '~/constants'
import type { LocaleObject } from '#i18n' import type { LocaleObject } from '#i18n'
export function setupPageHeader() { export function setupPageHeader() {
@ -49,28 +49,27 @@ export function setupPageHeader() {
export async function setupI18n() { export async function setupI18n() {
const { locale, setLocale, locales } = useI18n() const { locale, setLocale, locales } = useI18n()
const nuxtApp = useNuxtApp() const cookieLocale = useCookie(STORAGE_KEY_LANG, { maxAge: COOKIE_MAX_AGE })
nuxtApp.hook('app:suspense:resolve', async () => { const isFirstVisit = cookieLocale.value == null
const isFirstVisit = process.server ? false : !window.localStorage.getItem(STORAGE_KEY_LANG)
const localeStorage = process.server ? ref('en-US') : useLocalStorage(STORAGE_KEY_LANG, locale.value)
if (isFirstVisit) { if (process.client && isFirstVisit) {
const userLang = (navigator.language || 'en-US').toLowerCase() const userLang = (navigator.language || 'en-US').toLowerCase()
// cause vue-i18n not explicit export LocaleObject type // cause vue-i18n not explicit export LocaleObject type
const supportLocales = unref(locales) as { code: string }[] const supportLocales = unref(locales) as { code: string }[]
const lang = supportLocales.find(locale => userLang.startsWith(locale.code.toLowerCase()))?.code const lang = supportLocales.find(locale => userLang.startsWith(locale.code.toLowerCase()))?.code
|| supportLocales.find(locale => userLang.startsWith(locale.code.split('-')[0]))?.code || supportLocales.find(locale => userLang.startsWith(locale.code.split('-')[0]))?.code
localeStorage.value = lang || 'en-US' cookieLocale.value = lang || 'en-US'
} }
if (localeStorage.value !== locale.value) if (cookieLocale.value && cookieLocale.value !== locale.value)
await setLocale(localeStorage.value) await setLocale(cookieLocale.value)
if (process.client) {
watchEffect(() => { watchEffect(() => {
localeStorage.value = locale.value cookieLocale.value = locale.value
})
}) })
} }
}
export async function setupEmojis() { export async function setupEmojis() {
if (process.client) { if (process.client) {

View File

@ -19,7 +19,10 @@ export const STORAGE_KEY_HIDE_EXPLORE_TAGS_TIPS = 'elk-hide-explore-tags-tips'
export const STORAGE_KEY_NOTIFICATION = 'elk-notification' export const STORAGE_KEY_NOTIFICATION = 'elk-notification'
export const STORAGE_KEY_NOTIFICATION_POLICY = 'elk-notification-policy' export const STORAGE_KEY_NOTIFICATION_POLICY = 'elk-notification-policy'
export const COOKIE_MAX_AGE = 10 * 365 * 24 * 60 * 60 * 1000
export const COOKIE_KEY_FONT_SIZE = 'elk-font-size' export const COOKIE_KEY_FONT_SIZE = 'elk-font-size'
export const COOKIE_KEY_COLOR_MODE = 'elk-color-mode' export const COOKIE_KEY_COLOR_MODE = 'elk-color-mode'
export const COOKIE_KEY_LOCALE = 'elk-locale'
export const HANDLED_MASTO_URLS = /^(https?:\/\/)?([\w\d-]+\.)+\w+\/(@[@\w\d-\.]+)(\/objects)?(\/\d+)?$/ export const HANDLED_MASTO_URLS = /^(https?:\/\/)?([\w\d-]+\.)+\w+\/(@[@\w\d-\.]+)(\/objects)?(\/\d+)?$/

View File

@ -1,9 +1,9 @@
import type { ColorMode } from '~/types' import type { ColorMode } from '~/types'
import { InjectionKeyColorMode } from '~/constants/symbols' import { InjectionKeyColorMode } from '~/constants/symbols'
import { COOKIE_KEY_COLOR_MODE } from '~/constants' import { COOKIE_KEY_COLOR_MODE, COOKIE_MAX_AGE } from '~/constants'
export default defineNuxtPlugin((nuxt) => { export default defineNuxtPlugin((nuxt) => {
const cookieColorMode = useCookie<ColorMode | null>(COOKIE_KEY_COLOR_MODE, { default: () => null }) const cookieColorMode = useCookie<ColorMode | null>(COOKIE_KEY_COLOR_MODE, { maxAge: COOKIE_MAX_AGE })
const preferColorMode = process.server ? computed(() => 'light') : usePreferredColorScheme() const preferColorMode = process.server ? computed(() => 'light') : usePreferredColorScheme()
const colorMode = computed<ColorMode>({ const colorMode = computed<ColorMode>({

View File

@ -1,11 +1,11 @@
import type { FontSize } from '~/types' import type { FontSize } from '~/types'
import { InjectionKeyFontSize } from '~/constants/symbols' import { InjectionKeyFontSize } from '~/constants/symbols'
import { COOKIE_KEY_FONT_SIZE } from '~/constants' import { COOKIE_KEY_FONT_SIZE, COOKIE_MAX_AGE } from '~/constants'
import { fontSizeMap } from '~/constants/options' import { fontSizeMap } from '~/constants/options'
export default defineNuxtPlugin((nuxt) => { export default defineNuxtPlugin((nuxt) => {
const DEFAULT = 'md' const DEFAULT = 'md'
const cookieFontSize = useCookie<FontSize>(COOKIE_KEY_FONT_SIZE, { default: () => DEFAULT }) const cookieFontSize = useCookie<FontSize>(COOKIE_KEY_FONT_SIZE, { default: () => DEFAULT, maxAge: COOKIE_MAX_AGE })
nuxt.vueApp.provide(InjectionKeyFontSize, cookieFontSize) nuxt.vueApp.provide(InjectionKeyFontSize, cookieFontSize)
if (!process.server) { if (!process.server) {