diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 943dd293..20a36e2a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -132,7 +132,7 @@ You can run this code in your browser console to see how it works: #### Custom Plural Number Formatting Entries **Warning**: -Either **{0}**, **{v}** or **{followers}** should be used with the exception being custom plurals entries using the `{n}` placeholder. +Either **{0}** or **{v}** should be used with the exception being custom plurals entries using the `{n}` placeholder. This is the full list of entries that will be available for number formatting in Elk: - `action.boost_count` (no need to be included, we should use always `en-US` entry): `{0}` for formatted number and `{n}` for raw number - **{0} should be use** @@ -142,7 +142,7 @@ This is the full list of entries that will be available for number formatting in - `account.following_count`: `{0}` for formatted number and `{n}` for raw number - **{0} should be use** - `account.posts_count`: `{0}` for formatted number and `{n}` for raw number - **{0} should be use** - `compose.drafts`: `{v}` for formatted number and `{n}` for raw number - **{v} should be use** -- `notification.followed_you_count`: `{followers}` for formatted number and `{n}` for raw number - **{followers} should be use** +- `notification.followed_you_count`: `{0}` for formatted number and `{n}` for raw number - **{0} should be use** - `status.poll.count`: `{0}` for formatted number and `{n}` for raw number - **{0} should be use** - `time_ago_options.*`: `{0}` for formatted number and `{n}` for raw number - **{0} should be use**: since numbers will be always small, we can also use `{n}` - `timeline.show_new_items`: `{v}` for formatted number and `{n}` for raw number - **{v} should be use** diff --git a/components/account/AccountPostsFollowers.vue b/components/account/AccountPostsFollowers.vue index c004adb9..9aaba0d0 100644 --- a/components/account/AccountPostsFollowers.vue +++ b/components/account/AccountPostsFollowers.vue @@ -1,17 +1,9 @@ <script setup lang="ts"> import type { mastodon } from 'masto' -const props = defineProps<{ +defineProps<{ account: mastodon.v1.Account }>() -const { formatHumanReadableNumber, formatNumber, forSR } = useHumanReadableNumber() - -const statusesCount = $computed(() => formatHumanReadableNumber(props.account.statusesCount)) -const statusesCountSR = $computed(() => forSR(props.account.statusesCount)) -const followingCount = $computed(() => formatHumanReadableNumber(props.account.followingCount)) -const followingCountSR = $computed(() => forSR(props.account.followingCount)) -const followersCount = $computed(() => formatHumanReadableNumber(props.account.followersCount)) -const followersCountSR = $computed(() => forSR(props.account.followersCount)) </script> <template> @@ -21,48 +13,42 @@ const followersCountSR = $computed(() => forSR(props.account.followersCount)) replace text-secondary exact-active-class="text-primary" - :class="statusesCountSR ? 'flex gap-x-1' : null" > <template #default="{ isExactActive }"> - <i18n-t keypath="account.posts_count" :plural="account.statusesCount"> - <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 sr-only font-bold>{{ formatNumber(account.statusesCount) }}</span> - </CommonTooltip> - <span v-else font-bold :class="isExactActive ? 'text-primary' : 'text-base'">{{ statusesCount }}</span> - </i18n-t> + <CommonLocalizedNumber + keypath="account.posts_count" + :count="account.statusesCount" + font-bold + :class="isExactActive ? 'text-primary' : 'text-base'" + /> </template> </NuxtLink> <NuxtLink :to="getAccountFollowingRoute(account)" replace text-secondary exact-active-class="text-primary" - :class="followingCountSR ? 'flex gap-x-1' : null" > <template #default="{ isExactActive }"> - <i18n-t keypath="account.following_count" :plural="account.followingCount"> - <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 sr-only font-bold>{{ formatNumber(account.followingCount) }}</span> - </CommonTooltip> - <span v-else font-bold :class="isExactActive ? 'text-primary' : 'text-base'">{{ followingCount }}</span> - </i18n-t> + <CommonLocalizedNumber + keypath="account.following_count" + :count="account.followingCount" + font-bold + :class="isExactActive ? 'text-primary' : 'text-base'" + /> </template> </NuxtLink> <NuxtLink :to="getAccountFollowersRoute(account)" replace text-secondary exact-active-class="text-primary" - :class="followersCountSR ? 'flex gap-x-1' : null" > <template #default="{ isExactActive }"> - <i18n-t keypath="account.followers_count" :plural="account.followersCount"> - <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 sr-only font-bold>{{ formatNumber(account.followersCount) }}</span> - </CommonTooltip> - <span v-else font-bold :class="isExactActive ? 'text-primary' : 'text-base'">{{ followersCount }}</span> - </i18n-t> + <CommonLocalizedNumber + keypath="account.followers_count" + :count="account.followersCount" + font-bold + :class="isExactActive ? 'text-primary' : 'text-base'" + /> </template> </NuxtLink> </div> diff --git a/components/common/LocalizedNumber.vue b/components/common/LocalizedNumber.vue new file mode 100644 index 00000000..427fbaed --- /dev/null +++ b/components/common/LocalizedNumber.vue @@ -0,0 +1,26 @@ +<script setup lang="ts"> +const props = defineProps<{ + count: number + keypath: string +}>() + +defineOptions({ + inheritAttrs: false, +}) + +const { formatHumanReadableNumber, formatNumber, forSR } = useHumanReadableNumber() + +const useSR = $computed(() => forSR(props.count)) +const rawNumber = $computed(() => formatNumber(props.count)) +const humanReadableNumber = $computed(() => formatHumanReadableNumber(props.count)) +</script> + +<template> + <i18n-t :keypath="keypath" :plural="count" tag="span" class="flex gap-x-1"> + <CommonTooltip v-if="useSR" :content="rawNumber" placement="bottom"> + <span aria-hidden="true" v-bind="$attrs">{{ humanReadableNumber }}</span> + <span sr-only>{{ rawNumber }}</span> + </CommonTooltip> + <span v-else v-bind="$attrs">{{ humanReadableNumber }}</span> + </i18n-t> +</template> diff --git a/components/notification/NotificationGroupedFollow.vue b/components/notification/NotificationGroupedFollow.vue index b9b9f1dd..d29920f5 100644 --- a/components/notification/NotificationGroupedFollow.vue +++ b/components/notification/NotificationGroupedFollow.vue @@ -5,10 +5,7 @@ const { items } = defineProps<{ items: GroupedNotifications }>() -const { formatHumanReadableNumber, forSR } = useHumanReadableNumber() - const count = $computed(() => items.items.length) -const addSR = $computed(() => forSR(count)) const isExpanded = ref(false) const lang = $computed(() => { return count > 1 || count === 0 ? undefined : items.items[0].status?.language @@ -20,19 +17,10 @@ const lang = $computed(() => { <div flex items-center top-0 left-2 pt-2 px-3> <div i-ri:user-follow-fill me-3 color-primary aria-hidden="true" /> <template v-if="count > 1"> - <template v-if="addSR"> - <span - aria-hidden="true" - > - {{ $t('notification.followed_you_count', count, { named: { followers: formatHumanReadableNumber(count) } }) }} - </span> - <span sr-only> - {{ $t('notification.followed_you_count', count, { named: { followers: count } }) }} - </span> - </template> - <span v-else> - {{ $t('notification.followed_you_count', count, { named: { followers: count } }) }} - </span> + <CommonLocalizedNumber + keypath="notification.followed_you_count" + :count="count" + /> </template> <template v-else> <AccountDisplayName diff --git a/components/status/StatusActions.vue b/components/status/StatusActions.vue index 42cd4abd..406750ab 100644 --- a/components/status/StatusActions.vue +++ b/components/status/StatusActions.vue @@ -20,8 +20,6 @@ const { toggleReblog, } = $(useStatusActions(props)) -const { formatHumanReadableNumber, formatNumber, forSR } = useHumanReadableNumber() - const reply = () => { if (!checkLogin()) return @@ -44,13 +42,10 @@ const reply = () => { @click="reply" > <template v-if="status.repliesCount" #text> - <i18n-t keypath="action.reply_count" :plural="status.repliesCount"> - <CommonTooltip v-if="forSR(status.repliesCount)" :content="formatNumber(status.repliesCount)" placement="bottom"> - <span aria-hidden="true">{{ formatHumanReadableNumber(status.repliesCount) }}</span> - <span sr-only>{{ formatNumber(status.repliesCount) }}</span> - </CommonTooltip> - <span v-else>{{ formatHumanReadableNumber(status.repliesCount) }}</span> - </i18n-t> + <CommonLocalizedNumber + keypath="action.reply_count" + :count="status.repliesCount" + /> </template> </StatusActionButton> </div> @@ -68,13 +63,10 @@ const reply = () => { @click="toggleReblog()" > <template v-if="status.reblogsCount" #text> - <i18n-t keypath="action.boost_count" :plural="status.reblogsCount"> - <CommonTooltip v-if="forSR(status.reblogsCount)" :content="formatNumber(status.reblogsCount)" placement="bottom"> - <span aria-hidden="true">{{ formatHumanReadableNumber(status.reblogsCount) }}</span> - <span sr-only>{{ formatNumber(status.reblogsCount) }}</span> - </CommonTooltip> - <span v-else>{{ formatHumanReadableNumber(status.reblogsCount) }}</span> - </i18n-t> + <CommonLocalizedNumber + keypath="action.boost_count" + :count="status.reblogsCount" + /> </template> </StatusActionButton> </div> @@ -92,13 +84,10 @@ const reply = () => { @click="toggleFavourite()" > <template v-if="status.favouritesCount" #text> - <i18n-t keypath="action.favourite_count" :plural="status.favouritesCount"> - <CommonTooltip v-if="forSR(status.favouritesCount)" :content="formatNumber(status.favouritesCount)" placement="bottom"> - <span aria-hidden="true">{{ formatHumanReadableNumber(status.favouritesCount) }}</span> - <span sr-only>{{ formatNumber(status.favouritesCount) }}</span> - </CommonTooltip> - <span v-else>{{ formatHumanReadableNumber(status.favouritesCount) }}</span> - </i18n-t> + <CommonLocalizedNumber + keypath="action.favourite_count" + :count="status.favouritesCount" + /> </template> </StatusActionButton> </div> diff --git a/components/status/StatusPoll.vue b/components/status/StatusPoll.vue index dd82092e..8f2c745d 100644 --- a/components/status/StatusPoll.vue +++ b/components/status/StatusPoll.vue @@ -13,7 +13,7 @@ function toPercentage(num: number) { const timeAgoOptions = useTimeAgoOptions() const expiredTimeAgo = useTimeAgo(poll.expiresAt!, timeAgoOptions) const expiredTimeFormatted = useFormattedDateTime(poll.expiresAt!) -const { formatHumanReadableNumber, formatNumber, formatPercentage, forSR } = useHumanReadableNumber() +const { formatPercentage } = useHumanReadableNumber() const masto = useMasto() async function vote(e: Event) { @@ -34,9 +34,6 @@ async function vote(e: Event) { } const votersCount = $computed(() => poll.votersCount ?? 0) -const votersCountHR = $computed(() => formatHumanReadableNumber(votersCount)) -const votersCountNumber = $computed(() => formatNumber(votersCount)) -const votersCountSR = $computed(() => forSR(votersCount)) </script> <template> @@ -65,13 +62,10 @@ const votersCountSR = $computed(() => forSR(votersCount)) </div> </template> <div text-sm flex="~ inline" gap-x-1> - <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> + <CommonLocalizedNumber + keypath="status.poll.count" + :count="poll.votesCount" + /> · <CommonTooltip :content="expiredTimeFormatted" class="inline-block" placement="right"> <time :datetime="poll.expiresAt!">{{ $t(poll.expired ? 'status.poll.finished' : 'status.poll.ends', [expiredTimeAgo]) }}</time> diff --git a/locales/ar-EG.json b/locales/ar-EG.json index bdcb0b22..7d74fb78 100644 --- a/locales/ar-EG.json +++ b/locales/ar-EG.json @@ -154,7 +154,7 @@ "notification": { "favourited_post": "أُعجِب بمنشورك", "followed_you": "بدأ في متابعتك", - "followed_you_count": "لم يتبعك أحد|تبعك شخص واحد|تبعك شخصان|تبعك {followers} أشخاص|تبعك {followers} شخص| تبعك {followers} شخص", + "followed_you_count": "لم يتبعك أحد|تبعك شخص واحد|تبعك شخصان|تبعك {0} أشخاص|تبعك {0} شخص| تبعك {0} شخص", "missing_type": "MISSING notification.type:", "reblogged_post": "اعاد نشر منشورك", "request_to_follow": "طلب(ت) متابعتك", diff --git a/locales/en-GB.json b/locales/en-GB.json index 8589be68..e094cbf3 100644 --- a/locales/en-GB.json +++ b/locales/en-GB.json @@ -162,7 +162,7 @@ "notification": { "favourited_post": "favourited your post", "followed_you": "followed you", - "followed_you_count": "{followers} people followed you|{followers} person followed you|{followers} people followed you", + "followed_you_count": "{0} people followed you|{0} person followed you|{0} people followed you", "missing_type": "MISSING notification.type:", "reblogged_post": "reblogged your post", "request_to_follow": "requested to follow you", diff --git a/locales/en-US.json b/locales/en-US.json index e5d77b50..3eafa650 100644 --- a/locales/en-US.json +++ b/locales/en-US.json @@ -187,7 +187,7 @@ "notification": { "favourited_post": "favorited your post", "followed_you": "followed you", - "followed_you_count": "{followers} people followed you|{followers} person followed you|{followers} people followed you", + "followed_you_count": "{0} people followed you|{0} person followed you|{0} people followed you", "missing_type": "MISSING notification.type:", "reblogged_post": "reblogged your post", "request_to_follow": "requested to follow you", diff --git a/locales/es-ES.json b/locales/es-ES.json index 55cc9b00..b8ceb713 100644 --- a/locales/es-ES.json +++ b/locales/es-ES.json @@ -187,7 +187,7 @@ "notification": { "favourited_post": "marcó tu publicación como favorito", "followed_you": "te ha seguido", - "followed_you_count": "{followers} personas te siguieron|{followers} persona te siguió|{followers} personas te siguieron", + "followed_you_count": "{0} personas te siguieron|{0} persona te siguió|{0} personas te siguieron", "missing_type": "MISSING notification.type:", "reblogged_post": "retooteó tu publicación", "request_to_follow": "ha solicitado seguirte", diff --git a/locales/fr-FR.json b/locales/fr-FR.json index cdfaabe4..4bc0bf71 100644 --- a/locales/fr-FR.json +++ b/locales/fr-FR.json @@ -166,7 +166,7 @@ "notification": { "favourited_post": "aime votre message", "followed_you": "vous suit", - "followed_you_count": "{followers} personnes vous suivent|{followers} personne vous suit|{followers} personnes vous suivent", + "followed_you_count": "{0} personnes vous suivent|{0} personne vous suit|{0} personnes vous suivent", "missing_type": "MISSING notification.type:", "reblogged_post": "a relayé votre message", "request_to_follow": "vous demande de le suivre", diff --git a/locales/nl-NL.json b/locales/nl-NL.json index 98813c8c..b85ba328 100644 --- a/locales/nl-NL.json +++ b/locales/nl-NL.json @@ -166,7 +166,7 @@ "notification": { "favourited_post": "vindt jou post favoriet", "followed_you": "volgt jou", - "followed_you_count": "{followers} mensen hebben je gevolgd|{followers} persoon heeft je gevold|{followers} mensen hebben je gevolgd", + "followed_you_count": "{0} mensen hebben je gevolgd|{0} persoon heeft je gevold|{0} mensen hebben je gevolgd", "missing_type": "MISSEND notificatie.type:", "reblogged_post": "herblogd je post", "request_to_follow": "vraagt om jou te volgen", diff --git a/locales/uk-UA.json b/locales/uk-UA.json index 77ea7221..6e6a0239 100644 --- a/locales/uk-UA.json +++ b/locales/uk-UA.json @@ -184,7 +184,7 @@ "notification": { "favourited_post": "додали ваший допис до вибраного", "followed_you": "підписались на вас", - "followed_you_count": "{followers} людей підписалися на вас|{followers} людина підписалися на вас|{followers} людини підписалися на вас|{followers} людей підписалися на вас", + "followed_you_count": "{0} людей підписалися на вас|{0} людина підписалися на вас|{0} людини підписалися на вас|{0} людей підписалися на вас", "missing_type": "ВІДСУТНІЙ notification.type:", "reblogged_post": "поширили ваш допис", "request_to_follow": "попросили підписатися на вас",