Adjust in i18n
This commit is contained in:
parent
c573d8c2c6
commit
f1bdb9bf98
18 changed files with 126 additions and 75 deletions
21
.gitignore
vendored
21
.gitignore
vendored
|
@ -23,3 +23,24 @@ dist-ssr
|
||||||
*.sln
|
*.sln
|
||||||
*.sw?
|
*.sw?
|
||||||
/.vscode
|
/.vscode
|
||||||
|
.DS_Store
|
||||||
|
node_modules
|
||||||
|
dist
|
||||||
|
test-results/
|
||||||
|
package-lock.json
|
||||||
|
yarn.lock
|
||||||
|
vite.config.js.timestamp-*
|
||||||
|
/packages/create-svelte/template/CHANGELOG.md
|
||||||
|
/packages/package/test/**/package
|
||||||
|
/documentation/types.js
|
||||||
|
.env
|
||||||
|
.vercel_build_output
|
||||||
|
.svelte-kit
|
||||||
|
.cloudflare
|
||||||
|
.pnpm-debug.log
|
||||||
|
.netlify
|
||||||
|
.turbo
|
||||||
|
.vercel
|
||||||
|
.test-tmp
|
||||||
|
symlink-from
|
||||||
|
.idea/
|
||||||
|
|
|
@ -9,7 +9,7 @@ export const nodes = [
|
||||||
() => import('./nodes/5')
|
() => import('./nodes/5')
|
||||||
];
|
];
|
||||||
|
|
||||||
export const server_loads = [];
|
export const server_loads = [0];
|
||||||
|
|
||||||
export const dictionary = {
|
export const dictionary = {
|
||||||
"/": [2],
|
"/": [2],
|
||||||
|
|
|
@ -1,3 +1 @@
|
||||||
import * as universal from "../../../../src/routes/+layout.js";
|
|
||||||
export { universal };
|
|
||||||
export { default as component } from "../../../../src/routes/+layout.svelte";
|
export { default as component } from "../../../../src/routes/+layout.svelte";
|
|
@ -21,7 +21,7 @@ export const options = {
|
||||||
app: ({ head, body, assets, nonce, env }) => "<!doctype html>\n<html lang=\"en\">\n <head>\n <style>\n :root {\n font-family: Inter, Avenir, Helvetica, Arial, sans-serif;\n font-size: 16px;\n line-height: 24px;\n font-weight: 400;\n font-synthesis: none;\n text-rendering: optimizeLegibility;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n -webkit-text-size-adjust: 100%;\n }\n\n * {\n box-sizing: border-box;\n }\n\n body {\n display: flex;\n justify-content: center;\n flex-direction: column;\n margin: 0;\n width: 100%;\n height: 100%;\n }\n\n #app {\n display: flex;\n flex-direction: column;\n align-items: center;\n width: 100%;\n background-color: #f2f6f5;\n z-index: 10;\n }\n\n input[type='submit'] {\n width: 100%;\n font-size: 20px;\n margin-top: 20px;\n background-color: #05345f;\n font-weight: 700;\n color: white;\n padding: 10px;\n -webkit-appearance: none;\n border-radius: 0;\n }\n\n input[type='submit']:hover {\n cursor: pointer;\n background-color: black;\n color: white;\n }\n\n body a {\n text-decoration: none;\n color: #06345f;\n border-bottom: 3px solid #06345f;\n }\n\n body a:hover {\n background-color: #06345f;\n color: #ffffff;\n }\n\n :is(h1, h2, h3, h4, h5, h6) {\n color: #06345f;\n }\n\n strong {\n color: #06345f;\n }\n\n ul li::marker {\n color: #06345f;\n }\n </style>\n <meta charset=\"utf-8\" />\n <link rel=\"icon\" href=\"" + assets + "/favicon.png\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n " + head + "\n </head>\n <body data-sveltekit-preload-data=\"hover\">\n <div style=\"display: contents\">" + body + "</div>\n </body>\n</html>\n",
|
app: ({ head, body, assets, nonce, env }) => "<!doctype html>\n<html lang=\"en\">\n <head>\n <style>\n :root {\n font-family: Inter, Avenir, Helvetica, Arial, sans-serif;\n font-size: 16px;\n line-height: 24px;\n font-weight: 400;\n font-synthesis: none;\n text-rendering: optimizeLegibility;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n -webkit-text-size-adjust: 100%;\n }\n\n * {\n box-sizing: border-box;\n }\n\n body {\n display: flex;\n justify-content: center;\n flex-direction: column;\n margin: 0;\n width: 100%;\n height: 100%;\n }\n\n #app {\n display: flex;\n flex-direction: column;\n align-items: center;\n width: 100%;\n background-color: #f2f6f5;\n z-index: 10;\n }\n\n input[type='submit'] {\n width: 100%;\n font-size: 20px;\n margin-top: 20px;\n background-color: #05345f;\n font-weight: 700;\n color: white;\n padding: 10px;\n -webkit-appearance: none;\n border-radius: 0;\n }\n\n input[type='submit']:hover {\n cursor: pointer;\n background-color: black;\n color: white;\n }\n\n body a {\n text-decoration: none;\n color: #06345f;\n border-bottom: 3px solid #06345f;\n }\n\n body a:hover {\n background-color: #06345f;\n color: #ffffff;\n }\n\n :is(h1, h2, h3, h4, h5, h6) {\n color: #06345f;\n }\n\n strong {\n color: #06345f;\n }\n\n ul li::marker {\n color: #06345f;\n }\n </style>\n <meta charset=\"utf-8\" />\n <link rel=\"icon\" href=\"" + assets + "/favicon.png\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n " + head + "\n </head>\n <body data-sveltekit-preload-data=\"hover\">\n <div style=\"display: contents\">" + body + "</div>\n </body>\n</html>\n",
|
||||||
error: ({ status, message }) => "<!doctype html>\n<html lang=\"en\">\n\t<head>\n\t\t<meta charset=\"utf-8\" />\n\t\t<title>" + message + "</title>\n\n\t\t<style>\n\t\t\tbody {\n\t\t\t\t--bg: white;\n\t\t\t\t--fg: #222;\n\t\t\t\t--divider: #ccc;\n\t\t\t\tbackground: var(--bg);\n\t\t\t\tcolor: var(--fg);\n\t\t\t\tfont-family:\n\t\t\t\t\tsystem-ui,\n\t\t\t\t\t-apple-system,\n\t\t\t\t\tBlinkMacSystemFont,\n\t\t\t\t\t'Segoe UI',\n\t\t\t\t\tRoboto,\n\t\t\t\t\tOxygen,\n\t\t\t\t\tUbuntu,\n\t\t\t\t\tCantarell,\n\t\t\t\t\t'Open Sans',\n\t\t\t\t\t'Helvetica Neue',\n\t\t\t\t\tsans-serif;\n\t\t\t\tdisplay: flex;\n\t\t\t\talign-items: center;\n\t\t\t\tjustify-content: center;\n\t\t\t\theight: 100vh;\n\t\t\t\tmargin: 0;\n\t\t\t}\n\n\t\t\t.error {\n\t\t\t\tdisplay: flex;\n\t\t\t\talign-items: center;\n\t\t\t\tmax-width: 32rem;\n\t\t\t\tmargin: 0 1rem;\n\t\t\t}\n\n\t\t\t.status {\n\t\t\t\tfont-weight: 200;\n\t\t\t\tfont-size: 3rem;\n\t\t\t\tline-height: 1;\n\t\t\t\tposition: relative;\n\t\t\t\ttop: -0.05rem;\n\t\t\t}\n\n\t\t\t.message {\n\t\t\t\tborder-left: 1px solid var(--divider);\n\t\t\t\tpadding: 0 0 0 1rem;\n\t\t\t\tmargin: 0 0 0 1rem;\n\t\t\t\tmin-height: 2.5rem;\n\t\t\t\tdisplay: flex;\n\t\t\t\talign-items: center;\n\t\t\t}\n\n\t\t\t.message h1 {\n\t\t\t\tfont-weight: 400;\n\t\t\t\tfont-size: 1em;\n\t\t\t\tmargin: 0;\n\t\t\t}\n\n\t\t\t@media (prefers-color-scheme: dark) {\n\t\t\t\tbody {\n\t\t\t\t\t--bg: #222;\n\t\t\t\t\t--fg: #ddd;\n\t\t\t\t\t--divider: #666;\n\t\t\t\t}\n\t\t\t}\n\t\t</style>\n\t</head>\n\t<body>\n\t\t<div class=\"error\">\n\t\t\t<span class=\"status\">" + status + "</span>\n\t\t\t<div class=\"message\">\n\t\t\t\t<h1>" + message + "</h1>\n\t\t\t</div>\n\t\t</div>\n\t</body>\n</html>\n"
|
error: ({ status, message }) => "<!doctype html>\n<html lang=\"en\">\n\t<head>\n\t\t<meta charset=\"utf-8\" />\n\t\t<title>" + message + "</title>\n\n\t\t<style>\n\t\t\tbody {\n\t\t\t\t--bg: white;\n\t\t\t\t--fg: #222;\n\t\t\t\t--divider: #ccc;\n\t\t\t\tbackground: var(--bg);\n\t\t\t\tcolor: var(--fg);\n\t\t\t\tfont-family:\n\t\t\t\t\tsystem-ui,\n\t\t\t\t\t-apple-system,\n\t\t\t\t\tBlinkMacSystemFont,\n\t\t\t\t\t'Segoe UI',\n\t\t\t\t\tRoboto,\n\t\t\t\t\tOxygen,\n\t\t\t\t\tUbuntu,\n\t\t\t\t\tCantarell,\n\t\t\t\t\t'Open Sans',\n\t\t\t\t\t'Helvetica Neue',\n\t\t\t\t\tsans-serif;\n\t\t\t\tdisplay: flex;\n\t\t\t\talign-items: center;\n\t\t\t\tjustify-content: center;\n\t\t\t\theight: 100vh;\n\t\t\t\tmargin: 0;\n\t\t\t}\n\n\t\t\t.error {\n\t\t\t\tdisplay: flex;\n\t\t\t\talign-items: center;\n\t\t\t\tmax-width: 32rem;\n\t\t\t\tmargin: 0 1rem;\n\t\t\t}\n\n\t\t\t.status {\n\t\t\t\tfont-weight: 200;\n\t\t\t\tfont-size: 3rem;\n\t\t\t\tline-height: 1;\n\t\t\t\tposition: relative;\n\t\t\t\ttop: -0.05rem;\n\t\t\t}\n\n\t\t\t.message {\n\t\t\t\tborder-left: 1px solid var(--divider);\n\t\t\t\tpadding: 0 0 0 1rem;\n\t\t\t\tmargin: 0 0 0 1rem;\n\t\t\t\tmin-height: 2.5rem;\n\t\t\t\tdisplay: flex;\n\t\t\t\talign-items: center;\n\t\t\t}\n\n\t\t\t.message h1 {\n\t\t\t\tfont-weight: 400;\n\t\t\t\tfont-size: 1em;\n\t\t\t\tmargin: 0;\n\t\t\t}\n\n\t\t\t@media (prefers-color-scheme: dark) {\n\t\t\t\tbody {\n\t\t\t\t\t--bg: #222;\n\t\t\t\t\t--fg: #ddd;\n\t\t\t\t\t--divider: #666;\n\t\t\t\t}\n\t\t\t}\n\t\t</style>\n\t</head>\n\t<body>\n\t\t<div class=\"error\">\n\t\t\t<span class=\"status\">" + status + "</span>\n\t\t\t<div class=\"message\">\n\t\t\t\t<h1>" + message + "</h1>\n\t\t\t</div>\n\t\t</div>\n\t</body>\n</html>\n"
|
||||||
},
|
},
|
||||||
version_hash: "lnkeyd"
|
version_hash: "1f4q059"
|
||||||
};
|
};
|
||||||
|
|
||||||
export async function get_hooks() {
|
export async function get_hooks() {
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
{
|
{
|
||||||
"/": [
|
"/": [
|
||||||
"src/routes/+layout.js",
|
"src/routes/+layout.server.js",
|
||||||
"src/routes/+layout.js"
|
"src/routes/+layout.server.js"
|
||||||
],
|
],
|
||||||
"/about": [
|
"/about": [
|
||||||
"src/routes/+layout.js"
|
"src/routes/+layout.server.js"
|
||||||
],
|
],
|
||||||
"/donate": [
|
"/donate": [
|
||||||
"src/routes/+layout.js"
|
"src/routes/+layout.server.js"
|
||||||
],
|
],
|
||||||
"/viewer": [
|
"/viewer": [
|
||||||
"src/routes/+layout.js"
|
"src/routes/+layout.server.js"
|
||||||
]
|
]
|
||||||
}
|
}
|
10
.svelte-kit/types/src/routes/$types.d.ts
vendored
10
.svelte-kit/types/src/routes/$types.d.ts
vendored
|
@ -14,13 +14,15 @@ export type Snapshot<T = any> = Kit.Snapshot<T>;
|
||||||
type PageParentData = EnsureDefined<LayoutData>;
|
type PageParentData = EnsureDefined<LayoutData>;
|
||||||
type LayoutRouteId = RouteId | "/" | "/about" | "/donate" | "/viewer" | null
|
type LayoutRouteId = RouteId | "/" | "/about" | "/donate" | "/viewer" | null
|
||||||
type LayoutParams = RouteParams & { }
|
type LayoutParams = RouteParams & { }
|
||||||
|
type LayoutServerParentData = EnsureDefined<{}>;
|
||||||
type LayoutParentData = EnsureDefined<{}>;
|
type LayoutParentData = EnsureDefined<{}>;
|
||||||
|
|
||||||
export type PageServerData = null;
|
export type PageServerData = null;
|
||||||
export type PageData = Expand<PageParentData>;
|
export type PageData = Expand<PageParentData>;
|
||||||
export type PageProps = { data: PageData }
|
export type PageProps = { data: PageData }
|
||||||
export type LayoutServerData = null;
|
export type LayoutServerLoad<OutputData extends OutputDataShape<LayoutServerParentData> = OutputDataShape<LayoutServerParentData>> = Kit.ServerLoad<LayoutParams, LayoutServerParentData, OutputData, LayoutRouteId>;
|
||||||
export type LayoutLoad<OutputData extends OutputDataShape<LayoutParentData> = OutputDataShape<LayoutParentData>> = Kit.Load<LayoutParams, LayoutServerData, LayoutParentData, OutputData, LayoutRouteId>;
|
export type LayoutServerLoadEvent = Parameters<LayoutServerLoad>[0];
|
||||||
export type LayoutLoadEvent = Parameters<LayoutLoad>[0];
|
export type LayoutServerData = Expand<OptionalUnion<EnsureDefined<Kit.LoadProperties<Awaited<ReturnType<typeof import('./proxy+layout.server.js').load>>>>>>;
|
||||||
export type LayoutData = Expand<Omit<LayoutParentData, keyof Kit.LoadProperties<Awaited<ReturnType<typeof import('./proxy+layout.js').load>>>> & OptionalUnion<EnsureDefined<Kit.LoadProperties<Awaited<ReturnType<typeof import('./proxy+layout.js').load>>>>>>;
|
export type LayoutData = Expand<Omit<LayoutParentData, keyof LayoutServerData> & EnsureDefined<LayoutServerData>>;
|
||||||
export type LayoutProps = { data: LayoutData; children: import("svelte").Snippet }
|
export type LayoutProps = { data: LayoutData; children: import("svelte").Snippet }
|
||||||
|
export type RequestEvent = Kit.RequestEvent<RouteParams, RouteId>;
|
|
@ -1,17 +0,0 @@
|
||||||
// @ts-nocheck
|
|
||||||
import { loadTranslations } from '$lib/translations';
|
|
||||||
|
|
||||||
/** */
|
|
||||||
export const load = async () => {
|
|
||||||
const initLocale = primaryLanguage(navigator.language) || 'en';
|
|
||||||
|
|
||||||
// TODO: Fix the undefined location issue
|
|
||||||
await loadTranslations(initLocale);
|
|
||||||
|
|
||||||
return {};
|
|
||||||
};
|
|
||||||
|
|
||||||
const primaryLanguage = (/** @type {string} */ locale) => {
|
|
||||||
if (!locale) return '';
|
|
||||||
return locale.split('-')[0];
|
|
||||||
};
|
|
7
package-lock.json
generated
7
package-lock.json
generated
|
@ -8,6 +8,7 @@
|
||||||
"name": "embroidery-viewer",
|
"name": "embroidery-viewer",
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"accept-language-parser": "^1.5.0",
|
||||||
"sveltekit-i18n": "^2.4.2"
|
"sveltekit-i18n": "^2.4.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
@ -1165,6 +1166,12 @@
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/accept-language-parser": {
|
||||||
|
"version": "1.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/accept-language-parser/-/accept-language-parser-1.5.0.tgz",
|
||||||
|
"integrity": "sha512-QhyTbMLYo0BBGg1aWbeMG4ekWtds/31BrEU+DONOg/7ax23vxpL03Pb7/zBmha2v7vdD3AyzZVWBVGEZxKOXWw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/acorn": {
|
"node_modules/acorn": {
|
||||||
"version": "8.14.1",
|
"version": "8.14.1",
|
||||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz",
|
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz",
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
"vite": "^6.2.6"
|
"vite": "^6.2.6"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"accept-language-parser": "^1.5.0",
|
||||||
"sveltekit-i18n": "^2.4.2"
|
"sveltekit-i18n": "^2.4.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<script>
|
<script>
|
||||||
import { t, locale, locales } from '$lib/translations';
|
import { t, locale, locales, SUPPORTED_LOCALES } from '$lib/translations';
|
||||||
import logo from '$lib/assets/logo.webp';
|
import logo from '$lib/assets/logo.webp';
|
||||||
import MediaQuery from './MediaQuery.svelte';
|
import MediaQuery from './MediaQuery.svelte';
|
||||||
|
|
||||||
|
@ -10,7 +10,10 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
const onSwitchToOppositeLang = () => {
|
const onSwitchToOppositeLang = () => {
|
||||||
$locale = $locale === 'en' ? 'pt' : 'en';
|
$locale =
|
||||||
|
$locale === SUPPORTED_LOCALES.EN_US
|
||||||
|
? SUPPORTED_LOCALES.PT_BR
|
||||||
|
: SUPPORTED_LOCALES.EN_US;
|
||||||
};
|
};
|
||||||
|
|
||||||
let isMenuOpen = false;
|
let isMenuOpen = false;
|
||||||
|
@ -59,7 +62,7 @@
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<a
|
<a
|
||||||
class="common-switch {$locale === 'en'
|
class="common-switch {$locale === SUPPORTED_LOCALES.EN_US
|
||||||
? 'portuguese-switch'
|
? 'portuguese-switch'
|
||||||
: 'english-switch'}"
|
: 'english-switch'}"
|
||||||
href="#"
|
href="#"
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
// place files you want to import through the `$lib` alias in this folder.
|
|
|
@ -1,22 +1,33 @@
|
||||||
import i18n from 'sveltekit-i18n';
|
import i18n from 'sveltekit-i18n';
|
||||||
import lang from './lang.json';
|
|
||||||
|
/**
|
||||||
|
* A frozen object mapping locale identifiers to their respective locale codes.
|
||||||
|
*
|
||||||
|
* These values represent the supported languages in the application.
|
||||||
|
* Used for validating user preferences and loading the correct translations.
|
||||||
|
*
|
||||||
|
* @readonly
|
||||||
|
* @enum {string}
|
||||||
|
*/
|
||||||
|
export const SUPPORTED_LOCALES = Object.freeze({
|
||||||
|
EN_US: 'en-US',
|
||||||
|
PT_BR: 'pt-BR',
|
||||||
|
});
|
||||||
|
|
||||||
/** @type {import('sveltekit-i18n').Config} */
|
/** @type {import('sveltekit-i18n').Config} */
|
||||||
const config = {
|
const config = {
|
||||||
translations: {
|
initLocale: navigator.language,
|
||||||
en: { lang },
|
fallbackLocale: SUPPORTED_LOCALES.PT_BR,
|
||||||
pt: { lang },
|
|
||||||
},
|
|
||||||
loaders: [
|
loaders: [
|
||||||
{
|
{
|
||||||
locale: 'en',
|
locale: SUPPORTED_LOCALES.EN_US,
|
||||||
key: 'header',
|
key: 'header',
|
||||||
loader: async () => (await import('./en/header.json')).default,
|
loader: async () => (await import('./en-US/header.json')).default,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
locale: 'pt',
|
locale: SUPPORTED_LOCALES.PT_BR,
|
||||||
key: 'header',
|
key: 'header',
|
||||||
loader: async () => (await import('./pt/header.json')).default,
|
loader: async () => (await import('./pt-BR/header.json')).default,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
@ -25,17 +36,8 @@ export const { t, locale, locales, loading, loadTranslations } = new i18n(
|
||||||
config,
|
config,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Save to localStorage on change
|
|
||||||
locale.subscribe(($locale) => {
|
locale.subscribe(($locale) => {
|
||||||
if (typeof localStorage !== 'undefined') {
|
if (typeof document !== 'undefined') {
|
||||||
localStorage.setItem('locale', $locale);
|
document.cookie = `locale=${$locale}; path=/; SameSite=Strict;`;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Load from localStorage on initialization
|
|
||||||
if (typeof localStorage !== 'undefined') {
|
|
||||||
const savedLocale = localStorage.getItem('locale');
|
|
||||||
if (savedLocale && savedLocale !== 'null') {
|
|
||||||
locale.set(savedLocale);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
{
|
|
||||||
"en": "English",
|
|
||||||
"pt": "Português"
|
|
||||||
}
|
|
|
@ -1,16 +0,0 @@
|
||||||
import { loadTranslations } from '$lib/translations';
|
|
||||||
|
|
||||||
/** @type {import('@sveltejs/kit').Load} */
|
|
||||||
export const load = async () => {
|
|
||||||
const initLocale = primaryLanguage(navigator.language) || 'en';
|
|
||||||
|
|
||||||
// TODO: Fix the undefined location issue
|
|
||||||
await loadTranslations(initLocale);
|
|
||||||
|
|
||||||
return {};
|
|
||||||
};
|
|
||||||
|
|
||||||
const primaryLanguage = (/** @type {string} */ locale) => {
|
|
||||||
if (!locale) return '';
|
|
||||||
return locale.split('-')[0];
|
|
||||||
};
|
|
51
src/routes/+layout.server.js
Normal file
51
src/routes/+layout.server.js
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
import { parse } from 'accept-language-parser';
|
||||||
|
import { loadTranslations } from '$lib/translations';
|
||||||
|
import { SUPPORTED_LOCALES } from '$lib/translations';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A set of all supported locale codes, used to validate and match against
|
||||||
|
* user preferences from cookies or Accept-Language headers. We're using a
|
||||||
|
* Set for better performance in lookup.
|
||||||
|
*
|
||||||
|
* Example values: "en-US", "pt-BR"
|
||||||
|
* @type {Set<string>}
|
||||||
|
*/
|
||||||
|
const SUPPORTED_LOCALE_SET = new Set(Object.values(SUPPORTED_LOCALES));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a valid locale from cookies, or null if not valid/found.
|
||||||
|
* @param {{ get: (cookies: string) => any; }} cookies
|
||||||
|
*/
|
||||||
|
function localeFromCookies(cookies) {
|
||||||
|
const locale = cookies.get('locale');
|
||||||
|
return locale && SUPPORTED_LOCALE_SET.has(locale) ? locale : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses the Accept-Language header and returns the best matching locale.
|
||||||
|
* @param {string | null | undefined} header
|
||||||
|
*/
|
||||||
|
function localeFromHeader(header) {
|
||||||
|
if (!header) return null;
|
||||||
|
|
||||||
|
const parsedLanguages = parse(header);
|
||||||
|
for (const { code, region } of parsedLanguages) {
|
||||||
|
const locale = region ? `${code}-${region}` : code;
|
||||||
|
if (SUPPORTED_LOCALE_SET.has(locale)) {
|
||||||
|
return locale;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @type {import('@sveltejs/kit').ServerLoad}*/
|
||||||
|
export async function load({ request, cookies }) {
|
||||||
|
const cookieLocale = localeFromCookies(cookies);
|
||||||
|
const headerLocale = localeFromHeader(request.headers.get('accept-language'));
|
||||||
|
const language = cookieLocale || headerLocale || SUPPORTED_LOCALES.EN_US;
|
||||||
|
|
||||||
|
await loadTranslations(language);
|
||||||
|
|
||||||
|
return { language };
|
||||||
|
}
|
|
@ -1,5 +1,9 @@
|
||||||
<script>
|
<script>
|
||||||
|
import { locale } from '$lib/translations';
|
||||||
import Header from '$lib/components/Header.svelte';
|
import Header from '$lib/components/Header.svelte';
|
||||||
|
export let data;
|
||||||
|
|
||||||
|
$: locale.set(data.language);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Header />
|
<Header />
|
||||||
|
|
Loading…
Add table
Reference in a new issue