From e2a6a38ef5c6fd984b1e1581f002b2b7d11ebf99 Mon Sep 17 00:00:00 2001 From: Bradley Shellnut Date: Wed, 17 Jan 2024 16:34:33 -0800 Subject: [PATCH] Creating lang route, moving files under, setting up the i18n with en and es, and starting the message transition. --- .vscode/settings.json | 1 + languages/en.json | 18 ++++++++ languages/es.json | 18 ++++++++ package.json | 2 + project.inlang/settings.json | 4 +- src/app.html | 3 +- src/hooks.server.ts | 21 +++++++++ src/hooks.ts | 20 +++++++++ src/lib/components/nav/index.svelte | 32 +++++++++----- src/lib/i18n.ts | 43 +++++++++++++++++++ src/messages/en.json | 0 src/params/lang.ts | 2 + src/routes/+layout.svelte | 40 ++++++++++++++--- .../{ => [[lang=lang]]}/+page.server.ts | 0 src/routes/{ => [[lang=lang]]}/+page.svelte | 10 ++--- .../{ => [[lang=lang]]}/about/+page.svelte | 3 +- src/routes/{ => [[lang=lang]]}/about/+page.ts | 0 .../about/CourseCard.svelte | 0 .../about/TechListItem.svelte | 0 .../{ => [[lang=lang]]}/about/course.json | 0 .../api/articles/+server.ts | 0 .../{ => [[lang=lang]]}/articles/+page.svelte | 0 .../{ => [[lang=lang]]}/articles/+page.ts | 0 .../articles/[page]/+page.server.ts | 0 .../articles/[page]/+page.svelte | 0 .../portfolio/+page.server.ts | 0 .../portfolio/+page.svelte | 0 .../{ => [[lang=lang]]}/privacy/+page.svelte | 0 .../{ => [[lang=lang]]}/privacy/+page.ts | 0 .../{ => [[lang=lang]]}/uses/+page.svelte | 0 src/routes/{ => [[lang=lang]]}/uses/+page.ts | 0 svelte.config.js | 10 ++++- 32 files changed, 201 insertions(+), 26 deletions(-) create mode 100644 languages/en.json create mode 100644 languages/es.json create mode 100644 src/hooks.server.ts create mode 100644 src/hooks.ts create mode 100644 src/lib/i18n.ts delete mode 100644 src/messages/en.json create mode 100644 src/params/lang.ts rename src/routes/{ => [[lang=lang]]}/+page.server.ts (100%) rename src/routes/{ => [[lang=lang]]}/+page.svelte (85%) rename src/routes/{ => [[lang=lang]]}/about/+page.svelte (98%) rename src/routes/{ => [[lang=lang]]}/about/+page.ts (100%) rename src/routes/{ => [[lang=lang]]}/about/CourseCard.svelte (100%) rename src/routes/{ => [[lang=lang]]}/about/TechListItem.svelte (100%) rename src/routes/{ => [[lang=lang]]}/about/course.json (100%) rename src/routes/{ => [[lang=lang]]}/api/articles/+server.ts (100%) rename src/routes/{ => [[lang=lang]]}/articles/+page.svelte (100%) rename src/routes/{ => [[lang=lang]]}/articles/+page.ts (100%) rename src/routes/{ => [[lang=lang]]}/articles/[page]/+page.server.ts (100%) rename src/routes/{ => [[lang=lang]]}/articles/[page]/+page.svelte (100%) rename src/routes/{ => [[lang=lang]]}/portfolio/+page.server.ts (100%) rename src/routes/{ => [[lang=lang]]}/portfolio/+page.svelte (100%) rename src/routes/{ => [[lang=lang]]}/privacy/+page.svelte (100%) rename src/routes/{ => [[lang=lang]]}/privacy/+page.ts (100%) rename src/routes/{ => [[lang=lang]]}/uses/+page.svelte (100%) rename src/routes/{ => [[lang=lang]]}/uses/+page.ts (100%) diff --git a/.vscode/settings.json b/.vscode/settings.json index e6e1636..fce7129 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -7,6 +7,7 @@ "Mullvad", "nextjs", "Obispo", + "paraglide", "selfhosting", "Syncthing", "Wallabag" diff --git a/languages/en.json b/languages/en.json new file mode 100644 index 0000000..a993d19 --- /dev/null +++ b/languages/en.json @@ -0,0 +1,18 @@ +{ + "$schema": "https://inlang.com/schema/inlang-message-format", + "home_title": "Hello! I'm Bradley Shellnut.", + "home_about": "I'm a full stack software engineer currently working on Java Spring, PostgreSQL, and React / Angular JS.", + "home_learning": "At home you can usually find me learning new things and working with SvelteKit, Next.js, and Gatsby.", + "nav_home": "Home", + "nav_about": "About", + "nav_about_link": "about", + "nav_uses": "Uses", + "nav_uses_link": "uses", + "nav_articles": "Articles", + "nav_articles_link": "articles", + "nav_portfolio": "Portfolio", + "nav_portfolio_link": "portfolio", + "nav_privacy": "Privacy", + "nav_privacy_link": "privacy", + "about_whoami": "Hey! My name is Bradley Shellnut." +} \ No newline at end of file diff --git a/languages/es.json b/languages/es.json new file mode 100644 index 0000000..8a93ecf --- /dev/null +++ b/languages/es.json @@ -0,0 +1,18 @@ +{ + "$schema": "https://inlang.com/schema/inlang-message-format", + "home_title": "!Hola! Me llamo Bradley Shellnut.", + "home_about": "Soy un ingeniero de software de pila completa que actualmente trabaja en Java Spring, PostgreSQL y React / Angular JS.", + "home_learning": "En casa por lo general me puedes encontrar aprendiendo cosas nuevas y trabajando con SvelteKit, Next.js, y Gatsby.", + "nav_home": "Inicio", + "nav_about": "Acerca de", + "nav_about_link": "acerca-de", + "nav_uses": "Utiliza", + "nav_uses_link": "utiliza", + "nav_articles": "Artículos", + "nav_articles_link": "articulos", + "nav_portfolio": "Cartera", + "nav_portfolio_link": "cartera", + "nav_privacy": "Privacidad", + "nav_privacy_link": "privacidad", + "about_whoami": "¡Hola! Me llamo Bradley Shellnut." +} \ No newline at end of file diff --git a/package.json b/package.json index 4cc9808..3f316cf 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,8 @@ "test:ui": "svelte-kit sync && playwright test --ui", "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", + "compile": "paraglide-js compile --project ./project.inlang", + "watch": "paraglide-js compile --project ./project.inlang --watch", "lint": "prettier --plugin-search-dir . --check . && eslint .", "format": "prettier --plugin-search-dir . --write .", "test:integration": "playwright test", diff --git a/project.inlang/settings.json b/project.inlang/settings.json index 320e6e6..0fe625e 100644 --- a/project.inlang/settings.json +++ b/project.inlang/settings.json @@ -2,7 +2,7 @@ "$schema": "https://inlang.com/schema/project-settings", "sourceLanguageTag": "en", "languageTags": [ - "en" + "en", "es" ], "modules": [ "https://cdn.jsdelivr.net/npm/@inlang/message-lint-rule-empty-pattern@latest/dist/index.js", @@ -14,6 +14,6 @@ "https://cdn.jsdelivr.net/npm/@inlang/plugin-m-function-matcher@latest/dist/index.js" ], "plugin.inlang.messageFormat": { - "pathPattern": "./messages/{languageTag}.json" + "pathPattern": "./languages/{languageTag}.json" } } \ No newline at end of file diff --git a/src/app.html b/src/app.html index 6474910..bf73bd9 100644 --- a/src/app.html +++ b/src/app.html @@ -1,5 +1,6 @@ - + + diff --git a/src/hooks.server.ts b/src/hooks.server.ts new file mode 100644 index 0000000..b683fdb --- /dev/null +++ b/src/hooks.server.ts @@ -0,0 +1,21 @@ +import { getTextDirection } from "$lib/i18n" +import { sourceLanguageTag, type AvailableLanguageTag } from "$paraglide/runtime" + +/* +We set the `lang` and `dir` attributes on the `` element using a hook. +the `app.html` file contains placeholders for these attributes, which we just find and replace. +*/ + +export async function handle({ event, resolve }) { + const lang: AvailableLanguageTag = + (event.params.lang as AvailableLanguageTag) ?? sourceLanguageTag + const textDirection = getTextDirection(lang) + + return await resolve(event, { + transformPageChunk({ done, html }) { + if (done) { + return html.replace("%lang%", lang).replace("%textDir%", textDirection) + } + }, + }) +} \ No newline at end of file diff --git a/src/hooks.ts b/src/hooks.ts new file mode 100644 index 0000000..37ee062 --- /dev/null +++ b/src/hooks.ts @@ -0,0 +1,20 @@ +import type { Reroute } from '@sveltejs/kit'; + +const translated: Record = { + '/en/about': '/en/about', + '/en/uses': '/en/uses', + '/en/articles': '/en/articles', + '/en/portfolio': '/en/portfolio', + '/en/privacy': '/en/privacy', + '/es/acerca-de': '/es/about', + '/es/utiliza': '/es/uses', + '/es/articulos': '/es/articles', + '/es/cartera': '/es/portfolio', + '/es/privacidad': '/es/privacy' +}; + +export const reroute: Reroute = ({ url }) => { + if (url.pathname in translated) { + return translated[url.pathname]; + } +}; \ No newline at end of file diff --git a/src/lib/components/nav/index.svelte b/src/lib/components/nav/index.svelte index e6eb500..2eb2e85 100644 --- a/src/lib/components/nav/index.svelte +++ b/src/lib/components/nav/index.svelte @@ -1,28 +1,40 @@
diff --git a/src/lib/i18n.ts b/src/lib/i18n.ts new file mode 100644 index 0000000..4ae7f71 --- /dev/null +++ b/src/lib/i18n.ts @@ -0,0 +1,43 @@ +import { + sourceLanguageTag, + availableLanguageTags, + type AvailableLanguageTag, +} from "$paraglide/runtime" + +/** + * Takes in a path with or without a language tag and returns the path with the given language tag. + * @returns + */ +export function translatePath(path: string, lang: AvailableLanguageTag) { + path = getPathWithoutLang(path) + + // Don't prefix with the source language tag, that's the default + if (lang === sourceLanguageTag) return path + // Otherwise, prefix with the language tag + else return `/${lang}${path}` +} + +/** + * Removes the language tag from the path, if it exists. + */ +function getPathWithoutLang(path: string) { + const [_, maybeLang, ...rest] = path.split("/") + if (availableLanguageTags.includes(maybeLang as any)) { + return `/${rest.join("/")}`; + } else { + return path; + } +} + +/** + * Look up the text direction for a given locale. + * You could use a Polyfill for `Intl.Locale.prototype.getTextInfo` instead. + */ +export function getTextDirection(locale: AvailableLanguageTag) { + const directions: Record = { + en: "ltr", + es: "ltr", + } + + return directions[locale] +} diff --git a/src/messages/en.json b/src/messages/en.json deleted file mode 100644 index e69de29..0000000 diff --git a/src/params/lang.ts b/src/params/lang.ts new file mode 100644 index 0000000..2fbce7c --- /dev/null +++ b/src/params/lang.ts @@ -0,0 +1,2 @@ +import { isAvailableLanguageTag } from "$paraglide/runtime" +export const match = isAvailableLanguageTag \ No newline at end of file diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index 800eb30..6573245 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -7,9 +7,11 @@ import { PUBLIC_SITE_URL } from '$env/static/public'; import "nprogress/nprogress.css"; import '$root/styles/styles.pcss'; + import { setLanguageTag, sourceLanguageTag, type AvailableLanguageTag, availableLanguageTags } from "$paraglide/runtime"; import Header from '$lib/components/header/index.svelte'; import Footer from '$lib/components/footer/index.svelte'; import Analytics from '$lib/components/analytics/index.svelte'; + import { getTextDirection, translatePath } from '$lib/i18n'; NProgress.configure({ // Full list: https://github.com/rstacruz/nprogress#configuration @@ -37,6 +39,26 @@ ], ...$page.data.metaTagsChild } + + // Determine the current language from the URL. Fall back to the source language if none is specified. + $: lang = $page.params.lang as AvailableLanguageTag ?? sourceLanguageTag + + console.log('lang', lang) + + // Set the language tag in the Paraglide runtime. + // This determines which language the strings are translated to. + // You should only do this in the template, to avoid concurrent requests interfering with each other. + $: setLanguageTag(lang) + + + // Determine the text direction of the current language + $: textDirection = getTextDirection(lang) + + // Keep the lang and dir attributes in sync with the current language + $: if (browser) { + document.documentElement.dir = textDirection + document.documentElement.lang = lang + } {#if !dev} @@ -45,12 +67,20 @@ + + {#each availableLanguageTags as lang} + + {/each} + +
-
-
- -
-
+ {#key lang} +
+
+ +
+
+ {/key}