mirror of
https://github.com/modrinth/code.git
synced 2026-08-26 17:44:50 +00:00
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:
co-authored by
Calum H.
Calum H.
parent
9b2f0c88cd
commit
f62c60a681
@@ -1,12 +1,11 @@
|
||||
<script setup lang="ts">
|
||||
import { SpinnerIcon } from '@modrinth/assets'
|
||||
import { formatPrice } from '@modrinth/utils'
|
||||
import { computed } from 'vue'
|
||||
|
||||
import { useVIntl } from '../../composables/i18n'
|
||||
import { useFormatPrice } from '../../composables'
|
||||
import Accordion from '../base/Accordion.vue'
|
||||
|
||||
const { locale } = useVIntl()
|
||||
const formatPrice = useFormatPrice()
|
||||
|
||||
export type BillingItem = {
|
||||
title: string
|
||||
@@ -38,7 +37,7 @@ const periodSuffix = computed(() => {
|
||||
<template v-if="loading">
|
||||
<SpinnerIcon class="animate-spin size-4" />
|
||||
</template>
|
||||
<template v-else> {{ formatPrice(locale, total, currency) }} </template
|
||||
<template v-else> {{ formatPrice(total, currency) }} </template
|
||||
><span class="text-xs text-secondary">{{ periodSuffix }}</span>
|
||||
</span>
|
||||
</div>
|
||||
@@ -57,7 +56,7 @@ const periodSuffix = computed(() => {
|
||||
<template v-if="loading">
|
||||
<SpinnerIcon class="animate-spin size-4" />
|
||||
</template>
|
||||
<template v-else> {{ formatPrice(locale, amount, currency) }} </template
|
||||
<template v-else> {{ formatPrice(amount, currency) }} </template
|
||||
><span class="text-xs text-secondary">{{ periodSuffix }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<script setup lang="ts">
|
||||
import type { Labrinth } from '@modrinth/api-client'
|
||||
import { InfoIcon } from '@modrinth/assets'
|
||||
import { formatPrice } from '@modrinth/utils'
|
||||
import { Menu } from 'floating-vue'
|
||||
import { computed, inject, type Ref } from 'vue'
|
||||
|
||||
import { useFormatPrice } from '../../composables'
|
||||
import { type MessageDescriptor, useVIntl } from '../../composables/i18n'
|
||||
import { getPriceForInterval, monthsInInterval } from '../../utils/product-utils'
|
||||
import type { ServerBillingInterval } from './ModrinthServersPurchaseModal.vue'
|
||||
@@ -30,7 +30,8 @@ const emit = defineEmits<{
|
||||
(e: 'select', plan: Labrinth.Billing.Internal.Product): void
|
||||
}>()
|
||||
|
||||
const { formatMessage, locale } = useVIntl()
|
||||
const { formatMessage } = useVIntl()
|
||||
const formatPrice = useFormatPrice()
|
||||
|
||||
// TODO: Use DI framework when merged.
|
||||
const selectedInterval = inject<Ref<ServerBillingInterval>>('selectedInterval')
|
||||
@@ -101,7 +102,7 @@ const mostPopularStyle = computed(() => {
|
||||
</div>
|
||||
</div>
|
||||
<span class="m-0 text-lg font-bold text-contrast">
|
||||
{{ formatPrice(locale, perMonth, currency, true) }}
|
||||
{{ formatPrice(perMonth, currency, true) }}
|
||||
<span class="text-sm font-semibold text-secondary">
|
||||
/ month{{ selectedInterval !== 'monthly' ? `, billed ${selectedInterval}` : '' }}
|
||||
</span>
|
||||
|
||||
@@ -232,7 +232,7 @@
|
||||
}}%
|
||||
</span>
|
||||
<span class="ml-auto text-lg" :class="{ 'text-secondary': selectedPlan !== interval }">
|
||||
{{ formatPrice(locale, rawPrice, price.currency_code) }}
|
||||
{{ formatPrice(rawPrice, price.currency_code) }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -240,7 +240,7 @@
|
||||
<span class="text-xl text-secondary">Total</span>
|
||||
<div class="flex items-baseline gap-2">
|
||||
<span class="text-2xl font-extrabold text-primary">
|
||||
{{ formatPrice(locale, price.prices.intervals[selectedPlan], price.currency_code) }}
|
||||
{{ formatPrice(price.prices.intervals[selectedPlan], price.currency_code) }}
|
||||
</span>
|
||||
<span class="text-lg text-secondary">/ {{ selectedPlan }}</span>
|
||||
</div>
|
||||
@@ -304,23 +304,21 @@
|
||||
}}
|
||||
</span>
|
||||
<span v-if="existingPlan" class="text-secondary text-end">
|
||||
{{ formatPrice(locale, total - tax, price.currency_code) }}
|
||||
{{ formatPrice(total - tax, price.currency_code) }}
|
||||
</span>
|
||||
<span v-else class="text-secondary text-end">
|
||||
{{ formatPrice(locale, total - tax, price.currency_code) }} /
|
||||
{{ formatPrice(total - tax, price.currency_code) }} /
|
||||
{{ selectedPlan }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<span class="text-secondary">Tax</span>
|
||||
<span class="text-secondary text-end">{{
|
||||
formatPrice(locale, tax, price.currency_code)
|
||||
}}</span>
|
||||
<span class="text-secondary text-end">{{ formatPrice(tax, price.currency_code) }}</span>
|
||||
</div>
|
||||
<div class="mt-4 flex justify-between border-0 border-t border-solid border-code-bg pt-4">
|
||||
<span class="text-lg font-bold">Today's total</span>
|
||||
<span class="text-lg font-extrabold text-primary text-end">
|
||||
{{ formatPrice(locale, total, price.currency_code) }}
|
||||
{{ formatPrice(total, price.currency_code) }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -416,9 +414,9 @@
|
||||
<strong>By clicking "Subscribe", you are purchasing a recurring subscription.</strong>
|
||||
<br />
|
||||
You'll be charged
|
||||
{{ formatPrice(locale, price.prices.intervals[selectedPlan], price.currency_code) }}
|
||||
{{ formatPrice(price.prices.intervals[selectedPlan], price.currency_code) }}
|
||||
/ {{ selectedPlan }} plus applicable taxes starting
|
||||
{{ existingPlan ? dayjs(renewalDate).format('MMMM D, YYYY') : 'today' }}, until you cancel.
|
||||
{{ existingPlan ? formatDate(renewalDate) : 'today' }}, until you cancel.
|
||||
<br />
|
||||
You can cancel anytime from your settings page.
|
||||
</p>
|
||||
@@ -545,12 +543,13 @@ import {
|
||||
UnknownIcon,
|
||||
XIcon,
|
||||
} from '@modrinth/assets'
|
||||
import { calculateSavings, createStripeElements, formatPrice, getCurrency } from '@modrinth/utils'
|
||||
import { calculateSavings, createStripeElements, getCurrency } from '@modrinth/utils'
|
||||
import dayjs from 'dayjs'
|
||||
import { computed, nextTick, reactive, ref, watch } from 'vue'
|
||||
import { Multiselect } from 'vue-multiselect'
|
||||
|
||||
import { useVIntl } from '../../composables/i18n'
|
||||
import { useFormatDateTime, useFormatPrice } from '../../composables/index.ts'
|
||||
import { paymentMethodMessages } from '../../utils/common-messages'
|
||||
import Admonition from '../base/Admonition.vue'
|
||||
import Checkbox from '../base/Checkbox.vue'
|
||||
@@ -560,7 +559,9 @@ import AnimatedLogo from '../brand/AnimatedLogo.vue'
|
||||
import NewModal from '../modal/NewModal.vue'
|
||||
import LoaderIcon from '../servers/icons/LoaderIcon.vue'
|
||||
|
||||
const { locale, formatMessage } = useVIntl()
|
||||
const { formatMessage } = useVIntl()
|
||||
const formatPrice = useFormatPrice()
|
||||
const formatDate = useFormatDateTime({ dateStyle: 'long' })
|
||||
|
||||
const props = defineProps({
|
||||
product: {
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
<script setup lang="ts">
|
||||
import type { Labrinth } from '@modrinth/api-client'
|
||||
import { formatPrice } from '@modrinth/utils'
|
||||
import { computed, provide } from 'vue'
|
||||
|
||||
import { useFormatPrice } from '../../composables'
|
||||
import { defineMessages, useVIntl } from '../../composables/i18n'
|
||||
import { getPriceForInterval, monthsInInterval } from '../../utils/product-utils'
|
||||
import OptionGroup from '../base/OptionGroup.vue'
|
||||
import ModalBasedServerPlan from './ModalBasedServerPlan.vue'
|
||||
import type { ServerBillingInterval } from './ModrinthServersPurchaseModal.vue'
|
||||
|
||||
const { formatMessage, locale } = useVIntl()
|
||||
const { formatMessage } = useVIntl()
|
||||
const formatPrice = useFormatPrice()
|
||||
|
||||
const props = defineProps<{
|
||||
availableProducts: Labrinth.Billing.Internal.Product[]
|
||||
@@ -209,7 +210,7 @@ provide('selectedInterval', selectedInterval)
|
||||
<span class="text-2xl font-semibold text-contrast">Custom</span>
|
||||
</div>
|
||||
<span class="m-0 text-lg font-bold text-contrast">
|
||||
{{ formatPrice(locale, customStartingPrice, currency, true) }}
|
||||
{{ formatPrice(customStartingPrice, currency, true) }}
|
||||
<span class="text-sm font-semibold text-secondary">
|
||||
/ month<template v-if="selectedInterval !== 'monthly'"
|
||||
>, billed {{ selectedInterval }}</template
|
||||
@@ -221,7 +222,7 @@ provide('selectedInterval', selectedInterval)
|
||||
<div class="flex flex-col gap-2">
|
||||
<div class="flex items-center gap-3">
|
||||
<span v-if="customPricePerGb" class="text-sm text-secondary">
|
||||
From {{ formatPrice(locale, customPricePerGb, currency, true) }} / GB
|
||||
From {{ formatPrice(customPricePerGb, currency, true) }} / GB
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -3,7 +3,7 @@ import type { Archon, Labrinth } from '@modrinth/api-client'
|
||||
import { InfoIcon, SpinnerIcon, XIcon } from '@modrinth/assets'
|
||||
import { computed, onMounted, ref, watch } from 'vue'
|
||||
|
||||
import { formatPrice } from '../../../../utils'
|
||||
import { useFormatPrice } from '../../composables'
|
||||
import { defineMessages, useVIntl } from '../../composables/i18n'
|
||||
import { getPriceForInterval, monthsInInterval } from '../../utils/product-utils.ts'
|
||||
import { regionOverrides } from '../../utils/regions.ts'
|
||||
@@ -14,7 +14,8 @@ import type { RegionPing, ServerBillingInterval } from './ModrinthServersPurchas
|
||||
import ServersRegionButton from './ServersRegionButton.vue'
|
||||
import ServersSpecs from './ServersSpecs.vue'
|
||||
|
||||
const { formatMessage, locale } = useVIntl()
|
||||
const { formatMessage } = useVIntl()
|
||||
const formatPrice = useFormatPrice()
|
||||
|
||||
const props = defineProps<{
|
||||
regions: Archon.Servers.v1.Region[]
|
||||
@@ -283,7 +284,7 @@ onMounted(() => {
|
||||
<Slider v-model="selectedRam" :min="minRam" :max="maxRam" :step="2" unit="GB" />
|
||||
<p v-if="selectedPrice" class="mt-2 mb-0">
|
||||
<span class="text-contrast text-lg font-bold"
|
||||
>{{ formatPrice(locale, selectedPrice, currency, true) }} / month</span
|
||||
>{{ formatPrice(selectedPrice, currency, true) }} / month</span
|
||||
><span v-if="interval !== 'monthly'">, billed {{ interval }}</span>
|
||||
</p>
|
||||
<div class="bg-bg rounded-xl p-4 mt-2 text-secondary h-14">
|
||||
|
||||
@@ -10,11 +10,12 @@ import {
|
||||
SpinnerIcon,
|
||||
XIcon,
|
||||
} from '@modrinth/assets'
|
||||
import { formatPrice, getPingLevel } from '@modrinth/utils'
|
||||
import { getPingLevel } from '@modrinth/utils'
|
||||
import dayjs from 'dayjs'
|
||||
import type Stripe from 'stripe'
|
||||
import { computed } from 'vue'
|
||||
|
||||
import { useFormatPrice } from '../../composables'
|
||||
import { useVIntl } from '../../composables/i18n'
|
||||
import { getPriceForInterval, monthsInInterval } from '../../utils/product-utils'
|
||||
import { regionOverrides } from '../../utils/regions'
|
||||
@@ -27,8 +28,8 @@ import FormattedPaymentMethod from './FormattedPaymentMethod.vue'
|
||||
import type { ServerBillingInterval } from './ModrinthServersPurchaseModal.vue'
|
||||
import ServersSpecs from './ServersSpecs.vue'
|
||||
|
||||
const vintl = useVIntl()
|
||||
const { locale, formatMessage } = vintl
|
||||
const { formatMessage } = useVIntl()
|
||||
const formatPrice = useFormatPrice()
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'changePaymentMethod' | 'reloadPaymentIntent'): void
|
||||
@@ -246,7 +247,7 @@ function setInterval(newInterval: ServerBillingInterval) {
|
||||
>Pay monthly</span
|
||||
>
|
||||
<span class="text-sm text-secondary flex items-center gap-1"
|
||||
>{{ formatPrice(locale, monthlyPrice, currency, true) }} / month</span
|
||||
>{{ formatPrice(monthlyPrice, currency, true) }} / month</span
|
||||
>
|
||||
</div>
|
||||
</button>
|
||||
@@ -268,17 +269,10 @@ function setInterval(newInterval: ServerBillingInterval) {
|
||||
>{{ interval === 'quarterly' ? 'Saving' : 'Save' }} 16%</span
|
||||
></span
|
||||
>
|
||||
<span class="text-sm text-secondary flex items-center gap-1"
|
||||
>{{
|
||||
formatPrice(
|
||||
locale,
|
||||
(quarterlyPrice ?? 0) / monthsInInterval['quarterly'],
|
||||
currency,
|
||||
true,
|
||||
)
|
||||
}}
|
||||
/ month</span
|
||||
>
|
||||
<span class="text-sm text-secondary flex items-center gap-1">
|
||||
{{ formatPrice((quarterlyPrice ?? 0) / monthsInInterval['quarterly'], currency, true) }} /
|
||||
month
|
||||
</span>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
@@ -346,14 +340,14 @@ function setInterval(newInterval: ServerBillingInterval) {
|
||||
Today, you will be charged a prorated amount for the remainder of your current billing cycle.
|
||||
<br />
|
||||
Your subscription will renew at
|
||||
{{ formatPrice(locale, selectedPlanPriceForInterval, currency) }} / {{ period }} plus
|
||||
applicable taxes at the end of your current billing interval, until you cancel. You can cancel
|
||||
anytime from your settings page.
|
||||
{{ formatPrice(selectedPlanPriceForInterval, currency) }} / {{ period }} plus applicable taxes
|
||||
at the end of your current billing interval, until you cancel. You can cancel anytime from
|
||||
your settings page.
|
||||
</template>
|
||||
<template v-else>
|
||||
You'll be charged
|
||||
<SpinnerIcon v-if="loading" class="animate-spin relative top-0.5 mx-2" /><template v-else>{{
|
||||
formatPrice(locale, total, currency)
|
||||
formatPrice(total, currency)
|
||||
}}</template>
|
||||
every {{ period }} plus applicable taxes starting today, until you cancel. You can cancel
|
||||
anytime from your settings page.
|
||||
|
||||
Reference in New Issue
Block a user