feat: i18n
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"$schema": "https://inlang.com/schema/message-format-plugin",
|
||||
"hello_world": "Hallo Welt",
|
||||
"pfadi": "Pfadi"
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"$schema": "https://inlang.com/schema/message-format-plugin",
|
||||
"hello_world": "Hello World",
|
||||
"pfadi": "Scouts"
|
||||
}
|
||||
@@ -27,6 +27,8 @@
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"@fontsource/outfit": "^5.0.13",
|
||||
"@inlang/paraglide-js": "^1.11.0",
|
||||
"@inlang/paraglide-sveltekit": "^0.16.1",
|
||||
"@ts-stack/markdown": "^1.5.0",
|
||||
"mime-types": "^3.0.2",
|
||||
"svelte-preprocess": "^6.0.2",
|
||||
|
||||
Generated
+1216
-5
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"$schema": "https://inlang.com/schema/project-settings",
|
||||
"sourceLanguageTag": "de",
|
||||
"languageTags": [
|
||||
"de",
|
||||
"en"
|
||||
],
|
||||
"modules": [
|
||||
"https://cdn.jsdelivr.net/npm/@inlang/plugin-m-function-matcher@latest/dist/index.js",
|
||||
"https://cdn.jsdelivr.net/npm/@inlang/plugin-message-format@latest/dist/index.js"
|
||||
],
|
||||
"plugin.inlang.messageFormat": {
|
||||
"pathPattern": "./messages/{languageTag}.json"
|
||||
}
|
||||
}
|
||||
+10
-10
@@ -1,12 +1,12 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
%sveltekit.head%
|
||||
</head>
|
||||
<body data-sveltekit-preload-data="hover">
|
||||
<div style="display: contents">%sveltekit.body%</div>
|
||||
</body>
|
||||
<html lang="%paraglide.lang%" dir="%paraglide.textDirection%">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
%sveltekit.head%
|
||||
</head>
|
||||
<body data-sveltekit-preload-data="hover">
|
||||
<div style="display: contents">%sveltekit.body%</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
import { i18n } from "$lib/i18n"
|
||||
|
||||
export const handle = i18n.handle()
|
||||
@@ -0,0 +1,11 @@
|
||||
import { createI18n } from "@inlang/paraglide-sveltekit"
|
||||
import * as runtime from "$lib/paraglide/runtime"
|
||||
|
||||
export const i18n = createI18n(runtime, {
|
||||
pathnames: {
|
||||
"/about": {
|
||||
en: "/about",
|
||||
de: "/ueber-uns"
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -54,8 +54,8 @@ export async function getCoverImage(slug: string): Promise<string | null> {
|
||||
});
|
||||
}
|
||||
|
||||
export async function getPages() {
|
||||
return withCache("pages", async () => {
|
||||
export async function getPages(lang: string = 'de') {
|
||||
return withCache(`pages:${lang}`, async () => {
|
||||
try {
|
||||
const items = await client.getDirectoryContents("/");
|
||||
|
||||
@@ -71,7 +71,32 @@ export async function getPages() {
|
||||
const pages = await Promise.all(
|
||||
directories.map(async (item: any) => {
|
||||
const slug = item.basename;
|
||||
const title = slug.charAt(0).toUpperCase() + slug.slice(1);
|
||||
const baseName = slug.charAt(0).toUpperCase() + slug.slice(1);
|
||||
const filename = lang === 'de' ? `${baseName}.md` : `${baseName}.${lang}.md`;
|
||||
const path = `/${slug}/${filename}`;
|
||||
|
||||
let title = baseName;
|
||||
try {
|
||||
const content = await getPageContent(path);
|
||||
const headerMatch = content.match(/^#{1,6}\s+(.+)$/m);
|
||||
if (headerMatch) {
|
||||
title = headerMatch[1];
|
||||
}
|
||||
} catch (e) {
|
||||
// Fallback to German if English is missing
|
||||
if (lang !== 'de') {
|
||||
try {
|
||||
const fallbackContent = await getPageContent(`/${slug}/${baseName}.md`);
|
||||
const headerMatch = fallbackContent.match(/^#{1,6}\s+(.+)$/m);
|
||||
if (headerMatch) {
|
||||
title = headerMatch[1];
|
||||
}
|
||||
} catch (innerE) {
|
||||
console.warn(`Could not fetch fallback title for ${slug}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const coverImage = await getCoverImage(slug);
|
||||
|
||||
return {
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
import type { ParamMatcher } from '@sveltejs/kit';
|
||||
|
||||
export const match: ParamMatcher = (param) => {
|
||||
return ['de', 'en'].includes(param);
|
||||
};
|
||||
@@ -1,8 +1,8 @@
|
||||
import type { LayoutServerLoad } from './$types';
|
||||
import { getPages } from '$lib/server/nextcloud';
|
||||
|
||||
export const load: LayoutServerLoad = async () => {
|
||||
const pages = await getPages();
|
||||
export const load: LayoutServerLoad = async ({ params }) => {
|
||||
const pages = await getPages(params.lang);
|
||||
return {
|
||||
pages
|
||||
};
|
||||
|
||||
@@ -1,11 +1,34 @@
|
||||
<script lang="ts">
|
||||
import "../app.css";
|
||||
import type { Snippet } from 'svelte';
|
||||
import { ParaglideJS } from '@inlang/paraglide-sveltekit';
|
||||
import { i18n } from '$lib/i18n';
|
||||
import { languageTag } from '$lib/paraglide/runtime';
|
||||
|
||||
let { children }: { children?: Snippet } = $props();
|
||||
</script>
|
||||
|
||||
<header class="fixed z-50 mix-blend-difference p-1">
|
||||
<a href="/" class="text-white text-2xl">schreifuchs.ch</a>
|
||||
</header>
|
||||
{@render children?.()}
|
||||
<ParaglideJS {i18n}>
|
||||
<header class="fixed z-50 mix-blend-difference p-1 w-full flex justify-between items-start">
|
||||
<a href="/" class="text-white text-2xl">schreifuchs.ch</a>
|
||||
<nav class="flex gap-2 p-2">
|
||||
<a
|
||||
href="/"
|
||||
hreflang="de"
|
||||
data-no-translate
|
||||
class="text-white hover:underline {languageTag() === 'de' ? 'font-bold' : ''}"
|
||||
>
|
||||
DE
|
||||
</a>
|
||||
<a
|
||||
href="/en"
|
||||
hreflang="en"
|
||||
data-no-translate
|
||||
class="text-white hover:underline {languageTag() === 'en' ? 'font-bold' : ''}"
|
||||
>
|
||||
EN
|
||||
</a>
|
||||
</nav>
|
||||
</header>
|
||||
{@render children?.()}
|
||||
</ParaglideJS>
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
<script lang="ts">
|
||||
import ImageLinkTile from "$lib/components/ImageLinkTile.svelte";
|
||||
import type { PageData } from "./$types";
|
||||
import { i18n } from "$lib/i18n";
|
||||
import * as m from "$lib/paraglide/messages";
|
||||
|
||||
// Import local images to preserve existing design
|
||||
import mouse from "$lib/images/home/mouse.webp";
|
||||
@@ -8,7 +10,6 @@
|
||||
import scouts from "$lib/images/home/scouts.webp";
|
||||
import console_image from "$lib/images/home/console.webp";
|
||||
import lauch from "$lib/images/home/lauch.webp";
|
||||
import monitor from "$lib/images/informatik/monitor.webp"; // Using monitor for Informatik if console is not preferred
|
||||
|
||||
let { data }: { data: PageData } = $props();
|
||||
|
||||
@@ -42,7 +43,7 @@
|
||||
<!-- Static/External Links -->
|
||||
<ImageLinkTile src={scouts} href="https://pfadifrisco.ch/" target="_blank">
|
||||
<h2 class="text-3xl font-bold text-white hover:underline text-shadow-lg">
|
||||
Pfadi
|
||||
{m.pfadi()}
|
||||
</h2>
|
||||
</ImageLinkTile>
|
||||
</main>
|
||||
</main>
|
||||
@@ -0,0 +1,49 @@
|
||||
import { getCoverImage, getPageContent } from "$lib/server/nextcloud";
|
||||
import type { PageServerLoad } from "./$types";
|
||||
import { error } from "@sveltejs/kit";
|
||||
|
||||
export const load: PageServerLoad = async ({ params }) => {
|
||||
const { slug, lang } = params;
|
||||
const language = lang || 'de';
|
||||
|
||||
// Capitalize the first letter to match the convention: fotos -> Fotos.md
|
||||
const baseName = slug.charAt(0).toUpperCase() + slug.slice(1);
|
||||
const filename = language === 'de' ? `${baseName}.md` : `${baseName}.${language}.md`;
|
||||
const path = `/${slug}/${filename}`;
|
||||
|
||||
try {
|
||||
let rawContent;
|
||||
try {
|
||||
rawContent = await getPageContent(path);
|
||||
} catch (e) {
|
||||
if (language !== 'de') {
|
||||
console.warn(`Localized content ${filename} not found, falling back to German.`);
|
||||
rawContent = await getPageContent(`/${slug}/${baseName}.md`);
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
// Extract the first header (e.g., # Title or ## Title)
|
||||
const headerMatch = rawContent.match(/^#{1,6}\s+(.+)$/m);
|
||||
const title = headerMatch ? headerMatch[1] : baseName;
|
||||
|
||||
// Remove the first header from content so it's not rendered twice
|
||||
const content = headerMatch
|
||||
? rawContent.replace(headerMatch[0], "").trim()
|
||||
: rawContent;
|
||||
|
||||
const coverImage = await getCoverImage(slug);
|
||||
|
||||
return {
|
||||
content,
|
||||
title,
|
||||
slug,
|
||||
coverImage,
|
||||
lang: language
|
||||
};
|
||||
} catch (e) {
|
||||
console.error(`Error fetching ${filename} from Nextcloud`, e);
|
||||
throw error(404, "Page not found");
|
||||
}
|
||||
};
|
||||
@@ -1,27 +0,0 @@
|
||||
import { getCoverImage, getPageContent } from "$lib/server/nextcloud";
|
||||
import type { PageServerLoad } from "./$types";
|
||||
import { error } from "@sveltejs/kit";
|
||||
|
||||
export const load: PageServerLoad = async ({ params }) => {
|
||||
const { slug } = params;
|
||||
// Capitalize the first letter to match the convention: fotos -> Fotos.md
|
||||
const filename = slug.charAt(0).toUpperCase() + slug.slice(1) + ".md";
|
||||
const path = `/${slug}/${filename}`;
|
||||
|
||||
try {
|
||||
const [content, coverImage] = await Promise.all([
|
||||
getPageContent(path),
|
||||
getCoverImage(slug)
|
||||
]);
|
||||
|
||||
return {
|
||||
content,
|
||||
title: slug.charAt(0).toUpperCase() + slug.slice(1),
|
||||
slug,
|
||||
coverImage
|
||||
};
|
||||
} catch (e) {
|
||||
console.error(`Error fetching ${filename} from Nextcloud`, e);
|
||||
throw error(404, "Page not found");
|
||||
}
|
||||
};
|
||||
+8
-1
@@ -1,6 +1,13 @@
|
||||
import { paraglide } from '@inlang/paraglide-sveltekit/vite';
|
||||
import { sveltekit } from '@sveltejs/kit/vite';
|
||||
import { defineConfig } from 'vite';
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [sveltekit()]
|
||||
plugins: [
|
||||
paraglide({
|
||||
project: './project.inlang',
|
||||
outdir: './src/lib/paraglide'
|
||||
}),
|
||||
sveltekit()
|
||||
]
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user