Skip to content

Commit

Permalink
fix: take locale on hook, use custom dictionary
Browse files Browse the repository at this point in the history
  • Loading branch information
hmbanan666 committed Jun 21, 2024
1 parent 9176c53 commit ca8dd63
Show file tree
Hide file tree
Showing 64 changed files with 134 additions and 208 deletions.
4 changes: 2 additions & 2 deletions src/app.d.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
/// <reference types="@sveltejs/kit" />
import type { IProfile } from '$lib/types'
import type { IProfile, Locale } from '$lib/types'

declare global {
namespace App {
interface Locals {
profile: null | IProfile
lang: string
locale: Locale
}

// interface Error {}
Expand Down
36 changes: 33 additions & 3 deletions src/hooks.server.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,26 @@
import { type Handle, error } from '@sveltejs/kit'
import { type Handle, type RequestEvent, error, redirect } from '@sveltejs/kit'
import jwt from 'jsonwebtoken'
import { env as privateEnv } from '$env/dynamic/private'
import { env as publicEnv } from '$env/dynamic/public'
import type { IProfile } from '$lib/types'
import { type Locale, defaultLocale, supportedLocales } from '$lib/translations'

export const handle: Handle = async ({ event, resolve }) => {
handleJWT(event)
handleLang(event)

return resolve(event)
}

function handleJWT(event: RequestEvent) {
const cookieKey = publicEnv.PUBLIC_COOKIE_KEY
const jwtSecret = privateEnv.PRIVATE_JWT_SECRET_KEY

if (jwtSecret && cookieKey && event.cookies.get(cookieKey)) {
const token = event.cookies.get(cookieKey)
if (!token) {
event.locals.profile = null
return resolve(event)
return
}

try {
Expand All @@ -35,6 +43,28 @@ export const handle: Handle = async ({ event, resolve }) => {
}
}
}
}

return resolve(event)
function handleLang(event: RequestEvent) {
const { pathname, search } = new URL(event.request.url)

const pathLang = pathname.match(/[^/]+(?=\/|$)/)
const pathnameWithoutLang = pathLang ? pathname.replace(`/${pathLang}`, '') : pathname
const matchedLang = pathLang ? pathLang[0].toLowerCase() : null

// First time on website? Let's find locale
if (!matchedLang) {
const browserLocale = `${`${event.request.headers.get('accept-language')}`.match(/[a-z]+(?=[\-_,;])/i)}`.toLowerCase()
const locale = supportedLocales.find((locale) => locale === browserLocale) ? browserLocale : defaultLocale

event.locals.locale = locale as Locale
redirect(301, `/${locale}${pathnameWithoutLang}${search}`)
}

// We don't have this locale?
if (!supportedLocales.find((locale) => locale === matchedLang)) {
redirect(301, `/${defaultLocale}${pathnameWithoutLang}${search}`)
}

event.locals.locale = matchedLang as Locale
}
15 changes: 9 additions & 6 deletions src/lib/components/Header.svelte
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
<script>
import { t } from '$lib/translations'
<script lang='ts'>
import { page } from '$app/stores'
import unit from '$lib/assets/website/unit-64.png'
import Profile from '$lib/components/Profile.svelte'
import Locale from '$lib/components/Locale.svelte'
const locale = $page.data.locale
const t = $page.data.t
</script>

<header>
Expand All @@ -20,19 +22,20 @@
<nav>
<ul>
<li aria-current={$page.url.pathname === '/' ? 'page' : undefined}>
<a href='/'>{$t('header.menu.home')}</a>
<a href='/{locale}'>{t.header.menu.home}</a>
</li>
<li aria-current={$page.url.pathname === '/about' ? 'page' : undefined}>
<a href='/about'>{$t('header.menu.about')}</a>
<a href='/{locale}/about'>{t.header.menu.about}</a>
</li>
<li aria-current={$page.url.pathname === '/character' ? 'page' : undefined}>
<a href='/character'>{$t('header.menu.character')}</a>
<a href='/{locale}/character'>{t.header.menu.characters}</a>
</li>
</ul>
</nav>

<Locale />

<div class='right'>
<Locale />
<Profile />
</div>
</header>
Expand Down
29 changes: 17 additions & 12 deletions src/lib/components/Locale.svelte
Original file line number Diff line number Diff line change
@@ -1,19 +1,24 @@
<script lang='ts'>
import { locale, locales, t } from '$lib/translations'
import { page } from '$app/stores'
import { supportedLocales } from '$lib/translations'
type SelectEvent = Event & { currentTarget: EventTarget & HTMLInputElement }
const locale = $page.data.locale
let selected = locale
const handleChange = ({ currentTarget }: SelectEvent) => {
const handleChange = ({ currentTarget }: { currentTarget: HTMLSelectElement }) => {
const { value } = currentTarget
document.cookie = `lang=${value} ;`
window.location.href = `/${value}`
}
</script>

<div>
<select bind:value={$locale} on:change={() => handleChange}>
{#each $locales as value}
<option value={value} selected={$locale === value}>{$t(`lang.${value}`)}</option>
{/each}
</select>
</div>
<select bind:value={selected} onchange={handleChange}>
{#each supportedLocales as value}
<option value={value} selected={selected === value}>{value}</option>
{/each}
</select>

<style>
select {
margin: 0 2em;
}
</style>
20 changes: 20 additions & 0 deletions src/lib/translations/en.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
export type Dictionary = typeof en

export const en = {
about: undefined,
character: undefined,
error: {
404: 'Page not found.',
500: 'Server internal error.',
title: 'Oh, dear...',
default: 'Here we go... Or is that a feature?',
},
header: {
menu: {
home: 'Home',
about: 'About',
characters: 'Characters',
},
},
home: undefined,
}
3 changes: 0 additions & 3 deletions src/lib/translations/en/about.json

This file was deleted.

3 changes: 0 additions & 3 deletions src/lib/translations/en/character.json

This file was deleted.

6 changes: 0 additions & 6 deletions src/lib/translations/en/error.json

This file was deleted.

7 changes: 0 additions & 7 deletions src/lib/translations/en/header.json

This file was deleted.

3 changes: 0 additions & 3 deletions src/lib/translations/en/home.json

This file was deleted.

95 changes: 12 additions & 83 deletions src/lib/translations/index.ts
Original file line number Diff line number Diff line change
@@ -1,88 +1,17 @@
import I18n from 'sveltekit-i18n'
import type { Config } from 'sveltekit-i18n'
import lang from './lang.json'
import { dev } from '$app/environment'
import { ru } from '$lib/translations/ru'
import { type Dictionary, en } from '$lib/translations/en'

export type Locale = 'en' | 'ru'

export const defaultLocale = 'en'

export const config: Config = {
log: {
level: dev ? 'warn' : 'error',
},
translations: {
en: { lang },
ru: { lang },
},
loaders: [
{
locale: 'en',
key: 'header',
loader: async () => (await import('./en/header.json')).default,
},
{
locale: 'en',
key: 'error',
loader: async () => (await import('./en/error.json')).default,
},
{
locale: 'en',
key: 'home',
routes: ['/'],
loader: async () => (await import('./en/home.json')).default,
},
{
locale: 'en',
key: 'about',
routes: ['/about'],
loader: async () => (await import('./en/about.json')).default,
},
{
locale: 'en',
key: 'character',
routes: ['/character'],
loader: async () => (await import('./en/character.json')).default,
},
{
locale: 'ru',
key: 'header',
loader: async () => (await import('./ru/header.json')).default,
},
{
locale: 'ru',
key: 'error',
loader: async () => (await import('./ru/error.json')).default,
},
{
locale: 'ru',
key: 'home',
routes: ['/'],
loader: async () => (await import('./ru/home.json')).default,
},
{
locale: 'ru',
key: 'about',
routes: ['/about'],
loader: async () => (await import('./ru/about.json')).default,
},
{
locale: 'ru',
key: 'character',
routes: ['/character'],
loader: async () => (await import('./ru/character.json')).default,
},
],
}
export const supportedLocales = ['en', 'ru'] as Locale[]

export const {
t,
locale,
locales,
loading,
addTranslations,
loadTranslations,
translations,
setRoute,
setLocale,
} = new I18n(config)
const translations = {
en,
ru,
}

loading.subscribe(($loading) => $loading && console.log('Loading translations...'))
export function dictionary(locale: Locale): Dictionary {
return translations[locale]
}
4 changes: 0 additions & 4 deletions src/lib/translations/lang.json

This file was deleted.

20 changes: 20 additions & 0 deletions src/lib/translations/ru.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import type { Dictionary } from '$lib/translations/en'

export const ru = {
about: undefined,
character: undefined,
error: {
404: 'Страница не найдена.',
500: 'Произошла ошибка на сервере.',
title: 'О, Боже...',
default: 'Ну вот... Или это фича?',
},
header: {
menu: {
home: 'Главная',
about: 'Об игре',
characters: 'Персонажи',
},
},
home: undefined,
} satisfies Dictionary
3 changes: 0 additions & 3 deletions src/lib/translations/ru/about.json

This file was deleted.

3 changes: 0 additions & 3 deletions src/lib/translations/ru/character.json

This file was deleted.

6 changes: 0 additions & 6 deletions src/lib/translations/ru/error.json

This file was deleted.

7 changes: 0 additions & 7 deletions src/lib/translations/ru/header.json

This file was deleted.

3 changes: 0 additions & 3 deletions src/lib/translations/ru/home.json

This file was deleted.

15 changes: 0 additions & 15 deletions src/routes/(website)/+error.svelte

This file was deleted.

26 changes: 0 additions & 26 deletions src/routes/(website)/+layout.server.ts

This file was deleted.

Loading

0 comments on commit ca8dd63

Please sign in to comment.