From 38a07e3dfbda798010cc7f219abec911f747eaf7 Mon Sep 17 00:00:00 2001 From: ivarlovlie Date: Mon, 3 Oct 2022 16:45:26 +0800 Subject: feat: Fully functioning i18n --- apps/kit/src/global.d.ts | 13 ++++++ apps/kit/src/hooks.server.ts | 47 +++++++++++++++++++ apps/kit/src/hooks/index.server.ts | 52 ---------------------- apps/kit/src/lib/components/locale-switcher.svelte | 15 ++++--- apps/kit/src/routes/(main)/+layout.server.ts | 15 ++++++- apps/kit/src/routes/(main)/+layout.svelte | 23 ++++------ apps/kit/src/routes/(main)/+layout.ts | 22 +++++---- 7 files changed, 105 insertions(+), 82 deletions(-) create mode 100644 apps/kit/src/global.d.ts create mode 100644 apps/kit/src/hooks.server.ts delete mode 100644 apps/kit/src/hooks/index.server.ts (limited to 'apps/kit/src') diff --git a/apps/kit/src/global.d.ts b/apps/kit/src/global.d.ts new file mode 100644 index 0000000..e49922a --- /dev/null +++ b/apps/kit/src/global.d.ts @@ -0,0 +1,13 @@ +/// + +type Locales = import('$i18n/i18n-types').Locales +type TranslationFunctions = import('$i18n/i18n-types').TranslationFunctions + +declare namespace App { + interface Locals { + locale: Locales + LL: TranslationFunctions + } + + // interface Platform { } +} \ No newline at end of file diff --git a/apps/kit/src/hooks.server.ts b/apps/kit/src/hooks.server.ts new file mode 100644 index 0000000..0f6e0c0 --- /dev/null +++ b/apps/kit/src/hooks.server.ts @@ -0,0 +1,47 @@ +import { CookieNames } from "$lib/configuration"; +import { detectLocale, i18n, isLocale, locales } from '$lib/i18n/i18n-util' +import type { Handle, RequestEvent } from '@sveltejs/kit' +import { initAcceptLanguageHeaderDetector } from 'typesafe-i18n/detectors' +import { parse, serialize } from "cookie"; +import type { Locales } from "$lib/i18n/i18n-types"; +import { loadAllLocales } from "$lib/i18n/i18n-util.sync"; + + +loadAllLocales() +const L = i18n() + +export const handle: Handle = async ({ event, resolve }) => { + const cookies = parse(event.request.headers.get("Cookie") ?? ''); + const localeCookie = cookies[CookieNames.locale]; + const preferredLocale = getPreferredLocale(event); + let finalLocale = localeCookie ?? preferredLocale; + + console.log("Handling locale", { + locales, + localeCookie, + preferredLocale, + finalLocale + }); + + if (!isLocale(finalLocale)) finalLocale = "en"; + if (!localeCookie) { + // Set a locale cookie + event.setHeaders({ + "Set-Cookie": serialize(CookieNames.locale, finalLocale, { + path: "/", + expires: new Date(2099, 1, 1, 0, 0, 0, 0), + sameSite: "strict" + }) + }); + } + + event.locals.locale = finalLocale as Locales; + event.locals.LL = L[finalLocale as Locales]; + + return resolve(event, { transformPageChunk: ({ html }) => html.replace('%lang%', finalLocale) }); +} + +function getPreferredLocale(event: RequestEvent) { + const acceptLanguageDetector = initAcceptLanguageHeaderDetector(event.request); + return detectLocale(acceptLanguageDetector); +} diff --git a/apps/kit/src/hooks/index.server.ts b/apps/kit/src/hooks/index.server.ts deleted file mode 100644 index 414318d..0000000 --- a/apps/kit/src/hooks/index.server.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { CookieNames } from "$lib/configuration"; -import { detectLocale, locales } from '$lib/i18n/i18n-util' -import type { Handle, RequestEvent } from '@sveltejs/kit' -import { sequence } from "@sveltejs/kit/hooks"; -import { initAcceptLanguageHeaderDetector } from 'typesafe-i18n/detectors' -import { parse, serialize } from "cookie"; -import { logDebug } from "$lib/logger"; - -const handleLocale: Handle = async ({ event, resolve }) => { - const cookies = parse(event.request.headers.get("Cookie") ?? ''); - const localeCookie = cookies[CookieNames.locale]; - const preferredLocale = getPreferredLocale(event); - let finalLocale = localeCookie ?? preferredLocale; - - logDebug("Handling locale", { - locales, - localeCookie, - preferredLocale, - finalLocale - }); - - if (locales.findIndex((locale) => locale === finalLocale) === -1) finalLocale = "en"; - if (!localeCookie) { - // Set a locale cookie - event.setHeaders({ - "Set-Cookie": serialize(CookieNames.locale, finalLocale, { - path: "/", - expires: new Date(2099, 1, 1, 0, 0, 0, 0), - sameSite: "strict" - }) - }); - } - // replace html lang attribute with correct language - return resolve(event, { transformPageChunk: ({ html }) => html.replace('%lang%', finalLocale) }); -} - -function getPreferredLocale(event: RequestEvent) { - // detect the preferred language the user has configured in it's browser - // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Language - const headers = transformHeaders(event) - const acceptLanguageDetector = initAcceptLanguageHeaderDetector({ headers }) - - return detectLocale(acceptLanguageDetector) -} - -function transformHeaders({ request }: RequestEvent) { - const headers: Record = {} - request.headers.forEach((value, key) => (headers[key] = value)) - return headers -} - -export const handle = sequence(handleLocale); diff --git a/apps/kit/src/lib/components/locale-switcher.svelte b/apps/kit/src/lib/components/locale-switcher.svelte index 1f9eb37..477e2d7 100644 --- a/apps/kit/src/lib/components/locale-switcher.svelte +++ b/apps/kit/src/lib/components/locale-switcher.svelte @@ -1,16 +1,25 @@ + {#if !online} -
+
- +

You seem to be offline, please check your internet connection.

@@ -34,4 +25,6 @@
{/if} + + diff --git a/apps/kit/src/routes/(main)/+layout.ts b/apps/kit/src/routes/(main)/+layout.ts index 13837be..5d0e005 100644 --- a/apps/kit/src/routes/(main)/+layout.ts +++ b/apps/kit/src/routes/(main)/+layout.ts @@ -1,9 +1,15 @@ -import type { Locales } from "$lib/i18n/i18n-types"; -import { loadLocaleAsync } from "$lib/i18n/i18n-util.async"; -import type { LayoutLoad } from "./$types"; +import type { LayoutLoad } from './$types' +import type { Locales } from '$lib/i18n/i18n-types' +import { loadLocaleAsync } from '$lib/i18n/i18n-util.async' +import { setLocale } from '$lib/i18n/i18n-svelte' -export const load: LayoutLoad<{ locale: Locales }> = async ({ url, params }) => { - let lang = "en" as Locales; - await loadLocaleAsync(lang); - return { locale: lang }; -}; +export const load: LayoutLoad<{ locale: Locales }> = async ({ data: { locale } }) => { + // load dictionary into memory + await loadLocaleAsync(locale) + + // if you need to output a localized string in a `load` function, + // you always need to call `setLocale` right before you access the `LL` store + setLocale(locale) + // pass locale to the "rendering context" + return { locale } +} \ No newline at end of file -- cgit v1.3