add: internationalization translation to danish

This commit is contained in:
2025-11-25 21:59:53 +01:00
parent 0c8dc087ca
commit 3b7b54b4bf
14 changed files with 311 additions and 227 deletions

View File

@@ -1,18 +1,23 @@
<script lang="ts">
import { Button } from '$lib/components/ui/button';
import { ThemeToggle } from '$lib/components/ui/theme-toggle';
import { LanguageToggle } from '$lib/components/ui/language-toggle';
import { signOut } from '@auth/sveltekit/client';
import { languageStore } from '$lib/stores/language.svelte';
let { userName, userEmail }: { userName?: string | null; userEmail?: string | null } = $props();
const t = $derived(languageStore.t);
</script>
<div class="flex items-center justify-between">
<div>
<h1 class="text-3xl font-bold">Dashboard</h1>
<p class="text-muted-foreground">Welcome back, {userName || userEmail}</p>
<h1 class="text-3xl font-bold">{t.nav.dashboard}</h1>
<p class="text-muted-foreground">{t.dashboard.welcomeBack}, {userName || userEmail}</p>
</div>
<div class="flex items-center gap-2">
<div class="flex items-center gap-1 sm:gap-2">
<LanguageToggle />
<ThemeToggle />
<Button variant="outline" onclick={() => signOut({ callbackUrl: '/' })}>Sign Out</Button>
<Button variant="outline" onclick={() => signOut({ callbackUrl: '/' })}>{t.auth.signOut}</Button>
</div>
</div>

View File

@@ -7,6 +7,7 @@
import ImageSelector from './ImageSelector.svelte';
import ColorPicker from '$lib/components/ui/ColorPicker.svelte';
import { enhance } from '$app/forms';
import { languageStore } from '$lib/stores/language.svelte';
interface Props {
onSuccess?: () => void;
@@ -14,6 +15,8 @@
let { onSuccess }: Props = $props();
const t = $derived(languageStore.t);
const currencies = ['DKK', 'EUR', 'USD', 'SEK', 'NOK', 'GBP'];
let linkUrl = $state('');
@@ -52,7 +55,7 @@
<Card>
<CardHeader>
<CardTitle>Add New Item</CardTitle>
<CardTitle>{t.form.addNewItem}</CardTitle>
</CardHeader>
<CardContent>
<form
@@ -68,12 +71,12 @@
>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div class="space-y-2 md:col-span-2">
<Label for="title">Item Name *</Label>
<Label for="title">{t.form.itemName} *</Label>
<Input id="title" name="title" required placeholder="e.g., Blue Headphones" />
</div>
<div class="space-y-2 md:col-span-2">
<Label for="description">Description</Label>
<Label for="description">{t.form.description}</Label>
<Textarea
id="description"
name="description"
@@ -83,7 +86,7 @@
</div>
<div class="space-y-2 md:col-span-2">
<Label for="link">Link (URL)</Label>
<Label for="link">{t.form.link}</Label>
<Input
id="link"
name="link"
@@ -95,7 +98,7 @@
</div>
<div class="space-y-2 md:col-span-2">
<Label for="imageUrl">Image URL</Label>
<Label for="imageUrl">{t.form.imageUrl}</Label>
<Input
id="imageUrl"
name="imageUrl"
@@ -108,12 +111,12 @@
</div>
<div class="space-y-2">
<Label for="price">Price</Label>
<Label for="price">{t.form.price}</Label>
<Input id="price" name="price" type="number" step="0.01" placeholder="0.00" />
</div>
<div class="space-y-2 md:col-span-2">
<Label for="currency">Currency</Label>
<Label for="currency">{t.form.currency}</Label>
<select
id="currency"
name="currency"
@@ -127,14 +130,14 @@
<div class="md:col-span-2">
<div class="flex items-center justify-between">
<Label for="color">Card Color (optional)</Label>
<Label for="color">{t.form.cardColor}</Label>
<ColorPicker bind:color={color} />
</div>
<input type="hidden" name="color" value={color || ''} />
</div>
</div>
<Button type="submit" class="w-full md:w-auto">Add Item</Button>
<Button type="submit" class="w-full md:w-auto">{t.wishlist.addItem}</Button>
</form>
</CardContent>
</Card>

View File

@@ -8,6 +8,7 @@
import ColorPicker from '$lib/components/ui/ColorPicker.svelte';
import { enhance } from '$app/forms';
import type { Item } from '$lib/server/schema';
import { languageStore } from '$lib/stores/language.svelte';
interface Props {
item: Item;
@@ -21,6 +22,8 @@
let { item, onSuccess, onCancel, onColorChange, currentPosition = 1, totalItems = 1, onPositionChange }: Props = $props();
const t = $derived(languageStore.t);
const currencies = ['DKK', 'EUR', 'USD', 'SEK', 'NOK', 'GBP'];
let linkUrl = $state(item.link || '');
@@ -59,7 +62,7 @@
<Card>
<CardHeader>
<CardTitle>Edit Item</CardTitle>
<CardTitle>{t.wishlist.editItem}</CardTitle>
</CardHeader>
<CardContent>
<form
@@ -77,12 +80,12 @@
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div class="space-y-2 md:col-span-2">
<Label for="title">Item Name *</Label>
<Label for="title">{t.form.itemName} *</Label>
<Input id="title" name="title" required value={item.title} placeholder="e.g., Blue Headphones" />
</div>
<div class="space-y-2 md:col-span-2">
<Label for="description">Description</Label>
<Label for="description">{t.form.description}</Label>
<Textarea
id="description"
name="description"
@@ -93,7 +96,7 @@
</div>
<div class="space-y-2 md:col-span-2">
<Label for="link">Link (URL)</Label>
<Label for="link">{t.form.link}</Label>
<Input
id="link"
name="link"
@@ -105,7 +108,7 @@
</div>
<div class="space-y-2 md:col-span-2">
<Label for="imageUrl">Image URL</Label>
<Label for="imageUrl">{t.form.imageUrl}</Label>
<Input
id="imageUrl"
name="imageUrl"
@@ -118,12 +121,12 @@
</div>
<div class="space-y-2">
<Label for="price">Price</Label>
<Label for="price">{t.form.price}</Label>
<Input id="price" name="price" type="number" step="0.01" value={item.price || ''} placeholder="0.00" />
</div>
<div class="space-y-2 md:col-span-2">
<Label for="currency">Currency</Label>
<Label for="currency">{t.form.currency}</Label>
<select
id="currency"
name="currency"
@@ -137,14 +140,14 @@
<div class="md:col-span-2">
<div class="flex items-center justify-between">
<Label for="color">Card Color (optional)</Label>
<Label for="color">{t.form.cardColor}</Label>
<ColorPicker bind:color={color} onchange={() => onColorChange?.(item.id, color || '')} />
</div>
<input type="hidden" name="color" value={color || ''} />
</div>
<div class="space-y-2 md:col-span-2">
<Label for="position">Position in List</Label>
<Label for="position">{t.form.position}</Label>
<Input
id="position"
type="number"
@@ -166,9 +169,9 @@
</div>
<div class="flex gap-2">
<Button type="submit" class="flex-1 md:flex-none">Save Changes</Button>
<Button type="submit" class="flex-1 md:flex-none">{t.form.saveChanges}</Button>
{#if onCancel}
<Button type="button" variant="outline" class="flex-1 md:flex-none" onclick={onCancel}>Cancel</Button>
<Button type="button" variant="outline" class="flex-1 md:flex-none" onclick={onCancel}>{t.form.cancel}</Button>
{/if}
</div>
</form>

View File

@@ -6,6 +6,7 @@
import type { Item } from "$lib/server/schema";
import { enhance } from "$app/forms";
import { flip } from "svelte/animate";
import { languageStore } from '$lib/stores/language.svelte';
let {
items = $bindable([]),
@@ -18,6 +19,8 @@
onStartEditing: (item: Item) => void;
onReorder: (items: Item[]) => Promise<void>;
} = $props();
const t = $derived(languageStore.t);
</script>
<div class="space-y-4">
@@ -33,7 +36,7 @@
size="sm"
onclick={() => onStartEditing(item)}
>
Edit
{t.wishlist.edit}
</Button>
{#if rearranging}
<form
@@ -51,7 +54,7 @@
variant="destructive"
size="sm"
>
Delete
{t.form.delete}
</Button>
</form>
{/if}
@@ -64,7 +67,7 @@
<Card>
<CardContent class="p-12">
<EmptyState
message="No items yet. Click 'Add Item' to get started!"
message={t.wishlist.noItems + ". " + t.wishlist.addFirstItem + "!"}
/>
</CardContent>
</Card>

View File

@@ -3,6 +3,7 @@
import { Input } from '$lib/components/ui/input';
import { Label } from '$lib/components/ui/label';
import { Card, CardContent } from '$lib/components/ui/card';
import { languageStore } from '$lib/stores/language.svelte';
interface Props {
publicUrl: string;
@@ -11,6 +12,8 @@
let { publicUrl, ownerUrl }: Props = $props();
const t = $derived(languageStore.t);
let copiedPublic = $state(false);
let copiedOwner = $state(false);
@@ -34,22 +37,22 @@
<Card>
<CardContent class="space-y-4 pt-6">
<div class="space-y-2">
<Label>Share with friends (view only)</Label>
<Label>{t.wishlist.shareViewOnly}</Label>
<div class="flex gap-2">
<Input readonly value={publicLink} class="font-mono text-sm" />
<Button variant="outline" onclick={() => copyToClipboard(publicLink, 'public')}>
{copiedPublic ? 'Copied!' : 'Copy'}
{copiedPublic ? t.wishlist.copied : t.wishlist.copy}
</Button>
</div>
</div>
{#if ownerLink}
<div class="space-y-2">
<Label>Your edit link (keep this private!)</Label>
<Label>{t.wishlist.shareEditLink}</Label>
<div class="flex gap-2">
<Input readonly value={ownerLink} class="font-mono text-sm" />
<Button variant="outline" onclick={() => copyToClipboard(ownerLink, 'owner')}>
{copiedOwner ? 'Copied!' : 'Copy'}
{copiedOwner ? t.wishlist.copied : t.wishlist.copy}
</Button>
</div>
</div>

View File

@@ -1,7 +1,6 @@
<script lang="ts">
import { Button } from "$lib/components/ui/button";
import { Lock, LockOpen } from "lucide-svelte";
import { enhance } from "$app/forms";
import { languageStore } from '$lib/stores/language.svelte';
let {
rearranging = $bindable(false),
@@ -13,9 +12,7 @@
onToggleAddForm: () => void;
} = $props();
function toggleRearranging() {
rearranging = !rearranging;
}
const t = $derived(languageStore.t);
</script>
<div class="flex flex-col md:flex-row gap-4">
@@ -23,6 +20,6 @@
onclick={onToggleAddForm}
class="w-full md:w-auto"
>
{showAddForm ? "Cancel" : "+ Add Item"}
{showAddForm ? t.form.cancel : t.wishlist.addWish}
</Button>
</div>

View File

@@ -6,6 +6,7 @@
import { Pencil, Check, X } from "lucide-svelte";
import ColorPicker from "$lib/components/ui/ColorPicker.svelte";
import type { Wishlist } from "$lib/server/schema";
import { languageStore } from '$lib/stores/language.svelte';
let {
wishlist,
@@ -21,6 +22,8 @@
onEndDateUpdate: (endDate: string | null) => void;
} = $props();
const t = $derived(languageStore.t);
let editingTitle = $state(false);
let editingDescription = $state(false);
let wishlistTitle = $state(wishlist.title);
@@ -123,7 +126,7 @@
<!-- Description -->
<div class="space-y-2">
<div class="flex items-center justify-between gap-2">
<Label for="wishlist-description">Description (optional)</Label>
<Label for="wishlist-description">{t.form.descriptionOptional}</Label>
<button
type="button"
onclick={() => {
@@ -159,14 +162,14 @@
/>
{:else}
<div class="w-full py-2 px-3 rounded-md border border-input bg-transparent text-sm min-h-[80px]">
{wishlistDescription || "No description"}
{wishlistDescription || t.form.noDescription}
</div>
{/if}
</div>
<!-- End Date -->
<div class="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-2 sm:gap-4">
<Label for="wishlist-end-date">End Date (optional)</Label>
<Label for="wishlist-end-date">{t.form.endDateOptional}</Label>
<div class="flex items-center gap-2">
{#if wishlistEndDate}
<button

View File

@@ -4,6 +4,7 @@
import { GripVertical, ExternalLink } from "lucide-svelte";
import { getCardStyle } from '$lib/utils/colors';
import { Button } from "$lib/components/ui/button";
import { languageStore } from '$lib/stores/language.svelte';
interface Props {
item: Item;
@@ -19,6 +20,8 @@
showDragHandle = false,
}: Props = $props();
const t = $derived(languageStore.t);
const currencySymbols: Record<string, string> = {
DKK: "kr",
EUR: "€",
@@ -101,7 +104,7 @@
class="gap-1.5"
>
<ExternalLink class="w-4 h-4" />
View Product
{t.wishlist.viewProduct}
</Button>
{/if}