Impove Intl formatting (#5372)

* Improve Intl formatting

* Additional fixes

* Fixed formatters were not updated on locale change

* Fixed formatNumber was not updated on locale change

* Additional formatting and fixes after merge

* Run prepr:frontend

* Remove `'` in icon map

* Run `pnpm install`

* fix: lint + import

* Additional fixes

---------

Co-authored-by: Calum H. <calum@modrinth.com>
Co-authored-by: Calum H. (IMB11) <contact@cal.engineer>
This commit is contained in:
Jerozgen
2026-03-10 00:29:32 +03:00
committed by GitHub
parent 9b2f0c88cd
commit f62c60a681
88 changed files with 839 additions and 621 deletions

View File

@@ -182,7 +182,7 @@
<div>
{{
formatMessage(messages.createdOn, {
date: new Date(app.created).toLocaleDateString(),
date: formatDate(new Date(app.created)),
})
}}
</div>
@@ -257,6 +257,7 @@ import {
IntlFormatted,
normalizeChildren,
StyledInput,
useFormatDateTime,
useVIntl,
} from '@modrinth/ui'
@@ -272,6 +273,7 @@ import {
const { addNotification } = injectNotificationManager()
const { formatMessage } = useVIntl()
const formatDate = useFormatDateTime()
definePageMeta({
middleware: 'auth',

View File

@@ -25,12 +25,12 @@
</template>
</span>
<span>{{ formatPrice(vintl.locale, charge.amount, charge.currency_code) }}</span>
<span>{{ formatPrice(charge.amount, charge.currency_code) }}</span>
</div>
<div class="flex items-center gap-1">
<Badge :color="charge.status === 'succeeded' ? 'green' : 'red'" :type="charge.status" />
{{ $dayjs(charge.due).format('YYYY-MM-DD') }}
{{ formatDate(charge.due) }}
</div>
</div>
</div>
@@ -38,8 +38,7 @@
</div>
</template>
<script setup>
import { Badge, Breadcrumbs, useVIntl } from '@modrinth/ui'
import { formatPrice } from '@modrinth/utils'
import { Badge, Breadcrumbs, useFormatDateTime, useFormatPrice } from '@modrinth/ui'
import { products } from '~/generated/state.json'
@@ -47,7 +46,12 @@ definePageMeta({
middleware: 'auth',
})
const vintl = useVIntl()
const formatPrice = useFormatPrice()
const formatDate = useFormatDateTime({
year: 'numeric',
month: '2-digit',
day: '2-digit',
})
const { data: charges } = await useAsyncData(
'billing/payments',

View File

@@ -51,7 +51,6 @@
<template v-if="midasCharge">
{{
formatPrice(
vintl.locale,
midasSubscriptionPrice.prices.intervals[midasSubscription.interval],
midasSubscriptionPrice.currency_code,
)
@@ -60,7 +59,7 @@
{{ midasSubscription.interval }}
</template>
<template v-else>
{{ formatPrice(vintl.locale, price.prices.intervals.monthly, price.currency_code) }}
{{ formatPrice(price.prices.intervals.monthly, price.currency_code) }}
/ month
</template>
</span>
@@ -77,7 +76,7 @@
>
<span class="opacity-70">Next:</span>
<span class="font-semibold text-contrast">
{{ formatPrice(vintl.locale, midasCharge.amount, midasCharge.currency_code) }}
{{ formatPrice(midasCharge.amount, midasCharge.currency_code) }}
</span>
<span>/{{ midasCharge.subscription_interval.replace('ly', '') }}</span>
</div>
@@ -90,21 +89,17 @@
>
Save
{{
formatPrice(
vintl.locale,
midasCharge.amount * 12 - oppositePrice,
midasCharge.currency_code,
)
formatPrice(midasCharge.amount * 12 - oppositePrice, midasCharge.currency_code)
}}/year by switching to yearly billing!
</span>
<span class="text-sm text-secondary">
Since {{ $dayjs(midasSubscription.created).format('MMMM D, YYYY') }}
Since {{ formatDate(midasSubscription.created) }}
</span>
<span v-if="midasCharge.status === 'open'" class="text-sm text-secondary">
Renews {{ $dayjs(midasCharge.due).format('MMMM D, YYYY') }}
Renews {{ formatDate(midasCharge.due) }}
</span>
<span v-else-if="midasCharge.status === 'cancelled'" class="text-sm text-secondary">
Expires {{ $dayjs(midasCharge.due).format('MMMM D, YYYY') }}
Expires {{ formatDate(midasCharge.due) }}
</span>
<span
v-if="
@@ -116,14 +111,13 @@
class="text-sm text-secondary"
>
Switches to {{ midasCharge.subscription_interval }} billing on
{{ $dayjs(midasCharge.due).format('MMMM D, YYYY') }}
{{ formatDate(midasCharge.due) }}
</span>
</template>
<span v-else class="text-sm text-secondary">
Or
{{ formatPrice(vintl.locale, price.prices.intervals.yearly, price.currency_code) }} /
year (save
{{ formatPrice(price.prices.intervals.yearly, price.currency_code) }} / year (save
{{
calculateSavings(price.prices.intervals.monthly, price.prices.intervals.yearly)
}}%)!
@@ -188,7 +182,6 @@
v-tooltip="
midasCharge.subscription_interval === 'yearly'
? `Monthly billing will cost you an additional ${formatPrice(
vintl.locale,
oppositePrice * 12 - midasCharge.amount,
midasCharge.currency_code,
)} per year`
@@ -307,7 +300,6 @@
<span class="text-contrast">
{{
formatPrice(
vintl.locale,
getProductPrice(getPyroProduct(subscription), subscription.interval)
.prices.intervals[subscription.interval],
getProductPrice(getPyroProduct(subscription), subscription.interval)
@@ -333,7 +325,6 @@
<span class="font-semibold text-contrast">
{{
formatPrice(
vintl.locale,
getPyroCharge(subscription).amount,
getPyroCharge(subscription).currency_code,
)
@@ -351,13 +342,13 @@
</div>
<div v-if="getPyroCharge(subscription)" class="mb-4 flex flex-col items-end">
<span class="text-sm text-secondary">
Since {{ $dayjs(subscription.created).format('MMMM D, YYYY') }}
Since {{ formatDate(subscription.created) }}
</span>
<span
v-if="getPyroCharge(subscription).status === 'open'"
class="text-sm text-secondary"
>
Renews {{ $dayjs(getPyroCharge(subscription).due).format('MMMM D, YYYY') }}
Renews {{ formatDate(getPyroCharge(subscription).due) }}
</span>
<span
v-if="
@@ -371,7 +362,7 @@
Switches to
{{ getPyroCharge(subscription).subscription_interval }}
billing on
{{ $dayjs(getPyroCharge(subscription).due).format('MMMM D, YYYY') }}
{{ formatDate(getPyroCharge(subscription).due) }}
</span>
<span
v-else-if="getPyroCharge(subscription).status === 'processing'"
@@ -384,7 +375,7 @@
v-else-if="getPyroCharge(subscription).status === 'cancelled'"
class="text-sm text-secondary"
>
Expires {{ $dayjs(getPyroCharge(subscription).due).format('MMMM D, YYYY') }}
Expires {{ formatDate(getPyroCharge(subscription).due) }}
</span>
<span
v-else-if="getPyroCharge(subscription).status === 'failed'"
@@ -624,9 +615,11 @@ import {
paymentMethodMessages,
PurchaseModal,
ServerListing,
useFormatDateTime,
useFormatPrice,
useVIntl,
} from '@modrinth/ui'
import { calculateSavings, formatPrice, getCurrency } from '@modrinth/utils'
import { calculateSavings, getCurrency } from '@modrinth/utils'
import { computed, ref } from 'vue'
import { useBaseFetch } from '@/composables/fetch.js'
@@ -655,8 +648,13 @@ useHead({
const config = useRuntimeConfig()
const vintl = useVIntl()
const { formatMessage } = vintl
const { formatMessage } = useVIntl()
const formatPrice = useFormatPrice()
const formatDate = useFormatDateTime({
year: 'numeric',
month: 'long',
day: 'numeric',
})
const deleteModalMessages = defineMessages({
title: {

View File

@@ -119,16 +119,7 @@
<CopyCode :text="pat.access_token" />
</template>
<template v-else>
<span
v-tooltip="
pat.last_used
? formatMessage(commonMessages.dateAtTimeTooltip, {
date: new Date(pat.last_used),
time: new Date(pat.last_used),
})
: null
"
>
<span v-tooltip="pat.last_used ? formatDateTime(pat.last_used) : null">
<template v-if="pat.last_used">
{{
formatMessage(tokenMessages.lastUsed, {
@@ -139,14 +130,7 @@
<template v-else>{{ formatMessage(tokenMessages.neverUsed) }}</template>
</span>
<span
v-tooltip="
formatMessage(commonMessages.dateAtTimeTooltip, {
date: new Date(pat.expires),
time: new Date(pat.expires),
})
"
>
<span v-tooltip="formatDateTime(pat.expires)">
<template v-if="new Date(pat.expires) > new Date()">
{{
formatMessage(tokenMessages.expiresIn, {
@@ -163,14 +147,7 @@
</template>
</span>
<span
v-tooltip="
formatMessage(commonMessages.dateAtTimeTooltip, {
date: new Date(pat.created),
time: new Date(pat.created),
})
"
>
<span v-tooltip="formatDateTime(pat.created)">
{{
formatMessage(commonMessages.createdAgoLabel, {
ago: formatRelativeTime(pat.created),
@@ -222,6 +199,7 @@ import {
injectNotificationManager,
IntlFormatted,
StyledInput,
useFormatDateTime,
useRelativeTime,
useVIntl,
} from '@modrinth/ui'
@@ -240,6 +218,10 @@ const { addNotification } = injectNotificationManager()
const { formatMessage } = useVIntl()
const formatRelativeTime = useRelativeTime()
const formatDateTime = useFormatDateTime({
timeStyle: 'short',
dateStyle: 'long',
})
const createModalMessages = defineMessages({
createTitle: {

View File

@@ -15,14 +15,7 @@
</div>
<div>
<template v-if="session.city">{{ session.city }}, {{ session.country }} </template>
<span
v-tooltip="
formatMessage(commonMessages.dateAtTimeTooltip, {
date: new Date(session.last_login),
time: new Date(session.last_login),
})
"
>
<span v-tooltip="formatDateTime(session.last_login)">
{{
formatMessage(messages.lastAccessedAgoLabel, {
ago: formatRelativeTime(session.last_login),
@@ -30,14 +23,7 @@
}}
</span>
<span
v-tooltip="
formatMessage(commonMessages.dateAtTimeTooltip, {
date: new Date(session.created),
time: new Date(session.created),
})
"
>
<span v-tooltip="formatDateTime(session.created)">
{{
formatMessage(messages.createdAgoLabel, {
ago: formatRelativeTime(session.created),
@@ -62,6 +48,7 @@ import {
commonSettingsMessages,
defineMessages,
injectNotificationManager,
useFormatDateTime,
useRelativeTime,
useVIntl,
} from '@modrinth/ui'
@@ -73,6 +60,10 @@ definePageMeta({
const { addNotification } = injectNotificationManager()
const { formatMessage } = useVIntl()
const formatRelativeTime = useRelativeTime()
const formatDateTime = useFormatDateTime({
timeStyle: 'short',
dateStyle: 'long',
})
const messages = defineMessages({
currentSessionLabel: {