Creating lang route, moving files under, setting up the i18n with en and es, and starting the message transition.

This commit is contained in:
Bradley Shellnut 2024-01-17 16:34:33 -08:00
parent 5241572b76
commit e2a6a38ef5
32 changed files with 201 additions and 26 deletions

View file

@ -7,6 +7,7 @@
"Mullvad",
"nextjs",
"Obispo",
"paraglide",
"selfhosting",
"Syncthing",
"Wallabag"

18
languages/en.json Normal file
View file

@ -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."
}

18
languages/es.json Normal file
View file

@ -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."
}

View file

@ -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",

View file

@ -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"
}
}

View file

@ -1,5 +1,6 @@
<!DOCTYPE html>
<html lang="en">
<!-- Added Placeholders for lang & dir attributes. These get replaced in `hooks.server.ts` -->
<html lang="%lang%" dir="%textDir%">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%sveltekit.assets%/b_shell_nut_favicon.gif" />

21
src/hooks.server.ts Normal file
View file

@ -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 `<html>` 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)
}
},
})
}

20
src/hooks.ts Normal file
View file

@ -0,0 +1,20 @@
import type { Reroute } from '@sveltejs/kit';
const translated: Record<string, string> = {
'/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];
}
};

View file

@ -1,28 +1,40 @@
<script lang="ts">
import { page } from '$app/stores';
import { goto } from '$app/navigation';
import { translatePath } from '$lib/i18n';
import { availableLanguageTags, languageTag } from '$paraglide/runtime';
import * as m from "$paraglide/messages";
$: pathname = $page.url.pathname;
$: lang = languageTag();
</script>
<header aria-label="header navigation">
<nav>
<a href="/" class:active={$page.url.pathname === '/'}>Home</a>
<a href='/' class:active={pathname === '/'}>{m.nav_home()}</a>
<a
href="/about"
class:active={$page.url.pathname === '/about'}
href={`/${lang}/${m.nav_about_link()}`}
class:active={pathname === `/${m.nav_about_link()}`}
>
About
{m.nav_about()}
</a>
<a
href="/portfolio"
class:active={$page.url.pathname === '/portfolio'}
href={`/${lang}/${m.nav_portfolio_link()}`}
class:active={pathname === `/${m.nav_portfolio_link()}`}
>
Portfolio
{m.nav_portfolio()}
</a>
<a
href="/uses"
class:active={$page.url.pathname === '/uses'}
href={`/${lang}/${m.nav_uses_link()}`}
class:active={pathname === `/${m.nav_uses_link()}`}
>
Uses
{m.nav_uses()}
</a>
<select on:change={(e) => goto(translatePath(pathname, e?.target?.value)) }>
{#each availableLanguageTags as lang}
<option value={lang} selected={lang === languageTag()}>{lang}</option>
{/each}
</select>
</nav>
</header>

43
src/lib/i18n.ts Normal file
View file

@ -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<AvailableLanguageTag, "ltr" | "rtl"> = {
en: "ltr",
es: "ltr",
}
return directions[locale]
}

View file

2
src/params/lang.ts Normal file
View file

@ -0,0 +1,2 @@
import { isAvailableLanguageTag } from "$paraglide/runtime"
export const match = isAvailableLanguageTag

View file

@ -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 <html> lang and dir attributes in sync with the current language
$: if (browser) {
document.documentElement.dir = textDirection
document.documentElement.lang = lang
}
</script>
{#if !dev}
@ -45,12 +67,20 @@
<MetaTags {...metaTags} />
<svelte:head>
{#each availableLanguageTags as lang}
<link rel="alternate" hreflang={lang} href={translatePath($page.url.pathname, lang)} />
{/each}
</svelte:head>
<div class="wrapper">
<Header />
<main>
<slot />
</main>
<Footer />
{#key lang}
<Header />
<main>
<slot />
</main>
<Footer />
{/key}
</div>
<style lang="postcss">

View file

@ -1,5 +1,6 @@
<script lang="ts">
import type { PageData } from './$types';
import type { PageData } from '../$types';
import * as m from "$paraglide/messages";
import Bandcamp from '$lib/components/bandcamp/index.svelte';
import Articles from '$lib/components/Articles.svelte';
import type { Album } from '$lib/types/album';
@ -22,14 +23,13 @@
<div class="home">
<div>
<h1>Hello! I'm Bradley Shellnut.</h1>
<h1>{m.home_title()}</h1>
</div>
<p>
I'm a full stack software engineer currently working on Java Spring, PostgreSQL, and React / Angular JS.
{m.home_about()}
</p>
<p>
At home you can usually find me learning new things and working with
SvelteKit, Next.js, and Gatsby.
{m.home_learning()}
</p>
<p>
Or you may find me jamming out to music 🎶, hiking ⛰️, making{' '}

View file

@ -8,6 +8,7 @@
import Remix from '@iconify-icons/simple-icons/remix';
import Svelte from '@iconify-icons/simple-icons/svelte';
import TypeScript from '@iconify-icons/simple-icons/typescript';
import * as m from "$paraglide/messages";
import LazyImage from '$lib/components/LazyImage.svelte';
import antarctica from '$lib/assets/images/antarctica.png?as=run:0';
import tortie_derp from '$lib/assets/images/tortie_derp.jpg?as=run';
@ -24,7 +25,7 @@
<div class="about">
<div>
<h1>About</h1>
<p>Hey! My name is Bradley Shellnut.</p>
<p>{m.about_whoami()}</p>
<p>
I'm {new Date().getFullYear() - 1991} years old and I am a full stack
software engineer who's interested in new tech and not afraid to

View file

@ -23,8 +23,14 @@ const config = {
adapter: adapter(),
alias: {
$root: './src',
$paraglide: './src/paraglide'
}
$paraglide: './src/paraglide/'
},
// Need for crawling to work until
// https://github.com/sveltejs/kit/issues/11133
// is fixed
prerender: {
entries: ["/"],
},
}
};