Skip to content

Commit bc0d61e

Browse files
committed
feat: add i18n support to compare page
1 parent 0d06026 commit bc0d61e

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
@@ -30,7 +30,10 @@ export interface PackageComparisonData {
3030
*
3131
* @public
3232
*/
33-
export function usePackageComparison(packageNames: MaybeRefOrGetter<string[]>) {
33+
export function usePackageComparison(
34+
packageNames: MaybeRefOrGetter<string[]>,
35+
t: (key: string, params?: Record<string, unknown>) => string = key => key,
36+
) {
3437
const packages = computed(() => toValue(packageNames))
3538

3639
// Cache of fetched data by package name (source of truth)
@@ -196,7 +199,7 @@ export function usePackageComparison(packageNames: MaybeRefOrGetter<string[]>) {
196199

197200
return packagesData.value.map(pkg => {
198201
if (!pkg) return null
199-
return computeFacetValue(facet, pkg)
202+
return computeFacetValue(facet, pkg, t)
200203
})
201204
}
202205

@@ -230,7 +233,11 @@ function encodePackageName(name: string): string {
230233
return encodeURIComponent(name)
231234
}
232235

233-
function computeFacetValue(facet: ComparisonFacet, data: PackageComparisonData): FacetValue | null {
236+
function computeFacetValue(
237+
facet: ComparisonFacet,
238+
data: PackageComparisonData,
239+
t: (key: string, params?: Record<string, unknown>) => string,
240+
): FacetValue | null {
234241
switch (facet) {
235242
case 'downloads':
236243
if (data.downloads === undefined) return null
@@ -271,13 +278,19 @@ function computeFacetValue(facet: ComparisonFacet, data: PackageComparisonData):
271278
return {
272279
raw: types.kind,
273280
display:
274-
types.kind === 'included' ? 'Included' : types.kind === '@types' ? '@types' : 'None',
281+
types.kind === 'included'
282+
? t('compare.facets.values.types_included')
283+
: types.kind === '@types'
284+
? '@types'
285+
: t('compare.facets.values.types_none'),
275286
status: types.kind === 'included' ? 'good' : types.kind === '@types' ? 'info' : 'bad',
276287
}
277288

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

@@ -306,7 +326,9 @@ function computeFacetValue(facet: ComparisonFacet, data: PackageComparisonData):
306326

307327
case 'license':
308328
const license = data.metadata?.license
309-
if (!license) return { raw: null, display: 'Unknown', status: 'warning' }
329+
if (!license) {
330+
return { raw: null, display: t('compare.facets.values.unknown'), status: 'warning' }
331+
}
310332
return {
311333
raw: license,
312334
display: license,
@@ -326,7 +348,9 @@ function computeFacetValue(facet: ComparisonFacet, data: PackageComparisonData):
326348
const isDeprecated = !!data.metadata?.deprecated
327349
return {
328350
raw: isDeprecated,
329-
display: isDeprecated ? 'Deprecated' : 'No',
351+
display: isDeprecated
352+
? t('compare.facets.values.deprecated')
353+
: t('compare.facets.values.not_deprecated'),
330354
status: isDeprecated ? 'bad' : 'good',
331355
}
332356

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)