Skip to content

Commit

Permalink
feature: add multilanguage support
Browse files Browse the repository at this point in the history
The plan is to support german and english.
  • Loading branch information
martinhauke committed Aug 21, 2024
1 parent ebb46b4 commit 774bc78
Show file tree
Hide file tree
Showing 22 changed files with 360 additions and 219 deletions.
24 changes: 12 additions & 12 deletions .astro/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,30 +126,30 @@ declare module 'astro:content' {

type ContentEntryMap = {
"recipes": {
"Kichererbsencurry.md": {
id: "Kichererbsencurry.md";
slug: "kichererbsencurry";
"de/SchmortofuMitFrischemKichererbsenBohnenDipp.md": {
id: "de/SchmortofuMitFrischemKichererbsenBohnenDipp.md";
slug: "de/schmortofumitfrischemkichererbsenbohnendipp";
body: string;
collection: "recipes";
data: InferEntrySchema<"recipes">
} & { render(): Render[".md"] };
"Kindergartennudeln.md": {
id: "Kindergartennudeln.md";
slug: "kindergartennudeln";
"de/ScrambledTofuMitTomaten.md": {
id: "de/ScrambledTofuMitTomaten.md";
slug: "de/scrambledtofumittomaten";
body: string;
collection: "recipes";
data: InferEntrySchema<"recipes">
} & { render(): Render[".md"] };
"Nudelsalat.md": {
id: "Nudelsalat.md";
slug: "nudelsalat";
"en/SchmortofuMitFrischemKichererbsenBohnenDipp.md": {
id: "en/SchmortofuMitFrischemKichererbsenBohnenDipp.md";
slug: "en/schmortofumitfrischemkichererbsenbohnendipp";
body: string;
collection: "recipes";
data: InferEntrySchema<"recipes">
} & { render(): Render[".md"] };
"SchmortofuMitFrischemKichererbsenBohnenDipp.md": {
id: "SchmortofuMitFrischemKichererbsenBohnenDipp.md";
slug: "schmortofumitfrischemkichererbsenbohnendipp";
"en/ScrambledTofuMitTomaten.md": {
id: "en/ScrambledTofuMitTomaten.md";
slug: "en/scrambledtofumittomaten";
body: string;
collection: "recipes";
data: InferEntrySchema<"recipes">
Expand Down
13 changes: 11 additions & 2 deletions src/components/Header.astro
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
---
import Link from "./Link.astro";
import { getLangFromUrl, useTranslations } from '../i18n/utils';
import LanguagePicker from "./LanguagePicker.astro";
const lang = getLangFromUrl(Astro.url);
const t = useTranslations(lang);
---
<header>
<div class="content">
<nav>
<Link href=`${import.meta.env.BASE_URL}/` title="home">Home</Link>
<Link href=`${import.meta.env.BASE_URL}/${lang}/` title="home">{t("nav.home")}</Link>
</nav>
<LanguagePicker />
</div>
</header>

Expand All @@ -23,10 +29,13 @@ import Link from "./Link.astro";

nav {
z-index: 1;
display: flex;
align-items: center;
}

.content {
display: flex;

justify-content: space-between;
padding: 0 5px 10px;
}
</style>
38 changes: 38 additions & 0 deletions src/components/LanguagePicker.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
---
import { languages } from '../i18n/ui';
import {Astro} from "astro/env";
const url = Astro.url.pathname
---
<ul>
{Object.entries(languages).map(([lang, label]) => (
<li>
<a href={url.replace(/\/(en|de)\//, `/${lang}/`)}>{label}</a>
</li>
))}
</ul>

<style>
ul {
display: flex;
gap: 10px;
list-style: none;
}

a {
position: relative;
display: block;
padding: 10px;

font-weight: bold;
text-decoration: none;
border: 2px solid var(--darkred);
color: var(--darkred);
background: var(--flatpink);
box-shadow: 5px 5px 0;
}

a:hover {
transform: translate(5px, 5px);
box-shadow: none;
}
</style>
25 changes: 15 additions & 10 deletions src/components/RecipeList.astro
Original file line number Diff line number Diff line change
@@ -1,20 +1,25 @@
---
import RecipeListItem from "./RecipeListItem.astro";
import {getCollection} from 'astro:content';
import {getLangFromUrl} from '../i18n/utils';
const lang = getLangFromUrl(Astro.url);
const recipes = await getCollection('recipes')
---

<ul>
{recipes.filter(recipe => recipe.data.isPublic).map(recipe => (
<RecipeListItem
href={import.meta.env.BASE_URL + "/recipe/" + recipe.data.id}
title={recipe.data.name}
body={recipe.data.description ?? ''}
img={recipe.data.image}
metaInformation={recipe.data.metaInformation}
/>
))}
{recipes
.filter(recipe => recipe.data.isPublic && recipe.data.lang === lang)
.map(recipe => (
<RecipeListItem
href={import.meta.env.BASE_URL + "/" + lang + "/recipe/" + recipe.data.id}
title={recipe.data.name}
body={recipe.data.description ?? ''}
img={recipe.data.image}
metaInformation={recipe.data.metaInformation}
/>
))
}
</ul>

<style>
Expand Down
13 changes: 9 additions & 4 deletions src/components/RecipeMetaData.astro
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ import {type MetaInformation} from "../content/config";
// Font Awesome
import { library, icon } from "@fortawesome/fontawesome-svg-core";
import { faUsers, faClock } from "@fortawesome/free-solid-svg-icons";
import {getLangFromUrl, useTranslations} from "../i18n/utils";
import {Astro} from "astro/env";
// Declare all the icons you plan on using
library.add(faUsers, faClock);
// Instantiate the icon with the icon function
Expand All @@ -16,14 +19,16 @@ interface Props {
isCompactView?: boolean;
}
const {metaInformation, isCompactView} = Astro.props;
const lang = getLangFromUrl(Astro.url)
const t = useTranslations(lang)
const {metaInformation, isCompactView} = Astro.props
---

<ContentBox class={isCompactView ? "meta-information--compact-view" : "meta-information"}>
<ul class={isCompactView ? "compact-view" : ""}>
<li><Fragment set:html={numberOfServingsIcon.html}/><span class="label">Portionen:</span><span class="value">{metaInformation.numberOfServings}</span></li>
<li><Fragment set:html={timeNeededIcon.html}/><span class="label">Zubereitungszeit:</span><span class="value">{metaInformation.timeNeeded}</span></li>
<li><span class="label">Schwierigkeit:</span><span class="value">{metaInformation.difficulty}</span></li>
<li><Fragment set:html={numberOfServingsIcon.html}/><span class="label">{t("recipe.servings")}:</span><span class="value">{metaInformation.numberOfServings}</span></li>
<li><Fragment set:html={timeNeededIcon.html}/><span class="label">{t("recipe.time")}:</span><span class="value">{metaInformation.timeNeeded}</span></li>
<li><span class="label">{t("recipe.difficulty")}:</span><span class="value">{t(metaInformation.difficulty)}</span></li>
{metaInformation.kcalPerServing && <li><span class="label">Energiegehalt pro Portion:</span><span class="value">{metaInformation.kcalPerServing} kcal</span></li>}
</ul>
</ContentBox>
Expand Down
6 changes: 5 additions & 1 deletion src/components/Steps.astro
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
---
import Step from "./Step.astro";
import ContentBox from "./ContentBox.astro";
import {getLangFromUrl,useTranslations} from "../i18n/utils";
import {Astro} from "astro/env";
interface Props {
steps: Array<string>;
}
const lang = getLangFromUrl(Astro.url)
const t = useTranslations(lang)
const {steps} = Astro.props;
---

<ContentBox class="steps" title="Zubereitung">
<ContentBox class="steps" title={t("recipe.steps")}>
<ul>
{steps.map(step => (
<Step step={step}/>
Expand Down
6 changes: 5 additions & 1 deletion src/components/ingredients/IngredientList.astro
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,17 @@
import {type IngredientGroup} from "../../content/config";
import ContentBox from "../ContentBox.astro";
import Group from "./IngredientGroup.astro";
import {getLangFromUrl, useTranslations} from "../../i18n/utils";
import {Astro} from "astro/env";
interface Props {
ingredientGroups: Array<IngredientGroup>;
}
const lang = getLangFromUrl(Astro.url)
const t = useTranslations(lang)
const {ingredientGroups} = Astro.props;
---
<ContentBox class="ingredients" title="Zutaten">
<ContentBox class="ingredients" title={t("recipe.ingredients")}>
<ul>
{ingredientGroups.map(group => (
<Group ingredientGroup={group}/>
Expand Down
5 changes: 4 additions & 1 deletion src/content/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,16 @@ const metaInformation = z.object({
numberOfServings: z.number(),
timeNeeded: z.string().regex(/(\d+\s)(min|h)/),
kcalPerServing: z.number().optional(),
difficulty: z.enum(["einfach", "mittel", "schwer"])
difficulty: z.enum(["difficulty.easy", "difficulty.middle", "difficulty.hard"])
})

const language = z.enum(["de", "en"])

const recipe = z.object({
id: z.string(),
name: z.string(),
description: z.string().optional(),
lang: language,
ingredientGroups: z.array(ingredientGroup),
image: image,
steps: z.array(z.string()),
Expand Down
58 changes: 0 additions & 58 deletions src/content/recipes/Kichererbsencurry.md

This file was deleted.

36 changes: 0 additions & 36 deletions src/content/recipes/Kindergartennudeln.md

This file was deleted.

Loading

0 comments on commit 774bc78

Please sign in to comment.