diff --git a/frontend/src/lib/components/AdventureCard.svelte b/frontend/src/lib/components/AdventureCard.svelte index 00a8451..d85a5e2 100644 --- a/frontend/src/lib/components/AdventureCard.svelte +++ b/frontend/src/lib/components/AdventureCard.svelte @@ -49,8 +49,7 @@ } }); if (res.ok) { - console.log('Adventure deleted'); - addToast('info', 'Adventure deleted successfully!'); + addToast('info', $t('adventures.adventure_delete_success')); dispatch('delete', adventure.id); } else { console.log('Error deleting adventure'); @@ -107,7 +106,7 @@ {#if isWarningModalOpen}
{$t(`adventures.activities.${adventure.type}`)}
-
{isAdventureVisited(adventure) ? 'Visited' : 'Planned'}
-
{adventure.is_public ? 'Public' : 'Private'}
+
+ {isAdventureVisited(adventure) ? $t('adventures.visited') : $t('adventures.planned')} +
+
+ {adventure.is_public ? $t('adventures.public') : $t('adventures.private')} +
{#if adventure.location && adventure.location !== ''}
@@ -147,7 +150,7 @@

{adventure.visits.length} - {adventure.visits.length > 1 ? 'visits' : 'visit'} + {adventure.visits.length > 1 ? $t('adventures.visits') : $t('adventures.visit')}

{/if} diff --git a/frontend/src/lib/components/AdventureModal.svelte b/frontend/src/lib/components/AdventureModal.svelte index 386af69..240eefb 100644 --- a/frontend/src/lib/components/AdventureModal.svelte +++ b/frontend/src/lib/components/AdventureModal.svelte @@ -5,6 +5,7 @@ import { enhance } from '$app/forms'; import { addToast } from '$lib/toasts'; import { deserialize } from '$app/forms'; + import { t } from 'svelte-i18n'; export let longitude: number | null = null; export let latitude: number | null = null; @@ -111,9 +112,9 @@ images = images.filter((image) => image.id !== id); adventure.images = images; console.log(images); - addToast('success', 'Image removed'); + addToast('success', $t('adventures.image_removed_success')); } else { - addToast('error', 'Failed to remove image'); + addToast('error', $t('adventures.image_removed_error')); } } @@ -139,7 +140,7 @@ let res = await fetch(url); let data = await res.blob(); if (!data) { - imageError = 'No image found at that URL.'; + imageError = $t('adventures.no_image_url'); return; } let file = new File([data], 'image.jpg', { type: 'image/jpeg' }); @@ -155,9 +156,9 @@ if (data2.type === 'success') { images = [...images, data2]; adventure.images = images; - addToast('success', 'Image uploaded'); + addToast('success', $t('adventures.image_upload_success')); } else { - addToast('error', 'Failed to upload image'); + addToast('error', $t('adventures.image_upload_error')); } } @@ -187,10 +188,10 @@ console.log(newImage); images = [...images, newImage]; adventure.images = images; - addToast('success', 'Image uploaded'); + addToast('success', $t('adventures.image_upload_success')); } else { - addToast('error', 'Failed to upload image'); - wikiImageError = 'Failed to upload image'; + addToast('error', $t('adventures.image_upload_error')); + wikiImageError = $t('adventures.wiki_image_error'); } } } @@ -225,7 +226,7 @@ new_end_date = new_start_date; } if (new_start_date > new_end_date) { - addToast('error', 'Start date must be before end date'); + addToast('error', $t('adventures.start_before_end_error')); return; } if (new_start_date === '' || new_end_date === '') { diff --git a/frontend/src/lib/components/CollectionCard.svelte b/frontend/src/lib/components/CollectionCard.svelte index 3f440d5..62a7543 100644 --- a/frontend/src/lib/components/CollectionCard.svelte +++ b/frontend/src/lib/components/CollectionCard.svelte @@ -109,12 +109,14 @@

{collection.adventures.length} {$t('navbar.adventures')}

{#if collection.start_date && collection.end_date}

- Dates: {new Date(collection.start_date).toLocaleDateString(undefined, { timeZone: 'UTC' })} - + {$t('adventures.dates')}: {new Date(collection.start_date).toLocaleDateString(undefined, { + timeZone: 'UTC' + })} - {new Date(collection.end_date).toLocaleDateString(undefined, { timeZone: 'UTC' })}

- Duration: {Math.floor( + {$t('adventures.duration')}: {Math.floor( (new Date(collection.end_date).getTime() - new Date(collection.start_date).getTime()) / (1000 * 60 * 60 * 24) ) + 1}{' '} diff --git a/frontend/src/lib/localization.ts b/frontend/src/lib/localization.ts deleted file mode 100644 index e69de29..0000000 diff --git a/frontend/src/locales/en.json b/frontend/src/locales/en.json index a2a031e..9468a6f 100644 --- a/frontend/src/locales/en.json +++ b/frontend/src/locales/en.json @@ -110,6 +110,19 @@ "delete_collection_warning": "Are you sure you want to delete this collection? This will also delete all of the linked adventures. This action cannot be undone.", "cancel": "Cancel", "delete_collection": "Delete Collection", + "delete_adventure": "Delete Adventure", + "adventure_delete_success": "Adventure deleted successfully!", + "visited": "Visited", + "planned": "Planned", + "duration": "Duration", + "image_removed_success": "Image removed successfully!", + "image_removed_error": "Error removing image", + "no_image_url": "No image found at that URL.", + "image_upload_success": "Image uploaded successfully!", + "image_upload_error": "Error uploading image", + "dates": "Dates", + "wiki_image_error": "Error fetching image from Wikipedia", + "start_before_end_error": "Start date must be before end date", "activities": { "general": "General 🌍", "outdoor": "Outdoor 🏞️", @@ -134,5 +147,24 @@ "volunteer_work": "Volunteer Work 🤝", "other": "Other" } + }, + "worldtravel": { + "country_list": "Country List", + "num_countries": "countries found", + "all": "All", + "partially_visited": "Partially Visited", + "not_visited": "Not Visited", + "completely_visited": "Completely Visited", + "all_subregions": "All Subregions", + "clear_search": "Clear Search", + "no_countries_found": "No countries found" + }, + "auth": { + "username": "Username", + "password": "Password", + "forgot_password": "Forgot Password?", + "signup": "Signup", + "login_error": "Unable to login with the provided credentials.", + "login": "Login" } } diff --git a/frontend/src/locales/es.json b/frontend/src/locales/es.json index f206440..b3d0ddc 100644 --- a/frontend/src/locales/es.json +++ b/frontend/src/locales/es.json @@ -133,6 +133,38 @@ "edit_collection": "Editar colección", "share": "Compartir", "unarchive": "Desarchivar", - "cancel": "Cancelar" + "cancel": "Cancelar", + "adventure_delete_success": "¡Aventura eliminada con éxito!", + "delete_adventure": "Eliminar aventura", + "planned": "Planificado", + "visited": "Visitado", + "dates": "Fechas", + "duration": "Duración", + "image_removed_error": "Error al eliminar la imagen", + "image_removed_success": "¡Imagen eliminada exitosamente!", + "image_upload_error": "Error al subir la imagen", + "image_upload_success": "¡Imagen cargada exitosamente!", + "no_image_url": "No se encontró ninguna imagen en esa URL.", + "start_before_end_error": "La fecha de inicio debe ser anterior a la fecha de finalización.", + "wiki_image_error": "Error al obtener la imagen de Wikipedia" + }, + "worldtravel": { + "all": "Todo", + "all_subregions": "Todas las subregiones", + "clear_search": "Borrar búsqueda", + "completely_visited": "Completamente visitado", + "no_countries_found": "No se encontraron países", + "not_visited": "No visitado", + "num_countries": "países encontrados", + "partially_visited": "Parcialmente visitado", + "country_list": "Lista de países" + }, + "auth": { + "forgot_password": "¿Has olvidado tu contraseña?", + "login": "Acceso", + "login_error": "No se puede iniciar sesión con las credenciales proporcionadas.", + "password": "Contraseña", + "signup": "Inscribirse", + "username": "Nombre de usuario" } } diff --git a/frontend/src/locales/sv.json b/frontend/src/locales/sv.json new file mode 100644 index 0000000..1a872a7 --- /dev/null +++ b/frontend/src/locales/sv.json @@ -0,0 +1,154 @@ +{ + "about": { + "about": "Om", + "close": "Nära", + "license": "Licensierad under GPL-3.0-licensen.", + "message": "Tillverkad med ❤️ i USA.", + "nominatim_1": "Platssökning och geokodning tillhandahålls av", + "nominatim_2": "Deras data är licensierad under ODbL-licensen.", + "oss_attributions": "Tillskrivningar med öppen källkod", + "other_attributions": "Ytterligare attributioner finns i README-filen.", + "source_code": "Källkod" + }, + "adventures": { + "activities": { + "activity": "Aktivitet 🏄", + "art_museums": "Konst", + "attraction": "Attraktion 🎢", + "culture": "Kultur 🎭", + "dining": "Mat 🍽️", + "event": "Event 🎉", + "festivals": "Festivaler 🎪", + "fitness": "Fitness 🏋️", + "general": "Allmänt 🌍", + "hiking": "Vandring 🥾", + "historical_sites": "Historiska platser 🏛️", + "lodging": "Logi 🛌", + "music_concerts": "Musik", + "nightlife": "Nattliv 🌃", + "other": "Andra", + "outdoor": "Utomhus 🏞️", + "shopping": "Shopping 🛍️", + "spiritual_journeys": "Andliga resor 🧘‍♀️", + "transportation": "Transport 🚗", + "volunteer_work": "Volontärarbete 🤝", + "water_sports": "Vattensporter 🚤", + "wildlife": "Vilda djur 🦒" + }, + "add_to_collection": "Lägg till i samlingen", + "adventure": "Äventyr", + "adventure_delete_confirm": "Är du säker på att du vill ta bort det här äventyret? \nDenna åtgärd kan inte ångras.", + "adventure_delete_success": "Äventyret har raderats!", + "adventure_details": "Äventyrsdetaljer", + "adventure_type": "Äventyrstyp", + "archive": "Arkiv", + "archived": "Arkiverad", + "archived_collection_message": "Samlingen har arkiverats!", + "archived_collections": "Arkiverade samlingar", + "ascending": "Stigande", + "cancel": "Avboka", + "category_filter": "Kategorifilter", + "clear": "Rensa", + "close_filters": "Stäng filter", + "collection": "Samling", + "collection_adventures": "Inkludera samlingsäventyr", + "collection_link_error": "Det gick inte att länka äventyr till samling", + "collection_link_success": "Äventyr kopplat till samling framgångsrikt!", + "collection_remove_error": "Det gick inte att ta bort äventyr från samlingen", + "collection_remove_success": "Äventyret har tagits bort från samlingen!", + "count_txt": "resultat som matchar din sökning", + "create_new": "Skapa nytt...", + "date": "Datum", + "dates": "Datum", + "delete": "Radera", + "delete_adventure": "Ta bort äventyr", + "delete_collection": "Ta bort samling", + "delete_collection_success": "Samlingen har raderats!", + "delete_collection_warning": "Är du säker på att du vill ta bort den här samlingen? \nDetta tar också bort alla länkade äventyr. \nDenna åtgärd kan inte ångras.", + "descending": "Fallande", + "duration": "Varaktighet", + "edit_adventure": "Redigera äventyr", + "edit_collection": "Redigera samling", + "filter": "Filtrera", + "homepage": "Hemsida", + "latitude": "Latitud", + "longitude": "Longitud", + "my_collections": "Mina samlingar", + "name": "Namn", + "no_image_found": "Ingen bild hittades", + "not_found": "Äventyret hittades inte", + "not_found_desc": "Äventyret du letade efter kunde inte hittas. \nProva ett annat äventyr eller kom tillbaka senare.", + "open_details": "Öppna Detaljer", + "open_filters": "Öppna filter", + "order_by": "Beställ efter", + "order_direction": "Beställ riktning", + "planned": "Planerad", + "private": "Privat", + "public": "Offentlig", + "rating": "Gradering", + "remove_from_collection": "Ta bort från samlingen", + "share": "Dela", + "sort": "Sortera", + "sources": "Källor", + "unarchive": "Avarkivera", + "unarchived_collection_message": "Samlingen har tagits bort från arkivet!", + "visit": "Besök", + "visited": "Besökte", + "visits": "Besök" + }, + "home": { + "desc_1": "Upptäck, planera och utforska med lätthet", + "desc_2": "AdventureLog är designad för att förenkla din resa och förse dig med verktyg och resurser för att planera, packa och navigera i ditt nästa oförglömliga äventyr.", + "feature_1": "Reselogg", + "feature_1_desc": "Håll koll på dina äventyr med en personlig reselogg och dela dina upplevelser med vänner och familj.", + "feature_2": "Reseplanering", + "feature_2_desc": "Skapa enkelt anpassade resplaner och få en uppdelning av din resa dag för dag.", + "feature_3": "Resekarta", + "feature_3_desc": "Se dina resor över hela världen med en interaktiv karta och utforska nya destinationer.", + "go_to": "Gå till AdventureLog", + "hero_1": "Upptäck världens mest spännande äventyr", + "hero_2": "Upptäck och planera ditt nästa äventyr med AdventureLog. \nUtforska hisnande destinationer, skapa anpassade resplaner och håll kontakten när du är på språng.", + "key_features": "Nyckelfunktioner" + }, + "navbar": { + "about": "Om AdventureLog", + "adventures": "Äventyr", + "collections": "Samlingar", + "discord": "Disharmoni", + "documentation": "Dokumentation", + "greeting": "Hej", + "login": "Inloggning", + "logout": "Utloggning", + "map": "Karta", + "my_activities": "Mina aktiviteter", + "my_adventures": "Mina äventyr", + "profile": "Profil", + "search": "Söka", + "settings": "Inställningar", + "shared_with_me": "Delade med mig", + "signup": "Registrera dig", + "theme_selection": "Temaval", + "themes": { + "aestetic-dark": "Estetisk mörk", + "aestetic-light": "Estetiskt ljus", + "aqua": "Aqua", + "dark": "Mörk", + "forest": "Skog", + "light": "Ljus", + "night": "Natt" + }, + "users": "Användare", + "worldtravel": "Världsresor" + }, + "worldtravel": { + "all": "Alla", + "all_subregions": "Alla underregioner", + "clear_search": "Rensa sökning", + "completely_visited": "Helt besökt", + "country_list": "Lista över länder", + "no_countries_found": "Inga länder hittades", + "not_visited": "Ej besökt", + "num_countries": "hittade länder", + "partially_visited": "Delvis besökt" + } +} diff --git a/frontend/src/locales/zh.json b/frontend/src/locales/zh.json index 1157d5c..196f076 100644 --- a/frontend/src/locales/zh.json +++ b/frontend/src/locales/zh.json @@ -89,7 +89,20 @@ "unarchived_collection_message": "收藏解压成功!", "updated": "已更新", "visit": "访问", - "visits": "访问量" + "visits": "访问量", + "adventure_delete_success": "冒险删除成功!", + "dates": "枣子", + "delete_adventure": "删除冒险", + "duration": "期间", + "image_removed_error": "删除图像时出错", + "image_removed_success": "图片删除成功!", + "image_upload_error": "上传图片时出错", + "image_upload_success": "图片上传成功!", + "no_image_url": "在该 URL 中找不到图像。", + "planned": "计划", + "start_before_end_error": "开始日期必须早于结束日期", + "visited": "访问过", + "wiki_image_error": "从维基百科获取图像时出错" }, "home": { "desc_1": "轻松发现、规划和探索", @@ -134,5 +147,24 @@ }, "users": "用户", "worldtravel": "环球旅行" + }, + "auth": { + "forgot_password": "忘记密码?", + "login": "登录", + "login_error": "无法使用提供的凭据登录。", + "password": "密码", + "signup": "报名", + "username": "用户名" + }, + "worldtravel": { + "all": "全部", + "all_subregions": "所有次区域", + "clear_search": "清除搜索", + "completely_visited": "已完全访问", + "country_list": "国家列表", + "no_countries_found": "没有找到国家", + "not_visited": "未访问过", + "num_countries": "找到的国家", + "partially_visited": "部分访问" } } diff --git a/frontend/src/routes/+layout.svelte b/frontend/src/routes/+layout.svelte index 015570f..4834290 100644 --- a/frontend/src/routes/+layout.svelte +++ b/frontend/src/routes/+layout.svelte @@ -12,6 +12,7 @@ register('it', () => import('../locales/it.json')); register('zh', () => import('../locales/zh.json')); register('nl', () => import('../locales/nl.json')); + register('sv', () => import('../locales/sv.json')); if (browser) { init({ diff --git a/frontend/src/routes/+page.server.ts b/frontend/src/routes/+page.server.ts index 1afd8c0..7721524 100644 --- a/frontend/src/routes/+page.server.ts +++ b/frontend/src/routes/+page.server.ts @@ -1,5 +1,7 @@ const PUBLIC_SERVER_URL = process.env['PUBLIC_SERVER_URL']; import { redirect, type Actions } from '@sveltejs/kit'; +import type { PageServerLoad } from './$types'; +import { getRandomBackground } from '$lib'; const serverEndpoint = PUBLIC_SERVER_URL || 'http://localhost:8000'; diff --git a/frontend/src/routes/login/+page.svelte b/frontend/src/routes/login/+page.svelte index 336359d..e126f99 100644 --- a/frontend/src/routes/login/+page.svelte +++ b/frontend/src/routes/login/+page.svelte @@ -3,6 +3,7 @@ export let data; console.log(data); + import { t } from 'svelte-i18n'; import FileImageBox from '~icons/mdi/file-image-box'; @@ -32,36 +33,38 @@

AdventureLog

-

Login

+

{$t('auth.login')}

- +
- +
- +
{#if ($page.form?.message && $page.form?.message.length > 1) || $page.form?.type === 'error'}
- {$page.form.message || 'Unable to login with the provided credentials.'} + {$page.form.message || $t('auth.login_error')}
{/if}
diff --git a/frontend/src/routes/worldtravel/+page.svelte b/frontend/src/routes/worldtravel/+page.svelte index c7022f8..d27a676 100644 --- a/frontend/src/routes/worldtravel/+page.svelte +++ b/frontend/src/routes/worldtravel/+page.svelte @@ -2,6 +2,7 @@ import CountryCard from '$lib/components/CountryCard.svelte'; import type { Country } from '$lib/types'; import type { PageData } from './$types'; + import { t } from 'svelte-i18n'; export let data: PageData; console.log(data); @@ -51,10 +52,11 @@ } -

Country List

+

{$t('worldtravel.country_list')}

- {filteredCountries.length} countries found + {filteredCountries.length} + {$t('worldtravel.num_countries')}

@@ -62,7 +64,7 @@ class="join-item btn" type="radio" name="filter" - aria-label="All" + aria-label={$t('worldtravel.all')} checked on:click={() => (filterOption = 'all')} /> @@ -70,26 +72,26 @@ class="join-item btn" type="radio" name="filter" - aria-label="Partially Visited" + aria-label={$t('worldtravel.partially_visited')} on:click={() => (filterOption = 'partial')} /> (filterOption = 'complete')} /> (filterOption = 'not')} />
{#if searchQuery.length > 0}
- +
{/if}
@@ -119,7 +123,7 @@ {#if filteredCountries.length === 0} -

No countries found

+

{$t('worldtravel.no_countries_found')}

{/if}