translatable category headers (#5301)

This commit is contained in:
Prospector
2026-02-04 14:47:35 -08:00
committed by GitHub
parent 3f5e3b1d8b
commit ddb013e024
7 changed files with 58 additions and 14 deletions

View File

@@ -10,8 +10,13 @@ import {
TrashIcon, TrashIcon,
XIcon, XIcon,
} from '@modrinth/assets' } from '@modrinth/assets'
import { Button, DropdownSelect, injectNotificationManager } from '@modrinth/ui' import {
import { formatCategoryHeader } from '@modrinth/utils' Button,
DropdownSelect,
formatLoader,
injectNotificationManager,
useVIntl,
} from '@modrinth/ui'
import { useStorage } from '@vueuse/core' import { useStorage } from '@vueuse/core'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import { computed, ref } from 'vue' import { computed, ref } from 'vue'
@@ -23,6 +28,8 @@ import { duplicate, remove } from '@/helpers/profile.js'
const { handleError } = injectNotificationManager() const { handleError } = injectNotificationManager()
const { formatMessage } = useVIntl()
const props = defineProps({ const props = defineProps({
instances: { instances: {
type: Array, type: Array,
@@ -175,7 +182,7 @@ const filteredResults = computed(() => {
if (group === 'Loader') { if (group === 'Loader') {
instances.forEach((instance) => { instances.forEach((instance) => {
const loader = formatCategoryHeader(instance.loader) const loader = formatLoader(formatMessage, instance.loader)
if (!instanceMap.has(loader)) { if (!instanceMap.has(loader)) {
instanceMap.set(loader, []) instanceMap.set(loader, [])
} }

View File

@@ -74,7 +74,7 @@
<div class="chart-controls"> <div class="chart-controls">
<h2> <h2>
<span class="label__title"> <span class="label__title">
{{ formatCategoryHeader(selectedChart) }} {{ capitalizeString(selectedChart) }}
</span> </span>
<span class="label__subtitle"> <span class="label__subtitle">
{{ formattedCategorySubtitle }} {{ formattedCategorySubtitle }}
@@ -311,7 +311,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { DownloadIcon, PaletteIcon, UpdatedIcon } from '@modrinth/assets' import { DownloadIcon, PaletteIcon, UpdatedIcon } from '@modrinth/assets'
import { Button, Card, DropdownSelect } from '@modrinth/ui' import { Button, Card, DropdownSelect } from '@modrinth/ui'
import { formatCategoryHeader, formatMoney, formatNumber } from '@modrinth/utils' import { capitalizeString, formatMoney, formatNumber } from '@modrinth/utils'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import { computed } from 'vue' import { computed } from 'vue'

View File

@@ -38,7 +38,7 @@
<template v-for="header in Object.keys(categoryLists)" :key="`categories-${header}`"> <template v-for="header in Object.keys(categoryLists)" :key="`categories-${header}`">
<div class="label mb-3"> <div class="label mb-3">
<h4> <h4>
<span class="label__title">{{ formatCategoryHeader(header) }}</span> <span class="label__title">{{ formatCategoryHeader(formatMessage, header) }}</span>
</h4> </h4>
<span class="label__description"> <span class="label__description">
<template v-if="header === 'categories'"> <template v-if="header === 'categories'">
@@ -136,13 +136,14 @@ import { getCategoryIcon, StarIcon, TriangleAlertIcon } from '@modrinth/assets'
import { import {
Checkbox, Checkbox,
formatCategory, formatCategory,
formatCategoryHeader,
FormattedTag, FormattedTag,
injectProjectPageContext, injectProjectPageContext,
UnsavedChangesPopup, UnsavedChangesPopup,
useSavable, useSavable,
useVIntl, useVIntl,
} from '@modrinth/ui' } from '@modrinth/ui'
import { formatCategoryHeader, formatProjectType, sortedCategories } from '@modrinth/utils' import { formatProjectType, sortedCategories } from '@modrinth/utils'
import { computed } from 'vue' import { computed } from 'vue'
interface Category { interface Category {

View File

@@ -248,6 +248,18 @@
"form.placeholder.state": { "form.placeholder.state": {
"defaultMessage": "Enter state/province" "defaultMessage": "Enter state/province"
}, },
"header.category.category": {
"defaultMessage": "Category"
},
"header.category.feature": {
"defaultMessage": "Feature"
},
"header.category.performance-impact": {
"defaultMessage": "Performance impact"
},
"header.category.resolutions": {
"defaultMessage": "Resolutions"
},
"hosting.specs.burst": { "hosting.specs.burst": {
"defaultMessage": "Bursts up to {cpus} CPUs" "defaultMessage": "Bursts up to {cpus} CPUs"
}, },

View File

@@ -1,11 +1,11 @@
import type { Labrinth } from '@modrinth/api-client' import type { Labrinth } from '@modrinth/api-client'
import { ClientIcon, getCategoryIcon, getLoaderIcon, ServerIcon } from '@modrinth/assets' import { ClientIcon, getCategoryIcon, getLoaderIcon, ServerIcon } from '@modrinth/assets'
import { formatCategoryHeader, sortByNameOrNumber } from '@modrinth/utils' import { sortByNameOrNumber } from '@modrinth/utils'
import { type Component, computed, readonly, type Ref, ref } from 'vue' import { type Component, computed, readonly, type Ref, ref } from 'vue'
import { type LocationQueryRaw, type LocationQueryValue, useRoute } from 'vue-router' import { type LocationQueryRaw, type LocationQueryValue, useRoute } from 'vue-router'
import { defineMessage, useVIntl } from '../composables/i18n' import { defineMessage, useVIntl } from '../composables/i18n'
import { formatCategory, formatLoader } from './tag-messages.ts' import { formatCategory, formatCategoryHeader, formatLoader } from './tag-messages.ts'
type BaseOption = { type BaseOption = {
id: string id: string
@@ -132,7 +132,7 @@ export function useSearch(
if (!categoryFilters[filterTypeId]) { if (!categoryFilters[filterTypeId]) {
categoryFilters[filterTypeId] = { categoryFilters[filterTypeId] = {
id: filterTypeId, id: filterTypeId,
formatted_name: formatCategoryHeader(category.header), formatted_name: formatCategoryHeader(formatMessage, category.header),
supported_project_types: supported_project_types:
category.project_type === 'mod' category.project_type === 'mod'
? ['mod', 'plugin', 'datapack'] ? ['mod', 'plugin', 'datapack']

View File

@@ -388,6 +388,25 @@ export const categoryMessages = defineMessages({
}, },
}) })
export const categoryHeaderMessages = defineMessages({
resolutions: {
id: 'header.category.resolutions',
defaultMessage: 'Resolutions',
},
categories: {
id: 'header.category.category',
defaultMessage: 'Category',
},
features: {
id: 'header.category.feature',
defaultMessage: 'Feature',
},
'performance impact': {
id: 'header.category.performance-impact',
defaultMessage: 'Performance impact',
},
})
export function getTagMessage( export function getTagMessage(
tag: string, tag: string,
enforceType?: 'loader' | 'category', enforceType?: 'loader' | 'category',
@@ -409,6 +428,10 @@ export function getCategoryMessage(category: string) {
return getTagMessage(category, 'category') return getTagMessage(category, 'category')
} }
export function getCategoryHeaderMessage(header: string): MessageDescriptor | undefined {
return categoryHeaderMessages[header]
}
export function formatTag( export function formatTag(
formatter: VIntlFormatters['formatMessage'], formatter: VIntlFormatters['formatMessage'],
tag: string, tag: string,
@@ -425,3 +448,8 @@ export function formatCategory(formatter: VIntlFormatters['formatMessage'], cate
export function formatLoader(formatter: VIntlFormatters['formatMessage'], category: string) { export function formatLoader(formatter: VIntlFormatters['formatMessage'], category: string) {
return formatTag(formatter, category, 'loader') return formatTag(formatter, category, 'loader')
} }
export function formatCategoryHeader(formatter: VIntlFormatters['formatMessage'], header: string) {
const message = getCategoryHeaderMessage(header)
return message ? formatter(message) : capitalizeString(header)
}

View File

@@ -162,10 +162,6 @@ export const formatProjectType = (name, short = false) => {
return capitalizeString(name) return capitalizeString(name)
} }
export const formatCategoryHeader = (name) => {
return capitalizeString(name)
}
export const formatProjectStatus = (name) => { export const formatProjectStatus = (name) => {
if (name === 'approved') { if (name === 'approved') {
return 'Public' return 'Public'