mirror of
https://github.com/elk-zone/elk
synced 2024-11-30 15:58:06 +09:00
fix: layout fixes for RTL languages (#591)
* fix: rtl arrows on settings page * fix: border on settings page for RTL languages * fix: RTL fixes for logo, search box and logout icon * fix: RTL layout bugs in conversations * chore: remove rtl setting icon * improve arabic locale * add new entries to arabic locale * chore: include number format * fix: RTL layout on several pages * fix: RTL layout of account header and sign in modal * fix: always display account handle in LTR * fix: move character counter in publish widget to left side for RTL * fix: remove border-ss-none unocss rule * fix: many RTL fixes * fix: RTL fixes for many pages * fix: use viewer's direction in all content * chore: use new arabic plural rules * chore: flip arrow on main content header * chore: fix StatusPoll and show_new_items for zh-TW * chore: StatusPoll tooltip on bottom * chore: add `en` variants to i18n conf * chore: update entry to use new plural rule * fix: automatic content direction for status * fix: direction for account handle * fix: direction of polls Co-authored-by: userquin <userquin@gmail.com> Co-authored-by: Jean-Paul Khawam <jeanpaulkhawam@protonmail.com> Co-authored-by: Daniel Roe <daniel@roe.dev>
This commit is contained in:
parent
c5304be775
commit
727d05915f
@ -24,7 +24,7 @@ defineOptions({
|
|||||||
<!-- User info -->
|
<!-- User info -->
|
||||||
<div flex sm:flex-row flex-col flex-gap-2>
|
<div flex sm:flex-row flex-col flex-gap-2>
|
||||||
<div flex items-center justify-between>
|
<div flex items-center justify-between>
|
||||||
<div w-17 h-17 rounded-full border-4 border-bg-base z-2 mt--2 ml--1>
|
<div w-17 h-17 rounded-full border-4 border-bg-base z-2 mt--2 ms--1>
|
||||||
<AccountAvatar :account="account" />
|
<AccountAvatar :account="account" />
|
||||||
</div>
|
</div>
|
||||||
<a block sm:hidden href="javascript:;" @click.stop>
|
<a block sm:hidden href="javascript:;" @click.stop>
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
<!-- User info -->
|
<!-- User info -->
|
||||||
<div flex sm:flex-row flex-col flex-gap-2>
|
<div flex sm:flex-row flex-col flex-gap-2>
|
||||||
<div flex items-center justify-between>
|
<div flex items-center justify-between>
|
||||||
<div w-17 h-17 rounded-full border-4 border-bg-base z-2 mt--2 ml--1 of-hidden bg-base>
|
<div w-17 h-17 rounded-full border-4 border-bg-base z-2 mt--2 ms--1 of-hidden bg-base>
|
||||||
<div class="flex skeleton-loading-bg" w-full h-full />
|
<div class="flex skeleton-loading-bg" w-full h-full />
|
||||||
</div>
|
</div>
|
||||||
<div block sm:hidden class="skeleton-loading-bg" h-8 w-30 rounded-full />
|
<div block sm:hidden class="skeleton-loading-bg" h-8 w-30 rounded-full />
|
||||||
|
@ -9,7 +9,7 @@ const serverName = $computed(() => getServerName(account))
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<p line-clamp-1 whitespace-pre-wrap break-all text-secondary-light>
|
<p line-clamp-1 whitespace-pre-wrap break-all text-secondary-light dir="ltr">
|
||||||
<!-- fix: #274 only line-clamp-1 can be used here, using text-ellipsis is not valid -->
|
<!-- fix: #274 only line-clamp-1 can be used here, using text-ellipsis is not valid -->
|
||||||
<span text-secondary>{{ getShortHandle(account) }}</span>
|
<span text-secondary>{{ getShortHandle(account) }}</span>
|
||||||
<span v-if="serverName" text-secondary-light>@{{ serverName }}</span>
|
<span v-if="serverName" text-secondary-light>@{{ serverName }}</span>
|
||||||
|
@ -90,7 +90,7 @@ const isSelf = $computed(() => currentUser.value?.account.id === account.id)
|
|||||||
<AccountHandle :account="account" />
|
<AccountHandle :account="account" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div absolute top-18 right-0 flex gap-2 items-center>
|
<div absolute top-18 inset-ie-0 flex gap-2 items-center>
|
||||||
<AccountMoreButton :account="account" :command="command" />
|
<AccountMoreButton :account="account" :command="command" />
|
||||||
<AccountFollowButton :account="account" :command="command" />
|
<AccountFollowButton :account="account" :command="command" />
|
||||||
<!-- Edit profile -->
|
<!-- Edit profile -->
|
||||||
|
@ -11,7 +11,7 @@ const relationship = $(useRelationship(account))
|
|||||||
<template>
|
<template>
|
||||||
<div v-show="relationship" flex="~ col gap2" rounded min-w-90 max-w-120 z-100 overflow-hidden p-4>
|
<div v-show="relationship" flex="~ col gap2" rounded min-w-90 max-w-120 z-100 overflow-hidden p-4>
|
||||||
<div flex="~ gap2" items-center>
|
<div flex="~ gap2" items-center>
|
||||||
<NuxtLink :to="getAccountRoute(account)" flex-auto rounded-full hover:bg-active transition-100 pr5 mr-a>
|
<NuxtLink :to="getAccountRoute(account)" flex-auto rounded-full hover:bg-active transition-100 pe5 me-a>
|
||||||
<AccountInfo :account="account" />
|
<AccountInfo :account="account" />
|
||||||
</NuxtLink>
|
</NuxtLink>
|
||||||
<AccountFollowButton text-sm :account="account" :relationship="relationship" />
|
<AccountFollowButton text-sm :account="account" :relationship="relationship" />
|
||||||
|
@ -12,7 +12,7 @@ const { link = true, avatar = true } = defineProps<{
|
|||||||
<AccountHoverWrapper :account="account">
|
<AccountHoverWrapper :account="account">
|
||||||
<NuxtLink
|
<NuxtLink
|
||||||
:to="link ? getAccountRoute(account) : undefined"
|
:to="link ? getAccountRoute(account) : undefined"
|
||||||
:class="link ? 'text-link-rounded ml-0 pl-0' : ''"
|
:class="link ? 'text-link-rounded ms-0 ps-0' : ''"
|
||||||
min-w-0 flex gap-2 items-center
|
min-w-0 flex gap-2 items-center
|
||||||
>
|
>
|
||||||
<AccountAvatar v-if="avatar" :account="account" w-5 h-5 />
|
<AccountAvatar v-if="avatar" :account="account" w-5 h-5 />
|
||||||
|
@ -26,7 +26,7 @@ const followersCountSR = $computed(() => forSR(props.account.followersCount))
|
|||||||
<i18n-t keypath="account.posts_count" :plural="account.statusesCount">
|
<i18n-t keypath="account.posts_count" :plural="account.statusesCount">
|
||||||
<CommonTooltip v-if="statusesCountSR" :content="formatNumber(account.statusesCount)" placement="bottom">
|
<CommonTooltip v-if="statusesCountSR" :content="formatNumber(account.statusesCount)" placement="bottom">
|
||||||
<span aria-hidden="true" font-bold :class="isExactActive ? 'text-primary' : 'text-base'">{{ statusesCount }}</span>
|
<span aria-hidden="true" font-bold :class="isExactActive ? 'text-primary' : 'text-base'">{{ statusesCount }}</span>
|
||||||
<span sr-only font-bold>{{ account.statusesCount }}</span>
|
<span sr-only font-bold>{{ formatNumber(account.statusesCount) }}</span>
|
||||||
</CommonTooltip>
|
</CommonTooltip>
|
||||||
<span v-else font-bold :class="isExactActive ? 'text-primary' : 'text-base'">{{ statusesCount }}</span>
|
<span v-else font-bold :class="isExactActive ? 'text-primary' : 'text-base'">{{ statusesCount }}</span>
|
||||||
</i18n-t>
|
</i18n-t>
|
||||||
@ -41,7 +41,7 @@ const followersCountSR = $computed(() => forSR(props.account.followersCount))
|
|||||||
<i18n-t keypath="account.following_count" :plural="account.followingCount">
|
<i18n-t keypath="account.following_count" :plural="account.followingCount">
|
||||||
<CommonTooltip v-if="followingCountSR" :content="formatNumber(account.followingCount)" placement="bottom">
|
<CommonTooltip v-if="followingCountSR" :content="formatNumber(account.followingCount)" placement="bottom">
|
||||||
<span aria-hidden="true" font-bold :class="isExactActive ? 'text-primary' : 'text-base'">{{ followingCount }}</span>
|
<span aria-hidden="true" font-bold :class="isExactActive ? 'text-primary' : 'text-base'">{{ followingCount }}</span>
|
||||||
<span sr-only font-bold>{{ account.followingCount }}</span>
|
<span sr-only font-bold>{{ formatNumber(account.followingCount) }}</span>
|
||||||
</CommonTooltip>
|
</CommonTooltip>
|
||||||
<span v-else font-bold :class="isExactActive ? 'text-primary' : 'text-base'">{{ followingCount }}</span>
|
<span v-else font-bold :class="isExactActive ? 'text-primary' : 'text-base'">{{ followingCount }}</span>
|
||||||
</i18n-t>
|
</i18n-t>
|
||||||
@ -56,7 +56,7 @@ const followersCountSR = $computed(() => forSR(props.account.followersCount))
|
|||||||
<i18n-t keypath="account.followers_count" :plural="account.followersCount">
|
<i18n-t keypath="account.followers_count" :plural="account.followersCount">
|
||||||
<CommonTooltip v-if="followersCountSR" :content="formatNumber(account.followersCount)" placement="bottom">
|
<CommonTooltip v-if="followersCountSR" :content="formatNumber(account.followersCount)" placement="bottom">
|
||||||
<span aria-hidden="true" font-bold :class="isExactActive ? 'text-primary' : 'text-base'">{{ followersCount }}</span>
|
<span aria-hidden="true" font-bold :class="isExactActive ? 'text-primary' : 'text-base'">{{ followersCount }}</span>
|
||||||
<span sr-only font-bold>{{ account.followersCount }}</span>
|
<span sr-only font-bold>{{ formatNumber(account.followersCount) }}</span>
|
||||||
</CommonTooltip>
|
</CommonTooltip>
|
||||||
<span v-else font-bold :class="isExactActive ? 'text-primary' : 'text-base'">{{ followersCount }}</span>
|
<span v-else font-bold :class="isExactActive ? 'text-primary' : 'text-base'">{{ followersCount }}</span>
|
||||||
</i18n-t>
|
</i18n-t>
|
||||||
|
@ -23,7 +23,7 @@ const {
|
|||||||
:data-index="index"
|
:data-index="index"
|
||||||
@click="emits('activate')"
|
@click="emits('activate')"
|
||||||
>
|
>
|
||||||
<div v-if="cmd.icon" mr-2 :class="cmd.icon" />
|
<div v-if="cmd.icon" me-2 :class="cmd.icon" />
|
||||||
|
|
||||||
<div class="flex-1 flex items-baseline gap-2">
|
<div class="flex-1 flex items-baseline gap-2">
|
||||||
<div :class="{ 'font-medium': active }">
|
<div :class="{ 'font-medium': active }">
|
||||||
|
@ -11,7 +11,7 @@ const { modelValue } = defineModel<{
|
|||||||
<template>
|
<template>
|
||||||
<label
|
<label
|
||||||
class="common-checkbox flex items-center cursor-pointer py-1 text-md w-full gap-y-1"
|
class="common-checkbox flex items-center cursor-pointer py-1 text-md w-full gap-y-1"
|
||||||
:class="hover ? 'hover:bg-active ml--2 pl-4' : null"
|
:class="hover ? 'hover:bg-active ms--2 ps-4' : null"
|
||||||
@click.prevent="modelValue = !modelValue"
|
@click.prevent="modelValue = !modelValue"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
@ -23,7 +23,7 @@ const { modelValue } = defineModel<{
|
|||||||
type="checkbox"
|
type="checkbox"
|
||||||
sr-only
|
sr-only
|
||||||
>
|
>
|
||||||
<span ml-2 pointer-events-none>{{ label }}</span>
|
<span ms-2 pointer-events-none>{{ label }}</span>
|
||||||
</label>
|
</label>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ const { modelValue } = defineModel<{
|
|||||||
<template>
|
<template>
|
||||||
<label
|
<label
|
||||||
class="common-radio flex items-center cursor-pointer py-1 text-md w-full gap-y-1"
|
class="common-radio flex items-center cursor-pointer py-1 text-md w-full gap-y-1"
|
||||||
:class="hover ? 'hover:bg-active ml--2 pl-4' : null"
|
:class="hover ? 'hover:bg-active ms--2 ps-4' : null"
|
||||||
@click.prevent="modelValue = value"
|
@click.prevent="modelValue = value"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
@ -25,7 +25,7 @@ const { modelValue } = defineModel<{
|
|||||||
:value="value"
|
:value="value"
|
||||||
sr-only
|
sr-only
|
||||||
>
|
>
|
||||||
<span ml-2 pointer-events-none>{{ label }}</span>
|
<span ms-2 pointer-events-none>{{ label }}</span>
|
||||||
</label>
|
</label>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ const useEmojis = computed(() => {
|
|||||||
|
|
||||||
export default () => h(
|
export default () => h(
|
||||||
'span',
|
'span',
|
||||||
{ class: 'content-rich' },
|
{ class: 'content-rich', dir: 'auto' },
|
||||||
contentToVNode(content, {
|
contentToVNode(content, {
|
||||||
emojis: useEmojis.value,
|
emojis: useEmojis.value,
|
||||||
markdown,
|
markdown,
|
||||||
|
@ -15,7 +15,7 @@ const withAccounts = $computed(() =>
|
|||||||
<StatusCard v-if="conversation.lastStatus" :status="conversation.lastStatus" :actions="false">
|
<StatusCard v-if="conversation.lastStatus" :status="conversation.lastStatus" :actions="false">
|
||||||
<template #meta>
|
<template #meta>
|
||||||
<div flex gap-2 text-sm text-secondary font-bold>
|
<div flex gap-2 text-sm text-secondary font-bold>
|
||||||
<p mr-1>
|
<p me-1>
|
||||||
{{ $t('conversation.with') }}
|
{{ $t('conversation.with') }}
|
||||||
</p>
|
</p>
|
||||||
<AccountAvatar v-for="account in withAccounts" :key="account.id" h-5 w-5 :account="account" />
|
<AccountAvatar v-for="account in withAccounts" :key="account.id" h-5 w-5 :account="account" />
|
||||||
|
@ -44,7 +44,7 @@ const teams: Team[] = [
|
|||||||
<div i-ri:close-line />
|
<div i-ri:close-line />
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<img src="/logo.svg" w-20 h-20 height="80" width="80" mxa alt="logo">
|
<img :alt="$t('app_logo')" src="/logo.svg" w-20 h-20 height="80" width="80" mxa class="rtl-flip">
|
||||||
<h1 mxa text-4xl mb4>
|
<h1 mxa text-4xl mb4>
|
||||||
{{ $t('help.title') }}
|
{{ $t('help.title') }}
|
||||||
</h1>
|
</h1>
|
||||||
|
@ -21,7 +21,7 @@ defineProps<{
|
|||||||
:class="{ 'lg:hidden': backOnSmallScreen }"
|
:class="{ 'lg:hidden': backOnSmallScreen }"
|
||||||
@click="$router.go(-1)"
|
@click="$router.go(-1)"
|
||||||
>
|
>
|
||||||
<div i-ri:arrow-left-line />
|
<div i-ri:arrow-left-line class="rtl-flip" />
|
||||||
</NuxtLink>
|
</NuxtLink>
|
||||||
<div truncate>
|
<div truncate>
|
||||||
<slot name="title" />
|
<slot name="title" />
|
||||||
|
@ -55,12 +55,12 @@ function onClick(e: MouseEvent) {
|
|||||||
>
|
>
|
||||||
<div i-ri:close-line text-white />
|
<div i-ri:close-line text-white />
|
||||||
</button>
|
</button>
|
||||||
<div bg="black/30" dark:bg="white/10" ml-4 my-auto text-white rounded-full flex="~ center" overflow-hidden>
|
<div bg="black/30" dark:bg="white/10" ms-4 my-auto text-white rounded-full flex="~ center" overflow-hidden>
|
||||||
<div v-if="mediaPreviewList.length > 1" p="y-1 x-2" rounded-r-0 shrink-0>
|
<div v-if="mediaPreviewList.length > 1" p="y-1 x-2" rounded-r-0 shrink-0>
|
||||||
{{ mediaPreviewIndex + 1 }} / {{ mediaPreviewList.length }}
|
{{ mediaPreviewIndex + 1 }} / {{ mediaPreviewList.length }}
|
||||||
</div>
|
</div>
|
||||||
<p
|
<p
|
||||||
v-if="current.description" bg="dark/30" dark:bg="white/10" p="y-1 x-2" rounded-r-full line-clamp-1
|
v-if="current.description" bg="dark/30" dark:bg="white/10" p="y-1 x-2" rounded-ie-full line-clamp-1
|
||||||
ws-pre-wrap break-all :title="current.description" w-full
|
ws-pre-wrap break-all :title="current.description" w-full
|
||||||
>
|
>
|
||||||
{{ current.description }}
|
{{ current.description }}
|
||||||
|
@ -83,7 +83,7 @@ onBeforeUnmount(() => {
|
|||||||
hover="bg-gray-100 dark:(bg-gray-700 text-white)"
|
hover="bg-gray-100 dark:(bg-gray-700 text-white)"
|
||||||
@click="toggleDark()"
|
@click="toggleDark()"
|
||||||
>
|
>
|
||||||
<span class="i-ri:sun-line dark:i-ri:moon-line flex-shrink-0 text-xl mr-4 rtl-mr-0 rtl-ml-4 !align-middle" />
|
<span class="i-ri:sun-line dark:i-ri:moon-line flex-shrink-0 text-xl me-4 !align-middle" />
|
||||||
{{ colorMode.value === 'light' ? $t('menu.toggle_theme.dark') : $t('menu.toggle_theme.light') }}
|
{{ colorMode.value === 'light' ? $t('menu.toggle_theme.dark') : $t('menu.toggle_theme.light') }}
|
||||||
</button>
|
</button>
|
||||||
<NuxtLink
|
<NuxtLink
|
||||||
@ -94,7 +94,7 @@ onBeforeUnmount(() => {
|
|||||||
hover="bg-gray-100 dark:(bg-gray-700 text-white)"
|
hover="bg-gray-100 dark:(bg-gray-700 text-white)"
|
||||||
to="/settings"
|
to="/settings"
|
||||||
>
|
>
|
||||||
<span class="i-ri:settings-2-line flex-shrink-0 text-xl mr-4 rtl-mr-0 rtl-ml-4 !align-middle" />
|
<span class="i-ri:settings-2-line flex-shrink-0 text-xl me-4 !align-middle" />
|
||||||
{{ $t('nav.settings') }}
|
{{ $t('nav.settings') }}
|
||||||
</NuxtLink>
|
</NuxtLink>
|
||||||
</div>
|
</div>
|
||||||
|
@ -15,7 +15,7 @@ const sub = env === 'local' ? 'dev' : env === 'staging' ? 'preview' : 'alpha'
|
|||||||
to="/"
|
to="/"
|
||||||
external
|
external
|
||||||
>
|
>
|
||||||
<img :alt="$t('app_logo')" src="/logo.svg" shrink-0 aspect="1/1" sm:h-8 lg:h-10>
|
<img :alt="$t('app_logo')" src="/logo.svg" shrink-0 aspect="1/1" sm:h-8 lg:h-10 class="rtl-flip">
|
||||||
<div hidden lg:block>
|
<div hidden lg:block>
|
||||||
{{ $t('app_name') }} <sup text-sm italic text-secondary mt-1>{{ sub }}</sup>
|
{{ $t('app_name') }} <sup text-sm italic text-secondary mt-1>{{ sub }}</sup>
|
||||||
</div>
|
</div>
|
||||||
|
@ -12,18 +12,14 @@ const { notification } = defineProps<{
|
|||||||
<NuxtLink :to="getAccountRoute(notification.account)">
|
<NuxtLink :to="getAccountRoute(notification.account)">
|
||||||
<div
|
<div
|
||||||
flex items-center absolute
|
flex items-center absolute
|
||||||
pl-3 pr-4 left-0 rtl-left-none
|
ps-3 pe-4 inset-is-0
|
||||||
rounded-br-3
|
rounded-ie-be-3
|
||||||
rtl="pr-3 pl-4 right-0"
|
|
||||||
rtl-rounded-bl-3
|
|
||||||
rtl-rounded-br-0
|
|
||||||
py-3 bg-base top-0
|
py-3 bg-base top-0
|
||||||
:lang="notification.status?.language ?? undefined"
|
:lang="notification.status?.language ?? undefined"
|
||||||
:dir="notification.status?.language ? 'auto' : 'ltr'"
|
|
||||||
>
|
>
|
||||||
<div i-ri:user-follow-fill mr-1 color-primary />
|
<div i-ri:user-follow-fill me-1 color-primary />
|
||||||
<ContentRich
|
<ContentRich
|
||||||
text-primary mr-1 font-bold line-clamp-1 ws-pre-wrap break-all
|
text-primary me-1 font-bold line-clamp-1 ws-pre-wrap break-all
|
||||||
:content="getDisplayName(notification.account, { rich: true })"
|
:content="getDisplayName(notification.account, { rich: true })"
|
||||||
:emojis="notification.account.emojis"
|
:emojis="notification.account.emojis"
|
||||||
/>
|
/>
|
||||||
@ -34,15 +30,14 @@ const { notification } = defineProps<{
|
|||||||
<AccountBigCard
|
<AccountBigCard
|
||||||
:account="notification.account"
|
:account="notification.account"
|
||||||
:lang="notification.status?.language ?? undefined"
|
:lang="notification.status?.language ?? undefined"
|
||||||
:dir="notification.status?.language ? 'auto' : 'ltr'"
|
|
||||||
/>
|
/>
|
||||||
</NuxtLink>
|
</NuxtLink>
|
||||||
</template>
|
</template>
|
||||||
<template v-else-if="notification.type === 'admin.sign_up'">
|
<template v-else-if="notification.type === 'admin.sign_up'">
|
||||||
<div flex p3 items-center bg-shaded>
|
<div flex p3 items-center bg-shaded>
|
||||||
<div i-ri:admin-fill mr-1 color-purple />
|
<div i-ri:admin-fill me-1 color-purple />
|
||||||
<ContentRich
|
<ContentRich
|
||||||
text-purple mr-1 font-bold line-clamp-1 ws-pre-wrap break-all
|
text-purple me-1 font-bold line-clamp-1 ws-pre-wrap break-all
|
||||||
:content="getDisplayName(notification.account, { rich: true })"
|
:content="getDisplayName(notification.account, { rich: true })"
|
||||||
:emojis="notification.account.emojis"
|
:emojis="notification.account.emojis"
|
||||||
/>
|
/>
|
||||||
@ -50,9 +45,9 @@ const { notification } = defineProps<{
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template v-else-if="notification.type === 'follow_request'">
|
<template v-else-if="notification.type === 'follow_request'">
|
||||||
<div flex ml-4 items-center class="-top-2.5" absolute right-2 px-2>
|
<div flex ms-4 items-center class="-top-2.5" absolute inset-ie-2 px-2>
|
||||||
<div i-ri:user-follow-fill text-xl mr-1 />
|
<div i-ri:user-follow-fill text-xl me-1 />
|
||||||
<AccountInlineInfo :account="notification.account" mr1 />
|
<AccountInlineInfo :account="notification.account" me1 />
|
||||||
</div>
|
</div>
|
||||||
<!-- TODO: accept request -->
|
<!-- TODO: accept request -->
|
||||||
<AccountCard :account="notification.account" />
|
<AccountCard :account="notification.account" />
|
||||||
@ -61,8 +56,8 @@ const { notification } = defineProps<{
|
|||||||
<StatusCard :status="notification.status!" :faded="true">
|
<StatusCard :status="notification.status!" :faded="true">
|
||||||
<template #meta>
|
<template #meta>
|
||||||
<div flex="~" gap-1 items-center mt1>
|
<div flex="~" gap-1 items-center mt1>
|
||||||
<div i-ri:heart-fill text-xl mr-1 color-red />
|
<div i-ri:heart-fill text-xl me-1 color-red />
|
||||||
<AccountInlineInfo text-primary font-bold :account="notification.account" mr1 />
|
<AccountInlineInfo text-primary font-bold :account="notification.account" me1 />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</StatusCard>
|
</StatusCard>
|
||||||
@ -71,8 +66,8 @@ const { notification } = defineProps<{
|
|||||||
<StatusCard :status="notification.status!" :faded="true">
|
<StatusCard :status="notification.status!" :faded="true">
|
||||||
<template #meta>
|
<template #meta>
|
||||||
<div flex="~" gap-1 items-center mt1>
|
<div flex="~" gap-1 items-center mt1>
|
||||||
<div i-ri:repeat-fill text-xl mr-1 color-green />
|
<div i-ri:repeat-fill text-xl me-1 color-green />
|
||||||
<AccountInlineInfo text-primary font-bold :account="notification.account" mr1 />
|
<AccountInlineInfo text-primary font-bold :account="notification.account" me1 />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</StatusCard>
|
</StatusCard>
|
||||||
@ -81,8 +76,8 @@ const { notification } = defineProps<{
|
|||||||
<StatusCard :status="notification.status!" :faded="true">
|
<StatusCard :status="notification.status!" :faded="true">
|
||||||
<template #meta>
|
<template #meta>
|
||||||
<div flex="~" gap-1 items-center mt1>
|
<div flex="~" gap-1 items-center mt1>
|
||||||
<div i-ri:edit-2-fill text-xl mr-1 text-secondary />
|
<div i-ri:edit-2-fill text-xl me-1 text-secondary />
|
||||||
<AccountInlineInfo :account="notification.account" mr1 />
|
<AccountInlineInfo :account="notification.account" me1 />
|
||||||
<span ws-nowrap>
|
<span ws-nowrap>
|
||||||
{{ $t('notification.update_status') }}
|
{{ $t('notification.update_status') }}
|
||||||
</span>
|
</span>
|
||||||
|
@ -13,15 +13,12 @@ const isExpanded = ref(false)
|
|||||||
const lang = $computed(() => {
|
const lang = $computed(() => {
|
||||||
return count > 1 || count === 0 ? undefined : items.items[0].status?.language
|
return count > 1 || count === 0 ? undefined : items.items[0].status?.language
|
||||||
})
|
})
|
||||||
const dir = $computed(() => {
|
|
||||||
return lang ? 'auto' : 'ltr'
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<article flex flex-col relative :lang="lang ?? undefined" :dir="dir">
|
<article flex flex-col relative :lang="lang ?? undefined">
|
||||||
<div flex items-center top-0 left-2 pt-2 px-3>
|
<div flex items-center top-0 left-2 pt-2 px-3>
|
||||||
<div i-ri:user-follow-fill mr-3 color-primary aria-hidden="true" />
|
<div i-ri:user-follow-fill me-3 color-primary aria-hidden="true" />
|
||||||
<template v-if="count > 1">
|
<template v-if="count > 1">
|
||||||
<template v-if="addSR">
|
<template v-if="addSR">
|
||||||
<span
|
<span
|
||||||
@ -39,11 +36,11 @@ const dir = $computed(() => {
|
|||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<ContentRich
|
<ContentRich
|
||||||
text-primary mr-1 font-bold line-clamp-1 ws-pre-wrap break-all
|
text-primary me-1 font-bold line-clamp-1 ws-pre-wrap break-all
|
||||||
:content="getDisplayName(items.items[0]?.account, { rich: true })"
|
:content="getDisplayName(items.items[0]?.account, { rich: true })"
|
||||||
:emojis="items.items[0]?.account.emojis"
|
:emojis="items.items[0]?.account.emojis"
|
||||||
/>
|
/>
|
||||||
<span mr-1 ws-nowrap>
|
<span me-1 ws-nowrap>
|
||||||
{{ $t('notification.followed_you') }}
|
{{ $t('notification.followed_you') }}
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
|
@ -12,10 +12,10 @@ const { group } = defineProps<{
|
|||||||
<template #meta>
|
<template #meta>
|
||||||
<div flex flex-col gap-1 mt-1>
|
<div flex flex-col gap-1 mt-1>
|
||||||
<div v-for="like of group.likes" :key="like.account.id" flex>
|
<div v-for="like of group.likes" :key="like.account.id" flex>
|
||||||
<div v-if="like.reblog" i-ri:repeat-fill text-xl mr-2 color-green />
|
<div v-if="like.reblog" i-ri:repeat-fill text-xl me-2 color-green />
|
||||||
<div v-if="like.favourite && !like.reblog" i-ri:heart-fill text-xl mr-2 color-red />
|
<div v-if="like.favourite && !like.reblog" i-ri:heart-fill text-xl me-2 color-red />
|
||||||
<AccountInlineInfo text-primary font-bold :account="like.account" mr2 />
|
<AccountInlineInfo text-primary font-bold :account="like.account" me2 />
|
||||||
<div v-if="like.favourite && like.reblog" i-ri:heart-fill text-xl mr-2 color-red />
|
<div v-if="like.favourite && like.reblog" i-ri:heart-fill text-xl me-2 color-red />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -99,13 +99,14 @@ function groupItems(items: Notification[]): NotificationSlot[] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const { clearNotifications } = useNotifications()
|
const { clearNotifications } = useNotifications()
|
||||||
|
const { formatNumber } = useHumanReadableNumber()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<CommonPaginator :paginator="paginator" :stream="stream" :eager="3" event-type="notification">
|
<CommonPaginator :paginator="paginator" :stream="stream" :eager="3" event-type="notification">
|
||||||
<template #updater="{ number, update }">
|
<template #updater="{ number, update }">
|
||||||
<button py-4 border="b base" flex="~ col" p-3 w-full text-primary font-bold @click="() => { update(); clearNotifications() }">
|
<button py-4 border="b base" flex="~ col" p-3 w-full text-primary font-bold @click="() => { update(); clearNotifications() }">
|
||||||
{{ $t('timeline.show_new_items', [number]) }}
|
{{ $t('timeline.show_new_items', number, { named: { v: formatNumber(number) } }) }}
|
||||||
</button>
|
</button>
|
||||||
</template>
|
</template>
|
||||||
<template #items="{ items }">
|
<template #items="{ items }">
|
||||||
|
@ -234,8 +234,7 @@ defineExpose({
|
|||||||
aria-describedby="upload-failed"
|
aria-describedby="upload-failed"
|
||||||
flex="~ col"
|
flex="~ col"
|
||||||
gap-1 text-sm
|
gap-1 text-sm
|
||||||
pt-1 pl-2 pr-1 pb-2
|
pt-1 ps-2 pe-1 pb-2
|
||||||
rtl="pl-1 pr-2"
|
|
||||||
text-red-600 dark:text-red-400
|
text-red-600 dark:text-red-400
|
||||||
border="~ base rounded red-600 dark:red-400"
|
border="~ base rounded red-600 dark:red-400"
|
||||||
>
|
>
|
||||||
@ -255,10 +254,10 @@ defineExpose({
|
|||||||
</button>
|
</button>
|
||||||
</CommonTooltip>
|
</CommonTooltip>
|
||||||
</head>
|
</head>
|
||||||
<div v-if="isExceedingAttachmentLimit" pl-2 sm:pl-1 text-small>
|
<div v-if="isExceedingAttachmentLimit" ps-2 sm:ps-1 text-small>
|
||||||
{{ $t('state.attachments_exceed_server_limit') }}
|
{{ $t('state.attachments_exceed_server_limit') }}
|
||||||
</div>
|
</div>
|
||||||
<ol pl-2 sm:pl-1>
|
<ol ps-2 sm:ps-1>
|
||||||
<li v-for="file in failed" :key="file.name">
|
<li v-for="file in failed" :key="file.name">
|
||||||
{{ file.name }}
|
{{ file.name }}
|
||||||
</li>
|
</li>
|
||||||
@ -279,7 +278,7 @@ defineExpose({
|
|||||||
<div flex gap-4>
|
<div flex gap-4>
|
||||||
<div w-12 h-full sm:block hidden />
|
<div w-12 h-full sm:block hidden />
|
||||||
<div
|
<div
|
||||||
v-if="shouldExpanded" flex="~ gap-2 1" m="l--1" pt-2 justify="between" max-full
|
v-if="shouldExpanded" flex="~ gap-2 1" m="s--1" pt-2 justify="between" max-full
|
||||||
border="t base"
|
border="t base"
|
||||||
>
|
>
|
||||||
<PublishEmojiPicker
|
<PublishEmojiPicker
|
||||||
@ -308,7 +307,7 @@ defineExpose({
|
|||||||
|
|
||||||
<div flex-auto />
|
<div flex-auto />
|
||||||
|
|
||||||
<div pointer-events-none pr-1 pt-2 text-sm tabular-nums text-secondary flex gap-0.5>
|
<div dir="ltr" pointer-events-none pe-1 pt-2 text-sm tabular-nums text-secondary flex gap-0.5>
|
||||||
{{ editor?.storage.characterCount.characters() }}<span text-secondary-light>/</span><span text-secondary-light>{{ characterLimit }}</span>
|
{{ editor?.storage.characterCount.characters() }}<span text-secondary-light>/</span><span text-secondary-light>{{ characterLimit }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -323,7 +322,7 @@ defineExpose({
|
|||||||
<CommonDropdown>
|
<CommonDropdown>
|
||||||
<button :aria-label="$t('tooltip.change_content_visibility')" btn-action-icon w-12>
|
<button :aria-label="$t('tooltip.change_content_visibility')" btn-action-icon w-12>
|
||||||
<div :class="currentVisibility.icon" />
|
<div :class="currentVisibility.icon" />
|
||||||
<div i-ri:arrow-down-s-line text-sm text-secondary mr--1 />
|
<div i-ri:arrow-down-s-line text-sm text-secondary me--1 />
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<template #popper>
|
<template #popper>
|
||||||
|
@ -16,6 +16,6 @@
|
|||||||
{{ $t('pwa.dismiss') }}
|
{{ $t('pwa.dismiss') }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div i-ri-arrow-down-circle-line absolute text-8em bottom--10 right--10 rtl="left--10 right-unset" text-primary op10 class="-z-1" />
|
<div i-ri-arrow-down-circle-line absolute text-8em bottom--10 inset-ie--10 text-primary op10 class="-z-1" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -54,19 +54,17 @@ const activate = () => {
|
|||||||
<template>
|
<template>
|
||||||
<div ref="el" relative px4 py2 group>
|
<div ref="el" relative px4 py2 group>
|
||||||
<div bg-base border="~ base" h10 rounded-full flex="~ row" items-center relative focus-within:box-shadow-outline>
|
<div bg-base border="~ base" h10 rounded-full flex="~ row" items-center relative focus-within:box-shadow-outline>
|
||||||
<div i-ri:search-2-line mx4 absolute pointer-events-none text-secondary mt="1px" />
|
<div i-ri:search-2-line mx4 absolute pointer-events-none text-secondary mt="1px" class="rtl-flip" />
|
||||||
<input
|
<input
|
||||||
ref="input"
|
ref="input"
|
||||||
v-model="query"
|
v-model="query"
|
||||||
h-full
|
h-full
|
||||||
pl-10
|
ps-10
|
||||||
rtl-pr-10
|
|
||||||
rounded-full
|
rounded-full
|
||||||
w-full
|
w-full
|
||||||
bg-transparent
|
bg-transparent
|
||||||
outline="focus:none"
|
outline="focus:none"
|
||||||
pr-4
|
pe-4
|
||||||
rtl-pl-4
|
|
||||||
:placeholder="t('nav.search')"
|
:placeholder="t('nav.search')"
|
||||||
pb="1px"
|
pb="1px"
|
||||||
placeholder-text-secondary
|
placeholder-text-secondary
|
||||||
|
@ -57,7 +57,7 @@ useCommand({
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div i-ri:arrow-right-s-line rtl-i-ri:arrow-left-s-line text-xl text-secondary-light />
|
<div i-ri:arrow-right-s-line text-xl text-secondary-light class="rtl-flip" />
|
||||||
</div>
|
</div>
|
||||||
</NuxtLink>
|
</NuxtLink>
|
||||||
</template>
|
</template>
|
||||||
|
@ -94,7 +94,7 @@ async function editStatus() {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<CommonDropdown flex-none ml3 placement="bottom" :eager-mount="command">
|
<CommonDropdown flex-none ms3 placement="bottom" :eager-mount="command">
|
||||||
<StatusActionButton
|
<StatusActionButton
|
||||||
:content="$t('action.more')"
|
:content="$t('action.more')"
|
||||||
color="text-purple"
|
color="text-purple"
|
||||||
|
@ -97,14 +97,13 @@ const isDM = $computed(() => status.visibility === 'direct')
|
|||||||
tabindex="0"
|
tabindex="0"
|
||||||
focus:outline-none focus-visible:ring="2 primary"
|
focus:outline-none focus-visible:ring="2 primary"
|
||||||
:lang="status.language ?? undefined"
|
:lang="status.language ?? undefined"
|
||||||
:dir="status.language ? 'auto' : 'ltr'"
|
|
||||||
@click="onclick"
|
@click="onclick"
|
||||||
@keydown.enter="onclick"
|
@keydown.enter="onclick"
|
||||||
>
|
>
|
||||||
<div flex justify-between>
|
<div flex justify-between>
|
||||||
<slot name="meta">
|
<slot name="meta">
|
||||||
<div v-if="rebloggedBy && !collapseRebloggedBy" text-secondary text-sm ws-nowrap flex="~" gap-1 items-center py1 bg-base>
|
<div v-if="rebloggedBy && !collapseRebloggedBy" text-secondary text-sm ws-nowrap flex="~" gap-1 items-center py1 bg-base>
|
||||||
<div i-ri:repeat-fill mr-1 text-primary />
|
<div i-ri:repeat-fill me-1 text-primary />
|
||||||
<AccountInlineInfo font-bold :account="rebloggedBy" :avatar="!avatarOnAvatar" />
|
<AccountInlineInfo font-bold :account="rebloggedBy" :avatar="!avatarOnAvatar" />
|
||||||
</div>
|
</div>
|
||||||
<div v-else />
|
<div v-else />
|
||||||
@ -113,11 +112,11 @@ const isDM = $computed(() => status.visibility === 'direct')
|
|||||||
</div>
|
</div>
|
||||||
<div flex gap-3 :class="{ 'text-secondary': faded }">
|
<div flex gap-3 :class="{ 'text-secondary': faded }">
|
||||||
<div relative>
|
<div relative>
|
||||||
<div v-if="showRebloggedByAvatarOnAvatar" absolute top--3px left--0.8 rtl-left-none rtl-right--0.8 z--1 w-25px h-25px rounded-full>
|
<div v-if="showRebloggedByAvatarOnAvatar" absolute top--3px inset-is--0.8 z--1 w-25px h-25px rounded-full>
|
||||||
<AccountAvatar :account="rebloggedBy" />
|
<AccountAvatar :account="rebloggedBy" />
|
||||||
</div>
|
</div>
|
||||||
<div v-else-if="collapseRebloggedBy" absolute left--0.8 rtl-left-none rtl-right--0.8 w-5.5 h-5.5 rounded-full bg-base>
|
<div v-else-if="collapseRebloggedBy" absolute inset-is--0.8 w-5.5 h-5.5 rounded-full bg-base>
|
||||||
<div i-ri:repeat-fill mr-1 text-primary text-sm />
|
<div i-ri:repeat-fill me-1 text-primary text-sm />
|
||||||
</div>
|
</div>
|
||||||
<AccountHoverWrapper :account="status.account">
|
<AccountHoverWrapper :account="status.account">
|
||||||
<NuxtLink :to="getAccountRoute(status.account)" rounded-full>
|
<NuxtLink :to="getAccountRoute(status.account)" rounded-full>
|
||||||
@ -133,12 +132,12 @@ const isDM = $computed(() => status.visibility === 'direct')
|
|||||||
<AccountHoverWrapper :account="status.account">
|
<AccountHoverWrapper :account="status.account">
|
||||||
<StatusAccountDetails :account="status.account" />
|
<StatusAccountDetails :account="status.account" />
|
||||||
</AccountHoverWrapper>
|
</AccountHoverWrapper>
|
||||||
<div v-if="!directReply && collapseReplyingTo" flex="~" pl-1 items-center justify-center>
|
<div v-if="!directReply && collapseReplyingTo" flex="~" ps-1 items-center justify-center>
|
||||||
<StatusReplyingTo :collapsed="true" :status="status" :class="faded ? 'text-secondary-light' : ''" />
|
<StatusReplyingTo :collapsed="true" :status="status" :class="faded ? 'text-secondary-light' : ''" />
|
||||||
</div>
|
</div>
|
||||||
<div flex-auto />
|
<div flex-auto />
|
||||||
<div v-if="!isZenMode" text-sm text-secondary flex="~ row nowrap" hover:underline>
|
<div v-if="!isZenMode" text-sm text-secondary flex="~ row nowrap" hover:underline>
|
||||||
<AccountBotIndicator v-if="status.account.bot" mr-2 />
|
<AccountBotIndicator v-if="status.account.bot" me-2 />
|
||||||
<div flex>
|
<div flex>
|
||||||
<CommonTooltip :content="createdAt">
|
<CommonTooltip :content="createdAt">
|
||||||
<a :title="status.createdAt" :href="getStatusRoute(status).href" @click.prevent="go($event)">
|
<a :title="status.createdAt" :href="getStatusRoute(status).href" @click.prevent="go($event)">
|
||||||
@ -150,7 +149,7 @@ const isDM = $computed(() => status.visibility === 'direct')
|
|||||||
<StatusEditIndicator :status="status" inline />
|
<StatusEditIndicator :status="status" inline />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<StatusActionsMore v-if="actions !== false" :status="status" mr--2 />
|
<StatusActionsMore v-if="actions !== false" :status="status" me--2 />
|
||||||
</div>
|
</div>
|
||||||
<StatusContent :status="status" :context="context" mb2 :class="{ mt2: isDM }" />
|
<StatusContent :status="status" :context="context" mb2 :class="{ mt2: isDM }" />
|
||||||
<div>
|
<div>
|
||||||
|
@ -23,7 +23,7 @@ const isFiltered = $computed(() => filterPhrase && (context && context !== 'deta
|
|||||||
<div
|
<div
|
||||||
space-y-3
|
space-y-3
|
||||||
:class="{
|
:class="{
|
||||||
'pt2 pb0.5 px3.5 br2 border-1 rounded-3 rounded-tl-none': isDM,
|
'pt2 pb0.5 px3.5 border-1 rounded-3 rounded-bs-is-none': isDM,
|
||||||
'bg-fade border-primary-light': isDM,
|
'bg-fade border-primary-light': isDM,
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
|
@ -29,9 +29,9 @@ const isDM = $computed(() => status.visibility === 'direct')
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div :id="`status-${status.id}`" flex flex-col gap-2 pt2 pb1 px-4 relative :lang="status.language ?? undefined" dir="auto">
|
<div :id="`status-${status.id}`" flex flex-col gap-2 pt2 pb1 px-4 relative :lang="status.language ?? undefined">
|
||||||
<StatusActionsMore :status="status" absolute right-2 top-2 />
|
<StatusActionsMore :status="status" absolute inset-ie-2 top-2 />
|
||||||
<NuxtLink :to="getAccountRoute(status.account)" rounded-full hover:bg-active transition-100 pr5 mr-a>
|
<NuxtLink :to="getAccountRoute(status.account)" rounded-full hover:bg-active transition-100 pe5 me-a>
|
||||||
<AccountHoverWrapper :account="status.account">
|
<AccountHoverWrapper :account="status.account">
|
||||||
<AccountInfo :account="status.account" />
|
<AccountInfo :account="status.account" />
|
||||||
</AccountHoverWrapper>
|
</AccountHoverWrapper>
|
||||||
@ -44,7 +44,7 @@ const isDM = $computed(() => status.visibility === 'direct')
|
|||||||
:status="status"
|
:status="status"
|
||||||
:inline="false"
|
:inline="false"
|
||||||
>
|
>
|
||||||
<span ml1 font-bold cursor-pointer>{{ $t('state.edited') }}</span>
|
<span ms1 font-bold cursor-pointer>{{ $t('state.edited') }}</span>
|
||||||
</StatusEditIndicator>
|
</StatusEditIndicator>
|
||||||
</div>
|
</div>
|
||||||
<div>·</div>
|
<div>·</div>
|
||||||
|
@ -13,7 +13,7 @@ function toPercentage(num: number) {
|
|||||||
const timeAgoOptions = useTimeAgoOptions()
|
const timeAgoOptions = useTimeAgoOptions()
|
||||||
const expiredTimeAgo = useTimeAgo(poll.expiresAt!, timeAgoOptions)
|
const expiredTimeAgo = useTimeAgo(poll.expiresAt!, timeAgoOptions)
|
||||||
const expiredTimeFormatted = useFormattedDateTime(poll.expiresAt!)
|
const expiredTimeFormatted = useFormattedDateTime(poll.expiresAt!)
|
||||||
const { formatHumanReadableNumber } = useHumanReadableNumber()
|
const { formatHumanReadableNumber, formatNumber, formatPercentage, forSR } = useHumanReadableNumber()
|
||||||
|
|
||||||
const masto = useMasto()
|
const masto = useMasto()
|
||||||
async function vote(e: Event) {
|
async function vote(e: Event) {
|
||||||
@ -32,10 +32,15 @@ async function vote(e: Event) {
|
|||||||
|
|
||||||
await masto.poll.vote(poll.id, { choices })
|
await masto.poll.vote(poll.id, { choices })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const votersCount = $computed(() => poll.votersCount ?? 0)
|
||||||
|
const votersCountHR = $computed(() => formatHumanReadableNumber(votersCount))
|
||||||
|
const votersCountNumber = $computed(() => formatNumber(votersCount))
|
||||||
|
const votersCountSR = $computed(() => forSR(votersCount))
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div flex flex-col w-full items-stretch gap-3>
|
<div flex flex-col w-full items-stretch gap-3 dir="auto">
|
||||||
<form v-if="!poll.voted && !poll.expired" flex flex-col gap-4 accent-primary @click.stop="noop" @submit.prevent="vote">
|
<form v-if="!poll.voted && !poll.expired" flex flex-col gap-4 accent-primary @click.stop="noop" @submit.prevent="vote">
|
||||||
<label v-for="(option, index) of poll.options" :key="index" flex items-center gap-2 px-2>
|
<label v-for="(option, index) of poll.options" :key="index" flex items-center gap-2 px-2>
|
||||||
<input name="choices" :value="index" :type="poll.multiple ? 'checkbox' : 'radio'">
|
<input name="choices" :value="index" :type="poll.multiple ? 'checkbox' : 'radio'">
|
||||||
@ -50,17 +55,23 @@ async function vote(e: Event) {
|
|||||||
<div flex justify-between pb-2 w-full>
|
<div flex justify-between pb-2 w-full>
|
||||||
<span inline-flex align-items>
|
<span inline-flex align-items>
|
||||||
{{ option.title }}
|
{{ option.title }}
|
||||||
<span v-if="poll.voted && poll.ownVotes?.includes(index)" ml-2 mt-1 inline-block i-ri:checkbox-circle-line />
|
<span v-if="poll.voted && poll.ownVotes?.includes(index)" ms-2 mt-1 inline-block i-ri:checkbox-circle-line />
|
||||||
</span>
|
</span>
|
||||||
<span text-primary-active> {{ poll.votesCount ? toPercentage((option.votesCount || 0) / (poll.votesCount)) : '0%' }}</span>
|
<span text-primary-active> {{ formatPercentage(votersCount > 0 ? (option.votesCount || 0) / votersCount : 0) }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="bg-gray/40" rounded-l-sm rounded-r-lg h-5px w-full>
|
<div class="bg-gray/40" rounded-l-sm rounded-r-lg h-5px w-full>
|
||||||
<div bg-primary-active h-full class="w-[var(--bar-width)]" />
|
<div bg-primary-active h-full class="w-[var(--bar-width)]" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<div text-sm>
|
<div text-sm flex="~ inline" gap-x-1>
|
||||||
{{ $t('status.poll.count', [formatHumanReadableNumber(poll.votersCount ?? 0)]) }}
|
<i18n-t keypath="status.poll.count" :plural="votersCount">
|
||||||
|
<CommonTooltip v-if="votersCountSR" :content="votersCountNumber" placement="bottom">
|
||||||
|
<span aria-hidden="true">{{ votersCountHR }}</span>
|
||||||
|
<span sr-only>{{ votersCountNumber }}</span>
|
||||||
|
</CommonTooltip>
|
||||||
|
<span v-else>{{ votersCountNumber }}</span>
|
||||||
|
</i18n-t>
|
||||||
·
|
·
|
||||||
<CommonTooltip :content="expiredTimeFormatted" class="inline-block" placement="right">
|
<CommonTooltip :content="expiredTimeFormatted" class="inline-block" placement="right">
|
||||||
<time :datetime="poll.expiresAt!">{{ $t(poll.expired ? 'status.poll.finished' : 'status.poll.ends', [expiredTimeAgo]) }}</time>
|
<time :datetime="poll.expiresAt!">{{ $t(poll.expired ? 'status.poll.finished' : 'status.poll.ends', [expiredTimeAgo]) }}</time>
|
||||||
|
@ -102,10 +102,10 @@ const meta = $computed(() => {
|
|||||||
<span v-else>{{ meta.user }}</span>
|
<span v-else>{{ meta.user }}</span>
|
||||||
</a>
|
</a>
|
||||||
<a sm:text-lg :href="card.url" target="_blank">
|
<a sm:text-lg :href="card.url" target="_blank">
|
||||||
<span v-if="meta.type === 'issue'" text-secondary-light mr-2>
|
<span v-if="meta.type === 'issue'" text-secondary-light me-2>
|
||||||
#{{ meta.number }}
|
#{{ meta.number }}
|
||||||
</span>
|
</span>
|
||||||
<span v-if="meta.type === 'pull'" text-secondary-light mr-2>
|
<span v-if="meta.type === 'pull'" text-secondary-light me-2>
|
||||||
PR #{{ meta.number }}
|
PR #{{ meta.number }}
|
||||||
</span>
|
</span>
|
||||||
<span text-secondary leading-tight>{{ meta.details }}</span>
|
<span text-secondary leading-tight>{{ meta.details }}</span>
|
||||||
|
@ -11,6 +11,7 @@ const { paginator, stream } = defineProps<{
|
|||||||
preprocess?: (items: any[]) => any[]
|
preprocess?: (items: any[]) => any[]
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
|
const { formatNumber } = useHumanReadableNumber()
|
||||||
const virtualScroller = $(computedEager(() => useFeatureFlags().experimentalVirtualScroll))
|
const virtualScroller = $(computedEager(() => useFeatureFlags().experimentalVirtualScroll))
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -18,7 +19,7 @@ const virtualScroller = $(computedEager(() => useFeatureFlags().experimentalVirt
|
|||||||
<CommonPaginator v-bind="{ paginator, stream, preprocess }" :virtual-scroller="virtualScroller">
|
<CommonPaginator v-bind="{ paginator, stream, preprocess }" :virtual-scroller="virtualScroller">
|
||||||
<template #updater="{ number, update }">
|
<template #updater="{ number, update }">
|
||||||
<button py-4 border="b base" flex="~ col" p-3 w-full text-primary font-bold @click="update">
|
<button py-4 border="b base" flex="~ col" p-3 w-full text-primary font-bold @click="update">
|
||||||
{{ $t('timeline.show_new_items', number) }}
|
{{ $t('timeline.show_new_items', number, { named: { v: formatNumber(number) } }) }}
|
||||||
</button>
|
</button>
|
||||||
</template>
|
</template>
|
||||||
<template #default="{ item, older, newer, active }">
|
<template #default="{ item, older, newer, active }">
|
||||||
|
@ -92,7 +92,7 @@ onMounted(async () => {
|
|||||||
<template>
|
<template>
|
||||||
<form text-center justify-center items-center max-w-150 py6 flex="~ col gap-3" @submit.prevent="oauth">
|
<form text-center justify-center items-center max-w-150 py6 flex="~ col gap-3" @submit.prevent="oauth">
|
||||||
<div flex="~ center" mb2>
|
<div flex="~ center" mb2>
|
||||||
<img src="/logo.svg" w-12 h-12 mxa height="48" width="48" alt="logo">
|
<img src="/logo.svg" w-12 h-12 mxa height="48" width="48" :alt="$t('app_logo')" class="rtl-flip">
|
||||||
<div text-3xl>
|
<div text-3xl>
|
||||||
{{ $t('action.sign_in') }}
|
{{ $t('action.sign_in') }}
|
||||||
</div>
|
</div>
|
||||||
@ -102,13 +102,14 @@ onMounted(async () => {
|
|||||||
</div>
|
</div>
|
||||||
<div :class="error ? 'animate animate-shake-x animate-delay-100' : null">
|
<div :class="error ? 'animate animate-shake-x animate-delay-100' : null">
|
||||||
<div
|
<div
|
||||||
|
dir="ltr"
|
||||||
flex bg-gray:10 px4 py2 mxa rounded
|
flex bg-gray:10 px4 py2 mxa rounded
|
||||||
border="~ base" items-center font-mono
|
border="~ base" items-center font-mono
|
||||||
focus:outline-none focus:ring="2 primary inset"
|
focus:outline-none focus:ring="2 primary inset"
|
||||||
relative
|
relative
|
||||||
:class="displayError ? 'border-red-600 dark:border-red-400' : null"
|
:class="displayError ? 'border-red-600 dark:border-red-400' : null"
|
||||||
>
|
>
|
||||||
<span text-secondary-light mr1>https://</span>
|
<span text-secondary-light me1>https://</span>
|
||||||
|
|
||||||
<input
|
<input
|
||||||
ref="input"
|
ref="input"
|
||||||
@ -134,7 +135,7 @@ onMounted(async () => {
|
|||||||
class="max-h-[8rem]"
|
class="max-h-[8rem]"
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
v-for="name, idx in filteredServers"
|
v-for="(name, idx) in filteredServers"
|
||||||
:id="toSelector(name)"
|
:id="toSelector(name)"
|
||||||
:key="name"
|
:key="name"
|
||||||
:value="name"
|
:value="name"
|
||||||
@ -155,7 +156,7 @@ onMounted(async () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div text-secondary text-sm flex>
|
<div text-secondary text-sm flex>
|
||||||
<div i-ri:lightbulb-line mr-1 />
|
<div i-ri:lightbulb-line me-1 />
|
||||||
<span>
|
<span>
|
||||||
<i18n-t keypath="user.tip_no_account">
|
<i18n-t keypath="user.tip_no_account">
|
||||||
<a href="https://joinmastodon.org/servers" target="_blank" hover="underline text-primary">{{ $t('user.tip_register_account') }}</a>
|
<a href="https://joinmastodon.org/servers" target="_blank" hover="underline text-primary">{{ $t('user.tip_register_account') }}</a>
|
||||||
@ -163,7 +164,7 @@ onMounted(async () => {
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<button flex="~ row" gap-x-2 items-center btn-solid mt2 :disabled="!server || busy">
|
<button flex="~ row" gap-x-2 items-center btn-solid mt2 :disabled="!server || busy">
|
||||||
<span aria-hidden="true" inline-block :class="busy ? 'i-ri:loader-2-fill animate animate-spin' : 'i-ri:login-circle-line'" />
|
<span aria-hidden="true" inline-block :class="busy ? 'i-ri:loader-2-fill animate animate-spin' : 'i-ri:login-circle-line'" class="rtl-flip" />
|
||||||
{{ $t('action.sign_in') }}
|
{{ $t('action.sign_in') }}
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
|
@ -53,7 +53,7 @@ const switchUser = (user: UserLogin) => {
|
|||||||
<CommonDropdownItem
|
<CommonDropdownItem
|
||||||
v-if="isMastoInitialised && currentUser"
|
v-if="isMastoInitialised && currentUser"
|
||||||
:text="$t('user.sign_out_account', [getFullHandle(currentUser.account)])"
|
:text="$t('user.sign_out_account', [getFullHandle(currentUser.account)])"
|
||||||
icon="i-ri:logout-box-line"
|
icon="i-ri:logout-box-line rtl-flip"
|
||||||
@click="signout"
|
@click="signout"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -3,46 +3,30 @@ import type { MaybeComputedRef, UseTimeAgoOptions } from '@vueuse/core'
|
|||||||
|
|
||||||
const formatter = Intl.NumberFormat()
|
const formatter = Intl.NumberFormat()
|
||||||
|
|
||||||
const humanReadableNumber = (
|
|
||||||
num: number,
|
|
||||||
{ k, m }: { k: string; m: string } = { k: 'K', m: 'M' },
|
|
||||||
useFormatter: Intl.NumberFormat = formatter,
|
|
||||||
) => {
|
|
||||||
if (num < 10000)
|
|
||||||
return useFormatter.format(num)
|
|
||||||
|
|
||||||
// show 1 decimal: we cannot use toFixed(1), it is a string
|
|
||||||
if (num < 1000000)
|
|
||||||
return `${useFormatter.format(Math.floor(num / 100) / 10)}${k}`
|
|
||||||
|
|
||||||
// show 2 decimals: we cannot use toFixed(2), it is a string
|
|
||||||
return `${useFormatter.format(Math.floor(num / 10000) / 100)}${m}`
|
|
||||||
}
|
|
||||||
|
|
||||||
export const formattedNumber = (num: number, useFormatter: Intl.NumberFormat = formatter) => {
|
export const formattedNumber = (num: number, useFormatter: Intl.NumberFormat = formatter) => {
|
||||||
return useFormatter.format(num)
|
return useFormatter.format(num)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useHumanReadableNumber = () => {
|
export const useHumanReadableNumber = () => {
|
||||||
const i18n = useI18n()
|
const { t, n, locale } = useI18n()
|
||||||
const numberFormatter = $computed(() => Intl.NumberFormat(i18n.locale.value))
|
|
||||||
|
const fn = (num: number) => {
|
||||||
|
if (num < 10000)
|
||||||
|
return n(num, 'smallCounting', locale.value)
|
||||||
|
|
||||||
|
// show 1 decimal: we cannot use toFixed(1), it is a string
|
||||||
|
if (num < 1000000)
|
||||||
|
return `${n(Math.floor(num / 100) / 10, 'kiloCounting', locale.value)}${t('common.kiloSuffix')}`
|
||||||
|
|
||||||
|
// show 2 decimals: we cannot use toFixed(2), it is a string
|
||||||
|
return `${n(Math.floor(num / 10000) / 100, 'millionCounting', locale.value)}${t('common.megaSuffix')}`
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
formatHumanReadableNumber: (num: MaybeRef<number>) => {
|
formatHumanReadableNumber: (num: MaybeRef<number>) => fn(unref(num)),
|
||||||
return humanReadableNumber(
|
formatNumber: (num: MaybeRef<number>) => n(unref(num), 'smallCounting', locale.value),
|
||||||
unref(num),
|
formatPercentage: (num: MaybeRef<number>) => n(unref(num), 'percentage', locale.value),
|
||||||
{ k: i18n.t('common.kiloSuffix'), m: i18n.t('common.megaSuffix') },
|
forSR: (num: MaybeRef<number>) => unref(num) > 10000,
|
||||||
numberFormatter,
|
|
||||||
)
|
|
||||||
},
|
|
||||||
formatNumber: (num: MaybeRef<number>) => {
|
|
||||||
return formattedNumber(
|
|
||||||
unref(num),
|
|
||||||
numberFormatter,
|
|
||||||
)
|
|
||||||
},
|
|
||||||
forSR: (num: MaybeRef<number>) => {
|
|
||||||
return unref(num) > 10000
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,9 +43,17 @@ export const useFormattedDateTime = (
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const useTimeAgoOptions = (short = false): UseTimeAgoOptions<false> => {
|
export const useTimeAgoOptions = (short = false): UseTimeAgoOptions<false> => {
|
||||||
const { d, t } = useI18n()
|
const { d, t, n: fnf, locale } = useI18n()
|
||||||
const prefix = short ? 'short_' : ''
|
const prefix = short ? 'short_' : ''
|
||||||
|
|
||||||
|
const fn = (n: number, past: boolean, key: string) => {
|
||||||
|
return t(`time_ago_options.${prefix}${key}_${past ? 'past' : 'future'}`, n, {
|
||||||
|
named: {
|
||||||
|
v: fnf(n, 'smallCounting', locale.value),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
rounding: 'floor',
|
rounding: 'floor',
|
||||||
showSecond: !short,
|
showSecond: !short,
|
||||||
@ -72,13 +64,13 @@ export const useTimeAgoOptions = (short = false): UseTimeAgoOptions<false> => {
|
|||||||
past: n => n,
|
past: n => n,
|
||||||
// just return the value
|
// just return the value
|
||||||
future: n => n,
|
future: n => n,
|
||||||
second: (n, p) => t(`time_ago_options.${prefix}second_${p ? 'past' : 'future'}`, n),
|
second: (n, p) => fn(n, p, 'second'),
|
||||||
minute: (n, p) => t(`time_ago_options.${prefix}minute_${p ? 'past' : 'future'}`, n),
|
minute: (n, p) => fn(n, p, 'minute'),
|
||||||
hour: (n, p) => t(`time_ago_options.${prefix}hour_${p ? 'past' : 'future'}`, n),
|
hour: (n, p) => fn(n, p, 'hour'),
|
||||||
day: (n, p) => t(`time_ago_options.${prefix}day_${p ? 'past' : 'future'}`, n),
|
day: (n, p) => fn(n, p, 'day'),
|
||||||
week: (n, p) => t(`time_ago_options.${prefix}week_${p ? 'past' : 'future'}`, n),
|
week: (n, p) => fn(n, p, 'week'),
|
||||||
month: (n, p) => t(`time_ago_options.${prefix}month_${p ? 'past' : 'future'}`, n),
|
month: (n, p) => fn(n, p, 'month'),
|
||||||
year: (n, p) => t(`time_ago_options.${prefix}year_${p ? 'past' : 'future'}`, n),
|
year: (n, p) => fn(n, p, 'year'),
|
||||||
invalid: '',
|
invalid: '',
|
||||||
},
|
},
|
||||||
fullDateFormatter(date) {
|
fullDateFormatter(date) {
|
||||||
|
@ -1,9 +1,16 @@
|
|||||||
import type { NuxtI18nOptions } from '@nuxtjs/i18n'
|
import type { NuxtI18nOptions } from '@nuxtjs/i18n'
|
||||||
import type { DateTimeFormats } from '@intlify/core-base'
|
import type { DateTimeFormats, NumberFormats, PluralizationRule, PluralizationRules } from '@intlify/core-base'
|
||||||
|
|
||||||
import type { LocaleObject } from '#i18n'
|
import type { LocaleObject } from '#i18n'
|
||||||
|
|
||||||
|
interface LocaleObjectData extends LocaleObject {
|
||||||
|
numberFormats?: NumberFormats
|
||||||
|
dateTimeFormats?: DateTimeFormats
|
||||||
|
pluralRule?: PluralizationRule
|
||||||
|
}
|
||||||
|
|
||||||
// @ts-expect-error dir is there, ts complaining
|
// @ts-expect-error dir is there, ts complaining
|
||||||
const locales: LocaleObject[] = [
|
const locales: LocaleObjectData[] = [
|
||||||
{
|
{
|
||||||
code: 'en-US',
|
code: 'en-US',
|
||||||
file: 'en-US.json',
|
file: 'en-US.json',
|
||||||
@ -50,27 +57,79 @@ const locales: LocaleObject[] = [
|
|||||||
name: 'Česky',
|
name: 'Česky',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
code: 'ar',
|
code: 'ar-EG',
|
||||||
file: 'ar-EG.json',
|
file: 'ar-EG.json',
|
||||||
name: 'العربية',
|
name: 'العربية',
|
||||||
dir: 'rtl',
|
dir: 'rtl',
|
||||||
|
pluralRule: (choice: number) => {
|
||||||
|
const name = new Intl.PluralRules('ar-EG').select(choice)
|
||||||
|
return { zero: 0, one: 1, two: 2, few: 3, many: 4, other: 5 }[name]
|
||||||
|
},
|
||||||
},
|
},
|
||||||
].sort((a, b) => a.code.localeCompare(b.code))
|
].sort((a, b) => a.code.localeCompare(b.code))
|
||||||
|
|
||||||
const datetimeFormats = Object.keys(locales).reduce((acc, key) => {
|
const datetimeFormats = Object.values(locales).reduce((acc, data) => {
|
||||||
acc[key] = {
|
const dateTimeFormats = data.dateTimeFormats
|
||||||
short: {
|
if (dateTimeFormats) {
|
||||||
dateStyle: 'short',
|
acc[data.code] = { ...dateTimeFormats }
|
||||||
timeStyle: 'short',
|
delete data.dateTimeFormats
|
||||||
},
|
|
||||||
long: {
|
|
||||||
dateStyle: 'long',
|
|
||||||
timeStyle: 'medium',
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
acc[data.code] = {
|
||||||
|
short: {
|
||||||
|
dateStyle: 'short',
|
||||||
|
timeStyle: 'short',
|
||||||
|
},
|
||||||
|
long: {
|
||||||
|
dateStyle: 'long',
|
||||||
|
timeStyle: 'medium',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return acc
|
return acc
|
||||||
}, <DateTimeFormats>{})
|
}, <DateTimeFormats>{})
|
||||||
|
|
||||||
|
const numberFormats = Object.values(locales).reduce((acc, data) => {
|
||||||
|
const numberFormats = data.numberFormats
|
||||||
|
if (numberFormats) {
|
||||||
|
acc[data.code] = { ...numberFormats }
|
||||||
|
delete data.numberFormats
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
acc[data.code] = {
|
||||||
|
percentage: {
|
||||||
|
style: 'percent',
|
||||||
|
maximumFractionDigits: 1,
|
||||||
|
},
|
||||||
|
smallCounting: {
|
||||||
|
style: 'decimal',
|
||||||
|
maximumFractionDigits: 0,
|
||||||
|
},
|
||||||
|
kiloCounting: {
|
||||||
|
style: 'decimal',
|
||||||
|
maximumFractionDigits: 1,
|
||||||
|
},
|
||||||
|
millionCounting: {
|
||||||
|
style: 'decimal',
|
||||||
|
maximumFractionDigits: 2,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return acc
|
||||||
|
}, <NumberFormats>{})
|
||||||
|
|
||||||
|
const pluralRules = Object.values(locales).reduce((acc, data) => {
|
||||||
|
const pluralRule = data.pluralRule
|
||||||
|
if (pluralRule) {
|
||||||
|
acc[data.code] = pluralRule
|
||||||
|
delete data.pluralRule
|
||||||
|
}
|
||||||
|
|
||||||
|
return acc
|
||||||
|
}, <PluralizationRules>{})
|
||||||
|
|
||||||
export const i18n: NuxtI18nOptions = {
|
export const i18n: NuxtI18nOptions = {
|
||||||
locales,
|
locales,
|
||||||
strategy: 'no_prefix',
|
strategy: 'no_prefix',
|
||||||
@ -82,6 +141,8 @@ export const i18n: NuxtI18nOptions = {
|
|||||||
fallbackWarn: false,
|
fallbackWarn: false,
|
||||||
missingWarn: false,
|
missingWarn: false,
|
||||||
datetimeFormats,
|
datetimeFormats,
|
||||||
|
numberFormats,
|
||||||
|
pluralRules,
|
||||||
},
|
},
|
||||||
lazy: true,
|
lazy: true,
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,11 @@
|
|||||||
{
|
{
|
||||||
|
"a11y": {
|
||||||
|
"loading_page": "الصفحة قيد التحميل، يرجى الانتظار",
|
||||||
|
"loading_titled_page": "الصفحة {0} قيد التحميل ، يرجى الانتظار",
|
||||||
|
"locale_changed": "تم تغيير اللغة إلى {0}",
|
||||||
|
"locale_changing": "يتم تغيير اللغة، يرجى الانتظار",
|
||||||
|
"route_loaded": "تم تحميل الصفحة {0}"
|
||||||
|
},
|
||||||
"account": {
|
"account": {
|
||||||
"avatar_description": "صورة حساب {0}",
|
"avatar_description": "صورة حساب {0}",
|
||||||
"blocked_by": "تم حظرك من قبل هذا المستخدم",
|
"blocked_by": "تم حظرك من قبل هذا المستخدم",
|
||||||
@ -11,9 +18,9 @@
|
|||||||
"follow_back": "إعادة متابعة",
|
"follow_back": "إعادة متابعة",
|
||||||
"follow_requested": "طلبت المتابعة",
|
"follow_requested": "طلبت المتابعة",
|
||||||
"followers": "متابِعون",
|
"followers": "متابِعون",
|
||||||
"followers_count": "{0} متابِعون|{0} متابِع|{0} متابِعون",
|
"followers_count": "لا يوجد متابعون|{0} متابِع|{0} متابِعين|{0} متابِعون|{0} متابِع|{0} متابِع",
|
||||||
"following": "مُتابَع",
|
"following": "مُتابَع",
|
||||||
"following_count": "{0} مُتابَع",
|
"following_count": "لا يتبع أحدا|{0} مُتابَع|{0} مُتابَعين|{0} مُتابَعون|{0} مُتابَع|{0} مُتابَع",
|
||||||
"follows_you": "يتابعك",
|
"follows_you": "يتابعك",
|
||||||
"go_to_profile": "اعرض الصفحة التعريفية",
|
"go_to_profile": "اعرض الصفحة التعريفية",
|
||||||
"joined": "انضم",
|
"joined": "انضم",
|
||||||
@ -23,7 +30,7 @@
|
|||||||
"mutuals": "المتبادلين",
|
"mutuals": "المتبادلين",
|
||||||
"pinned": "المثبتة",
|
"pinned": "المثبتة",
|
||||||
"posts": "المنشورات",
|
"posts": "المنشورات",
|
||||||
"posts_count": "{0} منشورات|{0} منشور|{0} منشورات",
|
"posts_count": "{0} منشورات|{0} منشور|{0} منشورين|{0} منشورات|{0} منشور|{0} منشور",
|
||||||
"profile_description": "{0} رأسية حساب",
|
"profile_description": "{0} رأسية حساب",
|
||||||
"profile_unavailable": "حساب غير متوفر",
|
"profile_unavailable": "حساب غير متوفر",
|
||||||
"unblock": "إلغاء حظر",
|
"unblock": "إلغاء حظر",
|
||||||
@ -31,12 +38,16 @@
|
|||||||
"unmute": "إلغاء كتم"
|
"unmute": "إلغاء كتم"
|
||||||
},
|
},
|
||||||
"action": {
|
"action": {
|
||||||
"bookmark": "إضافة إلى المرجعية",
|
"apply": "تطبيق",
|
||||||
"bookmarked": "مضاف إلى المرجعية",
|
"bookmark": "إضافة إلى العلامات المرجعية",
|
||||||
|
"bookmarked": "مضاف إلى العلامات المرجعية",
|
||||||
"boost": "إعادة نشر",
|
"boost": "إعادة نشر",
|
||||||
"boosted": "أعيد نشرها",
|
"boosted": "أعيد نشرها",
|
||||||
|
"clear_upload_failed": "مسح أخطاء تحميل الملف",
|
||||||
"close": "أغلق",
|
"close": "أغلق",
|
||||||
"compose": "منشور جديد",
|
"compose": "منشور جديد",
|
||||||
|
"confirm": "أكد",
|
||||||
|
"edit": "تعديل",
|
||||||
"enter_app": "أدخل التطبيق",
|
"enter_app": "أدخل التطبيق",
|
||||||
"favourite": "إضافة إلى المفضلين",
|
"favourite": "إضافة إلى المفضلين",
|
||||||
"favourited": "مضاف إلى المفضلين",
|
"favourited": "مضاف إلى المفضلين",
|
||||||
@ -45,6 +56,7 @@
|
|||||||
"prev": "السابق",
|
"prev": "السابق",
|
||||||
"publish": "!نشر",
|
"publish": "!نشر",
|
||||||
"reply": "رد",
|
"reply": "رد",
|
||||||
|
"save": "حفظ",
|
||||||
"save_changes": "حفظ التغييرات",
|
"save_changes": "حفظ التغييرات",
|
||||||
"sign_in": "تسجيل الدخول",
|
"sign_in": "تسجيل الدخول",
|
||||||
"switch_account": "تغيير الحساب",
|
"switch_account": "تغيير الحساب",
|
||||||
@ -53,6 +65,10 @@
|
|||||||
"app_desc_short": "موقع الكتروني ماستدون رشيق",
|
"app_desc_short": "موقع الكتروني ماستدون رشيق",
|
||||||
"app_logo": "Elk شعار",
|
"app_logo": "Elk شعار",
|
||||||
"app_name": "Elk",
|
"app_name": "Elk",
|
||||||
|
"attachment": {
|
||||||
|
"edit_title": "وصف",
|
||||||
|
"remove_label": "قم بإزالة المرفق"
|
||||||
|
},
|
||||||
"command": {
|
"command": {
|
||||||
"activate": "تفعيل",
|
"activate": "تفعيل",
|
||||||
"complete": "أكمل",
|
"complete": "أكمل",
|
||||||
@ -68,6 +84,7 @@
|
|||||||
"common": {
|
"common": {
|
||||||
"end_of_list": "نهاية القائمة",
|
"end_of_list": "نهاية القائمة",
|
||||||
"error": "حدث خطأ",
|
"error": "حدث خطأ",
|
||||||
|
"in": "في",
|
||||||
"kiloSuffix": "ألف",
|
"kiloSuffix": "ألف",
|
||||||
"megaSuffix": "مليون",
|
"megaSuffix": "مليون",
|
||||||
"not_found": "404 غير معثور عليه",
|
"not_found": "404 غير معثور عليه",
|
||||||
@ -79,8 +96,10 @@
|
|||||||
"error": {
|
"error": {
|
||||||
"account_not_found": "حساب {0} غير موجود",
|
"account_not_found": "حساب {0} غير موجود",
|
||||||
"explore-list-empty": "لا توجد مشاركات شائعة الآن. تحقق مرة أخرى لاحقًا!",
|
"explore-list-empty": "لا توجد مشاركات شائعة الآن. تحقق مرة أخرى لاحقًا!",
|
||||||
|
"file_size_cannot_exceed_n_mb": "لا يمكن أن يتجاوز حجم الملف {0} ميغابايت",
|
||||||
"sign_in_error": "لا يمكن الاتصال بالموقع",
|
"sign_in_error": "لا يمكن الاتصال بالموقع",
|
||||||
"status_not_found": "لا يمكن إيجاد المنشور"
|
"status_not_found": "لا يمكن إيجاد المنشور",
|
||||||
|
"unsupported_file_format": "لا يمكن تحميل هذا النوع من الملفات"
|
||||||
},
|
},
|
||||||
"help": {
|
"help": {
|
||||||
"desc_highlight": "توقع بعض الأخطاء والميزات المفقودة هنا وهناك.",
|
"desc_highlight": "توقع بعض الأخطاء والميزات المفقودة هنا وهناك.",
|
||||||
@ -111,23 +130,25 @@
|
|||||||
"unblock_account": "رفع الحظر عن {0}",
|
"unblock_account": "رفع الحظر عن {0}",
|
||||||
"unblock_domain": "رفع الحظر عن النطاق {0}",
|
"unblock_domain": "رفع الحظر عن النطاق {0}",
|
||||||
"unmute_account": "إلغاء كتم الحساب {0}",
|
"unmute_account": "إلغاء كتم الحساب {0}",
|
||||||
"unmute_conversation": "إعادة الصوت",
|
"unmute_conversation": "إلغاء كتم المحادثة",
|
||||||
"unpin_on_profile": "إلغاء التثبيت من الملف الشخصي"
|
"unpin_on_profile": "إلغاء التثبيت من الملف الشخصي"
|
||||||
},
|
},
|
||||||
"nav": {
|
"nav": {
|
||||||
"bookmarks": "الفواصل المرجعية",
|
"bookmarks": "العلامات المرجعية",
|
||||||
"built_at": "Built {0}",
|
"built_at": "Built {0}",
|
||||||
"conversations": "المحادثات",
|
"conversations": "المحادثات",
|
||||||
"explore": "استكشف",
|
"explore": "استكشف",
|
||||||
"favourites": "المفضلة",
|
"favourites": "المفضلة",
|
||||||
"federated": "الفديرالية",
|
"federated": "الفديرالية",
|
||||||
"home": "الخيط الزمني الرئيسي",
|
"home": "الرئيسيّة",
|
||||||
"local": "المحلي",
|
"local": "المحلي",
|
||||||
"notifications": "الإشعارات",
|
"notifications": "التنبيهات",
|
||||||
"profile": "الصفحة التعريفية",
|
"profile": "الصفحة التعريفية",
|
||||||
"search": "البحث",
|
"search": "البحث",
|
||||||
"select_feature_flags": "تبديل علامات الميزات",
|
"select_feature_flags": "تبديل علامات الميزات",
|
||||||
|
"select_font_size": "حجم الخط",
|
||||||
"select_language": "اختار اللغة",
|
"select_language": "اختار اللغة",
|
||||||
|
"settings": "الإعدادات",
|
||||||
"show_intro": "عرض المقدمة",
|
"show_intro": "عرض المقدمة",
|
||||||
"toggle_theme": "تبديل المظهر",
|
"toggle_theme": "تبديل المظهر",
|
||||||
"zen_mode": "الوضع الهادئ"
|
"zen_mode": "الوضع الهادئ"
|
||||||
@ -135,7 +156,7 @@
|
|||||||
"notification": {
|
"notification": {
|
||||||
"favourited_post": "أُعجِب بمنشورك",
|
"favourited_post": "أُعجِب بمنشورك",
|
||||||
"followed_you": "بدأ في متابعتك",
|
"followed_you": "بدأ في متابعتك",
|
||||||
"followed_you_count": "تبعك {followers} أشخاص|تبعك {followers} شخص| تبعك {followers} أشخاص",
|
"followed_you_count": "لم يتبعك أحد|تبعك شخص واحد|تبعك شخصان|تبعك {followers} أشخاص|تبعك {followers} شخص| تبعك {followers} شخص",
|
||||||
"missing_type": "MISSING notification.type:",
|
"missing_type": "MISSING notification.type:",
|
||||||
"reblogged_post": "اعاد نشر منشورك",
|
"reblogged_post": "اعاد نشر منشورك",
|
||||||
"request_to_follow": "طلب(ت) متابعتك",
|
"request_to_follow": "طلب(ت) متابعتك",
|
||||||
@ -146,31 +167,33 @@
|
|||||||
"mention": "المنشورات التي تذكرني",
|
"mention": "المنشورات التي تذكرني",
|
||||||
"poll": "استطلاعات الرأي",
|
"poll": "استطلاعات الرأي",
|
||||||
"reblog": "إعادة نشر منشورك",
|
"reblog": "إعادة نشر منشورك",
|
||||||
"title": "ما هي الإشعارات التي تريد تلقيها؟"
|
"title": "ما هي التنبيهات التي تريد تلقيها؟"
|
||||||
},
|
},
|
||||||
"close_btn": "أغلق إعدادات الإشعارات",
|
"close_btn": "أغلق إعدادات التنبيهات",
|
||||||
"policy": {
|
"policy": {
|
||||||
"all": "من اي شخص",
|
"all": "من اي شخص",
|
||||||
"followed": "من الناس الذين أتابعهم",
|
"followed": "من الناس الذين أتابعهم",
|
||||||
"follower": "من الناس الذين يتبعونني",
|
"follower": "من الناس الذين يتبعونني",
|
||||||
"none": "من لا أحد",
|
"none": "من لا أحد",
|
||||||
"title": "من الذي يمكنني تلقي إشعارات منه؟"
|
"title": "من الذي يمكنني تلقي التنبيهات منه؟"
|
||||||
},
|
},
|
||||||
"save_settings": "حفظ التغييرات الإعدادات",
|
"save_settings": "حفظ التغييرات الإعدادات",
|
||||||
"show_btn": "إظهار إعدادات الإشعارات",
|
"show_btn": "إظهار إعدادات التنبيهات",
|
||||||
"title": "إعدادات الإشعارات",
|
"title": "إعدادات التنبيهات",
|
||||||
"undo_settings": "تراجع عن تغييرات الإعدادات",
|
"undo_settings": "تراجع عن تغييرات الإعدادات",
|
||||||
"unsubscribe": "تعطيل الإشعارات",
|
"unsubscribe": "تعطيل التنبيهات",
|
||||||
"unsubscribed_with_warning": "مكّن الإشعارات لتلقي الإشعارات من هذا الحساب بالنقر فوق الزر \"@:notification.settings.warning.enable_desktop{'\"'}",
|
"unsubscribed_with_warning": "مكّن الإشعارات لتلقي التنبيهات من هذا الحساب بالنقر فوق الزر \"@:notification.settings.warning.enable_desktop{'\"'}",
|
||||||
"unsupported": "متصفحك لا يدعم الإشعارات",
|
"unsupported": "متصفحك لا يدعم التنبيهات",
|
||||||
"warning": {
|
"warning": {
|
||||||
"enable_close": "أغلق",
|
"enable_close": "أغلق",
|
||||||
"enable_description": "لتلقي إشعارات عندما لا يكون Elk مفتوحًا ، قم بتمكين إشعارات النظام. يمكنك التحكم بدقة في أنواع التفاعلات التي تنشئ إشعارات النظام عبر الزر \"Show Settings\" أعلاه بمجرد تمكينه.",
|
"enable_description": "لتلقي التنبيهات عندما لا يكون Elk مفتوحًا، قم بتمكين تنبيهات النظام. يمكنك التحكم بدقة في أنواع التفاعلات التي تنشئ تنبيهات النظام عبر الزر \"Show Settings\" أعلاه.",
|
||||||
"enable_description_short": "لتغيير إعدادات إشعارات النظام عندما لا يكون Elk مفتوحًا ، يجب أولاً تمكين إشعارات النظام.",
|
"enable_description_short": "لتغيير إعدادات تنبيهات النظام عندما لا يكون Elk مفتوحًا، يجب أولاً تمكين تنبيهات النظام.",
|
||||||
"enable_desktop": "تفعيل إشعارات النظام",
|
"enable_desktop": "تفعيل تنبيهات النظام",
|
||||||
"enable_title": "لا تفوت أي شيء"
|
"enable_title": "لا تفوت عليك أي شيء",
|
||||||
|
"re_auth": "يبدو أن الخادم الخاص بك لا يدعم دفع التنبيهات. حاول تسجيل الخروج ثم تسجيل الدخول مرة أخرى ، إذا استمرت هذه الرسالة في الظهور ، فاتصل بمسؤول الخادم."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"signed_up": "تسجل",
|
||||||
"update_status": "قام(ت) بتحديث حالته(ا)"
|
"update_status": "قام(ت) بتحديث حالته(ا)"
|
||||||
},
|
},
|
||||||
"placeholder": {
|
"placeholder": {
|
||||||
@ -182,23 +205,65 @@
|
|||||||
},
|
},
|
||||||
"pwa": {
|
"pwa": {
|
||||||
"dismiss": "تجاهل",
|
"dismiss": "تجاهل",
|
||||||
"title": "يتوفر تحديث Elk الجديد"
|
"title": "يتوفر تحديث Elk الجديد",
|
||||||
|
"update": "تحديث",
|
||||||
|
"update_available_short": "تحديث Elk"
|
||||||
},
|
},
|
||||||
"search": {
|
"search": {
|
||||||
"search_desc": "ابحث عن الأشخاص والهاشتاج"
|
"search_desc": "ابحث عن الأشخاص والهاشتاج"
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
|
"about": {
|
||||||
|
"label": "بشأن Elk"
|
||||||
|
},
|
||||||
"feature_flags": {
|
"feature_flags": {
|
||||||
"avatar_on_avatar": "الصورة الرمزية على الصورة الرمزية",
|
"avatar_on_avatar": "الصورة الرمزية على الصورة الرمزية",
|
||||||
"github_cards": "GitHub بطاقات",
|
"github_cards": "GitHub بطاقات",
|
||||||
|
"title": "الميزات التجريبية",
|
||||||
"user_picker": "الشريط الجانبي لمبدل المستخدم",
|
"user_picker": "الشريط الجانبي لمبدل المستخدم",
|
||||||
"virtual_scroll": "التمرير الافتراضي"
|
"virtual_scroll": "التمرير الافتراضي"
|
||||||
|
},
|
||||||
|
"interface": {
|
||||||
|
"color_mode": "وضع اللون",
|
||||||
|
"dark_mode": "الوضع الداكن",
|
||||||
|
"default": "(إفتراضي)",
|
||||||
|
"font_size": "حجم الخط",
|
||||||
|
"label": "واجهه المستخدم",
|
||||||
|
"light_mode": "وضع الضوء"
|
||||||
|
},
|
||||||
|
"language": {
|
||||||
|
"display_language": "اللغة المعروضة",
|
||||||
|
"label": "اللغة"
|
||||||
|
},
|
||||||
|
"preferences": {
|
||||||
|
"label": "التفضيلات"
|
||||||
|
},
|
||||||
|
"profile": {
|
||||||
|
"appearance": {
|
||||||
|
"bio": "النبذة التعريفية",
|
||||||
|
"description": "تعديل الصورة الرمزية واسم المستخدم والملف الشخصي...",
|
||||||
|
"display_name": "الاسم المعروض",
|
||||||
|
"label": "المظهر",
|
||||||
|
"title": "تعديل الملف الشخصي"
|
||||||
|
},
|
||||||
|
"featured_tags": {
|
||||||
|
"description": "يمكن للأشخاص تصفح مشاركاتك العامة تحت علامات الهاشتاغ هذه",
|
||||||
|
"label": "الهاشتاغ البارزة"
|
||||||
|
},
|
||||||
|
"label": "الملف الشخصي"
|
||||||
|
},
|
||||||
|
"select_a_settings": "اختر الإعداد",
|
||||||
|
"users": {
|
||||||
|
"export": "Export User Tokens",
|
||||||
|
"import": "Import User Tokens",
|
||||||
|
"label": "المستخدمون المسجلون"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"state": {
|
"state": {
|
||||||
"edited": "(معدل)",
|
"edited": "(معدل)",
|
||||||
"editing": "تعديل",
|
"editing": "تعديل",
|
||||||
"loading": "جاري التحميل ...",
|
"loading": "جاري التحميل ...",
|
||||||
|
"upload_failed": "التحميل فشل",
|
||||||
"uploading": "جاري التحميل ..."
|
"uploading": "جاري التحميل ..."
|
||||||
},
|
},
|
||||||
"status": {
|
"status": {
|
||||||
@ -211,7 +276,7 @@
|
|||||||
"dismiss": "تجاهل"
|
"dismiss": "تجاهل"
|
||||||
},
|
},
|
||||||
"poll": {
|
"poll": {
|
||||||
"count": "{0} أصوات|{0} صوت|{0} أصوات",
|
"count": "لا توجد اصوات|صوت {0}|صوتين|{0} أصوات|{0} صوت|{0} صوت",
|
||||||
"ends": "ينتهي في {0}",
|
"ends": "ينتهي في {0}",
|
||||||
"finished": "انتهى في {0}"
|
"finished": "انتهى في {0}"
|
||||||
},
|
},
|
||||||
@ -219,7 +284,6 @@
|
|||||||
"someone": "شخص ما",
|
"someone": "شخص ما",
|
||||||
"spoiler_show_less": "عرض أقل",
|
"spoiler_show_less": "عرض أقل",
|
||||||
"spoiler_show_more": "عرض المزيد",
|
"spoiler_show_more": "عرض المزيد",
|
||||||
"thread": "المحادثة",
|
|
||||||
"try_original_site": "جرب الموقع الأصلي"
|
"try_original_site": "جرب الموقع الأصلي"
|
||||||
},
|
},
|
||||||
"status_history": {
|
"status_history": {
|
||||||
@ -237,38 +301,38 @@
|
|||||||
"posts_with_replies": "المنشورات والردود"
|
"posts_with_replies": "المنشورات والردود"
|
||||||
},
|
},
|
||||||
"time_ago_options": {
|
"time_ago_options": {
|
||||||
"day_future": "في 0 يوم|غداً|في {n} يوم",
|
"day_future": "في 0 أيام|غدا|في يومين|في {v} أيام|في {v} يوم|في {v} يوم",
|
||||||
"day_past": "قبل {n} يوم|البارحة| قبل 0 يوم",
|
"day_past": "منذ 0 أيام|البارحة|منذ يومين|منذ {v} أيام|منذ {v} يوم|منذ {v} يوم",
|
||||||
"hour_future": "في 0 ساعة|في 1 ساعة|في {n} ساعة",
|
"hour_future": "في 0 ساعات|في ساعة|في ساعتين|في {v} ساعات|في {v} ساعة|في {v} ساعة",
|
||||||
"hour_past": "قبل 0 ساعة|قبل ساعة واحدة|{n} من الساعات الماضية",
|
"hour_past": "منذ 0 ساعات|منذ ساعة واحدة|منذ ساعتين|منذ {v} ساعات|منذ {v} ساعة|منذ {v} ساعة",
|
||||||
"just_now": "الآن",
|
"just_now": "الآن",
|
||||||
"minute_future": "في 0 دقيقة|في دقيقة واحدة|في {n} دقيقة",
|
"minute_future": "في 0 دقائق|في دقيقة واحدة|في دقيقتين|في {v} دقائق|في {v} دقيقة|في {v} دقيقة",
|
||||||
"minute_past": "قبل 0 دقيقة|قبل دقيقة واحدة|قبل {n} دقيقة",
|
"minute_past": "منذ 0 دقائق|منذ دقيقة واحدة|منذ دقيقتين|منذ {v} دقائق|منذ {v} دقيقة|منذ {v} دقيقة",
|
||||||
"month_future": "في 0 شهر|الشهر القادم|في {n} شهر",
|
"month_future": "في 0 أشهر|الشهر القادم|في شهرين|في {v} أشهر|في {v} شهر|في {v} شهر",
|
||||||
"month_past": "قبل 0 شهر|الشهر الماضي|منذ {n} شهر",
|
"month_past": "منذ 0 أشهر|الشهر الماضي|منذ شهرين|منذ {v} أشهر|منذ {v} شهر|منذ {v} شهر",
|
||||||
"second_future": "الآن|في ثانية|في {n} ثواني",
|
"second_future": "الآن|في ثانية|في ثانيتين|في {v} ثواني|في {v} ثانية|في {v} ثانية",
|
||||||
"second_past": "للتو|منذ ثانية|منذ {n} ثانية",
|
"second_past": "للتو|منذ ثانية|منذ ثانيتين|منذ {v} ثواني|منذ {v} ثانية|منذ {v} ثانية",
|
||||||
"short_day_future": "في {n} ي",
|
"short_day_future": "في 0 أيام|غدا|في يومين|في {v} أيام|في {v} يوم|في {v} يوم",
|
||||||
"short_day_past": "{n}ي",
|
"short_day_past": "منذ 0 أيام|البارحة|منذ يومين|منذ {v} أيام|منذ {v} يوم|منذ {v} يوم",
|
||||||
"short_hour_future": "في {n} س",
|
"short_hour_future": "في 0 ساعات|في ساعة|في ساعتين|في {v} ساعات|في {v} ساعة|في {v} ساعة",
|
||||||
"short_hour_past": "{n}س",
|
"short_hour_past": "منذ 0 ساعات|منذ ساعة واحدة|منذ ساعتين|منذ {v} ساعات|منذ {v} ساعة|منذ {v} ساعة",
|
||||||
"short_minute_future": "في {n} دق",
|
"short_minute_future": "في 0 دقائق|في دقيقة واحدة|في دقيقتين|في {v} دقائق|في {v} دقيقة|في {v} دقيقة",
|
||||||
"short_minute_past": "{n}دق",
|
"short_minute_past": "منذ 0 دقائق|منذ دقيقة واحدة|منذ دقيقتين|منذ {v} دقائق|منذ {v} دقيقة|منذ {v} دقيقة",
|
||||||
"short_month_future": "في {n} ش",
|
"short_month_future": "في 0 أشهر|الشهر القادم|في شهرين|في {v} أشهر|في {v} شهر|في {v} شهر",
|
||||||
"short_month_past": "{n}ش",
|
"short_month_past": "منذ 0 أشهر|الشهر الماضي|منذ شهرين|منذ {v} أشهر|منذ {v} شهر|منذ {v} شهر",
|
||||||
"short_second_future": "في {n} ",
|
"short_second_future": "الآن|في ثانية|في ثانيتين|في {v} ثواني|في {v} ثانية|في {v} ثانية",
|
||||||
"short_second_past": "{n}",
|
"short_second_past": "للتو|منذ ثانية|منذ ثانيتين|منذ {v} ثواني|منذ {v} ثانية|منذ {v} ثانية",
|
||||||
"short_week_future": "في {n} اسبوع",
|
"short_week_future": "في 0 أسابيع|الاسبوع القادم|في اسبوعين|في {v} أسابيع|في {v} اسبوع|في {v} اسبوع",
|
||||||
"short_week_past": "{n}اسبوع",
|
"short_week_past": "منذ 0 أسابيع|الاسبوع الماضي|منذ اسبوعين|منذ {v} أسابيع|منذ {v} اسبوع|منذ {v} اسبوع",
|
||||||
"short_year_future": "في {n} سنة",
|
"short_year_future": "هذا العام|العام القادم|في عامين|في {v} عاما|في {v} عام|في {v} عام",
|
||||||
"short_year_past": "{n}سنة",
|
"short_year_past": "هذا العام|العام الماضي|منذ عامين|منذ {v} عاما|منذ {v} عام|منذ {v} عام",
|
||||||
"week_future": "في 0 أسبوع | الأسبوع القادم | في {n} أسبوع",
|
"week_future": "في 0 أسابيع|الاسبوع القادم|في اسبوعين|في {v} أسابيع|في {v} اسبوع|في {v} اسبوع",
|
||||||
"week_past": "قبل 0 أسبوع | الأسبوع الماضي | {n} أسبوع مضى",
|
"week_past": "منذ 0 أسابيع|الاسبوع الماضي|منذ اسبوعين|منذ {v} أسابيع|منذ {v} اسبوع|منذ {v} اسبوع",
|
||||||
"year_future": "في 0 سنة|العام القادم|في {n} سنة",
|
"year_future": "هذا العام|العام القادم|في عامين|في {v} عاما|في {v} عام|في {v} عام",
|
||||||
"year_past": "منذ 0 سنة|العام الماضي|منذ {n} سنة"
|
"year_past": "هذا العام|العام الماضي|منذ عامين|منذ {v} عاما|منذ {v} عام|منذ {v} عام"
|
||||||
},
|
},
|
||||||
"timeline": {
|
"timeline": {
|
||||||
"show_new_items": "إظهار {n} عناصر جديدة|إظهار {n} عنصر جديد|إظهار {n} عناصر جديدة"
|
"show_new_items": "لا توجد عناصر جديدة|إظهار {v} عنصر جديد|إظهار {v} عنصرين جديدين|إظهار {v} عناصر جديدة|إظهار {v} عنصر جديد|إظهار {v} عنصر جديد"
|
||||||
},
|
},
|
||||||
"title": {
|
"title": {
|
||||||
"federated_timeline": "الجدول الزمني الموحد",
|
"federated_timeline": "الجدول الزمني الموحد",
|
||||||
@ -278,15 +342,17 @@
|
|||||||
"add_content_warning": "إضافة تحذير المحتوى",
|
"add_content_warning": "إضافة تحذير المحتوى",
|
||||||
"add_media": "أضف صورًا أو مقطع فيديو أو ملفًا صوتيًا",
|
"add_media": "أضف صورًا أو مقطع فيديو أو ملفًا صوتيًا",
|
||||||
"change_content_visibility": "تغيير خصوصية المحتوى",
|
"change_content_visibility": "تغيير خصوصية المحتوى",
|
||||||
|
"emoji": "رمز تعبيري",
|
||||||
"explore_links_intro": "يتم التحدث عن هذه القصص الإخبارية من قبل الأشخاص الموجودين على هذه الشبكة وغيرها من الشبكات اللامركزية في الوقت الحالي",
|
"explore_links_intro": "يتم التحدث عن هذه القصص الإخبارية من قبل الأشخاص الموجودين على هذه الشبكة وغيرها من الشبكات اللامركزية في الوقت الحالي",
|
||||||
"explore_posts_intro": "تكتسب هذه المنشورات من هذه الشبكة وغيرها من الشبكات اللامركزية زخمًا على هذه الشبكة في الوقت الحالي",
|
"explore_posts_intro": "تكتسب هذه المنشورات الكثير من النشاط على الشبكة وغيرها من الشبكات اللامركزية في الوقت الحالي",
|
||||||
"explore_tags_intro": "تكتسب هذه الهاشتاغ زخمًا بين الأشخاص على هذه الشبكة وغيرها من الشبكات اللامركزية في الوقت الحالي",
|
"explore_tags_intro": "تكتسب هذه الهاشتاغ الكثير من النشاط بين الأشخاص على هذه الشبكة وغيرها من الشبكات اللامركزية في الوقت الحالي",
|
||||||
"toggle_code_block": "تبديل كتلة التعليمات البرمجية"
|
"toggle_code_block": "تبديل كتلة التعليمات البرمجية"
|
||||||
},
|
},
|
||||||
"user": {
|
"user": {
|
||||||
"add_existing": "إضافة حساب قائم",
|
"add_existing": "إضافة حساب قائم",
|
||||||
"server_address_label": "عنوان خادم ماستودون",
|
"server_address_label": "عنوان خادم ماستودون",
|
||||||
"sign_in_desc": "قم بتسجيل الدخول لمتابعة الملفات الشخصية والمشاركة والرد على المنشورات أو التفاعل من حسابك على خادم مختلف",
|
"sign_in_desc": "قم بتسجيل الدخول لمتابعة الملفات الشخصية والمشاركة والرد على المنشورات أو التفاعل من حسابك على خادم مختلف",
|
||||||
|
"sign_in_notice_title": "عرض البيانات العامة من {0}",
|
||||||
"sign_out_account": "تسجيل الخروج من {0}",
|
"sign_out_account": "تسجيل الخروج من {0}",
|
||||||
"tip_no_account": "إذا ليس لديك حساب ماستودون ، {0}",
|
"tip_no_account": "إذا ليس لديك حساب ماستودون ، {0}",
|
||||||
"tip_register_account": "اختر خادم ماستودون الخاص بك وقم بتسجيل حساب"
|
"tip_register_account": "اختر خادم ماستودون الخاص بك وقم بتسجيل حساب"
|
||||||
|
@ -225,7 +225,7 @@
|
|||||||
"year_past": "před 0 roky|minulý rok|před {n} lety "
|
"year_past": "před 0 roky|minulý rok|před {n} lety "
|
||||||
},
|
},
|
||||||
"timeline": {
|
"timeline": {
|
||||||
"show_new_items": "Ukázat {n} nových položek|Ukázat {n} novou položku|Ukázat {n} nových položek"
|
"show_new_items": "Ukázat {v} nových položek|Ukázat {v} novou položku|Ukázat {v} nových položek"
|
||||||
},
|
},
|
||||||
"title": {
|
"title": {
|
||||||
"federated_timeline": "Federovaná časová osa",
|
"federated_timeline": "Federovaná časová osa",
|
||||||
|
@ -227,7 +227,7 @@
|
|||||||
"year_past": "vor 0 Jahren|letztes Jahren|vor {n} Jahren"
|
"year_past": "vor 0 Jahren|letztes Jahren|vor {n} Jahren"
|
||||||
},
|
},
|
||||||
"timeline": {
|
"timeline": {
|
||||||
"show_new_items": "Zeige {n} neue Beiträge|Zeige {n} neuen Beitrag|Zeige {n} neue Beiträge"
|
"show_new_items": "Zeige {v} neue Beiträge|Zeige {v} neuen Beitrag|Zeige {v} neue Beiträge"
|
||||||
},
|
},
|
||||||
"title": {
|
"title": {
|
||||||
"federated_timeline": "Föderierte Timeline",
|
"federated_timeline": "Föderierte Timeline",
|
||||||
|
@ -333,7 +333,7 @@
|
|||||||
"year_past": "0 years ago|last year|{n} years ago"
|
"year_past": "0 years ago|last year|{n} years ago"
|
||||||
},
|
},
|
||||||
"timeline": {
|
"timeline": {
|
||||||
"show_new_items": "Show {n} new items|Show {n} new item|Show {n} new items"
|
"show_new_items": "Show {v} new items|Show {v} new item|Show {v} new items"
|
||||||
},
|
},
|
||||||
"title": {
|
"title": {
|
||||||
"federated_timeline": "Federated Timeline",
|
"federated_timeline": "Federated Timeline",
|
||||||
|
@ -333,7 +333,7 @@
|
|||||||
"year_past": "0 years ago|last year|{n} years ago"
|
"year_past": "0 years ago|last year|{n} years ago"
|
||||||
},
|
},
|
||||||
"timeline": {
|
"timeline": {
|
||||||
"show_new_items": "Show {n} new items|Show {n} new item|Show {n} new items"
|
"show_new_items": "Show {v} new items|Show {v} new item|Show {v} new items"
|
||||||
},
|
},
|
||||||
"title": {
|
"title": {
|
||||||
"federated_timeline": "Federated Timeline",
|
"federated_timeline": "Federated Timeline",
|
||||||
|
@ -324,7 +324,7 @@
|
|||||||
"year_past": "hace 0 años|el año pasado|hace {n} años"
|
"year_past": "hace 0 años|el año pasado|hace {n} años"
|
||||||
},
|
},
|
||||||
"timeline": {
|
"timeline": {
|
||||||
"show_new_items": "Mostrar {n} nuevas publicaciones|Mostrar {n} nueva publicación|Mostrar {n} nuevas publicaciones"
|
"show_new_items": "Mostrar {v} nuevas publicaciones|Mostrar {v} nueva publicación|Mostrar {v} nuevas publicaciones"
|
||||||
},
|
},
|
||||||
"title": {
|
"title": {
|
||||||
"federated_timeline": "Línea de tiempo federada",
|
"federated_timeline": "Línea de tiempo federada",
|
||||||
|
@ -285,7 +285,7 @@
|
|||||||
"year_past": "il y a 0 année|l'année dernière|il y a {n} années"
|
"year_past": "il y a 0 année|l'année dernière|il y a {n} années"
|
||||||
},
|
},
|
||||||
"timeline": {
|
"timeline": {
|
||||||
"show_new_items": "Voir le nouveau message|Voir les {n} nouveaux messages"
|
"show_new_items": "Voir le nouveau message|Voir les {v} nouveaux messages"
|
||||||
},
|
},
|
||||||
"title": {
|
"title": {
|
||||||
"federated_timeline": "Fil d'actualité fédéré",
|
"federated_timeline": "Fil d'actualité fédéré",
|
||||||
|
@ -86,7 +86,7 @@
|
|||||||
"posts_with_replies": "投稿と返信"
|
"posts_with_replies": "投稿と返信"
|
||||||
},
|
},
|
||||||
"timeline": {
|
"timeline": {
|
||||||
"show_new_items": "{n}件の新しい投稿"
|
"show_new_items": "{v}件の新しい投稿"
|
||||||
},
|
},
|
||||||
"title": {
|
"title": {
|
||||||
"federated_timeline": "連合タイムライン",
|
"federated_timeline": "連合タイムライン",
|
||||||
|
@ -333,7 +333,7 @@
|
|||||||
"year_past": "现在|去年|{n}年前"
|
"year_past": "现在|去年|{n}年前"
|
||||||
},
|
},
|
||||||
"timeline": {
|
"timeline": {
|
||||||
"show_new_items": "展示 {n} 条新帖文"
|
"show_new_items": "展示 {v} 条新帖文"
|
||||||
},
|
},
|
||||||
"title": {
|
"title": {
|
||||||
"federated_timeline": "跨站时间线",
|
"federated_timeline": "跨站时间线",
|
||||||
|
@ -333,7 +333,7 @@
|
|||||||
"year_past": "現在|去年|{n}年前"
|
"year_past": "現在|去年|{n}年前"
|
||||||
},
|
},
|
||||||
"timeline": {
|
"timeline": {
|
||||||
"show_new_items": "展示 {n} 條新帖文"
|
"show_new_items": "展示 {v} 條新帖文"
|
||||||
},
|
},
|
||||||
"title": {
|
"title": {
|
||||||
"federated_timeline": "跨站時間線",
|
"federated_timeline": "跨站時間線",
|
||||||
|
@ -14,7 +14,7 @@ useHeadFixed({
|
|||||||
<template>
|
<template>
|
||||||
<MainContent>
|
<MainContent>
|
||||||
<template #title>
|
<template #title>
|
||||||
<div i-ri:pushpin-line h-6 mr-1 />
|
<div i-ri:pushpin-line h-6 me-1 />
|
||||||
<span>{{ t('account.pinned') }}</span>
|
<span>{{ t('account.pinned') }}</span>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ useHeadFixed({
|
|||||||
<MainContent>
|
<MainContent>
|
||||||
<template #title>
|
<template #title>
|
||||||
<NuxtLink to="/search" text-lg font-bold flex items-center gap-2 @click="$scrollToTop">
|
<NuxtLink to="/search" text-lg font-bold flex items-center gap-2 @click="$scrollToTop">
|
||||||
<div i-ri:search-line />
|
<div i-ri:search-line class="rtl-flip" />
|
||||||
<span>{{ $t('nav.search') }}</span>
|
<span>{{ $t('nav.search') }}</span>
|
||||||
</NuxtLink>
|
</NuxtLink>
|
||||||
</template>
|
</template>
|
||||||
|
@ -11,7 +11,7 @@ const isRootPath = computedEager(() => route.name === 'settings')
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div min-h-screen flex>
|
<div min-h-screen flex>
|
||||||
<div border="r base" :class="isRootPath ? 'block lg:flex-none flex-1' : 'hidden lg:block'">
|
<div border="e base" :class="isRootPath ? 'block lg:flex-none flex-1' : 'hidden lg:block'">
|
||||||
<MainContent>
|
<MainContent>
|
||||||
<template #title>
|
<template #title>
|
||||||
<div text-lg font-bold flex items-center gap-2 @click="$scrollToTop">
|
<div text-lg font-bold flex items-center gap-2 @click="$scrollToTop">
|
||||||
|
@ -188,6 +188,10 @@ body {
|
|||||||
stroke-width: 2;
|
stroke-width: 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
html[dir="rtl"] .rtl-flip {
|
||||||
|
transform: scale(-1, 1)
|
||||||
|
}
|
||||||
|
|
||||||
em-emoji-picker {
|
em-emoji-picker {
|
||||||
--border-radius: 0;
|
--border-radius: 0;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user