fix: #4568 & i18n on user page (#4572)

* fix: #4568

* fix: lint
This commit is contained in:
Calum H.
2025-10-20 01:23:06 +01:00
committed by GitHub
parent ad3b5aec69
commit 0e17427a58
2 changed files with 160 additions and 45 deletions

View File

@@ -1112,6 +1112,12 @@
"moderation.technical.search.placeholder": { "moderation.technical.search.placeholder": {
"message": "Search tech reviews..." "message": "Search tech reviews..."
}, },
"profile.bio.fallback.creator": {
"message": "A Modrinth creator."
},
"profile.bio.fallback.user": {
"message": "A Modrinth user."
},
"profile.button.billing": { "profile.button.billing": {
"message": "Manage user billing" "message": "Manage user billing"
}, },
@@ -1124,18 +1130,48 @@
"profile.button.manage-projects": { "profile.button.manage-projects": {
"message": "Manage projects" "message": "Manage projects"
}, },
"profile.details.label.auth-providers": {
"message": "Auth providers"
},
"profile.details.label.email": {
"message": "Email"
},
"profile.details.label.has-password": {
"message": "Has password"
},
"profile.details.label.has-totp": {
"message": "Has TOTP"
},
"profile.details.label.payment-methods": {
"message": "Payment methods"
},
"profile.details.tooltip.email-not-verified": {
"message": "Email not verified"
},
"profile.details.tooltip.email-verified": {
"message": "Email verified"
},
"profile.error.not-found": { "profile.error.not-found": {
"message": "User not found" "message": "User not found"
}, },
"profile.joined-at": {
"message": "Joined <date>{ago}</date>"
},
"profile.label.badges": { "profile.label.badges": {
"message": "Badges" "message": "Badges"
}, },
"profile.label.collection": {
"message": "Collection"
},
"profile.label.details": { "profile.label.details": {
"message": "Details" "message": "Details"
}, },
"profile.label.downloads": {
"message": "{count} {count, plural, one {download} other {downloads}}"
},
"profile.label.joined": {
"message": "Joined"
},
"profile.label.no": {
"message": "No"
},
"profile.label.no-collections": { "profile.label.no-collections": {
"message": "This user has no collections!" "message": "This user has no collections!"
}, },
@@ -1151,18 +1187,21 @@
"profile.label.organizations": { "profile.label.organizations": {
"message": "Organizations" "message": "Organizations"
}, },
"profile.label.projects": {
"message": "{count} {count, plural, one {project} other {projects}}"
},
"profile.label.saving": {
"message": "Saving..."
},
"profile.label.yes": {
"message": "Yes"
},
"profile.meta.description": { "profile.meta.description": {
"message": "Download {username}'s projects on Modrinth" "message": "Download {username}'s projects on Modrinth"
}, },
"profile.meta.description-with-bio": { "profile.meta.description-with-bio": {
"message": "{bio} - Download {username}'s projects on Modrinth" "message": "{bio} - Download {username}'s projects on Modrinth"
}, },
"profile.stats.downloads": {
"message": "{count, plural, one {<stat>{count}</stat> project download} other {<stat>{count}</stat> project downloads}}"
},
"profile.stats.projects": {
"message": "{count, plural, one {<stat>{count}</stat> project} other {<stat>{count}</stat> projects}}"
},
"profile.stats.projects-followers": { "profile.stats.projects-followers": {
"message": "{count, plural, one {<stat>{count}</stat> project follower} other {<stat>{count}</stat> project followers}}" "message": "{count, plural, one {<stat>{count}</stat> project follower} other {<stat>{count}</stat> project followers}}"
}, },

View File

@@ -16,7 +16,7 @@
<ButtonStyled> <ButtonStyled>
<button @click="cancelRoleEdit"> <button @click="cancelRoleEdit">
<XIcon /> <XIcon />
Cancel {{ formatMessage(commonMessages.cancelButton) }}
</button> </button>
</ButtonStyled> </ButtonStyled>
<ButtonStyled color="brand"> <ButtonStyled color="brand">
@@ -25,9 +25,11 @@
@click="saveRoleEdit" @click="saveRoleEdit"
> >
<template v-if="isSavingRole"> <template v-if="isSavingRole">
<SpinnerIcon class="animate-spin" /> Saving... <SpinnerIcon class="animate-spin" /> {{ formatMessage(messages.savingLabel) }}
</template>
<template v-else>
<SaveIcon /> {{ formatMessage(commonMessages.saveChangesButton) }}
</template> </template>
<template v-else> <SaveIcon /> Save changes </template>
</button> </button>
</ButtonStyled> </ButtonStyled>
</div> </div>
@@ -36,10 +38,16 @@
<NewModal v-if="auth.user && isStaff(auth.user)" ref="userDetailsModal" header="User details"> <NewModal v-if="auth.user && isStaff(auth.user)" ref="userDetailsModal" header="User details">
<div class="flex flex-col gap-3"> <div class="flex flex-col gap-3">
<div class="flex flex-col gap-1"> <div class="flex flex-col gap-1">
<span class="text-lg font-bold text-primary">Email</span> <span class="text-lg font-bold text-primary">{{
formatMessage(messages.emailLabel)
}}</span>
<div> <div>
<span <span
v-tooltip="user.email_verified ? 'Email verified' : 'Email not verified'" v-tooltip="
user.email_verified
? formatMessage(messages.emailVerifiedTooltip)
: formatMessage(messages.emailNotVerifiedTooltip)
"
class="flex w-fit items-center gap-1" class="flex w-fit items-center gap-1"
> >
<span>{{ user.email }}</span> <span>{{ user.email }}</span>
@@ -50,12 +58,16 @@
</div> </div>
<div class="flex flex-col gap-1"> <div class="flex flex-col gap-1">
<span class="text-lg font-bold text-primary"> Auth providers </span> <span class="text-lg font-bold text-primary">{{
formatMessage(messages.authProvidersLabel)
}}</span>
<span>{{ user.auth_providers.join(', ') }}</span> <span>{{ user.auth_providers.join(', ') }}</span>
</div> </div>
<div class="flex flex-col gap-1"> <div class="flex flex-col gap-1">
<span class="text-lg font-bold text-primary"> Payment methods</span> <span class="text-lg font-bold text-primary">{{
formatMessage(messages.paymentMethodsLabel)
}}</span>
<span> <span>
<template v-if="user.payout_data?.paypal_address"> <template v-if="user.payout_data?.paypal_address">
Paypal ({{ user.payout_data.paypal_address }} - {{ user.payout_data.paypal_country }}) Paypal ({{ user.payout_data.paypal_address }} - {{ user.payout_data.paypal_country }})
@@ -70,16 +82,22 @@
</div> </div>
<div class="flex flex-col gap-1"> <div class="flex flex-col gap-1">
<span class="text-lg font-bold text-primary"> Has password </span> <span class="text-lg font-bold text-primary">{{
formatMessage(messages.hasPasswordLabel)
}}</span>
<span> <span>
{{ user.has_password ? 'Yes' : 'No' }} {{
user.has_password ? formatMessage(messages.yesLabel) : formatMessage(messages.noLabel)
}}
</span> </span>
</div> </div>
<div class="flex flex-col gap-1"> <div class="flex flex-col gap-1">
<span class="text-lg font-bold text-primary"> Has TOTP </span> <span class="text-lg font-bold text-primary">{{
formatMessage(messages.hasTotpLabel)
}}</span>
<span> <span>
{{ user.has_totp ? 'Yes' : 'No' }} {{ user.has_totp ? formatMessage(messages.yesLabel) : formatMessage(messages.noLabel) }}
</span> </span>
</div> </div>
</div> </div>
@@ -98,8 +116,8 @@
user.bio user.bio
? user.bio ? user.bio
: projects.length === 0 : projects.length === 0
? 'A Modrinth user.' ? formatMessage(messages.bioFallbackUser)
: 'A Modrinth creator.' : formatMessage(messages.bioFallbackCreator)
}} }}
</template> </template>
<template #stats> <template #stats>
@@ -107,16 +125,22 @@
class="flex items-center gap-2 border-0 border-r border-solid border-divider pr-4 font-semibold" class="flex items-center gap-2 border-0 border-r border-solid border-divider pr-4 font-semibold"
> >
<BoxIcon class="h-6 w-6 text-secondary" /> <BoxIcon class="h-6 w-6 text-secondary" />
{{ formatCompactNumber(projects?.length || 0) }} {{
projects formatMessage(messages.profileProjectsLabel, {
count: formatCompactNumber(projects?.length || 0),
})
}}
</div> </div>
<div <div
v-tooltip="sumDownloads.toLocaleString()" v-tooltip="sumDownloads.toLocaleString()"
class="flex items-center gap-2 border-0 border-r border-solid border-divider pr-4 font-semibold" class="flex items-center gap-2 border-0 border-r border-solid border-divider pr-4 font-semibold"
> >
<DownloadIcon class="h-6 w-6 text-secondary" /> <DownloadIcon class="h-6 w-6 text-secondary" />
{{ formatCompactNumber(sumDownloads) }} {{
downloads formatMessage(messages.profileDownloadsLabel, {
count: formatCompactNumber(sumDownloads),
})
}}
</div> </div>
<div <div
v-tooltip=" v-tooltip="
@@ -128,7 +152,7 @@
class="flex items-center gap-2 font-semibold" class="flex items-center gap-2 font-semibold"
> >
<CalendarIcon class="h-6 w-6 text-secondary" /> <CalendarIcon class="h-6 w-6 text-secondary" />
Joined {{ formatMessage(messages.profileJoinedLabel) }}
{{ formatRelativeTime(user.created) }} {{ formatRelativeTime(user.created) }}
</div> </div>
</template> </template>
@@ -287,7 +311,7 @@
<h2 class="title">{{ collection.name }}</h2> <h2 class="title">{{ collection.name }}</h2>
<div class="stats"> <div class="stats">
<LibraryIcon aria-hidden="true" /> <LibraryIcon aria-hidden="true" />
Collection {{ formatMessage(messages.collectionLabel) }}
</div> </div>
</div> </div>
</div> </div>
@@ -298,25 +322,27 @@
<div class="stats"> <div class="stats">
<BoxIcon /> <BoxIcon />
{{ {{
`${$formatNumber(collection.projects?.length || 0, false)} project${(collection.projects?.length || 0) !== 1 ? 's' : ''}` `${$formatNumber(collection.projects?.length || 0, false)} project${
(collection.projects?.length || 0) !== 1 ? 's' : ''
}`
}} }}
</div> </div>
<div class="stats"> <div class="stats">
<template v-if="collection.status === 'listed'"> <template v-if="collection.status === 'listed'">
<GlobeIcon /> <GlobeIcon />
<span> Public </span> <span> {{ formatMessage(commonMessages.publicLabel) }} </span>
</template> </template>
<template v-else-if="collection.status === 'unlisted'"> <template v-else-if="collection.status === 'unlisted'">
<LinkIcon /> <LinkIcon />
<span> Unlisted </span> <span> {{ formatMessage(commonMessages.unlistedLabel) }} </span>
</template> </template>
<template v-else-if="collection.status === 'private'"> <template v-else-if="collection.status === 'private'">
<LockIcon /> <LockIcon />
<span> Private </span> <span> {{ formatMessage(commonMessages.privateLabel) }} </span>
</template> </template>
<template v-else-if="collection.status === 'rejected'"> <template v-else-if="collection.status === 'rejected'">
<XIcon /> <XIcon />
<span> Rejected </span> <span> {{ formatMessage(commonMessages.rejectedLabel) }} </span>
</template> </template>
</div> </div>
</div> </div>
@@ -450,25 +476,75 @@ const formatRelativeTime = useRelativeTime()
const { addNotification } = injectNotificationManager() const { addNotification } = injectNotificationManager()
const messages = defineMessages({ const messages = defineMessages({
profileProjectsStats: { profileProjectsLabel: {
id: 'profile.stats.projects', id: 'profile.label.projects',
defaultMessage: defaultMessage: '{count} {count, plural, one {project} other {projects}}',
'{count, plural, one {<stat>{count}</stat> project} other {<stat>{count}</stat> projects}}',
}, },
profileDownloadsStats: { profileDownloadsLabel: {
id: 'profile.stats.downloads', id: 'profile.label.downloads',
defaultMessage: defaultMessage: '{count} {count, plural, one {download} other {downloads}}',
'{count, plural, one {<stat>{count}</stat> project download} other {<stat>{count}</stat> project downloads}}', },
profileJoinedLabel: {
id: 'profile.label.joined',
defaultMessage: 'Joined',
},
savingLabel: {
id: 'profile.label.saving',
defaultMessage: 'Saving...',
},
emailLabel: {
id: 'profile.details.label.email',
defaultMessage: 'Email',
},
emailVerifiedTooltip: {
id: 'profile.details.tooltip.email-verified',
defaultMessage: 'Email verified',
},
emailNotVerifiedTooltip: {
id: 'profile.details.tooltip.email-not-verified',
defaultMessage: 'Email not verified',
},
authProvidersLabel: {
id: 'profile.details.label.auth-providers',
defaultMessage: 'Auth providers',
},
paymentMethodsLabel: {
id: 'profile.details.label.payment-methods',
defaultMessage: 'Payment methods',
},
hasPasswordLabel: {
id: 'profile.details.label.has-password',
defaultMessage: 'Has password',
},
hasTotpLabel: {
id: 'profile.details.label.has-totp',
defaultMessage: 'Has TOTP',
},
yesLabel: {
id: 'profile.label.yes',
defaultMessage: 'Yes',
},
noLabel: {
id: 'profile.label.no',
defaultMessage: 'No',
},
bioFallbackUser: {
id: 'profile.bio.fallback.user',
defaultMessage: 'A Modrinth user.',
},
bioFallbackCreator: {
id: 'profile.bio.fallback.creator',
defaultMessage: 'A Modrinth creator.',
},
collectionLabel: {
id: 'profile.label.collection',
defaultMessage: 'Collection',
}, },
profileProjectsFollowersStats: { profileProjectsFollowersStats: {
id: 'profile.stats.projects-followers', id: 'profile.stats.projects-followers',
defaultMessage: defaultMessage:
'{count, plural, one {<stat>{count}</stat> project follower} other {<stat>{count}</stat> project followers}}', '{count, plural, one {<stat>{count}</stat> project follower} other {<stat>{count}</stat> project followers}}',
}, },
profileJoinedAt: {
id: 'profile.joined-at',
defaultMessage: 'Joined <date>{ago}</date>',
},
profileUserId: { profileUserId: {
id: 'profile.user-id', id: 'profile.user-id',
defaultMessage: 'User ID: {id}', defaultMessage: 'User ID: {id}',