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 diff --git a/bun.lockb b/bun.lockb index fbbdab7e5..537d7449e 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/package.json b/package.json index 7948e74a6..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", @@ -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..b761af869 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 $profile?.user && (amMod($profile?.user, comment.community) || isAdmin($profile.user))} @@ -56,7 +66,7 @@ - Actions + {$t('comment.actions.label')} { navigator.share?.({ @@ -76,13 +86,25 @@ }} > - Copy Link +
{$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)}> - 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/components/lemmy/comment/CommentForm.svelte b/src/lib/components/lemmy/comment/CommentForm.svelte index 20109510e..33b56a830 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 @@ -40,10 +41,6 @@ dispatch('comment', response) value = '' - toast({ - content: 'Your comment was submitted.', - type: 'success', - }) } catch (err) { console.error(err) toast({ @@ -69,7 +66,7 @@ {...$$restProps} {rows} placeholder={locked - ? 'This post is locked.' + ? $t('comment.locked') : placeholder ?? placeholders.get('comment')} bind:value disabled={locked || loading} @@ -92,7 +89,7 @@ {loading} disabled={locked || loading} > - Submit + {$t('form.submit')}
{/if} diff --git a/src/lib/components/lemmy/comment/CommentVote.svelte b/src/lib/components/lemmy/comment/CommentVote.svelte index 4cda666d0..4725b8148 100644 --- a/src/lib/components/lemmy/comment/CommentVote.svelte +++ b/src/lib/components/lemmy/comment/CommentVote.svelte @@ -17,6 +17,7 @@ import { shouldShowVoteColor } from '../post/PostVote.svelte' import { fly } from 'svelte/transition' import { backOut } from 'svelte/easing' + import { t } from '$lib/translations' export let vote: number = 0 export let upvotes: number @@ -25,7 +26,7 @@ const castVote = async (newVote: number) => { if (!$profile?.jwt) { - toast({ content: 'You must be logged in to vote.', type: 'warning' }) + toast({ content: $t('toast.loginVoteGate'), type: 'warning' }) return } diff --git a/src/lib/components/lemmy/comment/Comments.svelte b/src/lib/components/lemmy/comment/Comments.svelte index e2fd645ed..94655cb6f 100644 --- a/src/lib/components/lemmy/comment/Comments.svelte +++ b/src/lib/components/lemmy/comment/Comments.svelte @@ -18,6 +18,7 @@ import { Button } from 'mono-svelte' import { afterNavigate } from '$app/navigation' import { backOut } from 'svelte/easing' + import { t } from '$lib/translations' export let nodes: CommentNodeI[] export let isParent: boolean @@ -62,7 +63,7 @@ if (newComments.comments.length == 0) { loadingChildren = false toast({ - content: 'The API returned no comments.', + content: $t('toast.noComments'), type: 'error', }) return @@ -81,7 +82,7 @@ parent.children = treeParent.children if (treeParent.children.length == 0) { toast({ - content: 'The API returned no comments.', + content: $t('toast.noComments'), type: 'warning', }) } @@ -90,7 +91,7 @@ parent.children = tree if (tree.length == 0) { toast({ - content: 'The API returned no comments.', + content: $t('toast.noComments'), type: 'warning', }) } @@ -99,7 +100,7 @@ } catch (error) { console.error(error) toast({ - content: `Failed to fetch comments. ${error as any}`, + content: error as any, type: 'error', }) } @@ -112,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} - Purging Community + + {$t('admin.purgeCommunity.title')} + +

- Purging community - {community_view.community.title} - -

-

- Are you sure you want to do this? (The button will enable in 3 seconds.) + {$t('admin.purgeCommunity.warning')}

@@ -224,23 +223,25 @@ > - About + + {$t('cards.site.about')} - Stats + + {$t('cards.site.stats')}
@@ -250,7 +251,8 @@ {#if moderators && moderators.length > 0} - Moderators + + {$t('cards.community.moderators')} ({ @@ -286,8 +288,8 @@ /> {community_view.subscribed == 'Subscribed' || community_view.subscribed == 'Pending' - ? 'Subscribed' - : 'Subscribe'} + ? $t('cards.community.subscribed') + : $t('cards.community.subscribe')} {/if} {#if $profile?.user && amMod($profile.user, community_view.community)} @@ -307,17 +309,19 @@ - Modlog + {$t('cards.community.modlog')} {#if $profile?.jwt} - {community_view.blocked ? 'Unblock' : 'Block'} + {community_view.blocked + ? $t('cards.community.unblock') + : $t('cards.community.block')} {#if $profile?.user} - Block instance + {$t('cards.community.blockInstance')} {/if} {#if $profile?.user && isAdmin($profile.user)} @@ -326,7 +330,7 @@ on:click={() => (purgingCommunity = !purgingCommunity)} > - Purge + {$t('admin.purge')} {/if} {/if} diff --git a/src/lib/components/lemmy/community/CommunityForm.svelte b/src/lib/components/lemmy/community/CommunityForm.svelte index 8d7aa7249..51cd1b8b1 100644 --- a/src/lib/components/lemmy/community/CommunityForm.svelte +++ b/src/lib/components/lemmy/community/CommunityForm.svelte @@ -7,6 +7,8 @@ import { addSubscription } from '$lib/lemmy/user.js' import { Button, Checkbox, TextInput } from 'mono-svelte' import { uploadImage } from '$lib/util.js' + import { t } from '$lib/translations' + import Header from '$lib/components/ui/layout/pages/Header.svelte' /** * The community ID to edit. @@ -68,7 +70,7 @@ }) toast({ - content: `Your community was ${edit ? 'saved' : 'created'}.`, + content: $t('toast.updatedCommunity'), type: 'success', }) @@ -106,23 +108,31 @@
-

Create Community

+
{$t('routes.createCommunity')}
{ formData.name = formData.name.toLowerCase().replaceAll(' ', '_') }} disabled={edit != undefined} /> - - - - + + + + - NSFW + {$t('post.badges.nsfw')} Only moderators can post @@ -134,6 +144,6 @@ loading={formData.submitting} disabled={formData.submitting} > - {edit ? 'Save' : 'Create'} + {edit ? $t('common.save') : $t('form.submit')} diff --git a/src/lib/components/lemmy/community/CommunityItem.svelte b/src/lib/components/lemmy/community/CommunityItem.svelte index cfaf4658c..d552b440c 100644 --- a/src/lib/components/lemmy/community/CommunityItem.svelte +++ b/src/lib/components/lemmy/community/CommunityItem.svelte @@ -20,6 +20,7 @@ import CommunityCard from '$lib/components/lemmy/community/CommunityCard.svelte' import LabelStat from '$lib/components/ui/LabelStat.svelte' import PostBody from '../post/PostBody.svelte' + import { t } from '$lib/translations' export let community: CommunityView @@ -77,9 +78,9 @@ slot="prefix" /> {#if isSubscribed(community.subscribed)} - Subscribed + {$t('cards.community.subscribed')} {:else} - Subscribe + {$t('cards.community.subscribe')} {/if} diff --git a/src/lib/components/lemmy/dropdowns/Location.svelte b/src/lib/components/lemmy/dropdowns/Location.svelte index c74eaf88c..0fb33786d 100644 --- a/src/lib/components/lemmy/dropdowns/Location.svelte +++ b/src/lib/components/lemmy/dropdowns/Location.svelte @@ -6,6 +6,7 @@ import { Select } from 'mono-svelte' import { GlobeAmericas, Icon } from 'svelte-hero-icons' import { amModOfAny } from '../moderation/moderation' + import { t } from '$lib/translations' export let selected: string export let navigate: boolean = true @@ -33,19 +34,19 @@ {#if showLabel} - Location + {$t('filter.location.label')} {/if} - - + + diff --git a/src/lib/components/lemmy/dropdowns/Sort.svelte b/src/lib/components/lemmy/dropdowns/Sort.svelte index 740f25794..56c2f81ce 100644 --- a/src/lib/components/lemmy/dropdowns/Sort.svelte +++ b/src/lib/components/lemmy/dropdowns/Sort.svelte @@ -2,6 +2,7 @@ import { page } from '$app/stores' import { site } from '$lib/lemmy.js' import { userSettings } from '$lib/settings' + import { t } from '$lib/translations' import { searchParam } from '$lib/util.js' import { feature } from '$lib/version.js' import type { SortType } from 'lemmy-js-client' @@ -33,21 +34,19 @@ > - Sort + {$t('filter.sort.label')} - - + + {#if feature('scaledSort', $site?.version)} - + {/if} - - - {#if feature('controversialSort', $site?.version)} - - {/if} - - - + + + + + + {#if selected?.startsWith('Top')}
@@ -62,18 +61,26 @@ > - Time + {$t('filter.sort.top.time.label')} - - - - - - - - - - + + + + + + + + + +
{/if} diff --git a/src/lib/components/lemmy/dropdowns/ViewSelect.svelte b/src/lib/components/lemmy/dropdowns/ViewSelect.svelte index 2dde66557..17bc28606 100644 --- a/src/lib/components/lemmy/dropdowns/ViewSelect.svelte +++ b/src/lib/components/lemmy/dropdowns/ViewSelect.svelte @@ -1,5 +1,6 @@ -

Deny Application

-
deny()} class="flex flex-col gap-4"> -

- Denying 's Application -

- - - +

+ {$t('routes.admin.applications.modalTitle')} +

+
deny()} class="flex flex-col gap-4"> + + + +
diff --git a/src/lib/components/lemmy/modal/PrivateMessageModal.svelte b/src/lib/components/lemmy/modal/PrivateMessageModal.svelte index fba0e7539..9662b72ce 100644 --- a/src/lib/components/lemmy/modal/PrivateMessageModal.svelte +++ b/src/lib/components/lemmy/modal/PrivateMessageModal.svelte @@ -3,8 +3,10 @@ import UserLink from '$lib/components/lemmy/user/UserLink.svelte' import MarkdownEditor from '$lib/components/markdown/MarkdownEditor.svelte' import { getClient } from '$lib/lemmy.js' + import { t } from '$lib/translations' import type { Person } from 'lemmy-js-client' import { Button, Modal, toast } from 'mono-svelte' + import { Icon, PaperAirplane } from 'svelte-hero-icons' export let open: boolean = false export let user: Person @@ -25,7 +27,7 @@ }) toast({ - content: 'Successfully sent that person a message.', + content: $t('toast.sentMessage'), type: 'success', }) @@ -45,16 +47,16 @@

Message

- Sending a message + +

diff --git a/src/lib/components/lemmy/moderation/BanModal.svelte b/src/lib/components/lemmy/moderation/BanModal.svelte index 43d31c541..04671dc2d 100644 --- a/src/lib/components/lemmy/moderation/BanModal.svelte +++ b/src/lib/components/lemmy/moderation/BanModal.svelte @@ -6,6 +6,8 @@ import { profile } from '$lib/auth.js' import { Button, Checkbox, Modal, TextInput } from 'mono-svelte' import MarkdownEditor from '$lib/components/markdown/MarkdownEditor.svelte' + import { t } from '$lib/translations' + import CommunityLink from '../community/CommunityLink.svelte' export let open = false let item: Person | undefined @@ -40,7 +42,7 @@ date = Date.parse(expires) if (Number.isNaN(date)) { toast({ - content: 'Invalid date. It must be an absolute date.', + content: $t('toast.invalidDateAbsolute'), type: 'error', }) @@ -51,7 +53,7 @@ if (date < Date.now()) { toast({ - content: 'Invalid date. It is before the current time.', + content: $t('toast.invalidDateBeforeCurrent'), type: 'error', }) @@ -82,9 +84,7 @@ open = false toast({ - content: `Successfully ${ - banned ? 'unbanned' : 'banned' - } that user. You may need to refresh to see changes.`, + content: banned ? $t('toast.unbannedUser') : $t('toast.bannedUser'), type: 'success', }) @@ -101,42 +101,38 @@ -

{banned ? 'Unbanning' : 'Banning'} user

+

+ {banned ? $t('moderation.ban.unbanning') : $t('moderation.ban.banning')} +

{#if item}
{item.name}
-

- {banned ? 'Unbanning' : 'Banning'} from - {community ? community.name : 'site'} -

+ {#if community} + + {/if} {#if !banned} - Delete data + {$t('moderation.ban.deleteData')} - This will delete ALL of this user's posts and comments on this {community - ? 'community' - : 'site'}. + {$t('moderation.ban.warning')} {/if} {/if} diff --git a/src/lib/components/lemmy/moderation/CommentModerationMenu.svelte b/src/lib/components/lemmy/moderation/CommentModerationMenu.svelte index 228b7a781..c176d9557 100644 --- a/src/lib/components/lemmy/moderation/CommentModerationMenu.svelte +++ b/src/lib/components/lemmy/moderation/CommentModerationMenu.svelte @@ -6,6 +6,7 @@ import { profile } from '$lib/auth.js' import ShieldIcon from '$lib/components/lemmy/moderation/ShieldIcon.svelte' import { Button, Menu, MenuButton, MenuDivider } from 'mono-svelte' + import { t } from '$lib/translations' export let item: PostView | CommentView @@ -22,16 +23,20 @@ {#if ($profile?.user && amMod($profile.user, item.community)) || ($profile?.user && isAdmin($profile.user))} - Moderation {#if !item.community.local && !amMod($profile.user, item.community)} - (Instance Only) + {#if !item.community.local && !amMod($profile.user, item.community)} + {$t('moderation.labelInstanceOnly')} + {:else} + {$t('moderation.label')} {/if} remove(item)}> {#if isCommentView(item)} - {item.comment.removed ? 'Restore' : 'Remove'} + {item.comment.removed + ? $t('moderation.restore') + : $t('moderation.remove')} {:else} - {item.post.removed ? 'Restore' : 'Remove'} + {item.post.removed ? $t('moderation.restore') : $t('moderation.remove')} {/if} {#if $profile?.user && $profile.user?.local_user_view.person.id != item.creator.id} @@ -42,17 +47,17 @@ > {item.creator_banned_from_community - ? 'Unban from community' - : 'Ban from community'} + ? $t('moderation.ban.unbanFromCommunity') + : $t('moderation.ban.banFromCommunity')} {/if} {/if} {#if $profile?.user && isAdmin($profile.user)} - Admin + {$t('admin.label')} remove(item, true)}> - Purge + {$t('admin.purge')} {/if} diff --git a/src/lib/components/lemmy/moderation/ModerationMenu.svelte b/src/lib/components/lemmy/moderation/ModerationMenu.svelte index de9710331..c2f1a6282 100644 --- a/src/lib/components/lemmy/moderation/ModerationMenu.svelte +++ b/src/lib/components/lemmy/moderation/ModerationMenu.svelte @@ -15,6 +15,8 @@ import { Menu, MenuButton, MenuDivider, toast } from 'mono-svelte' import { profile } from '$lib/auth.js' import { Button } from 'mono-svelte' + import { t } from '$lib/translations' + import ShieldIcon from './ShieldIcon.svelte' export let item: PostView | CommentView @@ -34,11 +36,6 @@ }) item.post.locked = lock - - toast({ - content: `Successfully ${lock ? 'locked' : 'unlocked'} that post.`, - type: 'success', - }) } catch (err) { toast({ content: err as any, @@ -62,11 +59,6 @@ }) item.post.featured_community = pinned - - toast({ - content: `Successfully ${pinned ? 'pinned' : 'unpinned'} that post.`, - type: 'success', - }) } catch (err) { toast({ content: err as any, @@ -87,26 +79,14 @@ loading={acting} {...$$restProps} > - - - + {#if ($profile?.user && amMod($profile.user, item.community)) || ($profile?.user && isAdmin($profile.user))} - Moderation {#if !item.community.local && !amMod($profile.user, item.community)} - (Instance Only) + {#if !item.community.local && !amMod($profile.user, item.community)} + {$t('moderation.labelInstanceOnly')} + {:else} + {$t('moderation.label')} {/if} - {item.post.locked ? 'Unlock' : 'Lock'} + {item.post.locked ? $t('moderation.unlock') : $t('moderation.lock')} - {item.post.featured_community ? 'Unfeature' : 'Feature'} + + {item.post.featured_community + ? $t('moderation.unfeature') + : $t('moderation.feature')} + {#if isAdmin($profile.user)} - Community + {$t('form.post.community')} {/if}
remove(item)}> {#if isCommentView(item)} - {item.comment.removed ? 'Restore' : 'Remove'} + {item.comment.removed + ? $t('moderation.restore') + : $t('moderation.remove')} {:else} - {item.post.removed ? 'Restore' : 'Remove'} + {item.post.removed ? $t('moderation.restore') : $t('moderation.remove')} {/if} {#if $profile?.user && $profile.user.local_user_view.person.id != item.creator.id} @@ -157,13 +143,13 @@ > {item.creator_banned_from_community - ? 'Unban from community' - : 'Ban from community'} + ? $t('moderation.ban.unbanFromCommunity') + : $t('moderation.ban.banFromCommunity')} {/if} {/if} {#if $profile?.user && isAdmin($profile.user)} - Admin + {$t('admin.label')} @@ -173,13 +159,17 @@
- {item.post.featured_local ? 'Unfeature' : 'Feature'} - Instance + + {item.post.featured_local + ? $t('moderation.unfeature') + : $t('moderation.feature')} + + {$t('admin.instance')}
remove(item, true)}> - Purge + {$t('admin.purge')} {/if} diff --git a/src/lib/components/lemmy/moderation/RemoveModal.svelte b/src/lib/components/lemmy/moderation/RemoveModal.svelte index 4989d8cca..9d7dbbb4d 100644 --- a/src/lib/components/lemmy/moderation/RemoveModal.svelte +++ b/src/lib/components/lemmy/moderation/RemoveModal.svelte @@ -14,6 +14,7 @@ import { fullCommunityName } from '$lib/util.js' import { amMod, isAdmin } from './moderation' import { Button, Checkbox, Modal } from 'mono-svelte' + import { t } from '$lib/translations' export let open: boolean export let item: PostView | CommentView | undefined = undefined @@ -68,7 +69,7 @@ } toast({ - content: 'Successfully purged that submission.', + content: $t('moderation.removeSubmission.successPurge'), type: 'success', }) @@ -81,7 +82,7 @@ if (commentReason) { if (replyReason == '') { toast({ - content: 'Your reply cannot be empty if "Reply reason" is enabled.', + content: $t('moderation.removeSubmission.failEmptyReply'), }) return } @@ -96,7 +97,7 @@ }) .catch(() => { toast({ - content: 'Failed to message user. Removing anyway...', + content: $t('moderation.removeSubmission.failMessage'), type: 'warning', }) }) @@ -109,7 +110,7 @@ }) .catch(() => { toast({ - content: 'Failed to post reply. Removing anyway...', + content: $t('moderation.removeSubmission.failReply'), type: 'warning', }) }) @@ -134,13 +135,6 @@ } open = false - - toast({ - content: `Successfully ${ - removed ? 'restored' : 'removed' - } that submission.`, - type: 'success', - }) } catch (err) { toast({ content: err as any, @@ -166,7 +160,11 @@ - {purge ? 'Purging' : removed ? 'Restoring' : 'Removing'} submission + {purge + ? $t('moderation.removeSubmission.titlePurge') + : removed + ? $t('moderation.removeSubmission.titleRestore') + : $t('moderation.removeSubmission.title')} {#if item}
{#if !removed && $profile?.user && (amMod($profile.user, item.community) || (isAdmin($profile.user) && item.community.local))} - Reply with reason + + {$t('moderation.removeSubmission.withReason')} + {#if commentReason}
- Reply + {$t('comment.reply')} +
+ + + +
+ {#if result} + {#await result} +
+ +
+ {:then result} + {#if !error} + + {/if} + {:catch err} + + {/await} + {:else} +