From 64107e51a0bb9b787ad5daa1793235176190c4c3 Mon Sep 17 00:00:00 2001 From: Xylight Date: Mon, 3 Jun 2024 15:16:48 -0700 Subject: [PATCH 01/54] i18n: localize frontpage's layout --- bun.lockb | Bin 296876 -> 298084 bytes package.json | 1 + src/lib/components/lemmy/SiteCard.svelte | 41 ++++--- .../lemmy/dropdowns/Location.svelte | 11 +- .../components/lemmy/dropdowns/Sort.svelte | 53 ++++---- .../lemmy/dropdowns/ViewSelect.svelte | 11 +- .../components/lemmy/util/SearchBar.svelte | 3 +- src/lib/components/ui/navbar/Navbar.svelte | 29 +++-- src/lib/components/ui/sidebar/Sidebar.svelte | 33 +++-- src/lib/i18n/en.json | 113 ++++++++++++++++++ src/lib/translations.ts | 15 +++ src/routes/+layout.ts | 9 +- src/routes/+page.svelte | 19 +-- 13 files changed, 248 insertions(+), 90 deletions(-) create mode 100644 src/lib/i18n/en.json create mode 100644 src/lib/translations.ts diff --git a/bun.lockb b/bun.lockb index fbbdab7e571c9d24dde234521af8e7362b01f15a..45e1b00d26456976be6df336ff31794267309162 100755 GIT binary patch delta 45028 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 Gtse-pC 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 CLBf>) diff --git a/package.json b/package.json index 7948e74a6..97ac17b93 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,7 @@ "svelte-check": "^3.0.1", "svelte-hero-icons": "^5.0.0", "svelte-tiny-virtual-list": "^2.0.5", + "sveltekit-i18n": "^2.4.2", "tailwindcss": "^3.3.3", "tslib": "^2.4.1", "typescript": "^5.0.0", diff --git a/src/lib/components/lemmy/SiteCard.svelte b/src/lib/components/lemmy/SiteCard.svelte index 17bd15c75..f6398eb63 100644 --- a/src/lib/components/lemmy/SiteCard.svelte +++ b/src/lib/components/lemmy/SiteCard.svelte @@ -2,21 +2,14 @@ import Markdown from '$lib/components/markdown/Markdown.svelte' import Avatar from '$lib/components/ui/Avatar.svelte' import StickyCard from '$lib/components/ui/StickyCard.svelte' - import FormattedNumber from '$lib/components/util/FormattedNumber.svelte' - import RelativeDate from '$lib/components/util/RelativeDate.svelte' - import { publishedToDate } from '$lib/components/util/date.js' - import { getClient } from '$lib/lemmy.js' import type { PersonView, SiteView, Tagline } from 'lemmy-js-client' - import { Button, Disclosure, Popover } from 'mono-svelte' + import { Button } from 'mono-svelte' import { BuildingOffice, - Calendar, ChartBar, - ChatBubbleOvalLeftEllipsis, Icon, InformationCircle, Newspaper, - PencilSquare, ServerStack, UserGroup, } from 'svelte-hero-icons' @@ -24,6 +17,7 @@ import LabelStat from '../ui/LabelStat.svelte' import ItemList from './generic/ItemList.svelte' import { userLink } from '$lib/lemmy/generic' + import { t } from '$lib/translations' export let site: SiteView export let taglines: Tagline[] | undefined = undefined @@ -49,15 +43,25 @@
- - {/if} @@ -143,7 +149,7 @@ color="ghost" loading={saving} disabled={saving} - title={post.saved ? 'Unsave' : 'Save'} + title={post.saved ? $t('post.actions.unsave') : $t('post.actions.save')} > - - Creator + {$t('post.actions.more.creator')} {new URL(post.community.actor_id).hostname}
- Actions + {$t('post.actions.more.actions')} {#if $profile?.user && $profile?.jwt && $profile.user.local_user_view.person.id == post.creator.id} (editing = true)}> - Edit + {$t('post.actions.more.edit')} {/if} {#if $profile?.jwt} @@ -222,7 +232,9 @@ }} > - Mark as {post.read ? 'Unread' : 'Read'} + {post.read + ? $t('post.actions.more.markUnread') + : $t('post.actions.more.markRead')} {/if} - Share + {$t('post.actions.more.share')} {#if $profile?.jwt} - Crosspost + {$t('post.actions.more.crosspost')} {#if $profile.user && post.creator.id == $profile.user.local_user_view.person.id} - {post.post.deleted ? 'Restore' : 'Delete'} + {post.post.deleted + ? $t('post.actions.more.restore') + : $t('post.actions.more.delete')} {/if} {#if $profile.user?.local_user_view.person.id != post.creator.id} report(post)} color="danger-subtle"> - Report + {$t('moderation.report')} {/if} {/if} diff --git a/src/lib/components/ui/Pageination.svelte b/src/lib/components/ui/Pageination.svelte index 94e3c166b..f58a7c9a1 100644 --- a/src/lib/components/ui/Pageination.svelte +++ b/src/lib/components/ui/Pageination.svelte @@ -1,4 +1,5 @@ - {Intl.NumberFormat(locale, options).format(number)} + {Intl.NumberFormat(localeToUse, options).format(number)} diff --git a/src/lib/i18n/en.json b/src/lib/i18n/en.json index 844e7021e..9796c69b3 100644 --- a/src/lib/i18n/en.json +++ b/src/lib/i18n/en.json @@ -93,7 +93,10 @@ "submit": "Submit" }, "routes": { - "frontpage": "Frontpage", + "frontpage": { + "title": "Frontpage", + "footer": "{{users:number}} active {{users; 1:user; default:users;}}" + }, "modlog": "Modlog", "instances": "Instances", "legal": "Legal" @@ -109,5 +112,31 @@ "users": "Users", "posts": "Posts", "communities": "Communities" + }, + "post": { + "actions": { + "comments": "Comments", + "save": "Save", + "unsave": "Unsave", + "more": { + "label": "More Actions", + "edit": "Edit", + "creator": "Creator", + "actions": "Actions", + "markRead": "Mark as Read", + "markUnread": "Mark as Unread", + "share": "Share", + "crosspost": "Crosspost", + "delete": "Delete", + "restore": "Restore" + } + } + }, + "moderation": { + "report": "Report" + }, + "common": { + "back": "Back", + "next": "Next" } } \ No newline at end of file diff --git a/src/lib/settings.ts b/src/lib/settings.ts index 6dc153c95..beb9a5cdc 100644 --- a/src/lib/settings.ts +++ b/src/lib/settings.ts @@ -77,6 +77,7 @@ interface Settings { deduplicateEmbed: boolean compactFeatured: boolean } + language: string | null } export const defaultSettings: Settings = { @@ -128,12 +129,13 @@ export const defaultSettings: Settings = { }, dock: { noGap: toBool(env.PUBLIC_DOCK_PANEL) ?? null, - top: toBool(env.PUBLIC_DOCK_TOP) ?? null + top: toBool(env.PUBLIC_DOCK_TOP) ?? null, }, posts: { deduplicateEmbed: toBool(env.PUBLIC_DEDUPLICATE_EMBED) ?? true, - compactFeatured: toBool(env.PUBLIC_COMPACT_FEATURED) ?? true - } + compactFeatured: toBool(env.PUBLIC_COMPACT_FEATURED) ?? true, + }, + language: null, } export const userSettings = writable(defaultSettings) diff --git a/src/lib/translations.ts b/src/lib/translations.ts index 90f5fcbb3..de9400d5f 100644 --- a/src/lib/translations.ts +++ b/src/lib/translations.ts @@ -8,6 +8,7 @@ const config: Config = { loader: async () => (await import('./i18n/en.json')).default, }, ], + fallbackLocale: 'en', } export const { t, locale, locales, loading, loadTranslations } = new i18n( diff --git a/src/routes/+layout.ts b/src/routes/+layout.ts index 447a691ef..079bd8260 100644 --- a/src/routes/+layout.ts +++ b/src/routes/+layout.ts @@ -1,10 +1,16 @@ import { env } from '$env/dynamic/public' +import { userSettings } from '$lib/settings.js' import { loadTranslations } from '$lib/translations.js' +import { get } from 'svelte/store' export let ssr = (env.PUBLIC_SSR_ENABLED?.toLowerCase() ?? 'false') == 'true' -export const load = async ({ url }) => { - await loadTranslations('en') +export const load = async ({}) => { + const initLocale = get(userSettings)?.language ?? navigator?.language ?? 'en' + + console.log(`Loading locale ${initLocale}`) + + await loadTranslations(initLocale) return } diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index 32b18f35c..dc665895d 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -24,7 +24,7 @@
-
{$t('routes.frontpage')}
+
{$t('routes.frontpage.title')}
@@ -45,11 +45,9 @@ > - - active users + {$t('routes.frontpage.footer', { + users: $site?.site_view.counts.users_active_day ?? '??', + })}
diff --git a/src/routes/settings/+page.svelte b/src/routes/settings/+page.svelte index 67fe6fbda..436f45cce 100644 --- a/src/routes/settings/+page.svelte +++ b/src/routes/settings/+page.svelte @@ -3,7 +3,14 @@ import Setting from './Setting.svelte' import MultiSelect from '$lib/components/input/Switch.svelte' import Sort from '$lib/components/lemmy/dropdowns/Sort.svelte' - import { Disclosure, Material, Switch, TextInput, toast } from 'mono-svelte' + import { + Disclosure, + Material, + Note, + Switch, + TextInput, + toast, + } from 'mono-svelte' import SectionTitle from '$lib/components/ui/SectionTitle.svelte' import Link from '$lib/components/input/Link.svelte' import { @@ -25,6 +32,7 @@ import { removeItem } from '$lib/util.js' import Section from './Section.svelte' import ToggleSetting from './ToggleSetting.svelte' + import { locales } from '$lib/translations' @@ -90,6 +98,22 @@ Go to themes + + Language +

+ The language used for Photon's UI. + + All languages other than US English are community translated, and may + be incomplete! + +

+ +
Post style From 0f0e34d347b31dda2d5738e21fbe7f34052345f0 Mon Sep 17 00:00:00 2001 From: Xylight Date: Mon, 3 Jun 2024 16:01:32 -0700 Subject: [PATCH 03/54] i18n: localize profile menu --- src/lib/components/ui/navbar/Profile.svelte | 42 +++--- src/lib/i18n/fr.json | 142 ++++++++++++++++++++ src/lib/settings.ts | 7 + src/lib/translations.ts | 5 + src/routes/+page.svelte | 1 + 5 files changed, 180 insertions(+), 17 deletions(-) create mode 100644 src/lib/i18n/fr.json diff --git a/src/lib/components/ui/navbar/Profile.svelte b/src/lib/components/ui/navbar/Profile.svelte index 844974fcc..e426816c1 100644 --- a/src/lib/components/ui/navbar/Profile.svelte +++ b/src/lib/components/ui/navbar/Profile.svelte @@ -35,6 +35,7 @@ import { userSettings } from '$lib/settings' import { site } from '$lib/lemmy' import SiteCard from '$lib/components/lemmy/SiteCard.svelte' + import { t } from '$lib/translations' let showInstance = false @@ -59,7 +60,7 @@ class="w-10 h-10 rounded-full ring-1 ring-slate-200 dark:ring-zinc-700 transition-all bg-slate-50 dark:bg-zinc-900 relative hover:dark:brightness-125 hover:brightness {$$props.buttonClass}" - aria-label="Profile" + title={$t('profile.profile')} slot="target" > {#if $profile?.user} @@ -93,15 +94,16 @@ {$profile?.user?.local_user_view?.person.name}
{:else} - Profile + {$t('nav.menu.label')} {/if} {#if $profile?.user} - Profile + + {$t('profile.profile')} - Inbox + {$t('profile.inbox')} {#if $profile.user.notifications.inbox > 0} {$profile.user.notifications.inbox} @@ -109,18 +111,19 @@ {/if} - Saved + + {$t('profile.saved')} {/if} - Accounts + {$t('account.accounts')}
- App + {$t('nav.menu.app')} - Settings + {$t('nav.menu.settings')} - Color Scheme + {$t('nav.menu.colorscheme.label')}
{}}>
- Theme + {$t('nav.menu.theme')} {#if $userSettings.debugInfo} @@ -174,7 +177,7 @@ -
diff --git a/src/lib/i18n/fr.json b/src/lib/i18n/fr.json new file mode 100644 index 000000000..a22daa43b --- /dev/null +++ b/src/lib/i18n/fr.json @@ -0,0 +1,142 @@ +{ + "profile": { + "profile": "Profil", + "inbox": "Boîte de réception", + "saved": "Enregistré", + "subscribed": "Abonné" + }, + "nav": { + "home": "Accueil", + "admin": "Admin", + "moderation": "Modération", + "communities": "Explorer", + "search": "Rechercher", + "create": { + "label": "Créer", + "post": "Post", + "community": "Communauté", + "logingate": "Vous devez vous connecter pour créer du contenu." + }, + "menu": { + "label": "Profil", + "app": "App", + "settings": "Paramètres", + "colorscheme": { + "label": "Schéma de couleurs", + "system": "Système", + "dark": "Sombre", + "light": "Clair" + }, + "theme": "Thème", + "about": "À propos", + "source": "Source", + "donate": "Faire un don", + "instance": "Instance" + } + }, + "account": { + "login": "Se connecter", + "logout": "Se déconnecter", + "signup": "S'inscrire", + "accounts": "Comptes", + "changeinstance": "Changer d'instance" + }, + "filter": { + "location": { + "label": "Lieu", + "all": "Tout", + "local": "Local", + "subscribed": "Abonné", + "moderator": "Modérateur" + }, + "sort": { + "label": "Trier", + "active": "Actif", + "hot": "Populaire", + "top": { + "label": "Top", + "time": { + "label": "Temps", + "all": "Tout", + "9months": "9 Mois", + "6months": "6 Mois", + "3months": "3 Mois", + "month": "Mois", + "week": "Semaine", + "day": "Jour", + "12hours": "12 Heures", + "6hours": "6 Heures", + "hour": "Heure" + } + }, + "new": "Nouveau", + "old": "Ancien", + "controversial": "Controversé", + "scaled": "Adapté", + "mostcomments": "Commentaires", + "newcomments": "Nouvelles réponses" + }, + "view": { + "label": "Vue", + "cozy": "Cosy", + "list": "Liste", + "compact": "Compact", + "legacy": "Ancien" + } + }, + "form": { + "username": "Nom d'utilisateur", + "instance": "URL de l'instance", + "password": "Mot de passe", + "2fa": "Code 2FA", + "forgotpassword": "Mot de passe oublié", + "submit": "Soumettre" + }, + "routes": { + "frontpage": { + "title": "Page d'accueil", + "footer": "{{users:number}} {{users; 1:utilisateur; default:utilisateurs;}} actif(s)" + }, + "modlog": "Modlog", + "instances": "Instances", + "legal": "Légal" + }, + "cards": { + "site": { + "about": "À propos", + "stats": "Statistiques", + "admins": "Admins" + } + }, + "content": { + "users": "Utilisateurs", + "posts": "Posts", + "communities": "Communautés" + }, + "post": { + "actions": { + "comments": "Commentaires", + "save": "Enregistrer", + "unsave": "Désénregistrer", + "more": { + "label": "Plus d'actions", + "edit": "Éditer", + "creator": "Créateur", + "actions": "Actions", + "markRead": "Marquer comme lu", + "markUnread": "Marquer comme non lu", + "share": "Partager", + "crosspost": "Crossposter", + "delete": "Supprimer", + "restore": "Restaurer" + } + } + }, + "moderation": { + "report": "Signaler" + }, + "common": { + "back": "Retour", + "next": "Suivant" + } +} diff --git a/src/lib/settings.ts b/src/lib/settings.ts index beb9a5cdc..ab9c94258 100644 --- a/src/lib/settings.ts +++ b/src/lib/settings.ts @@ -1,6 +1,8 @@ import type { CommentSortType, SortType } from 'lemmy-js-client' import { writable } from 'svelte/store' import { env } from '$env/dynamic/public' +import { locale } from './translations' +import { browser } from '$app/environment' console.log('Using the following default settings from the environment:') console.log(env) @@ -168,4 +170,9 @@ userSettings.subscribe((settings) => { if (typeof window != 'undefined') { localStorage.setItem('settings', JSON.stringify(settings)) } + if (settings.language) { + locale.set(settings.language) + } else { + if (browser) locale.set(navigator?.language) + } }) diff --git a/src/lib/translations.ts b/src/lib/translations.ts index de9400d5f..e0f575f36 100644 --- a/src/lib/translations.ts +++ b/src/lib/translations.ts @@ -7,6 +7,11 @@ const config: Config = { key: '', loader: async () => (await import('./i18n/en.json')).default, }, + { + locale: 'fr', + key: '', + loader: async () => (await import('./i18n/fr.json')).default, + }, ], fallbackLocale: 'en', } diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index dc665895d..5e6dde2e4 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -46,6 +46,7 @@ {$t('routes.frontpage.footer', { + // @ts-ignore users: $site?.site_view.counts.users_active_day ?? '??', })} From f9935cee3241fb9e846a1f3e7aee42272b5803e0 Mon Sep 17 00:00:00 2001 From: Xylight Date: Mon, 3 Jun 2024 16:06:08 -0700 Subject: [PATCH 04/54] i18n: localize post badges --- src/lib/components/lemmy/post/PostMeta.svelte | 35 +++++++++++++------ src/lib/components/util/RelativeDate.svelte | 4 ++- src/lib/i18n/en.json | 10 +++++- src/lib/i18n/fr.json | 8 +++++ 4 files changed, 44 insertions(+), 13 deletions(-) diff --git a/src/lib/components/lemmy/post/PostMeta.svelte b/src/lib/components/lemmy/post/PostMeta.svelte index fa1ff4abe..843c6eba7 100644 --- a/src/lib/components/lemmy/post/PostMeta.svelte +++ b/src/lib/components/lemmy/post/PostMeta.svelte @@ -20,6 +20,7 @@ import ShieldIcon from '../moderation/ShieldIcon.svelte' import { userSettings } from '$lib/settings' import Markdown from '$lib/components/markdown/Markdown.svelte' + import { t } from '$lib/translations' export let community: Community | undefined = undefined export let subscribed: SubscribedType | undefined = undefined @@ -113,36 +114,48 @@ style="grid-area: badges;" > {#if badges.nsfw} - NSFW + {$t('post.badges.nsfw')} {/if} {#if badges.saved} - + - Saved + {$t('post.badges.saved')} {/if} {#if badges.locked} - + - Locked + {$t('post.badges.locked')} {/if} {#if badges.removed} - + - Removed + {$t('post.badges.removed')} {/if} {#if badges.deleted} - + - Deleted + {$t('post.badges.deleted')} {/if} {#if badges.featured} - + - Featured + {$t('post.badges.featured')} {/if} diff --git a/src/lib/components/util/RelativeDate.svelte b/src/lib/components/util/RelativeDate.svelte index f2c6aa429..89a1e6dbe 100644 --- a/src/lib/components/util/RelativeDate.svelte +++ b/src/lib/components/util/RelativeDate.svelte @@ -1,4 +1,6 @@ @@ -17,7 +18,12 @@ '/profile/blocks', '/profile/password', ]} - optionNames={['User', 'Settings', 'Blocks', 'Credentials']} + optionNames={[ + $t('routes.profile.user'), + $t('routes.profile.settings'), + $t('routes.profile.blocks'), + $t('routes.profile.credentials'), + ]} selected={$page.url.pathname} on:select={(e) => { goto(e.detail) diff --git a/src/routes/u/[name]/+page.svelte b/src/routes/u/[name]/+page.svelte index 8a2818078..47f14c6f3 100644 --- a/src/routes/u/[name]/+page.svelte +++ b/src/routes/u/[name]/+page.svelte @@ -44,6 +44,7 @@ import Expandable from '$lib/components/ui/Expandable.svelte' import { communityLink } from '$lib/lemmy/generic.js' import ItemList from '$lib/components/lemmy/generic/ItemList.svelte' + import { t } from '$lib/translations.js' export let data @@ -158,59 +159,7 @@ alt="User banner" /> {/if} -
-
-
- - -
- {#if data.items.length == 0} - - {:else} -
- {#each data.items as item} - {#if isCommentView(item) && (data.type == 'all' || data.type == 'comments')} - - {:else if !isCommentView(item) && (data.type == 'all' || data.type == 'posts')} - - {/if} - {/each} -
- {/if} - searchParam($page.url, 'page', p.detail.toString())} - /> -
- +
{#if (data.moderates ?? []).length > 0} @@ -252,7 +201,7 @@ > - Moderates + {$t('routes.profile.moderates')} ({ @@ -324,4 +273,56 @@
{/if}
+ +
+
+ + +
+ {#if data.items.length == 0} + + {:else} +
+ {#each data.items as item} + {#if isCommentView(item) && (data.type == 'all' || data.type == 'comments')} + + {:else if !isCommentView(item) && (data.type == 'all' || data.type == 'posts')} + + {/if} + {/each} +
+ {/if} + searchParam($page.url, 'page', p.detail.toString())} + /> +
From 8278cff51e812da413dd4cc559d3f4deb08f4f15 Mon Sep 17 00:00:00 2001 From: Xylight Date: Mon, 3 Jun 2024 16:16:24 -0700 Subject: [PATCH 06/54] i18n: localize accounts page --- src/lib/i18n/en.json | 13 ++++++++++--- src/routes/accounts/+page.svelte | 16 ++++++++++------ 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/src/lib/i18n/en.json b/src/lib/i18n/en.json index ec5eaf58a..6830a22c3 100644 --- a/src/lib/i18n/en.json +++ b/src/lib/i18n/en.json @@ -39,7 +39,12 @@ "logout": "Log Out", "signup": "Sign Up", "accounts": "Accounts", - "changeinstance": "Change Instance" + "changeinstance": "Change Instance", + "resetColor": "Reset Color", + "addGuest": "Add Guest", + "moveUp": "Move Up", + "moveDown": "Move Down", + "guest": "Guest" }, "filter": { "location": { @@ -107,7 +112,8 @@ "blocks": "Blocks", "credentials": "Credentials", "moderates": "Moderates" - } + }, + "accounts": "Accounts" }, "cards": { "site": { @@ -155,6 +161,7 @@ }, "common": { "back": "Back", - "next": "Next" + "next": "Next", + "debug": "Debug" } } diff --git a/src/routes/accounts/+page.svelte b/src/routes/accounts/+page.svelte index aa90e9907..99285ddaa 100644 --- a/src/routes/accounts/+page.svelte +++ b/src/routes/accounts/+page.svelte @@ -38,6 +38,8 @@ } from 'svelte-hero-icons' import { flip } from 'svelte/animate' import { expoInOut, expoOut } from 'svelte/easing' + import { t } from '$lib/translations' + import Header from '$lib/components/ui/layout/pages/Header.svelte' let newInstance: string = $profileData.defaultInstance ?? DEFAULT_INSTANCE_URL let loading = false @@ -183,7 +185,7 @@ {:else}
-

Accounts

+
{$t('routes.accounts')}
{ @@ -256,6 +258,7 @@
@@ -298,11 +302,11 @@
From 3d76bb733020f037b60d1506bbbdb460e97dba3e Mon Sep 17 00:00:00 2001 From: Xylight Date: Mon, 3 Jun 2024 16:21:28 -0700 Subject: [PATCH 07/54] i18n: localize login page --- src/lib/i18n/en.json | 4 +++- src/routes/login/+page.svelte | 29 +++++++++++++++-------------- src/routes/login/guest/+page.svelte | 21 +++++++++++---------- 3 files changed, 29 insertions(+), 25 deletions(-) diff --git a/src/lib/i18n/en.json b/src/lib/i18n/en.json index 6830a22c3..f727cbf53 100644 --- a/src/lib/i18n/en.json +++ b/src/lib/i18n/en.json @@ -44,7 +44,8 @@ "addGuest": "Add Guest", "moveUp": "Move Up", "moveDown": "Move Down", - "guest": "Guest" + "guest": "Guest", + "versionGate": "This version of Photon supports instances running {{version}} or higher." }, "filter": { "location": { @@ -92,6 +93,7 @@ }, "form": { "username": "Username", + "name": "Name", "instance": "Instance URL", "password": "Password", "2fa": "2FA Code", diff --git a/src/routes/login/+page.svelte b/src/routes/login/+page.svelte index 77f49273d..82df9e8eb 100644 --- a/src/routes/login/+page.svelte +++ b/src/routes/login/+page.svelte @@ -18,6 +18,8 @@ } from 'svelte-hero-icons' import { DOMAIN_REGEX_FORMS } from '$lib/util.js' import { MINIMUM_VERSION } from '$lib/version.js' + import { t } from '$lib/translations' + import Header from '$lib/components/ui/layout/pages/Header.svelte' let data = { instance: DEFAULT_INSTANCE_URL, @@ -69,14 +71,13 @@
-

Log In

+
{$t('account.login')}
{#if $site && mayBeIncompatible(MINIMUM_VERSION, $site.version.replace('v', ''))} - This version of Photon supports instances running - - v{MINIMUM_VERSION} - - or higher. + {$t('account.versionGate', { + //@ts-ignore + version: `v${MINIMUM_VERSION}`, + })} {/if}
@@ -84,14 +85,14 @@ {#if !LINKED_INSTANCE_URL} - Log In + {$t('account.login')}
diff --git a/src/routes/login/guest/+page.svelte b/src/routes/login/guest/+page.svelte index 4c0178f8a..3d0b62a51 100644 --- a/src/routes/login/guest/+page.svelte +++ b/src/routes/login/guest/+page.svelte @@ -7,10 +7,12 @@ import { profile, profileData, type Profile } from '$lib/auth' import { LINKED_INSTANCE_URL } from '$lib/instance' import { goto } from '$app/navigation' + import { t } from '$lib/translations' + import Header from '$lib/components/ui/layout/pages/Header.svelte' let form = { instance: '', - username: `Guest ${$profileData.profiles.filter((p) => p.jwt == undefined).length + 1}`, + username: `${$t('account.guest')} ${$profileData.profiles.filter((p) => p.jwt == undefined).length + 1}`, loading: false, } @@ -53,21 +55,20 @@
-

Add Guest

+
{$t('account.addGuest')}
{#if $site && mayBeIncompatible(MINIMUM_VERSION, $site.version.replace('v', ''))} - This version of Photon supports instances running - - v{MINIMUM_VERSION} - - or higher. + {$t('account.versionGate', { + //@ts-ignore + version: `v${MINIMUM_VERSION}`, + })} {/if}
- Submit + {$t('form.submit')}
From b626ea34f947227414d0399f7b62a7b12e4b376b Mon Sep 17 00:00:00 2001 From: Xylight Date: Mon, 3 Jun 2024 16:31:46 -0700 Subject: [PATCH 08/54] i18n: localize post layout --- src/lib/i18n/en.json | 17 ++++++++- .../post/[instance]/[id=integer]/+page.svelte | 38 +++++++++---------- 2 files changed, 34 insertions(+), 21 deletions(-) diff --git a/src/lib/i18n/en.json b/src/lib/i18n/en.json index f727cbf53..f7b0d9963 100644 --- a/src/lib/i18n/en.json +++ b/src/lib/i18n/en.json @@ -115,7 +115,22 @@ "credentials": "Credentials", "moderates": "Moderates" }, - "accounts": "Accounts" + "accounts": "Accounts", + "post": { + "crosspostCount": "crossposts", + "commentCount": "comments", + "addComment": "Add a comment", + "scrollToTop": "Scroll to top", + "instanceWarning": "This post was requested from a different server than your account's. Many actions won't work.", + "remoteView": "Remote View", + "localView": "Local View", + "thread": { + "single": "You're viewing a single thread.", + "allComments": "All Comments", + "part": "You're viewing part of a thread.", + "context": "Show Context" + } + } }, "cards": { "site": { diff --git a/src/routes/post/[instance]/[id=integer]/+page.svelte b/src/routes/post/[instance]/[id=integer]/+page.svelte index 83999350b..d8598193d 100644 --- a/src/routes/post/[instance]/[id=integer]/+page.svelte +++ b/src/routes/post/[instance]/[id=integer]/+page.svelte @@ -42,6 +42,7 @@ import Expandable from '$lib/components/ui/Expandable.svelte' import { addResumable } from '$lib/lemmy/item.js' import { Popover } from 'mono-svelte' + import { t } from '$lib/translations.js' export let data @@ -161,11 +162,10 @@ slot="target" class="bg-slate-200 dark:bg-zinc-700 p-0.5 rounded-full text-primary-900 dark:text-primary-100" /> - This post was fetched from a different server than your account's. Many actions - won't work. + {$t('routes.post.instanceWarning')} - Remote View + {$t('routes.post.remoteView')} {#if $profile?.jwt} {/if}
@@ -243,7 +243,7 @@ class="inline-block w-full text-left text-base font-normal" > {post.cross_posts.length} - crossposts + {$t('routes.post.crosspostCount')}

- You're viewing part of a thread. + {$t('routes.post.thread.part')}

{:else if data.thread.singleThread} @@ -285,10 +285,10 @@ flex-wrap gap-4 sticky top-20 w-full box-border z-20 mt-4" >

- You're viewing a single thread. + {$t('routes.post.thread.single')}

{/if} @@ -298,7 +298,7 @@ flex-wrap gap-4 sticky top-20 w-full box-border z-20 mt-4" - comments + {$t('routes.post.commentCount')}
{/if} From 1d5b4d4390c1821b2baa7c432c742e7a9f136df6 Mon Sep 17 00:00:00 2001 From: Xylight Date: Mon, 3 Jun 2024 16:34:02 -0700 Subject: [PATCH 09/54] i18n: localize community card --- .../lemmy/community/CommunityCard.svelte | 14 +++++++++----- src/lib/i18n/en.json | 4 ++++ 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/lib/components/lemmy/community/CommunityCard.svelte b/src/lib/components/lemmy/community/CommunityCard.svelte index 16bfbef59..7c967d689 100644 --- a/src/lib/components/lemmy/community/CommunityCard.svelte +++ b/src/lib/components/lemmy/community/CommunityCard.svelte @@ -46,6 +46,7 @@ import ShieldIcon from '../moderation/ShieldIcon.svelte' import ItemList from '../generic/ItemList.svelte' import { communityLink, userLink } from '$lib/lemmy/generic' + import { t } from '$lib/translations' export let community_view: CommunityView export let moderators: CommunityModeratorView[] = [] @@ -224,23 +225,25 @@ > - About + + {$t('cards.site.about')} - Stats + + {$t('cards.site.stats')}
@@ -250,7 +253,8 @@ {#if moderators && moderators.length > 0} - Moderators + + {$t('cards.community.moderators')} ({ diff --git a/src/lib/i18n/en.json b/src/lib/i18n/en.json index f7b0d9963..80fdcee19 100644 --- a/src/lib/i18n/en.json +++ b/src/lib/i18n/en.json @@ -137,6 +137,10 @@ "about": "About", "stats": "Stats", "admins": "Admins" + }, + "community": { + "members": "Members", + "moderators": "Moderators" } }, "content": { From a421093a232cfeffd8869717a29edb7a6e93c066 Mon Sep 17 00:00:00 2001 From: Xylight Date: Mon, 3 Jun 2024 16:38:24 -0700 Subject: [PATCH 10/54] i18n: localize comments --- .../components/lemmy/comment/Comment.svelte | 7 ++++--- .../lemmy/comment/CommentActions.svelte | 21 ++++++++++++------- src/lib/i18n/en.json | 7 +++++++ 3 files changed, 25 insertions(+), 10 deletions(-) diff --git a/src/lib/components/lemmy/comment/Comment.svelte b/src/lib/components/lemmy/comment/Comment.svelte index 2b09322f9..0a98af0e8 100644 --- a/src/lib/components/lemmy/comment/Comment.svelte +++ b/src/lib/components/lemmy/comment/Comment.svelte @@ -22,6 +22,7 @@ import ShieldIcon from '../moderation/ShieldIcon.svelte' import { page } from '$app/stores' import { onMount } from 'svelte' + import { t } from '$lib/translations' export let node: CommentNodeI export let postId: number @@ -145,7 +146,7 @@ src={Trash} solid size="12" - title="Deleted" + title={$t('post.badges.deleted')} class="text-red-600 dark:text-red-500" /> {/if} @@ -154,7 +155,7 @@ src={Bookmark} solid size="12" - title="Saved" + title={$t('post.badges.saved')} class="text-yellow-600 dark:text-yellow-500" /> {/if} @@ -181,7 +182,7 @@
-

Reply

+

{$t('comment.reply')}

- Actions + {$t('comment.actions.label')} { navigator.share?.({ @@ -76,13 +77,13 @@ }} > - Copy Link +
{$t('comment.actions.link')}
{#if $profile?.jwt} {#if comment.creator.id == $profile.user?.local_user_view.person.id} dispatcher('edit', comment)}> - Edit + {$t('post.actions.more.edit')} {/if} - {comment.saved ? 'Unsave' : 'Save'} + + {comment.saved ? $t('post.actions.unsave') : $t('post.actions.save')} + {#if $profile?.user && $profile.jwt && $profile.user.local_user_view.person.id == comment.creator.id} - {comment.comment.deleted ? 'Restore' : 'Delete'} + + {comment.comment.deleted + ? $t('post.actions.more.restore') + : $t('post.actions.more.delete')} + {/if} {#if $profile.jwt && $profile.user?.local_user_view.person.id != comment.creator.id} report(comment)} color="danger-subtle"> - Report + {$t('moderation.report')} {/if} {/if} diff --git a/src/lib/i18n/en.json b/src/lib/i18n/en.json index 80fdcee19..1aacd60a6 100644 --- a/src/lib/i18n/en.json +++ b/src/lib/i18n/en.json @@ -177,6 +177,13 @@ "saved": "Saved" } }, + "comment": { + "reply": "Reply", + "actions": { + "label": "Actions", + "link": "Copy Link" + } + }, "moderation": { "report": "Report" }, From 2aaacf07a7ce6df5de761186adbec629ae20c0ff Mon Sep 17 00:00:00 2001 From: Xylight Date: Mon, 3 Jun 2024 16:41:45 -0700 Subject: [PATCH 11/54] i18n: localize comment form --- src/lib/components/lemmy/comment/CommentForm.svelte | 5 +++-- src/lib/components/markdown/MarkdownEditor.svelte | 3 ++- src/lib/i18n/en.json | 7 +++++-- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/lib/components/lemmy/comment/CommentForm.svelte b/src/lib/components/lemmy/comment/CommentForm.svelte index 20109510e..907503c53 100644 --- a/src/lib/components/lemmy/comment/CommentForm.svelte +++ b/src/lib/components/lemmy/comment/CommentForm.svelte @@ -8,6 +8,7 @@ import MarkdownEditor from '$lib/components/markdown/MarkdownEditor.svelte' import { placeholders } from '$lib/util.js' import { Button } from 'mono-svelte' + import { t } from '$lib/translations' export let postId: number export let parentId: number | undefined = undefined @@ -69,7 +70,7 @@ {...$$restProps} {rows} placeholder={locked - ? 'This post is locked.' + ? $t('comment.locked') : placeholder ?? placeholders.get('comment')} bind:value disabled={locked || loading} @@ -92,7 +93,7 @@ {loading} disabled={locked || loading} > - Submit + {$t('form.submit')}
{/if} diff --git a/src/lib/components/markdown/MarkdownEditor.svelte b/src/lib/components/markdown/MarkdownEditor.svelte index 065b9feee..6e34d4f45 100644 --- a/src/lib/components/markdown/MarkdownEditor.svelte +++ b/src/lib/components/markdown/MarkdownEditor.svelte @@ -2,6 +2,7 @@ import { profile } from '$lib/auth.js' import MultiSelect from '$lib/components/input/Switch.svelte' import Markdown from '$lib/components/markdown/Markdown.svelte' + import { t } from '$lib/translations' import { uploadImage } from '$lib/util.js' import { ImageInput, toast } from 'mono-svelte' import { Button, Label, Modal, TextArea } from 'mono-svelte' @@ -317,7 +318,7 @@ overflow-hidden transition-colors" {/if} diff --git a/src/lib/i18n/en.json b/src/lib/i18n/en.json index 1aacd60a6..5f6c87fff 100644 --- a/src/lib/i18n/en.json +++ b/src/lib/i18n/en.json @@ -98,7 +98,9 @@ "password": "Password", "2fa": "2FA Code", "forgotpassword": "Forgot Password", - "submit": "Submit" + "submit": "Submit", + "edit": "Edit", + "preview": "Preview" }, "routes": { "frontpage": { @@ -182,7 +184,8 @@ "actions": { "label": "Actions", "link": "Copy Link" - } + }, + "locked": "This post is locked." }, "moderation": { "report": "Report" From 9089dd9ac39840e0219add117b8d0460d0a57885 Mon Sep 17 00:00:00 2001 From: Xylight Date: Mon, 3 Jun 2024 16:54:32 -0700 Subject: [PATCH 12/54] i18n: localize explore and search pages --- .../components/ui/layout/pages/Header.svelte | 2 +- src/lib/i18n/en.json | 11 +++++++ src/routes/communities/+page.svelte | 30 +++++++------------ src/routes/search/+page.svelte | 30 +++++++++---------- 4 files changed, 36 insertions(+), 37 deletions(-) diff --git a/src/lib/components/ui/layout/pages/Header.svelte b/src/lib/components/ui/layout/pages/Header.svelte index 8a37efb58..2d8e3ac97 100644 --- a/src/lib/components/ui/layout/pages/Header.svelte +++ b/src/lib/components/ui/layout/pages/Header.svelte @@ -1,3 +1,3 @@ -

+

diff --git a/src/lib/i18n/en.json b/src/lib/i18n/en.json index 5f6c87fff..496bf256a 100644 --- a/src/lib/i18n/en.json +++ b/src/lib/i18n/en.json @@ -118,6 +118,17 @@ "moderates": "Moderates" }, "accounts": "Accounts", + "communities": "Communities", + "search": { + "title": "Search", + "federating": "Federating", + "query": "Query", + "noResults": { + "title": "No Results", + "description": "There are no results that match that filter. Try refining your search.", + "alt": "Search across the fediverse" + } + }, "post": { "crosspostCount": "crossposts", "commentCount": "comments", diff --git a/src/routes/communities/+page.svelte b/src/routes/communities/+page.svelte index 9d534f592..871d3e6b0 100644 --- a/src/routes/communities/+page.svelte +++ b/src/routes/communities/+page.svelte @@ -13,6 +13,9 @@ import Sort from '$lib/components/lemmy/dropdowns/Sort.svelte' import Placeholder from '$lib/components/ui/Placeholder.svelte' import CommunityItem from '$lib/components/lemmy/community/CommunityItem.svelte' + import Location from '$lib/components/lemmy/dropdowns/Location.svelte' + import { t } from '$lib/translations.js' + import Header from '$lib/components/ui/layout/pages/Header.svelte' export let data @@ -24,8 +27,8 @@ Communities -

- Communities +
+ {$t('routes.communities')} -

+
- +
searchParam($page.url, 'q', search, 'page')} @@ -73,8 +65,7 @@ >
{:then object} {#if object} From 44418961347b6e97111058e7304e64011e9fdb37 Mon Sep 17 00:00:00 2001 From: Xylight Date: Mon, 3 Jun 2024 17:19:46 -0700 Subject: [PATCH 13/54] i18n: localize post form --- .../lemmy/comment/CommentActions.svelte | 2 +- src/lib/components/lemmy/post/PostForm.svelte | 23 ++-- src/lib/i18n/en.json | 28 ++++- src/lib/i18n/fr.json | 113 ++++++++++++++---- 4 files changed, 129 insertions(+), 37 deletions(-) diff --git a/src/lib/components/lemmy/comment/CommentActions.svelte b/src/lib/components/lemmy/comment/CommentActions.svelte index 2a35a4c21..697d71fde 100644 --- a/src/lib/components/lemmy/comment/CommentActions.svelte +++ b/src/lib/components/lemmy/comment/CommentActions.svelte @@ -48,7 +48,7 @@ disabled={comment.post.locked} > - Reply + {$t('comment.reply')} {#if $profile?.user && (amMod($profile?.user, comment.community) || isAdmin($profile.user))} diff --git a/src/lib/components/lemmy/post/PostForm.svelte b/src/lib/components/lemmy/post/PostForm.svelte index 628ec7736..b2594476f 100644 --- a/src/lib/components/lemmy/post/PostForm.svelte +++ b/src/lib/components/lemmy/post/PostForm.svelte @@ -19,6 +19,7 @@ import ObjectAutocomplete from '$lib/components/lemmy/ObjectAutocomplete.svelte' import { Button } from 'mono-svelte' import Avatar from '$lib/components/ui/Avatar.svelte' + import { t } from '$lib/translations' export let edit = false @@ -217,7 +218,7 @@

- {edit ? 'Edit' : 'Create'} Post + {edit ? $t('form.post.edit') : $t('form.post.create')}

{#if !edit && data} @@ -227,7 +228,7 @@ bind:items={communities} jwt={$profile?.jwt} listing_type="All" - label="Community" + label={$t('form.post.community')} required on:select={(e) => { const c = e.detail @@ -243,7 +244,7 @@ /> {:else}
- Community + {$t('form.post.community')}
- NSFW + {$t('form.post.nsfw')}
{#if !edit} diff --git a/src/lib/i18n/en.json b/src/lib/i18n/en.json index 496bf256a..9bd31eb9c 100644 --- a/src/lib/i18n/en.json +++ b/src/lib/i18n/en.json @@ -89,7 +89,8 @@ "compact": "Compact", "legacy": "Legacy" }, - "type": "Type" + "type": "Type", + "filter": "Filter" }, "form": { "username": "Username", @@ -100,7 +101,18 @@ "forgotpassword": "Forgot Password", "submit": "Submit", "edit": "Edit", - "preview": "Preview" + "preview": "Preview", + "post": { + "create": "Create Post", + "edit": "Edit Post", + "community": "Community", + "title": "Title", + "url": "URL", + "body": "Body", + "nsfw": "NSFW", + "generateTitle": "Generate Title", + "uploadImage": "Upload Image" + } }, "routes": { "frontpage": { @@ -129,6 +141,7 @@ "alt": "Search across the fediverse" } }, + "createPost": "Create Post", "post": { "crosspostCount": "crossposts", "commentCount": "comments", @@ -143,6 +156,14 @@ "part": "You're viewing part of a thread.", "context": "Show Context" } + }, + "inbox": { + "title": "Inbox", + "markAsRead": "Mark All Read", + "empty": { + "title": "No new notifications", + "description": "Messages, replies, and mentions will appear here." + } } }, "cards": { @@ -204,6 +225,7 @@ "common": { "back": "Back", "next": "Next", - "debug": "Debug" + "debug": "Debug", + "refresh": "Refresh" } } diff --git a/src/lib/i18n/fr.json b/src/lib/i18n/fr.json index c61452e7b..11bf994e9 100644 --- a/src/lib/i18n/fr.json +++ b/src/lib/i18n/fr.json @@ -7,19 +7,19 @@ }, "nav": { "home": "Accueil", - "admin": "Admin", + "admin": "Administration", "moderation": "Modération", "communities": "Explorer", "search": "Rechercher", "create": { "label": "Créer", - "post": "Post", + "post": "Publication", "community": "Communauté", "logingate": "Vous devez vous connecter pour créer du contenu." }, "menu": { "label": "Profil", - "app": "App", + "app": "Application", "settings": "Paramètres", "colorscheme": { "label": "Schéma de couleurs", @@ -39,7 +39,13 @@ "logout": "Se déconnecter", "signup": "S'inscrire", "accounts": "Comptes", - "changeinstance": "Changer d'instance" + "changeinstance": "Changer d'instance", + "resetColor": "Réinitialiser la couleur", + "addGuest": "Ajouter un invité", + "moveUp": "Monter", + "moveDown": "Descendre", + "guest": "Invité", + "versionGate": "Cette version de Photon prend en charge les instances exécutant {{version}} ou une version supérieure." }, "filter": { "location": { @@ -58,60 +64,114 @@ "time": { "label": "Temps", "all": "Tout", - "9months": "9 Mois", - "6months": "6 Mois", - "3months": "3 Mois", + "9months": "9 mois", + "6months": "6 mois", + "3months": "3 mois", "month": "Mois", "week": "Semaine", "day": "Jour", - "12hours": "12 Heures", - "6hours": "6 Heures", + "12hours": "12 heures", + "6hours": "6 heures", "hour": "Heure" } }, "new": "Nouveau", "old": "Ancien", "controversial": "Controversé", - "scaled": "Adapté", + "scaled": "Redimensionné", "mostcomments": "Commentaires", "newcomments": "Nouvelles réponses" }, "view": { "label": "Vue", - "cozy": "Cosy", + "cozy": "Confortable", "list": "Liste", "compact": "Compact", - "legacy": "Ancien" - } + "legacy": "Hérité" + }, + "type": "Type" }, "form": { "username": "Nom d'utilisateur", + "name": "Nom", "instance": "URL de l'instance", "password": "Mot de passe", "2fa": "Code 2FA", "forgotpassword": "Mot de passe oublié", - "submit": "Soumettre" + "submit": "Soumettre", + "edit": "Modifier", + "preview": "Aperçu", + "post": { + "create": "Créer une publication", + "edit": "Modifier la publication", + "community": "Communauté", + "title": "Titre", + "url": "URL", + "body": "Corps", + "nsfw": "NSFW", + "generateTitle": "Générer le titre", + "uploadImage": "Télécharger une image" + } }, "routes": { "frontpage": { "title": "Page d'accueil", "footer": "{{users:number}} {{users; 1:utilisateur; default:utilisateurs;}} actif(s)" }, - "modlog": "Modlog", + "modlog": "Journal de modération", "instances": "Instances", - "legal": "Légal" + "legal": "Mentions légales", + "profile": { + "user": "Utilisateur", + "settings": "Paramètres", + "blocks": "Bloqués", + "credentials": "Informations d'identification", + "moderates": "Modère" + }, + "accounts": "Comptes", + "communities": "Communautés", + "search": { + "title": "Rechercher", + "federating": "Fédérer", + "query": "Requête", + "noResults": { + "title": "Aucun résultat", + "description": "Il n'y a aucun résultat correspondant à ce filtre. Essayez d'affiner votre recherche.", + "alt": "Rechercher dans le fediverse" + } + }, + "createPost": "Créer une publication", + "post": { + "crosspostCount": "rediffusions", + "commentCount": "commentaires", + "addComment": "Ajouter un commentaire", + "scrollToTop": "Défiler vers le haut", + "instanceWarning": "Cette publication a été demandée à partir d'un serveur différent de celui de votre compte. De nombreuses actions ne fonctionneront pas.", + "remoteView": "Vue distante", + "localView": "Vue locale", + "thread": { + "single": "Vous visualisez un fil unique.", + "allComments": "Tous les commentaires", + "part": "Vous visualisez une partie d'un fil.", + "context": "Afficher le contexte" + } + } }, "cards": { "site": { "about": "À propos", "stats": "Statistiques", - "admins": "Admins" + "admins": "Administrateurs" + }, + "community": { + "members": "Membres", + "moderators": "Modérateurs" } }, "content": { - "users": "Utilisateurs", "all": "Tout", - "posts": "Posts", + "users": "Utilisateurs", + "posts": "Publications", "comments": "Commentaires", "communities": "Communautés" }, @@ -122,13 +182,13 @@ "unsave": "Désénregistrer", "more": { "label": "Plus d'actions", - "edit": "Éditer", + "edit": "Modifier", "creator": "Créateur", "actions": "Actions", "markRead": "Marquer comme lu", "markUnread": "Marquer comme non lu", "share": "Partager", - "crosspost": "Crossposter", + "crosspost": "Republier", "delete": "Supprimer", "restore": "Restaurer" } @@ -142,11 +202,20 @@ "saved": "Enregistré" } }, + "comment": { + "reply": "Répondre", + "actions": { + "label": "Actions", + "link": "Copier le lien" + }, + "locked": "Cette publication est verrouillée." + }, "moderation": { "report": "Signaler" }, "common": { "back": "Retour", - "next": "Suivant" + "next": "Suivant", + "debug": "Débogage" } } From 92c57db80b41929a82068ef25a19eba979089824 Mon Sep 17 00:00:00 2001 From: Xylight Date: Mon, 3 Jun 2024 17:26:02 -0700 Subject: [PATCH 14/54] i18n: localize inbox --- .../components/ui/layout/pages/Header.svelte | 2 +- src/lib/i18n/en.json | 11 ++++++-- src/routes/inbox/+page.svelte | 28 ++++++++++--------- src/routes/inbox/InboxItem.svelte | 4 ++- 4 files changed, 28 insertions(+), 17 deletions(-) diff --git a/src/lib/components/ui/layout/pages/Header.svelte b/src/lib/components/ui/layout/pages/Header.svelte index 2d8e3ac97..77a508976 100644 --- a/src/lib/components/ui/layout/pages/Header.svelte +++ b/src/lib/components/ui/layout/pages/Header.svelte @@ -1,3 +1,3 @@ -

+

diff --git a/src/lib/i18n/en.json b/src/lib/i18n/en.json index 9bd31eb9c..963f6fce0 100644 --- a/src/lib/i18n/en.json +++ b/src/lib/i18n/en.json @@ -90,7 +90,13 @@ "legacy": "Legacy" }, "type": "Type", - "filter": "Filter" + "filter": "Filter", + "unread": "Unread", + "inbox": { + "messages": "Messages", + "replies": "Replies", + "mentions": "Mentions" + } }, "form": { "username": "Username", @@ -226,6 +232,7 @@ "back": "Back", "next": "Next", "debug": "Debug", - "refresh": "Refresh" + "refresh": "Refresh", + "jump": "Jump" } } diff --git a/src/routes/inbox/+page.svelte b/src/routes/inbox/+page.svelte index 8081c02d1..377e609d6 100644 --- a/src/routes/inbox/+page.svelte +++ b/src/routes/inbox/+page.svelte @@ -19,6 +19,8 @@ import { searchParam } from '$lib/util.js' import { Button, Select } from 'mono-svelte' import EndPlaceholder from '$lib/components/ui/EndPlaceholder.svelte' + import Header from '$lib/components/ui/layout/pages/Header.svelte' + import { t } from '$lib/translations' export let data @@ -51,11 +53,11 @@
-

Inbox

+
{$t('routes.inbox.title')}
@@ -67,7 +69,7 @@ class="!h-8" > - Mark All Read + {$t('routes.inbox.markAsRead')}
@@ -84,10 +86,10 @@ > - Filter + {$t('filter.filter')} - - + +
{#if !data.data || (data.data?.length ?? 0) == 0} {:else} {#each data.data as item} diff --git a/src/routes/inbox/InboxItem.svelte b/src/routes/inbox/InboxItem.svelte index b2d0f6a4c..6f1b069da 100644 --- a/src/routes/inbox/InboxItem.svelte +++ b/src/routes/inbox/InboxItem.svelte @@ -21,6 +21,7 @@ import type { InboxItem } from '$lib/lemmy/inbox.js' import PrivateMessage from '$lib/components/lemmy/inbox/PrivateMessage.svelte' import PrivateMessageModal from '$lib/components/lemmy/modal/PrivateMessageModal.svelte' + import { t } from '$lib/translations' export let item: InboxItem @@ -104,6 +105,7 @@ {loading} disabled={loading} on:click={() => markAsRead(!item.read)} + title={$t('post.actions.more.markRead')} > @@ -117,7 +119,7 @@ {/if} {:else} {:else}
-
From c6c53095df3215a14fd83f52197266b5f9e39300 Mon Sep 17 00:00:00 2001 From: Xylight Date: Mon, 3 Jun 2024 18:09:26 -0700 Subject: [PATCH 21/54] i18n: localize moderation --- src/lib/i18n/en.json | 10 ++++++++++ src/routes/moderation/+page.svelte | 16 +++++++++------- src/routes/moderation/Report.svelte | 6 +++--- 3 files changed, 22 insertions(+), 10 deletions(-) diff --git a/src/lib/i18n/en.json b/src/lib/i18n/en.json index b76151782..3ed85f23b 100644 --- a/src/lib/i18n/en.json +++ b/src/lib/i18n/en.json @@ -215,6 +215,16 @@ "title": "No new notifications", "description": "Messages, replies, and mentions will appear here." } + }, + "moderation": { + "title": "Moderation", + "empty": { + "title": "No new reports", + "description": "When submissions are reported, you can act on them here." + }, + "reason": "Reason", + "resolve": "Resolve", + "unresolve": "Unresolve" } }, "cards": { diff --git a/src/routes/moderation/+page.svelte b/src/routes/moderation/+page.svelte index 1f2902d06..8ad052dc9 100644 --- a/src/routes/moderation/+page.svelte +++ b/src/routes/moderation/+page.svelte @@ -14,12 +14,14 @@ import Placeholder from '$lib/components/ui/Placeholder.svelte' import { searchParam } from '$lib/util.js' import { Button, Material, Select } from 'mono-svelte' + import { t } from '$lib/translations' + import Header from '$lib/components/ui/layout/pages/Header.svelte' export let data
-

Moderation

+
{$t('routes.moderation.title')}
@@ -60,7 +62,7 @@ {:else} {/if} diff --git a/src/routes/moderation/Report.svelte b/src/routes/moderation/Report.svelte index f5ab3f93e..fafc76bd3 100644 --- a/src/routes/moderation/Report.svelte +++ b/src/routes/moderation/Report.svelte @@ -14,6 +14,7 @@ import { Button } from 'mono-svelte' import type { ReportView } from '$lib/lemmy/report.js' import PrivateMessage from '$lib/components/lemmy/inbox/PrivateMessage.svelte' + import { t } from '$lib/translations' export let item: ReportView @@ -105,7 +106,7 @@
- Reason + {$t('routes.moderation.reason')}

{item.reason} @@ -116,8 +117,7 @@ class="w-8 h-8 !p-1 ml-auto {item.resolved ? '!text-green-600 dark:!text-green-400' : ''}" - aria-label="Resolve" - title="Resolve" + title={$t('routes.moderation.resolve')} loading={resolving} disabled={resolving} > From 0cad34651bcb92d00bad5149de5fac2fb642dbf5 Mon Sep 17 00:00:00 2001 From: Xylight Date: Tue, 4 Jun 2024 10:37:20 -0700 Subject: [PATCH 22/54] i18n: remove test translations --- src/lib/i18n/fr.json | 222 ---------------------------------------- src/lib/translations.ts | 5 - 2 files changed, 227 deletions(-) delete mode 100644 src/lib/i18n/fr.json diff --git a/src/lib/i18n/fr.json b/src/lib/i18n/fr.json deleted file mode 100644 index 8533ae0c7..000000000 --- a/src/lib/i18n/fr.json +++ /dev/null @@ -1,222 +0,0 @@ -{ - "profile": { - "profile": "Profil", - "inbox": "Boîte de réception", - "saved": "Enregistré", - "subscribed": "Abonné" - }, - "nav": { - "home": "Accueil", - "admin": "Administration", - "moderation": "Modération", - "communities": "Explorer", - "search": "Rechercher", - "create": { - "label": "Créer", - "post": "Publication", - "community": "Communauté", - "logingate": "Vous devez vous connecter pour créer du contenu." - }, - "menu": { - "label": "Profil", - "app": "Application", - "settings": "Paramètres", - "colorscheme": { - "label": "Schéma de couleurs", - "system": "Système", - "dark": "Sombre", - "light": "Clair" - }, - "theme": "Thème", - "about": "À propos", - "source": "Source", - "donate": "Faire un don", - "instance": "Instance" - } - }, - "account": { - "login": "Se connecter", - "logout": "Se déconnecter", - "signup": "S'inscrire", - "accounts": "Comptes", - "changeinstance": "Changer d'instance", - "resetColor": "Réinitialiser la couleur", - "addGuest": "Ajouter un invité", - "moveUp": "Monter", - "moveDown": "Descendre", - "guest": "Invité", - "versionGate": "Cette version de Photon prend en charge les instances exécutant {{version}} ou une version supérieure." - }, - "filter": { - "location": { - "label": "Lieu", - "all": "Tout", - "local": "Local", - "subscribed": "Abonné", - "moderator": "Modérateur" - }, - "sort": { - "label": "Trier", - "active": "Actif", - "hot": "Populaire", - "top": { - "label": "Top", - "time": { - "label": "Temps", - "all": "Tout", - "9months": "9 mois", - "6months": "6 mois", - "3months": "3 mois", - "month": "Mois", - "week": "Semaine", - "day": "Jour", - "12hours": "12 heures", - "6hours": "6 heures", - "hour": "Heure" - } - }, - "new": "Nouveau", - "old": "Ancien", - "controversial": "Controversé", - "scaled": "Redimensionné", - "mostcomments": "Commentaires", - "newcomments": "Nouvelles réponses" - }, - "view": { - "label": "Vue", - "cozy": "Confortable", - "list": "Liste", - "compact": "Compact", - "legacy": "Hérité" - }, - "type": "Type" - }, - "form": { - "username": "Nom d'utilisateur", - "name": "Nom", - "instance": "URL de l'instance", - "password": "Mot de passe", - "2fa": "Code 2FA", - "forgotpassword": "Mot de passe oublié", - "submit": "Soumettre", - "edit": "Modifier", - "preview": "Aperçu", - "email": "Email", - "post": { - "create": "Créer une publication", - "edit": "Modifier la publication", - "community": "Communauté", - "title": "Titre", - "url": "URL", - "body": "Corps", - "nsfw": "NSFW", - "generateTitle": "Générer le titre", - "uploadImage": "Télécharger une image" - } - }, - "routes": { - "frontpage": { - "title": "Page d'accueil", - "footer": "{{users:number}} {{users; 1:utilisateur; default:utilisateurs;}} actif(s)" - }, - "modlog": "Journal de modération", - "instances": "Instances", - "legal": "Mentions légales", - "profile": { - "user": "Utilisateur", - "settings": "Paramètres", - "blocks": "Bloqués", - "credentials": "Informations d'identification", - "moderates": "Modère" - }, - "accounts": "Comptes", - "communities": "Communautés", - "search": { - "title": "Rechercher", - "federating": "Fédérer", - "query": "Requête", - "noResults": { - "title": "Aucun résultat", - "description": "Il n'y a aucun résultat correspondant à ce filtre. Essayez d'affiner votre recherche.", - "alt": "Rechercher dans le fediverse" - } - }, - "createPost": "Créer une publication", - "post": { - "crosspostCount": "rediffusions", - "commentCount": "commentaires", - "addComment": "Ajouter un commentaire", - "scrollToTop": "Défiler vers le haut", - "instanceWarning": "Cette publication a été demandée à partir d'un serveur différent de celui de votre compte. De nombreuses actions ne fonctionneront pas.", - "remoteView": "Vue distante", - "localView": "Vue locale", - "thread": { - "single": "Vous visualisez un fil unique.", - "allComments": "Tous les commentaires", - "part": "Vous visualisez une partie d'un fil.", - "context": "Afficher le contexte" - } - } - }, - "cards": { - "site": { - "about": "À propos", - "stats": "Statistiques", - "admins": "Administrateurs" - }, - "community": { - "members": "Membres", - "moderators": "Modérateurs" - } - }, - "content": { - "all": "Tout", - "users": "Utilisateurs", - "posts": "Publications", - "comments": "Commentaires", - "communities": "Communautés" - }, - "post": { - "actions": { - "comments": "Commentaires", - "save": "Enregistrer", - "unsave": "Désénregistrer", - "more": { - "label": "Plus d'actions", - "edit": "Modifier", - "creator": "Créateur", - "actions": "Actions", - "markRead": "Marquer comme lu", - "markUnread": "Marquer comme non lu", - "share": "Partager", - "crosspost": "Republier", - "delete": "Supprimer", - "restore": "Restaurer" - } - }, - "badges": { - "nsfw": "NSFW", - "locked": "Verrouillé", - "featured": "En vedette", - "removed": "Supprimé", - "deleted": "Supprimé", - "saved": "Enregistré" - } - }, - "comment": { - "reply": "Répondre", - "actions": { - "label": "Actions", - "link": "Copier le lien" - }, - "locked": "Cette publication est verrouillée." - }, - "moderation": { - "report": "Signaler" - }, - "common": { - "back": "Retour", - "next": "Suivant", - "debug": "Débogage" - } -} diff --git a/src/lib/translations.ts b/src/lib/translations.ts index e0f575f36..de9400d5f 100644 --- a/src/lib/translations.ts +++ b/src/lib/translations.ts @@ -7,11 +7,6 @@ const config: Config = { key: '', loader: async () => (await import('./i18n/en.json')).default, }, - { - locale: 'fr', - key: '', - loader: async () => (await import('./i18n/fr.json')).default, - }, ], fallbackLocale: 'en', } From 53d4e4bfa3fa5bcaaa9b31b4feffb9202c9b2366 Mon Sep 17 00:00:00 2001 From: Xylight Date: Tue, 4 Jun 2024 10:44:16 -0700 Subject: [PATCH 23/54] i18n: localize verify email page --- src/lib/i18n/en.json | 8 ++++++++ src/routes/verify_email/[token]/+error.svelte | 7 +++++-- src/routes/verify_email/[token]/+page.svelte | 5 +++-- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/lib/i18n/en.json b/src/lib/i18n/en.json index 3ed85f23b..fd583eaf3 100644 --- a/src/lib/i18n/en.json +++ b/src/lib/i18n/en.json @@ -225,6 +225,10 @@ "reason": "Reason", "resolve": "Resolve", "unresolve": "Unresolve" + }, + "verifyEmail": { + "message": "Your email was verified. You can now close this window.", + "error": "Failed to verify your email." } }, "cards": { @@ -304,5 +308,9 @@ "disabled": "Disabled", "enable": "Enable", "disable": "Disable" + }, + "message": { + "success": "Success", + "error": "Error" } } diff --git a/src/routes/verify_email/[token]/+error.svelte b/src/routes/verify_email/[token]/+error.svelte index 9cf26a4f5..8cdecd70f 100644 --- a/src/routes/verify_email/[token]/+error.svelte +++ b/src/routes/verify_email/[token]/+error.svelte @@ -1,5 +1,6 @@ @@ -9,7 +10,9 @@ >

-

Error

-

Failed to verify your email.

+

+ {$t('message.error')} +

+

{$t('routes.verifyEmail.error')}

{$page.error?.message}
diff --git a/src/routes/verify_email/[token]/+page.svelte b/src/routes/verify_email/[token]/+page.svelte index 60973023c..6fab2cbd1 100644 --- a/src/routes/verify_email/[token]/+page.svelte +++ b/src/routes/verify_email/[token]/+page.svelte @@ -1,5 +1,6 @@ @@ -10,10 +11,10 @@

- Success + {$t('message.success')}

- Your email was verified. You can safely close this window. + {$t('routes.verifyEmail.message')}

{#if !LINKED_INSTANCE_URL}

From 999804279598f2b87d123289cb59b035516f0011 Mon Sep 17 00:00:00 2001 From: Xylight Date: Tue, 4 Jun 2024 10:51:25 -0700 Subject: [PATCH 24/54] i18n: localize account pages --- src/lib/i18n/en.json | 14 +++++++++++++- src/routes/legal/+page.svelte | 18 ++++-------------- src/routes/login_reset/+page.svelte | 12 ++++++------ .../password_change/[token]/+error.svelte | 8 ++++---- .../password_change/[token]/+page.svelte | 16 ++++++++-------- 5 files changed, 35 insertions(+), 33 deletions(-) diff --git a/src/lib/i18n/en.json b/src/lib/i18n/en.json index fd583eaf3..3c03568f1 100644 --- a/src/lib/i18n/en.json +++ b/src/lib/i18n/en.json @@ -171,7 +171,10 @@ }, "modlog": "Modlog", "instances": "Instances", - "legal": "Legal", + "legal": { + "title": "Legal", + "noLegal": "This instance does not have any legal information." + }, "profile": { "user": "User", "settings": "Settings", @@ -229,6 +232,15 @@ "verifyEmail": { "message": "Your email was verified. You can now close this window.", "error": "Failed to verify your email." + }, + "passwordChange": { + "title": "Change Password", + "description": "Choose your new password.", + "instance": "Which instance is your account hosted on?" + }, + "resetLogin": { + "title": "Reset Password", + "description": "Enter your account's email, and a password reset link will be sent. If your account does not have an email, contact your instance admins." } }, "cards": { diff --git a/src/routes/legal/+page.svelte b/src/routes/legal/+page.svelte index 0e6ccf7ba..c9e421566 100644 --- a/src/routes/legal/+page.svelte +++ b/src/routes/legal/+page.svelte @@ -1,7 +1,9 @@

-

Reset Password

+

{$t('routes.resetLogin.title')}

- Enter the email of your account, and a password reset link will be sent. If - you did not have an email set up, contact your instance admins. + {$t('routes.resetLogin.description')}

{#if !LINKED_INSTANCE_URL} {/if}
diff --git a/src/routes/password_change/[token]/+error.svelte b/src/routes/password_change/[token]/+error.svelte index ed12fc81b..a980c10b6 100644 --- a/src/routes/password_change/[token]/+error.svelte +++ b/src/routes/password_change/[token]/+error.svelte @@ -1,5 +1,6 @@ @@ -9,9 +10,8 @@ >
-

Error

-

- That password reset token doesn't exist. -

+

+ {$t('message.error')} +

{$page.error?.message}
diff --git a/src/routes/password_change/[token]/+page.svelte b/src/routes/password_change/[token]/+page.svelte index f1d1e8350..2f1dedd01 100644 --- a/src/routes/password_change/[token]/+page.svelte +++ b/src/routes/password_change/[token]/+page.svelte @@ -6,6 +6,7 @@ instance as currentInstance, } from '$lib/instance.js' import { getClient, validateInstance } from '$lib/lemmy.js' + import { t } from '$lib/translations' import { Button, TextInput, toast } from 'mono-svelte' export let data: { @@ -46,38 +47,37 @@
-

Reset Password

+

{$t('routes.passwordChange.title')}

- You've clicked an email with the password reset link in it. Now, choose your - new password. + {$t('routes.passwordChange.description')}

{#if !LINKED_INSTANCE_URL} - What instance did you reset your password for? + {$t('routes.passwordChange.instance')} {/if}
From bf94ff6d8567faa5e15bb01c39ea2187b3816b10 Mon Sep 17 00:00:00 2001 From: Xylight Date: Tue, 4 Jun 2024 10:54:47 -0700 Subject: [PATCH 25/54] misc: remove about button --- src/lib/components/ui/navbar/Profile.svelte | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/lib/components/ui/navbar/Profile.svelte b/src/lib/components/ui/navbar/Profile.svelte index e426816c1..5eac3b4d3 100644 --- a/src/lib/components/ui/navbar/Profile.svelte +++ b/src/lib/components/ui/navbar/Profile.svelte @@ -198,14 +198,6 @@ > -
From 0493c44344393c9c9f403334fa10a13fc804ee77 Mon Sep 17 00:00:00 2001 From: Xylight Date: Tue, 4 Jun 2024 10:56:03 -0700 Subject: [PATCH 26/54] misc: remove node workflow --- .github/workflows/node.js.yml | 24 ------------------------ 1 file changed, 24 deletions(-) delete mode 100644 .github/workflows/node.js.yml diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml deleted file mode 100644 index e36eab457..000000000 --- a/.github/workflows/node.js.yml +++ /dev/null @@ -1,24 +0,0 @@ -name: Node.js CI - -on: - pull_request: - branches: ['main'] - -jobs: - build: - runs-on: ubuntu-latest - - strategy: - matrix: - node-version: [20.x] - # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ - - steps: - - uses: actions/checkout@v3 - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 - with: - node-version: ${{ matrix.node-version }} - cache: 'npm' - - run: npm install - - run: npm test From 62901081ab33ab240ec6416e6fc3f4b7749769ff Mon Sep 17 00:00:00 2001 From: Xylight Date: Tue, 4 Jun 2024 11:17:29 -0700 Subject: [PATCH 27/54] i18n: localize admin config page --- src/lib/i18n/en.json | 50 ++++++++- src/routes/admin/+layout.svelte | 11 +- src/routes/admin/config/+page.svelte | 151 ++++++++++++++++----------- src/routes/settings/+page.svelte | 4 +- 4 files changed, 147 insertions(+), 69 deletions(-) diff --git a/src/lib/i18n/en.json b/src/lib/i18n/en.json index 3c03568f1..c3b504d25 100644 --- a/src/lib/i18n/en.json +++ b/src/lib/i18n/en.json @@ -162,7 +162,8 @@ "description": "This instance has registrations closed. Find another instance.", "anotherInstance": "Find another instance" } - } + }, + "description": "Description" }, "routes": { "frontpage": { @@ -229,6 +230,53 @@ "resolve": "Resolve", "unresolve": "Unresolve" }, + "admin": { + "title": "Administration", + "config": { + "title": "Configuration", + "sidebar": "Sidebar", + "icon": "Icon", + "banner": "Banner", + "downvotesEnabled": "Enable Downvotes", + "nsfwEnabled": "Enable NSFW", + "registration": { + "label": "Registration Mode", + "open": "Open", + "application": "Require Application", + "closed": "Closed" + }, + "applicationQuestion": "Application Question", + "adminCommunityOnly": "Only admins can create communities", + "requireVerifyEmail": "Require email verification", + "emailAdminsOnApplication": "Email admins on receiving new applications", + "emailAdminsOnReport": "Email admins on receiving new reports", + "listingType": { + "label": "Listing Type", + "all": "All", + "local": "Local" + }, + "private": "Private instance", + "hideModlogModNames": "Hide modlog mod names", + "slurFilter": "Slur filter regex", + "federation": "Federation enabled", + "federationDebug": "Federation debug mode", + "captcha": { + "enabled": "Enabled" + } + }, + "applications": { + "title": "Applications" + }, + "taglines": { + "title": "Taglines" + }, + "team": { + "title": "Team" + }, + "federation": { + "title": "Federation" + } + }, "verifyEmail": { "message": "Your email was verified. You can now close this window.", "error": "Failed to verify your email." diff --git a/src/routes/admin/+layout.svelte b/src/routes/admin/+layout.svelte index 536b67679..fa1682502 100644 --- a/src/routes/admin/+layout.svelte +++ b/src/routes/admin/+layout.svelte @@ -3,6 +3,7 @@ import { page } from '$app/stores' import { profile } from '$lib/auth' import MultiSelect from '$lib/components/input/Switch.svelte' + import { t } from '$lib/translations' import { Badge } from 'mono-svelte' @@ -24,11 +25,11 @@ '/admin/federation', ]} optionNames={[ - 'Configuration', - 'Applications', - 'Taglines', - 'Team', - 'Federation', + $t('routes.admin.config.title'), + $t('routes.admin.applications.title'), + $t('routes.admin.taglines.title'), + $t('routes.admin.team.title'), + $t('routes.admin.federation.title'), ]} selected={$page.url.pathname} on:select={(e) => { diff --git a/src/routes/admin/config/+page.svelte b/src/routes/admin/config/+page.svelte index d285b101f..8ac019eb4 100644 --- a/src/routes/admin/config/+page.svelte +++ b/src/routes/admin/config/+page.svelte @@ -1,13 +1,15 @@ - Administration + {$t('routes.admin.title')}
-

Site configuration

+
{$t('routes.admin.config.title')}
{#if formData} - - + +
- - {#if uploading.icon} uploading.icon = false} + on:upload={() => (uploading.icon = false)} /> {/if}
- - {#if uploading.banner} uploading.banner = false} + on:upload={() => (uploading.banner = false)} /> {/if}
- - Enable downvotes - - - Enable NSFW - + + {$t('routes.admin.config.downvotesEnabled')} + + + {$t('routes.admin.config.nsfwEnabled')} + {#if formData.registration_mode == 'RequireApplication'} {/if} - - Only admins can create communities - - + - Require email verification - - + - Email admins on receiving new applications - - - Email admins on receiving new reports - + {$t('routes.admin.config.emailAdminsOnApplication')} + + + {$t('routes.admin.config.emailAdminsOnReport')} + - - Private instance - - - Hide modlog mod names - + + {$t('routes.admin.config.private')} + + + {$t('routes.admin.config.hideModlogModNames')} + - - Federation enabled - - - Federation debug mode - - - Captcha enabled - + + {$t('routes.admin.config.federation')} + + + {$t('routes.admin.config.federationDebug')} + + + {$t('routes.admin.config.captcha.enabled')} + {/if} diff --git a/src/routes/settings/+page.svelte b/src/routes/settings/+page.svelte index 436f45cce..374965b61 100644 --- a/src/routes/settings/+page.svelte +++ b/src/routes/settings/+page.svelte @@ -103,8 +103,8 @@

The language used for Photon's UI. - All languages other than US English are community translated, and may - be incomplete! + All languages other than US English and Hebrew are community + translated, and may be incomplete!

{#each $userSettings.moderation.presets as preset}
{:else} diff --git a/src/routes/admin/applications/Application.svelte b/src/routes/admin/applications/Application.svelte index 4b754408f..0c3e73f70 100644 --- a/src/routes/admin/applications/Application.svelte +++ b/src/routes/admin/applications/Application.svelte @@ -51,9 +51,9 @@ registrationApplicationAnswer ) toast({ - content: `Successfully ${ - approve ? 'approved' : 'denied' - } that application.`, + content: approve + ? $t('toast.approvedApplication') + : $t('toast.deniedApplication'), type: 'success', }) application.creator_local_user.accepted_application = approve diff --git a/src/routes/admin/config/+page.svelte b/src/routes/admin/config/+page.svelte index 8ac019eb4..2950a43f7 100644 --- a/src/routes/admin/config/+page.svelte +++ b/src/routes/admin/config/+page.svelte @@ -31,7 +31,7 @@ ...formData, }) toast({ - content: 'Updated your site.', + content: $t('toast.updatedSite'), type: 'success', }) } catch (err) { diff --git a/src/routes/admin/federation/+page.svelte b/src/routes/admin/federation/+page.svelte index 11a417ed9..a7bbe21ae 100644 --- a/src/routes/admin/federation/+page.svelte +++ b/src/routes/admin/federation/+page.svelte @@ -109,7 +109,7 @@ if (res) { toast({ - content: 'Edited your site.', + content: $t('toast.updatedSite'), type: 'success', }) } @@ -127,8 +127,7 @@ if (!data.federated_instances?.federated_instances?.blocked) throw new Error('Missing instance') const content = e.target?.result - if (!content) - toast({ content: 'No content in that file', type: 'warning' }) + if (!content) toast({ content: $t('toast.failCSV'), type: 'warning' }) try { const instances: Instance[] = [] @@ -152,12 +151,12 @@ data.federated_instances.federated_instances.blocked = instances } catch (err) { - toast({ content: err as 'Failed to parse CSV', type: 'error' }) + toast({ content: $t('toast.failCSV'), type: 'error' }) } } reader.onerror = (e) => - toast({ content: 'Failed to read file.', type: 'error' }) + toast({ content: $t('toast.failCSV'), type: 'error' }) reader.readAsText(files[0]) } diff --git a/src/routes/admin/taglines/+page.svelte b/src/routes/admin/taglines/+page.svelte index e34788b3f..fa59ffec1 100644 --- a/src/routes/admin/taglines/+page.svelte +++ b/src/routes/admin/taglines/+page.svelte @@ -29,7 +29,7 @@ taglines: taglines, }) toast({ - content: 'Successfully saved taglines.', + content: $t('toast.updatedSite'), type: 'success', }) } catch (err) { diff --git a/src/routes/admin/team/+page.svelte b/src/routes/admin/team/+page.svelte index d2cd3eb88..1c2bbded6 100644 --- a/src/routes/admin/team/+page.svelte +++ b/src/routes/admin/team/+page.svelte @@ -21,7 +21,7 @@ async function removeAdmin(id: number, confirm: boolean): Promise { if (!confirm) return toast({ - content: 'Are you sure you want to remove that admin?', + content: $t('toast.removeAdminWarning'), action: () => removeAdmin(id, true), }) @@ -37,7 +37,7 @@ if (result) { data.site!.admins = result.admins toast({ - content: 'Removed that admin.', + content: $t('toast.removeAdmin'), type: 'success', }) } diff --git a/src/routes/c/[name]/+page.svelte b/src/routes/c/[name]/+page.svelte index 6d40bbdfa..499fd985d 100644 --- a/src/routes/c/[name]/+page.svelte +++ b/src/routes/c/[name]/+page.svelte @@ -22,6 +22,7 @@ import Placeholder from '$lib/components/ui/Placeholder.svelte' import { profile } from '$lib/auth' import { addResumable } from '$lib/lemmy/item.js' + import { t } from '$lib/translations.js' export let data @@ -94,7 +95,7 @@ }` ) - toast({ content: 'Copied to clipboard.' }) + toast({ content: $t('toast.copied') }) }} class="dark:text-zinc-400 text-slate-600 text-sm text-left" > diff --git a/src/routes/c/[name]/settings/team/+page.svelte b/src/routes/c/[name]/settings/team/+page.svelte index 979276ac1..fcd502ade 100644 --- a/src/routes/c/[name]/settings/team/+page.svelte +++ b/src/routes/c/[name]/settings/team/+page.svelte @@ -9,6 +9,8 @@ import { getClient } from '$lib/lemmy.js' import { flip } from 'svelte/animate' import { Button, TextInput } from 'mono-svelte' + import { t } from '$lib/translations.js' + import Header from '$lib/components/ui/layout/pages/Header.svelte' export let data: PageData @@ -37,14 +39,14 @@ data.community.moderators = addModRes.moderators toast({ - content: 'Added that user as a moderator.', + content: $t('toast.addMod'), type: 'success', }) formData.newModerator = '' } else { toast({ - content: 'Could not find that user.', + content: $t('toast.failFindUser'), type: 'warning', }) } @@ -71,7 +73,7 @@ data.community.moderators = res.moderators toast({ - content: 'Successfully updated community moderators.', + content: $t('toast.updateMods'), type: 'success', }) } catch (err) { @@ -83,11 +85,7 @@ } - - Moderator Team - - -

Moderators

+
Moderators
{ diff --git a/src/routes/communities/Subscribe.svelte b/src/routes/communities/Subscribe.svelte index 83faff512..e85c2cfdd 100644 --- a/src/routes/communities/Subscribe.svelte +++ b/src/routes/communities/Subscribe.svelte @@ -26,7 +26,7 @@ subscribing = false return res } catch (error) { - toast({ content: 'Failed to subscribe to community', type: 'error' }) + toast({ content: error as any, type: 'error' }) } subscribing = false diff --git a/src/routes/login/+page.svelte b/src/routes/login/+page.svelte index 82df9e8eb..f5b85e982 100644 --- a/src/routes/login/+page.svelte +++ b/src/routes/login/+page.svelte @@ -48,7 +48,7 @@ const result = await setUser(response.jwt, data.instance, data.username) if (result) { - toast({ content: 'Successfully logged in.', type: 'success' }) + toast({ content: $t('toast.logIn'), type: 'success' }) goto('/') } } else { diff --git a/src/routes/login/guest/+page.svelte b/src/routes/login/guest/+page.svelte index 3d0b62a51..112f45cb8 100644 --- a/src/routes/login/guest/+page.svelte +++ b/src/routes/login/guest/+page.svelte @@ -19,7 +19,7 @@ async function addGuest() { form.loading = true if (!(await validateInstance(form.instance))) { - toast({ content: 'Failed to contact that instance URL.', type: 'error' }) + toast({ content: $t('toast.failInstanceURL'), type: 'error' }) form.loading = false return } @@ -44,7 +44,7 @@ } }) - toast({ content: 'Added that account.', type: 'success' }) + toast({ content: $t('toast.addAccount'), type: 'success' }) goto('/') diff --git a/src/routes/login_reset/+page.svelte b/src/routes/login_reset/+page.svelte index faacc23d5..007d8c5a8 100644 --- a/src/routes/login_reset/+page.svelte +++ b/src/routes/login_reset/+page.svelte @@ -16,14 +16,14 @@ loading = true try { if (!(await validateInstance(instance))) - throw new Error('Failed to contact instance url') + throw new Error($t('toast.failInstanceURL')) await getClient(instance).passwordReset({ email: email, }) toast({ - content: 'A password reset link was sent to your email.', + content: $t('toast.resetLink'), type: 'success', }) } catch (err) { diff --git a/src/routes/moderation/Report.svelte b/src/routes/moderation/Report.svelte index fafc76bd3..b26ae2293 100644 --- a/src/routes/moderation/Report.svelte +++ b/src/routes/moderation/Report.svelte @@ -34,9 +34,9 @@ item.resolved = res.comment_report_view.comment_report.resolved toast({ - content: `${ - item.resolved ? 'Resolved' : 'Unresolved' - } that report.`, + content: item.resolved + ? $t('toast.resolveReport') + : $t('toast.unresolveReport'), type: 'success', }) @@ -50,9 +50,9 @@ item.resolved = res.post_report_view.post_report.resolved toast({ - content: `${ - item.resolved ? 'Resolved' : 'Unresolved' - } that report.`, + content: item.resolved + ? $t('toast.resolveReport') + : $t('toast.unresolveReport'), type: 'success', }) @@ -67,9 +67,9 @@ item.resolved = res.private_message_report_view.private_message_report.resolved toast({ - content: `${ - item.resolved ? 'Resolved' : 'Unresolved' - } that report.`, + content: item.resolved + ? $t('toast.resolveReport') + : $t('toast.unresolveReport'), type: 'success', }) diff --git a/src/routes/password_change/[token]/+page.svelte b/src/routes/password_change/[token]/+page.svelte index 2f1dedd01..2b08e19af 100644 --- a/src/routes/password_change/[token]/+page.svelte +++ b/src/routes/password_change/[token]/+page.svelte @@ -22,7 +22,7 @@ loading = true try { if (!(await validateInstance(instance))) - throw new Error('Failed to contact instance url') + throw new Error($t('toast.failInstanceURL')) await getClient(instance).passwordChangeAfterReset({ password: password, @@ -31,7 +31,7 @@ }) toast({ - content: 'Your password was reset.', + content: $t('toast.passwordReset'), type: 'success', }) diff --git a/src/routes/post/[instance]/[id=integer]/+page.svelte b/src/routes/post/[instance]/[id=integer]/+page.svelte index d8598193d..66001a819 100644 --- a/src/routes/post/[instance]/[id=integer]/+page.svelte +++ b/src/routes/post/[instance]/[id=integer]/+page.svelte @@ -82,7 +82,7 @@ const fetchOnHome = async (jwt: string) => { const id = toast({ - content: 'Attempting to fetch this post on your home instance...', + content: $t('toast.fetchPostOnHome'), loading: true, }) diff --git a/src/routes/profile/(local_user)/password/+page.svelte b/src/routes/profile/(local_user)/password/+page.svelte index 0bca28f9d..8f432ce84 100644 --- a/src/routes/profile/(local_user)/password/+page.svelte +++ b/src/routes/profile/(local_user)/password/+page.svelte @@ -41,12 +41,12 @@ await setUser(res.jwt, instance, username!) $currentInstance = instance - toast({ content: 'Your login was refreshed.', type: 'success' }) + toast({ content: $t('toast.loginRefresh'), type: 'success' }) } else { - throw new Error('Invalid credentials') + throw new Error($t('toast.invalidLogin')) } - toast({ content: 'Successfully changed your password. ' }) + toast({ content: $t('toast.passwordReset') }) } catch (e) { toast({ content: e as any, @@ -139,7 +139,7 @@ on:click={() => { if (!totpLink) return navigator.clipboard?.writeText(totpLink) - toast({ content: 'Copied to clipboard.' }) + toast({ content: $t('toast.copied') }) }} > diff --git a/src/routes/profile/(local_user)/settings/+page.svelte b/src/routes/profile/(local_user)/settings/+page.svelte index 55b30a08e..00bbd1651 100644 --- a/src/routes/profile/(local_user)/settings/+page.svelte +++ b/src/routes/profile/(local_user)/settings/+page.svelte @@ -41,8 +41,7 @@ }) toast({ - content: - 'Saved your user settings. If you changed your email, a verification email will have been sent.', + content: $t('toast.saveSettings'), type: 'success', }) } catch (err) { @@ -65,21 +64,21 @@ switch (level) { case 0: { toast({ - content: 'Are you sure you want to delete your account?', + content: $t('toast.confirmDelete1'), action: () => deleteAccount(1), }) return } case 1: { toast({ - content: 'Are you really sure?', + content: $t('toast.confirmDelete2'), action: () => deleteAccount(2), }) return } case 2: { toast({ - content: 'Final warning. Are you reeeeeeally sure?', + content: $t('toast.confirmDelete3'), action: () => deleteAccount(3), }) return @@ -93,13 +92,13 @@ if (!(deletion.password || null)) { toast({ - content: 'You must provide your password.', + content: $t('toast.needPassword'), type: 'warning', }) } const id = toast({ - content: 'You did this. Deleting account...', + content: $t('toast.deleting'), loading: true, }) @@ -121,7 +120,7 @@ setUserID(-1) toast({ - content: 'Your account was deleted.', + content: $t('toast.deleted'), }) goto('/') } catch (err) { diff --git a/src/routes/settings/+page.svelte b/src/routes/settings/+page.svelte index 374965b61..634e23de7 100644 --- a/src/routes/settings/+page.svelte +++ b/src/routes/settings/+page.svelte @@ -32,7 +32,7 @@ import { removeItem } from '$lib/util.js' import Section from './Section.svelte' import ToggleSetting from './ToggleSetting.svelte' - import { locales } from '$lib/translations' + import { locales, t } from '$lib/translations' @@ -43,7 +43,7 @@ Settings
-
-
- -
+
- Dock position - Where the dock should be put + {$t('settings.navigation.dockPos.title')} + + {$t('settings.navigation.dockPos.description')} + - Panel mode + {$t('settings.navigation.panel.title')} - Extend the dock to screen edges, similar to a panel. + {$t('settings.navigation.panel.description')}
-
+
- Theming - Customize Photon's colors. + {$t('settings.app.theming.title')} + {$t('settings.app.theming.description')} - Language + {$t('settings.app.lang.title')}

- The language used for Photon's UI. + {$t('settings.app.lang.description')} - All languages other than US English and Hebrew are community - translated, and may be incomplete! + {$t('settings.app.lang.note')}

- Post style + {$t('settings.app.view.title')}

{#if $userSettings.view == 'list'} - Show posts in a list, with post bodies and compact images. + {$t('settings.app.view.list')} {:else if $userSettings.view == 'cozy'} - Show posts with large images, rich embeds and longer post bodies. + {$t('settings.app.view.cozy')} {:else if $userSettings.view == 'compact'} - Show posts in a list, without post bodies and with tighter spacing. + {$t('settings.app.view.compact')} {:else if $userSettings.view == 'card'} - Photon's old post style. + {$t('settings.app.view.legacy')} {/if}

- Default sort - The default sort to use for feeds. + {$t('settings.app.sort.title')} + {$t('settings.app.sort.description')}
@@ -154,70 +158,81 @@
- Thumbnail alignment + {$t('settings.app.thumbnailSide.title')} - Where thumbnails should be on the post in list/compact view. + {$t('settings.app.thumbnailSide.title')} + + {$t('settings.app.font.title')} + {$t('settings.app.font.description')} + +
-
+
YouTube - The website to use to embed YouTube content. + {$t('settings.embeds.youtube.description')} - - Font - What font Photon should use. - -
-
+
- Hide Submissions + {$t('settings.lemmy.hideSubmissions.title')} -

Hide certain types of submissions.

-

- Looking to hide read posts? That was moved to your - profile settings. - -

+

{$t('settings.lemmy.hideSubmissions.description')}

- Deleted + + {$t('settings.lemmy.hideSubmissions.deleted')} + - Removed by Moderator + {$t('settings.lemmy.hideSubmissions.removed')}
- Show instances - Show items' instances. + {$t('settings.lemmy.instances.title')} + + {$t('settings.lemmy.instances.description')} +
- Users + {$t('content.users')} - Comments + {$t('content.comments')} - Communities + {$t('content.communities')}
-
+
- Removal reply presets + {$t('settings.moderation.replyPresets.title')} -

Presets to use for "Reply reason" in a submission removal.

+

{$t('settings.moderation.replyPresets.description')}

    -
  • Syntax:
  • +
  • {$t('settings.moderation.replyPresets.syntax')}
  • {'{{reason}}'} - : The provided reason
  • {'{{post}}'} - : The title of the post
  • {'{{community}}'} - : The community the submission was removed in.
  • {'{{username}}'} - : The username of the creator of the submission.
@@ -395,11 +393,11 @@
-
+
From 3fd36cf13817747dd7f819147f995c03435f0998 Mon Sep 17 00:00:00 2001 From: Xylight Date: Tue, 4 Jun 2024 14:13:43 -0700 Subject: [PATCH 38/54] i18n: fix broken english --- src/lib/components/ui/navbar/Profile.svelte | 2 +- src/routes/settings/+page.svelte | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/lib/components/ui/navbar/Profile.svelte b/src/lib/components/ui/navbar/Profile.svelte index bcb923267..e24f6d05d 100644 --- a/src/lib/components/ui/navbar/Profile.svelte +++ b/src/lib/components/ui/navbar/Profile.svelte @@ -144,7 +144,7 @@
{}}>
diff --git a/src/routes/settings/+page.svelte b/src/routes/settings/+page.svelte index e8b861dba..6c1f87624 100644 --- a/src/routes/settings/+page.svelte +++ b/src/routes/settings/+page.svelte @@ -113,6 +113,9 @@ {$t(`settings.app.lang.${locale}`, { default: locale })} {/each} + {#if $userSettings.debugInfo} + + {/if} From d0fe030b32992b933ff8d3faf086b7881000c4aa Mon Sep 17 00:00:00 2001 From: Xylight Date: Wed, 5 Jun 2024 11:34:02 -0700 Subject: [PATCH 39/54] i18n: add server-side language selection --- src/routes/+layout.server.ts | 22 ++++++++++++++++++++++ src/routes/+layout.ts | 10 +++++++--- 2 files changed, 29 insertions(+), 3 deletions(-) create mode 100644 src/routes/+layout.server.ts diff --git a/src/routes/+layout.server.ts b/src/routes/+layout.server.ts new file mode 100644 index 000000000..747d1d803 --- /dev/null +++ b/src/routes/+layout.server.ts @@ -0,0 +1,22 @@ +import { loadTranslations, locales } from '$lib/translations.js' +import { get } from 'svelte/store' + +export const load = async ({ url, request }) => { + const languages = request.headers.get('Accept-Language')?.split(',') + const availableLangs = get(locales) + + let preferredLanguage = 'en' + + if (!languages) { + await loadTranslations(preferredLanguage) + return + } + for (const lang of languages.reverse()) { + const splitLang = lang.split(';')[0] + if (availableLangs.includes(splitLang)) { + preferredLanguage = splitLang + } + } + await loadTranslations(preferredLanguage) + return +} diff --git a/src/routes/+layout.ts b/src/routes/+layout.ts index 079bd8260..53021d840 100644 --- a/src/routes/+layout.ts +++ b/src/routes/+layout.ts @@ -1,3 +1,4 @@ +import { browser } from '$app/environment' import { env } from '$env/dynamic/public' import { userSettings } from '$lib/settings.js' import { loadTranslations } from '$lib/translations.js' @@ -6,11 +7,14 @@ import { get } from 'svelte/store' export let ssr = (env.PUBLIC_SSR_ENABLED?.toLowerCase() ?? 'false') == 'true' export const load = async ({}) => { - const initLocale = get(userSettings)?.language ?? navigator?.language ?? 'en' + if (browser) { + const initLocale = + get(userSettings)?.language ?? navigator?.language ?? 'en' - console.log(`Loading locale ${initLocale}`) + console.log(`Loading locale ${initLocale}`) - await loadTranslations(initLocale) + await loadTranslations(initLocale) + } return } From c5aa1510705a9bfdf5801f28c841a9d13d422602 Mon Sep 17 00:00:00 2001 From: Xylight Date: Wed, 5 Jun 2024 11:36:56 -0700 Subject: [PATCH 40/54] fix: ssr bug in markdown editor --- src/lib/components/markdown/MarkdownEditor.svelte | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/lib/components/markdown/MarkdownEditor.svelte b/src/lib/components/markdown/MarkdownEditor.svelte index 6e34d4f45..5df9b5b07 100644 --- a/src/lib/components/markdown/MarkdownEditor.svelte +++ b/src/lib/components/markdown/MarkdownEditor.svelte @@ -64,12 +64,11 @@ let uploadingImage = false let loading = false let image: any - $: previewURL = - image instanceof FileList - ? URL.createObjectURL(image[0]) - : image - ? URL.createObjectURL(image) - : '' + $: previewURL = image?.length + ? URL.createObjectURL(image[0]) + : image + ? URL.createObjectURL(image) + : '' async function upload() { if (!$profile?.jwt || !image) return From 7c257dca9d3b9fbdc51221d1d136c080c81a6598 Mon Sep 17 00:00:00 2001 From: Xylight Date: Wed, 5 Jun 2024 11:37:30 -0700 Subject: [PATCH 41/54] i18n: fix routes.legal --- src/lib/components/lemmy/SiteCard.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/components/lemmy/SiteCard.svelte b/src/lib/components/lemmy/SiteCard.svelte index f6398eb63..b761af869 100644 --- a/src/lib/components/lemmy/SiteCard.svelte +++ b/src/lib/components/lemmy/SiteCard.svelte @@ -53,7 +53,7 @@ diff --git a/src/lib/i18n/en.json b/src/lib/i18n/en.json index 092f67c7d..5a1501f98 100644 --- a/src/lib/i18n/en.json +++ b/src/lib/i18n/en.json @@ -197,6 +197,7 @@ }, "saved": "Saved", "createPost": "Create Post", + "createCommunity": "Create Community", "post": { "crosspostCount": "crossposts", "commentCount": "comments", From 7b5f575affc151c2340c17a0f08aa8d47366b974 Mon Sep 17 00:00:00 2001 From: Xylight Date: Wed, 5 Jun 2024 11:41:35 -0700 Subject: [PATCH 43/54] fix: broken sessionstorage --- src/lib/session.ts | 3 +++ src/routes/create/post/+page.svelte | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/lib/session.ts b/src/lib/session.ts index 091463634..e74d38e24 100644 --- a/src/lib/session.ts +++ b/src/lib/session.ts @@ -1,3 +1,4 @@ +import { browser } from '$app/environment' import type { Community } from 'lemmy-js-client' import { writable } from 'svelte/store' @@ -20,6 +21,7 @@ export const setSessionStorage = ( key: keyof SessionStorage, value: SessionStorage[typeof key] ) => { + if (!browser) return if (value == undefined) { sessionStorage.removeItem(key) } else { @@ -30,6 +32,7 @@ export const setSessionStorage = ( export const getSessionStorage = ( key: keyof SessionStorage ): SessionStorage[typeof key] => { + if (!browser) return return JSON.parse(sessionStorage.getItem(key)!) } diff --git a/src/routes/create/post/+page.svelte b/src/routes/create/post/+page.svelte index cab859bfe..d48337ba1 100644 --- a/src/routes/create/post/+page.svelte +++ b/src/routes/create/post/+page.svelte @@ -4,6 +4,7 @@ import { profile } from '$lib/auth.js' import { onDestroy, onMount } from 'svelte' import { getSessionStorage, setSessionStorage } from '$lib/session.js' + import { t } from '$lib/translations.js' export let data = { crosspost: false, @@ -27,7 +28,7 @@ - Create post + {$t('form.post.create')}
From fa1d2e67ad611c6d3fb4a390fda5c1e22851946e Mon Sep 17 00:00:00 2001 From: Xylight Date: Wed, 5 Jun 2024 11:45:57 -0700 Subject: [PATCH 44/54] misc: update error page --- src/routes/+error.svelte | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/src/routes/+error.svelte b/src/routes/+error.svelte index d1599637a..0c08a1073 100644 --- a/src/routes/+error.svelte +++ b/src/routes/+error.svelte @@ -5,18 +5,19 @@ import { Icon, XMark } from 'svelte-hero-icons' -
-
- -
-

+
+

+
+ +
{$page.status}

-

Failed to fetch that page.

- {$page.error?.message} - + + {$page.error?.message} + +
From 05e0d58521fa3ab09509d306423553af238bd499 Mon Sep 17 00:00:00 2001 From: Xylight Date: Wed, 5 Jun 2024 11:46:23 -0700 Subject: [PATCH 45/54] misc: update version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 97ac17b93..06447a1d7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "photon-lemmy", - "version": "1.29.6", + "version": "1.30.0", "private": true, "scripts": { "dev": "vite dev", From 9bb98acdd34598d92091842fd9f130154c8aa6d3 Mon Sep 17 00:00:00 2001 From: Xylight Date: Wed, 5 Jun 2024 11:48:13 -0700 Subject: [PATCH 46/54] fix: use $locale for relative date --- src/lib/components/util/RelativeDate.svelte | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/lib/components/util/RelativeDate.svelte b/src/lib/components/util/RelativeDate.svelte index 89a1e6dbe..d39b1e2f8 100644 --- a/src/lib/components/util/RelativeDate.svelte +++ b/src/lib/components/util/RelativeDate.svelte @@ -39,9 +39,6 @@ const value = Math.round(diffInMillis / thresholds[i].threshold) let language = $locale - if (typeof navigator != 'undefined') { - language = navigator.language - } const rtf = new Intl.RelativeTimeFormat(language, options) From e7d12916c32d0d9c6f997e25063a94c7f33f37e2 Mon Sep 17 00:00:00 2001 From: Xylight Date: Wed, 5 Jun 2024 12:27:28 -0700 Subject: [PATCH 47/54] misc: remove keying on comments --- src/lib/components/lemmy/comment/Comments.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/components/lemmy/comment/Comments.svelte b/src/lib/components/lemmy/comment/Comments.svelte index a89e82293..94655cb6f 100644 --- a/src/lib/components/lemmy/comment/Comments.svelte +++ b/src/lib/components/lemmy/comment/Comments.svelte @@ -113,7 +113,7 @@ ? 'divide-y dark:divide-zinc-800 divide-slate-100' : 'pl-3.5 border-l border-slate-200 dark:border-zinc-800 my-1'} > - {#each nodes as node (node.comment_view.comment.id)} + {#each nodes as node} Date: Wed, 5 Jun 2024 14:13:43 -0700 Subject: [PATCH 48/54] feat: add post and comment translation --- bun.lockb | Bin 298084 -> 298084 bytes .../lemmy/comment/CommentActions.svelte | 21 ++++ .../components/lemmy/post/PostActions.svelte | 19 ++++ .../components/markdown/MarkdownEditor.svelte | 5 +- .../components/translate/Translation.svelte | 90 ++++++++++++++++++ src/lib/components/translate/translation.ts | 3 + src/lib/i18n/en.json | 6 ++ src/lib/settings.ts | 2 + src/routes/settings/+page.svelte | 13 ++- 9 files changed, 156 insertions(+), 3 deletions(-) create mode 100644 src/lib/components/translate/Translation.svelte create mode 100644 src/lib/components/translate/translation.ts diff --git a/bun.lockb b/bun.lockb index 45e1b00d26456976be6df336ff31794267309162..537d7449e784bb68f0805cb594f89f38803e4955 100755 GIT binary patch delta 31 ncmaDdL+Hs2p@tU5Elj!p*%{-E^i1@O+Dra3Z7=!H{GkT`&z%iJ delta 31 jcmaDdL+Hs2p@tU5Elj!p*_jx?puOZj)Ao}8%pZCHy=n{c diff --git a/src/lib/components/lemmy/comment/CommentActions.svelte b/src/lib/components/lemmy/comment/CommentActions.svelte index 697d71fde..01b54968f 100644 --- a/src/lib/components/lemmy/comment/CommentActions.svelte +++ b/src/lib/components/lemmy/comment/CommentActions.svelte @@ -8,6 +8,7 @@ EllipsisHorizontal, Flag, Icon, + Language, PencilSquare, Square2Stack, Trash, @@ -24,6 +25,9 @@ import { deleteItem, save } from '$lib/lemmy/contentview.js' import { Button, Menu, MenuButton, MenuDivider } from 'mono-svelte' import { t } from '$lib/translations' + import Translation from '$lib/components/translate/Translation.svelte' + import { text } from '$lib/components/translate/translation' + import { userSettings } from '$lib/settings' export let comment: CommentView export let replying: boolean = false @@ -31,8 +35,13 @@ const dispatcher = createEventDispatcher<{ edit: CommentView }>() let reply = '' + let translating = false +{#if translating} + +{/if} +
{$t('comment.actions.link')}
+ {#if $userSettings.translator} + { + // @ts-ignore + text.set(comment.comment.content) + translating = !translating + }} + > + + {$t('post.actions.more.translate')} + + {/if} {#if $profile?.jwt} {#if comment.creator.id == $profile.user?.local_user_view.person.id} dispatcher('edit', comment)}> diff --git a/src/lib/components/lemmy/post/PostActions.svelte b/src/lib/components/lemmy/post/PostActions.svelte index a8ae48a50..af956f092 100644 --- a/src/lib/components/lemmy/post/PostActions.svelte +++ b/src/lib/components/lemmy/post/PostActions.svelte @@ -14,6 +14,7 @@ EyeSlash, Flag, Icon, + Language, Newspaper, PencilSquare, ServerStack, @@ -50,6 +51,8 @@ import { fediseer, type Data } from '$lib/fediseer/fediseer' import Fediseer from '$lib/fediseer/Fediseer.svelte' import { t } from '$lib/translations' + import { text } from '$lib/components/translate/translation' + import Translation from '$lib/components/translate/Translation.svelte' export let post: PostView @@ -62,6 +65,8 @@ let fediseerOpen = false let fediseerData: Data | null = null let fediseerLoading = false + + let translating = false {#if fediseerData} @@ -94,6 +99,8 @@ {/if} + +
{$t('post.actions.more.share')} + {#if post.post.body && $userSettings.translator} + { + // @ts-ignore + text.set(post.post.body) + translating = !translating + }} + > + + {$t('post.actions.more.translate')} + + {/if} {#if $profile?.jwt} { diff --git a/src/lib/components/markdown/MarkdownEditor.svelte b/src/lib/components/markdown/MarkdownEditor.svelte index 5df9b5b07..298e5a4e9 100644 --- a/src/lib/components/markdown/MarkdownEditor.svelte +++ b/src/lib/components/markdown/MarkdownEditor.svelte @@ -97,7 +97,7 @@ loading = false } - let previewing = false + export let previewing = false const shortcuts = { KeyB: () => wrapSelection('**', '**'), @@ -174,7 +174,8 @@ overflow-hidden transition-colors" > {#if previewing}
diff --git a/src/lib/components/translate/Translation.svelte b/src/lib/components/translate/Translation.svelte new file mode 100644 index 000000000..c3c7c971c --- /dev/null +++ b/src/lib/components/translate/Translation.svelte @@ -0,0 +1,90 @@ + + + + +
+ + + +
+ {#if result} + {#await result} +
+ +
+ {:then result} + + {:catch err} + + {/await} + {:else} + +
- translate($text)} bind:value={to} class="flex-1"> @@ -64,27 +83,34 @@ {#if result} {#await result}
{:then result} + {#if !error} + + {/if} + {:catch err} - {:catch err} - {/await} {:else}