Skip to content

Commit fc29ca4

Browse files
committed
feat: add i18n support to compare page
1 parent 4801787 commit fc29ca4

10 files changed

Lines changed: 1218 additions & 48 deletions

File tree

app/components/compare/FacetSelector.vue

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
<script setup lang="ts">
22
import type { ComparisonFacet } from '#shared/types'
3-
import { FACET_INFO, FACETS_BY_CATEGORY, CATEGORY_ORDER } from '#shared/types/comparison'
3+
import {
4+
FACET_INFO,
5+
FACETS_BY_CATEGORY,
6+
CATEGORY_ORDER,
7+
getFacetDescriptionKey,
8+
getFacetLabelKey,
9+
} from '#shared/types/comparison'
410
511
const {
612
isFacetSelected,
@@ -96,10 +102,12 @@ function isCategoryNoneSelected(category: string): boolean {
96102
v-for="{ facet, info } in facetsByCategory[category]"
97103
:key="facet"
98104
type="button"
99-
:title="info.comingSoon ? $t('compare.facets.coming_soon') : info.description"
105+
:title="
106+
info.comingSoon ? $t('compare.facets.coming_soon') : $t(getFacetDescriptionKey(facet))
107+
"
100108
:disabled="info.comingSoon"
101109
:aria-pressed="isFacetSelected(facet)"
102-
:aria-label="info.label"
110+
:aria-label="$t(getFacetLabelKey(facet))"
103111
class="inline-flex items-center gap-1 px-1.5 py-0.5 font-mono text-xs rounded border transition-colors duration-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50"
104112
:class="
105113
info.comingSoon
@@ -116,7 +124,7 @@ function isCategoryNoneSelected(category: string): boolean {
116124
:class="isFacetSelected(facet) ? 'i-carbon:checkmark' : 'i-carbon:add'"
117125
aria-hidden="true"
118126
/>
119-
{{ info.label }}
127+
{{ $t(getFacetLabelKey(facet)) }}
120128
<span v-if="info.comingSoon" class="text-[9px]"
121129
>({{ $t('compare.facets.coming_soon') }})</span
122130
>

app/composables/usePackageComparison.ts

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,10 @@ export interface PackageComparisonData {
2929
* Composable for fetching and comparing multiple packages.
3030
*
3131
*/
32-
export function usePackageComparison(packageNames: MaybeRefOrGetter<string[]>) {
32+
export function usePackageComparison(
33+
packageNames: MaybeRefOrGetter<string[]>,
34+
t: (key: string, params?: Record<string, unknown>) => string = key => key,
35+
) {
3336
const packages = computed(() => toValue(packageNames))
3437

3538
// Cache of fetched data by package name (source of truth)
@@ -195,7 +198,7 @@ export function usePackageComparison(packageNames: MaybeRefOrGetter<string[]>) {
195198

196199
return packagesData.value.map(pkg => {
197200
if (!pkg) return null
198-
return computeFacetValue(facet, pkg)
201+
return computeFacetValue(facet, pkg, t)
199202
})
200203
}
201204

@@ -229,7 +232,11 @@ function encodePackageName(name: string): string {
229232
return encodeURIComponent(name)
230233
}
231234

232-
function computeFacetValue(facet: ComparisonFacet, data: PackageComparisonData): FacetValue | null {
235+
function computeFacetValue(
236+
facet: ComparisonFacet,
237+
data: PackageComparisonData,
238+
t: (key: string, params?: Record<string, unknown>) => string,
239+
): FacetValue | null {
233240
switch (facet) {
234241
case 'downloads':
235242
if (data.downloads === undefined) return null
@@ -270,13 +277,19 @@ function computeFacetValue(facet: ComparisonFacet, data: PackageComparisonData):
270277
return {
271278
raw: types.kind,
272279
display:
273-
types.kind === 'included' ? 'Included' : types.kind === '@types' ? '@types' : 'None',
280+
types.kind === 'included'
281+
? t('compare.facets.values.types_included')
282+
: types.kind === '@types'
283+
? '@types'
284+
: t('compare.facets.values.types_none'),
274285
status: types.kind === 'included' ? 'good' : types.kind === '@types' ? 'info' : 'bad',
275286
}
276287

277288
case 'engines':
278289
const engines = data.metadata?.engines
279-
if (!engines?.node) return { raw: null, display: 'Any', status: 'neutral' }
290+
if (!engines?.node) {
291+
return { raw: null, display: t('compare.facets.values.any'), status: 'neutral' }
292+
}
280293
return {
281294
raw: engines.node,
282295
display: `Node ${engines.node}`,
@@ -289,7 +302,14 @@ function computeFacetValue(facet: ComparisonFacet, data: PackageComparisonData):
289302
const sev = data.vulnerabilities.severity
290303
return {
291304
raw: count,
292-
display: count === 0 ? 'None' : `${count} (${sev.critical}C/${sev.high}H)`,
305+
display:
306+
count === 0
307+
? t('compare.facets.values.none')
308+
: t('compare.facets.values.vulnerabilities_summary', {
309+
count,
310+
critical: sev.critical,
311+
high: sev.high,
312+
}),
293313
status: count === 0 ? 'good' : sev.critical > 0 || sev.high > 0 ? 'bad' : 'warning',
294314
}
295315

@@ -305,7 +325,9 @@ function computeFacetValue(facet: ComparisonFacet, data: PackageComparisonData):
305325

306326
case 'license':
307327
const license = data.metadata?.license
308-
if (!license) return { raw: null, display: 'Unknown', status: 'warning' }
328+
if (!license) {
329+
return { raw: null, display: t('compare.facets.values.unknown'), status: 'warning' }
330+
}
309331
return {
310332
raw: license,
311333
display: license,
@@ -325,7 +347,9 @@ function computeFacetValue(facet: ComparisonFacet, data: PackageComparisonData):
325347
const isDeprecated = !!data.metadata?.deprecated
326348
return {
327349
raw: isDeprecated,
328-
display: isDeprecated ? 'Deprecated' : 'No',
350+
display: isDeprecated
351+
? t('compare.facets.values.deprecated')
352+
: t('compare.facets.values.not_deprecated'),
329353
status: isDeprecated ? 'bad' : 'good',
330354
}
331355

app/pages/compare.vue

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
<script setup lang="ts">
2-
import { FACET_INFO, type ComparisonFacet } from '#shared/types/comparison'
2+
import {
3+
FACET_INFO,
4+
getFacetDescriptionKey,
5+
getFacetLabelKey,
6+
type ComparisonFacet,
7+
} from '#shared/types/comparison'
38
import { useRouteQuery } from '@vueuse/router'
49
510
definePageMeta({
@@ -28,9 +33,11 @@ const packages = computed({
2833
const { selectedFacets, selectAll, deselectAll, isAllSelected, isNoneSelected } =
2934
useFacetSelection()
3035
36+
const { t } = useI18n()
37+
3138
// Fetch comparison data
3239
const { packagesData, status, getFacetValues, isFacetLoading, isColumnLoading } =
33-
usePackageComparison(packages)
40+
usePackageComparison(packages, t)
3441
3542
// Get loading state for each column
3643
const columnLoading = computed(() => packages.value.map((_, i) => isColumnLoading(i)))
@@ -129,8 +136,8 @@ useSeoMeta({
129136
<CompareFacetRow
130137
v-for="facet in selectedFacets"
131138
:key="facet"
132-
:label="FACET_INFO[facet].label"
133-
:description="FACET_INFO[facet].description"
139+
:label="$t(getFacetLabelKey(facet))"
140+
:description="$t(getFacetDescriptionKey(facet))"
134141
:values="getFacetValues(facet)"
135142
:facet-loading="isFacetLoading(facet)"
136143
:column-loading="columnLoading"
@@ -145,8 +152,8 @@ useSeoMeta({
145152
<CompareFacetCard
146153
v-for="facet in selectedFacets"
147154
:key="facet"
148-
:label="FACET_INFO[facet].label"
149-
:description="FACET_INFO[facet].description"
155+
:label="$t(getFacetLabelKey(facet))"
156+
:description="$t(getFacetDescriptionKey(facet))"
150157
:values="getFacetValues(facet)"
151158
:facet-loading="isFacetLoading(facet)"
152159
:column-loading="columnLoading"

0 commit comments

Comments
 (0)