mirror of
https://github.com/versia-pub/frontend.git
synced 2026-03-13 03:29:16 +01:00
feat: ✨ Implement internationalization
This commit is contained in:
parent
02d9869737
commit
8c3ddc2a28
23 changed files with 399 additions and 123 deletions
|
|
@ -3,61 +3,61 @@
|
|||
<DropdownMenuTrigger as-child>
|
||||
<slot />
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent class="w-56">
|
||||
<DropdownMenuLabel>Profile Actions</DropdownMenuLabel>
|
||||
<DropdownMenuContent class="min-w-56">
|
||||
<DropdownMenuLabel>{{ m.spicy_loved_giraffe_empower() }}</DropdownMenuLabel>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem as="button" @click="copyText(account.username)">
|
||||
<AtSign class="mr-2 size-4" />
|
||||
<span>Copy username</span>
|
||||
{{ m.cool_dark_tapir_belong() }}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem as="button" @click="copyText(JSON.stringify(account, null, 4))">
|
||||
<Code class="mr-2 size-4" />
|
||||
<span>Copy API data</span>
|
||||
{{ m.yummy_moving_scallop_sail() }}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem as="button" @click="copyText(account.id)">
|
||||
<Hash class="mr-2 size-4" />
|
||||
<span>Copy ID</span>
|
||||
{{ m.sunny_zany_jellyfish_pop() }}
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem as="button" @click="copyText(url)">
|
||||
<Link class="mr-2 size-4" />
|
||||
<span>Copy link</span>
|
||||
{{ m.ago_new_pelican_drip() }}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem as="button" @click="copyText(account.url)">
|
||||
<Link class="mr-2 size-4" />
|
||||
<span>Copy link (origin)</span>
|
||||
{{ m.solid_witty_zebra_walk() }}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem as="a" v-if="isRemote" target="_blank" rel="noopener noreferrer" :href="account.url">
|
||||
<ExternalLink class="mr-2 size-4" />
|
||||
<span>Open on remote</span>
|
||||
{{ m.active_trite_lark_inspire() }}
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
<DropdownMenuSeparator v-if="isLoggedIn && !isMe" />
|
||||
<DropdownMenuGroup v-if="isLoggedIn && !isMe">
|
||||
<DropdownMenuItem as="button" @click="muteUser(account.id)">
|
||||
<VolumeX class="mr-2 size-4" />
|
||||
<span>Mute</span>
|
||||
{{ m.spare_wild_mole_intend() }}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem as="button" @click="blockUser(account.id)">
|
||||
<Ban class="mr-2 size-4" />
|
||||
<span>Block</span>
|
||||
{{ m.misty_soft_sparrow_vent() }}
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
<DropdownMenuSeparator v-if="isRemote" />
|
||||
<DropdownMenuGroup v-if="isRemote">
|
||||
<DropdownMenuItem as="button" @click="refresh">
|
||||
<RefreshCw class="mr-2 size-4" />
|
||||
<span>Refresh</span>
|
||||
{{ m.slow_chunky_chipmunk_hush() }}
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
<DropdownMenuSeparator v-if="isLoggedIn && !isMe" />
|
||||
<DropdownMenuGroup v-if="isLoggedIn && !isMe">
|
||||
<DropdownMenuItem as="button" :disabled="true">
|
||||
<Flag class="mr-2 size-4" />
|
||||
<span>Report</span>
|
||||
{{ m.great_few_jaguar_rise() }}
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
</DropdownMenuContent>
|
||||
|
|
@ -87,6 +87,7 @@ import {
|
|||
VolumeX,
|
||||
} from "lucide-vue-next";
|
||||
import { toast } from "vue-sonner";
|
||||
import * as m from "~/paraglide/messages.js";
|
||||
|
||||
const { account } = defineProps<{
|
||||
account: Account;
|
||||
|
|
@ -98,14 +99,14 @@ const isLoggedIn = !!identity.value;
|
|||
const { copy } = useClipboard();
|
||||
const copyText = (text: string) => {
|
||||
copy(text);
|
||||
toast.success("Copied to clipboard");
|
||||
toast.success(m.flat_nice_worm_dream());
|
||||
};
|
||||
|
||||
const url = wrapUrl(`/@${account.acct}`);
|
||||
const isRemote = account.acct.includes("@");
|
||||
|
||||
const muteUser = async (userId: string) => {
|
||||
const id = toast.loading("Muting user...");
|
||||
const id = toast.loading(m.ornate_tidy_coyote_grow());
|
||||
await client.value.muteAccount(userId);
|
||||
toast.dismiss(id);
|
||||
|
||||
|
|
@ -113,7 +114,7 @@ const muteUser = async (userId: string) => {
|
|||
};
|
||||
|
||||
const blockUser = async (userId: string) => {
|
||||
const id = toast.loading("Blocking user...");
|
||||
const id = toast.loading(m.empty_smug_raven_bloom());
|
||||
await client.value.blockAccount(userId);
|
||||
toast.dismiss(id);
|
||||
|
||||
|
|
@ -121,10 +122,10 @@ const blockUser = async (userId: string) => {
|
|||
};
|
||||
|
||||
const refresh = async () => {
|
||||
const id = toast.loading("Requesting refresh...");
|
||||
const id = toast.loading(m.real_every_macaw_wish());
|
||||
await client.value.refetchAccount(account.id);
|
||||
toast.dismiss(id);
|
||||
|
||||
toast.success("Account refreshed");
|
||||
toast.success(m.many_cool_fox_love());
|
||||
};
|
||||
</script>
|
||||
|
|
@ -3,20 +3,20 @@
|
|||
<div class="flex flex-row flex-wrap gap-2 *:flex *:items-center *:gap-1 *:text-muted-foreground">
|
||||
<div>
|
||||
<CalendarDays class="size-4" />
|
||||
Joined <span class="text-primary font-semibold">{{ formattedCreationDate }}</span>
|
||||
{{ m.gross_fancy_platypus_seek() }} <span class="text-primary font-semibold">{{ formattedCreationDate }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-row flex-wrap gap-2 *:flex *:items-center *:gap-1 *:text-muted-foreground">
|
||||
<div>
|
||||
<span class="text-primary font-semibold">{{ noteCount }}</span> Notes
|
||||
<span class="text-primary font-semibold">{{ noteCount }}</span> {{ m.real_gray_stork_seek() }}
|
||||
</div>
|
||||
·
|
||||
<div>
|
||||
<span class="text-primary font-semibold">{{ followerCount }}</span> Followers
|
||||
<span class="text-primary font-semibold">{{ followerCount }}</span> {{ m.teal_helpful_parakeet_hike() }}
|
||||
</div>
|
||||
·
|
||||
<div>
|
||||
<span class="text-primary font-semibold">{{ followingCount }}</span> Following
|
||||
<span class="text-primary font-semibold">{{ followingCount }}</span> {{ m.aloof_royal_samuel_startle() }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -24,6 +24,8 @@
|
|||
|
||||
<script lang="ts" setup>
|
||||
import { CalendarDays } from "lucide-vue-next";
|
||||
import * as m from "~/paraglide/messages.js";
|
||||
import { languageTag } from "~/paraglide/runtime";
|
||||
|
||||
const { creationDate } = defineProps<{
|
||||
creationDate: Date;
|
||||
|
|
@ -32,7 +34,7 @@ const { creationDate } = defineProps<{
|
|||
followingCount: number;
|
||||
}>();
|
||||
|
||||
const formattedCreationDate = new Intl.DateTimeFormat("en-US", {
|
||||
const formattedCreationDate = new Intl.DateTimeFormat(languageTag(), {
|
||||
month: "long",
|
||||
year: "numeric",
|
||||
}).format(creationDate);
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
@click="relationship?.following ? unfollow() : follow()">
|
||||
<Loader v-if="isLoading" class="animate-spin" />
|
||||
<span v-else>
|
||||
{{ relationship?.following ? "Unfollow" : relationship?.requested ? "Requested" : "Follow" }}
|
||||
{{ relationship?.following ? m.brief_upper_otter_cuddle() : relationship?.requested ? m.weak_bright_larva_grasp() : m.lazy_major_loris_grasp() }}
|
||||
</span>
|
||||
</Button>
|
||||
<ProfileActions :account="account">
|
||||
|
|
@ -29,10 +29,10 @@
|
|||
</CopyableText>
|
||||
</div>
|
||||
<div class="flex flex-row flex-wrap gap-2 -mx-2" v-if="isDeveloper || account.bot || roles.length > 0">
|
||||
<ProfileBadge v-if="isDeveloper" name="Versia Developer" description="This user is a Versia developer."
|
||||
<ProfileBadge v-if="isDeveloper" :name="m.nice_bad_grizzly_coax()" :description="m.honest_jolly_shell_blend()"
|
||||
:verified="true" />
|
||||
<ProfileBadge v-if="account.bot" name="Automated"
|
||||
description="This account is not operated as living entity." />
|
||||
<ProfileBadge v-if="account.bot" :name="m.merry_red_shrimp_bump()"
|
||||
:description="m.sweet_mad_jannes_create()" />
|
||||
<ProfileBadge v-for="role in roles" :key="role.id" :name="role.name" :description="role.description"
|
||||
:icon="role.icon" />
|
||||
</div>
|
||||
|
|
@ -55,6 +55,7 @@ import CopyableText from "~/components/notes/copyable-text.vue";
|
|||
import { Button } from "~/components/ui/button";
|
||||
import { Card, CardContent, CardFooter, CardTitle } from "~/components/ui/card";
|
||||
import { Separator } from "~/components/ui/separator";
|
||||
import * as m from "~/paraglide/messages.js";
|
||||
import { SettingIds } from "~/settings";
|
||||
import { confirmModalService } from "../modals/composable";
|
||||
import ProfileActions from "./profile-actions.vue";
|
||||
|
|
@ -84,44 +85,48 @@ const confirmFollows = useSetting(SettingIds.ConfirmFollow);
|
|||
const follow = async () => {
|
||||
if (confirmFollows.value.value) {
|
||||
const confirmation = await confirmModalService.confirm({
|
||||
title: "Follow user",
|
||||
message: `Are you sure you want to follow @${account.acct}?`,
|
||||
confirmText: "Follow",
|
||||
cancelText: "Cancel",
|
||||
title: m.many_fair_capybara_imagine(),
|
||||
message: m.mellow_yummy_jannes_cuddle({
|
||||
acct: `@${account.acct}`,
|
||||
}),
|
||||
confirmText: m.cuddly_even_tern_loop(),
|
||||
cancelText: m.soft_bold_ant_attend(),
|
||||
});
|
||||
|
||||
if (!confirmation) {
|
||||
if (!confirmation.confirmed) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const id = toast.loading("Following user...");
|
||||
const id = toast.loading(m.quick_basic_peacock_bubble());
|
||||
const { data } = await client.value.followAccount(account.id);
|
||||
toast.dismiss(id);
|
||||
|
||||
relationship.value = data;
|
||||
toast.success("User followed");
|
||||
toast.success(m.awake_quick_cuckoo_smile());
|
||||
};
|
||||
|
||||
const unfollow = async () => {
|
||||
if (confirmFollows.value.value) {
|
||||
const confirmation = await confirmModalService.confirm({
|
||||
title: "Unfollow user",
|
||||
message: `Are you sure you want to unfollow @${account.acct}?`,
|
||||
confirmText: "Unfollow",
|
||||
cancelText: "Cancel",
|
||||
title: m.funny_aloof_swan_loop(),
|
||||
message: m.white_best_dolphin_catch({
|
||||
acct: `@${account.acct}`,
|
||||
}),
|
||||
confirmText: m.cute_polite_oryx_blend(),
|
||||
cancelText: m.soft_bold_ant_attend(),
|
||||
});
|
||||
|
||||
if (!confirmation) {
|
||||
if (!confirmation.confirmed) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const id = toast.loading("Unfollowing user...");
|
||||
const id = toast.loading(m.big_safe_guppy_mix());
|
||||
const { data } = await client.value.unfollowAccount(account.id);
|
||||
toast.dismiss(id);
|
||||
|
||||
relationship.value = data;
|
||||
toast.success("User unfollowed");
|
||||
toast.success(m.misty_level_stingray_expand());
|
||||
};
|
||||
</script>
|
||||
Loading…
Add table
Add a link
Reference in a new issue