Skip to content

Commit 7dbd791

Browse files
committed
feat: add i18n support to compare page
1 parent 3171614 commit 7dbd791

9 files changed

Lines changed: 303 additions & 46 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 { isFacetSelected, toggleFacet, selectCategory, deselectCategory } = useFacetSelection()
612
@@ -87,10 +93,12 @@ function isCategoryNoneSelected(category: string): boolean {
8793
v-for="{ facet, info } in facetsByCategory[category]"
8894
:key="facet"
8995
type="button"
90-
:title="info.comingSoon ? $t('compare.facets.coming_soon') : info.description"
96+
:title="
97+
info.comingSoon ? $t('compare.facets.coming_soon') : $t(getFacetDescriptionKey(facet))
98+
"
9199
:disabled="info.comingSoon"
92100
:aria-pressed="isFacetSelected(facet)"
93-
:aria-label="info.label"
101+
:aria-label="$t(getFacetLabelKey(facet))"
94102
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"
95103
:class="
96104
info.comingSoon
@@ -107,7 +115,7 @@ function isCategoryNoneSelected(category: string): boolean {
107115
:class="isFacetSelected(facet) ? 'i-carbon:checkmark' : 'i-carbon:add'"
108116
aria-hidden="true"
109117
/>
110-
{{ info.label }}
118+
{{ $t(getFacetLabelKey(facet)) }}
111119
<span v-if="info.comingSoon" class="text-[9px]"
112120
>({{ $t('compare.facets.coming_soon') }})</span
113121
>

app/composables/usePackageComparison.ts

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,7 @@ export function usePackageComparison(packageNames: MaybeRefOrGetter<string[]>) {
244244
function computeFacetValue(
245245
facet: ComparisonFacet,
246246
data: PackageComparisonData,
247-
t: (key: string) => string,
247+
t: (key: string, params?: Record<string, unknown>) => string,
248248
): FacetValue | null {
249249
switch (facet) {
250250
case 'downloads':
@@ -294,13 +294,19 @@ function computeFacetValue(
294294
return {
295295
raw: types.kind,
296296
display:
297-
types.kind === 'included' ? 'Included' : types.kind === '@types' ? '@types' : 'None',
297+
types.kind === 'included'
298+
? t('compare.facets.values.types_included')
299+
: types.kind === '@types'
300+
? '@types'
301+
: t('compare.facets.values.types_none'),
298302
status: types.kind === 'included' ? 'good' : types.kind === '@types' ? 'info' : 'bad',
299303
}
300304

301305
case 'engines':
302306
const engines = data.metadata?.engines
303-
if (!engines?.node) return { raw: null, display: 'Any', status: 'neutral' }
307+
if (!engines?.node) {
308+
return { raw: null, display: t('compare.facets.values.any'), status: 'neutral' }
309+
}
304310
return {
305311
raw: engines.node,
306312
display: `Node ${engines.node}`,
@@ -313,7 +319,14 @@ function computeFacetValue(
313319
const sev = data.vulnerabilities.severity
314320
return {
315321
raw: count,
316-
display: count === 0 ? 'None' : `${count} (${sev.critical}C/${sev.high}H)`,
322+
display:
323+
count === 0
324+
? t('compare.facets.values.none')
325+
: t('compare.facets.values.vulnerabilities_summary', {
326+
count,
327+
critical: sev.critical,
328+
high: sev.high,
329+
}),
317330
status: count === 0 ? 'good' : sev.critical > 0 || sev.high > 0 ? 'bad' : 'warning',
318331
}
319332

@@ -329,7 +342,9 @@ function computeFacetValue(
329342

330343
case 'license':
331344
const license = data.metadata?.license
332-
if (!license) return { raw: null, display: 'Unknown', status: 'warning' }
345+
if (!license) {
346+
return { raw: null, display: t('compare.facets.values.unknown'), status: 'warning' }
347+
}
333348
return {
334349
raw: license,
335350
display: license,
@@ -349,7 +364,9 @@ function computeFacetValue(
349364
const isDeprecated = !!data.metadata?.deprecated
350365
return {
351366
raw: isDeprecated,
352-
display: isDeprecated ? 'Deprecated' : 'No',
367+
display: isDeprecated
368+
? t('compare.facets.values.deprecated')
369+
: t('compare.facets.values.not_deprecated'),
353370
status: isDeprecated ? 'bad' : 'good',
354371
}
355372

app/pages/compare.vue

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
<script setup lang="ts">
2-
import { FACET_INFO } from '#shared/types/comparison'
2+
import {
3+
getFacetDescriptionKey,
4+
getFacetLabelKey,
5+
} from '#shared/types/comparison'
36
import { useRouteQuery } from '@vueuse/router'
47
58
definePageMeta({
@@ -129,8 +132,8 @@ useSeoMeta({
129132
<CompareFacetRow
130133
v-for="facet in selectedFacets"
131134
:key="facet"
132-
:label="FACET_INFO[facet].label"
133-
:description="FACET_INFO[facet].description"
135+
:label="$t(getFacetLabelKey(facet))"
136+
:description="$t(getFacetDescriptionKey(facet))"
134137
:values="getFacetValues(facet)"
135138
:facet-loading="isFacetLoading(facet)"
136139
:column-loading="columnLoading"
@@ -145,8 +148,8 @@ useSeoMeta({
145148
<CompareFacetCard
146149
v-for="facet in selectedFacets"
147150
:key="facet"
148-
:label="FACET_INFO[facet].label"
149-
:description="FACET_INFO[facet].description"
151+
:label="$t(getFacetLabelKey(facet))"
152+
:description="$t(getFacetDescriptionKey(facet))"
150153
:values="getFacetValues(facet)"
151154
:facet-loading="isFacetLoading(facet)"
152155
:column-loading="columnLoading"

i18n/locales/en.json

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -860,6 +860,66 @@
860860
"health": "Health",
861861
"compatibility": "Compatibility",
862862
"security": "Security & Compliance"
863+
},
864+
"items": {
865+
"packageSize": {
866+
"label": "Package Size",
867+
"description": "Size of the package itself (unpacked)"
868+
},
869+
"installSize": {
870+
"label": "Install Size",
871+
"description": "Total install size including all dependencies"
872+
},
873+
"dependencies": {
874+
"label": "# Direct Deps",
875+
"description": "Number of direct dependencies"
876+
},
877+
"totalDependencies": {
878+
"label": "# Total Deps",
879+
"description": "Total number of dependencies including transitive"
880+
},
881+
"downloads": {
882+
"label": "Downloads/wk",
883+
"description": "Weekly download count"
884+
},
885+
"lastUpdated": {
886+
"label": "Published",
887+
"description": "When this version was published"
888+
},
889+
"deprecated": {
890+
"label": "Deprecated?",
891+
"description": "Whether the package is deprecated"
892+
},
893+
"engines": {
894+
"label": "Engines",
895+
"description": "Node.js version requirements"
896+
},
897+
"types": {
898+
"label": "Types",
899+
"description": "TypeScript type definitions"
900+
},
901+
"moduleFormat": {
902+
"label": "Module Format",
903+
"description": "ESM/CJS support"
904+
},
905+
"license": {
906+
"label": "License",
907+
"description": "Package license"
908+
},
909+
"vulnerabilities": {
910+
"label": "Vulnerabilities",
911+
"description": "Known security vulnerabilities"
912+
}
913+
},
914+
"values": {
915+
"any": "Any",
916+
"none": "None",
917+
"unknown": "Unknown",
918+
"deprecated": "Deprecated",
919+
"not_deprecated": "No",
920+
"types_included": "Included",
921+
"types_none": "None",
922+
"vulnerabilities_summary": "{count} ({critical}C/{high}H)"
863923
}
864924
}
865925
}

i18n/locales/pl-PL.json

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,7 @@
290290
"cjs": "Obsługuje CommonJS",
291291
"no_esm": "Brak obsługi ES Modules",
292292
"types_label": "Typy",
293-
"types_included": "Typy w pakiecie",
293+
"types_included": "Typy wbudowane",
294294
"types_available": "Typy dostępne przez {package}",
295295
"no_types": "Brak typów TypeScript"
296296
},
@@ -850,6 +850,66 @@
850850
"health": "Zdrowie",
851851
"compatibility": "Kompatybilność",
852852
"security": "Bezpieczeństwo i zgodność"
853+
},
854+
"items": {
855+
"packageSize": {
856+
"label": "Rozmiar pakietu",
857+
"description": "Rozmiar samego pakietu (rozpakowany)"
858+
},
859+
"installSize": {
860+
"label": "Rozmiar instalacji",
861+
"description": "Łączny rozmiar instalacji wraz ze wszystkimi zależnościami"
862+
},
863+
"dependencies": {
864+
"label": "Bezpośrednie zależności",
865+
"description": "Liczba bezpośrednich zależności"
866+
},
867+
"totalDependencies": {
868+
"label": "# Wszystkich zależności",
869+
"description": "Łączna liczba zależności, w tym przechodnich"
870+
},
871+
"downloads": {
872+
"label": "Pobrania/tydz.",
873+
"description": "Tygodniowa liczba pobrań"
874+
},
875+
"lastUpdated": {
876+
"label": "Opublikowano",
877+
"description": "Kiedy ta wersja została opublikowana"
878+
},
879+
"deprecated": {
880+
"label": "Wycofany?",
881+
"description": "Czy pakiet jest wycofany"
882+
},
883+
"engines": {
884+
"label": "Silniki",
885+
"description": "Wymagania wersji Node.js"
886+
},
887+
"types": {
888+
"label": "Typy",
889+
"description": "Definicje typów TypeScript"
890+
},
891+
"moduleFormat": {
892+
"label": "Format modułu",
893+
"description": "Obsługa ESM/CJS"
894+
},
895+
"license": {
896+
"label": "Licencja",
897+
"description": "Licencja pakietu"
898+
},
899+
"vulnerabilities": {
900+
"label": "Podatności",
901+
"description": "Znane luki bezpieczeństwa"
902+
}
903+
},
904+
"values": {
905+
"any": "Dowolne",
906+
"none": "Brak",
907+
"unknown": "Nieznana",
908+
"deprecated": "Wycofany",
909+
"not_deprecated": "Nie",
910+
"types_included": "Wbudowane",
911+
"types_none": "Brak",
912+
"vulnerabilities_summary": "{count} ({critical}K/{high}W)"
853913
}
854914
}
855915
}

lunaria/files/en-US.json

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -860,6 +860,66 @@
860860
"health": "Health",
861861
"compatibility": "Compatibility",
862862
"security": "Security & Compliance"
863+
},
864+
"items": {
865+
"packageSize": {
866+
"label": "Package Size",
867+
"description": "Size of the package itself (unpacked)"
868+
},
869+
"installSize": {
870+
"label": "Install Size",
871+
"description": "Total install size including all dependencies"
872+
},
873+
"dependencies": {
874+
"label": "# Direct Deps",
875+
"description": "Number of direct dependencies"
876+
},
877+
"totalDependencies": {
878+
"label": "# Total Deps",
879+
"description": "Total number of dependencies including transitive"
880+
},
881+
"downloads": {
882+
"label": "Downloads/wk",
883+
"description": "Weekly download count"
884+
},
885+
"lastUpdated": {
886+
"label": "Published",
887+
"description": "When this version was published"
888+
},
889+
"deprecated": {
890+
"label": "Deprecated?",
891+
"description": "Whether the package is deprecated"
892+
},
893+
"engines": {
894+
"label": "Engines",
895+
"description": "Node.js version requirements"
896+
},
897+
"types": {
898+
"label": "Types",
899+
"description": "TypeScript type definitions"
900+
},
901+
"moduleFormat": {
902+
"label": "Module Format",
903+
"description": "ESM/CJS support"
904+
},
905+
"license": {
906+
"label": "License",
907+
"description": "Package license"
908+
},
909+
"vulnerabilities": {
910+
"label": "Vulnerabilities",
911+
"description": "Known security vulnerabilities"
912+
}
913+
},
914+
"values": {
915+
"any": "Any",
916+
"none": "None",
917+
"unknown": "Unknown",
918+
"deprecated": "Deprecated",
919+
"not_deprecated": "No",
920+
"types_included": "Included",
921+
"types_none": "None",
922+
"vulnerabilities_summary": "{count} ({critical}C/{high}H)"
863923
}
864924
}
865925
}

0 commit comments

Comments
 (0)