feat(SPA): i18n internationzalization, english and french
This commit is contained in:
1 parent
7f1e8e572d
commit
721311a643
88 files changed
+4438
-1148
No files matched your search
@@ -1,4 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { t, formatNumber } from '@/i18n'
|
||||
|
||||
import { computed, onBeforeUnmount, ref, watch } from 'vue'
|
||||
import type { MediaCounts } from '@/composables/useMedia'
|
||||
import type { MediaControls, MediaFilter, MediaSort, MediaView } from '@/lib/mediaQuery'
|
||||
@@ -7,15 +9,35 @@ import { UNDERLINE_TAB_TRIGGER } from '@/lib/tabStyles'
|
||||
const SEARCH_DEBOUNCE_MS = 120
|
||||
|
||||
const SORT_LABELS: Record<MediaSort, string> = {
|
||||
newest: 'Newest',
|
||||
oldest: 'Oldest',
|
||||
name: 'Name',
|
||||
largest: 'Largest',
|
||||
get newest() {
|
||||
return t('Newest')
|
||||
},
|
||||
get oldest() {
|
||||
return t('Oldest')
|
||||
},
|
||||
get name() {
|
||||
return t('Name')
|
||||
},
|
||||
get largest() {
|
||||
return t('Largest')
|
||||
},
|
||||
}
|
||||
|
||||
const VIEW_OPTIONS: { value: MediaView; icon: string; label: string }[] = [
|
||||
{ value: 'grid', icon: 'i-lucide-layout-grid', label: 'Grid view' },
|
||||
{ value: 'list', icon: 'i-lucide-list', label: 'List view' },
|
||||
{
|
||||
value: 'grid',
|
||||
icon: 'i-lucide-layout-grid',
|
||||
get label() {
|
||||
return t('Grid view')
|
||||
},
|
||||
},
|
||||
{
|
||||
value: 'list',
|
||||
icon: 'i-lucide-list',
|
||||
get label() {
|
||||
return t('List view')
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
const props = defineProps<{
|
||||
@@ -68,9 +90,27 @@ function clearSearch() {
|
||||
onBeforeUnmount(clearDebounce)
|
||||
|
||||
const tabItems = computed(() => [
|
||||
{ label: 'All', value: 'all', count: props.counts?.all },
|
||||
{ label: 'Unused', value: 'unused', count: props.counts?.unused },
|
||||
{ label: 'Duplicates', value: 'duplicates', count: props.counts?.duplicates },
|
||||
{
|
||||
get label() {
|
||||
return t('All')
|
||||
},
|
||||
value: 'all',
|
||||
count: props.counts?.all,
|
||||
},
|
||||
{
|
||||
get label() {
|
||||
return t('Unused')
|
||||
},
|
||||
value: 'unused',
|
||||
count: props.counts?.unused,
|
||||
},
|
||||
{
|
||||
get label() {
|
||||
return t('Duplicates')
|
||||
},
|
||||
value: 'duplicates',
|
||||
count: props.counts?.duplicates,
|
||||
},
|
||||
])
|
||||
|
||||
const tab = computed({
|
||||
@@ -115,12 +155,12 @@ const sortItems = computed(() =>
|
||||
v-if="item.value === 'duplicates' && item.count"
|
||||
data-testid="duplicates-count"
|
||||
class="inline-flex h-4.5 min-w-4.5 items-center justify-center bg-(--rc-info-soft) px-1.25 font-mono text-[0.6875rem] font-medium text-info"
|
||||
>{{ item.count }}</span
|
||||
>{{ item.count === undefined ? undefined : formatNumber(item.count) }}</span
|
||||
>
|
||||
<span
|
||||
v-else-if="item.value !== 'duplicates' && item.count !== undefined"
|
||||
class="font-mono text-[0.6875rem] font-medium text-muted"
|
||||
>{{ item.count }}</span
|
||||
>{{ item.count === undefined ? undefined : formatNumber(item.count) }}</span
|
||||
>
|
||||
</span>
|
||||
</template>
|
||||
@@ -130,10 +170,13 @@ const sortItems = computed(() =>
|
||||
v-model="searchText"
|
||||
type="text"
|
||||
icon="i-lucide-search"
|
||||
placeholder="Search by filename"
|
||||
aria-label="Search by filename"
|
||||
:placeholder="t('Search by filename')"
|
||||
:aria-label="t('Search by filename')"
|
||||
class="order-1 w-full md:order-none md:mb-1.5 md:w-60"
|
||||
:ui="{ base: 'h-11 text-lg md:h-8 md:text-sm', leadingIcon: 'size-3.5' }"
|
||||
:ui="{
|
||||
base: 'h-11 text-lg md:h-8 md:text-sm',
|
||||
leadingIcon: 'size-3.5',
|
||||
}"
|
||||
>
|
||||
<template v-if="searchText" #trailing>
|
||||
<UButton
|
||||
@@ -141,7 +184,7 @@ const sortItems = computed(() =>
|
||||
variant="link"
|
||||
size="xs"
|
||||
icon="i-lucide-x"
|
||||
aria-label="Clear search"
|
||||
:aria-label="t('Clear search')"
|
||||
class="text-muted"
|
||||
@click="clearSearch"
|
||||
/>
|
||||
@@ -154,7 +197,7 @@ const sortItems = computed(() =>
|
||||
color="neutral"
|
||||
variant="outline"
|
||||
trailing-icon="i-lucide-chevron-down"
|
||||
aria-label="Sort"
|
||||
:aria-label="t('Sort')"
|
||||
class="h-11 flex-1 justify-between border border-accented bg-default px-2.5 text-sm font-normal text-highlighted ring-0 md:h-8 md:w-32 md:flex-none"
|
||||
:ui="{ trailingIcon: 'size-3.5 text-muted' }"
|
||||
>
|
||||
@@ -162,7 +205,7 @@ const sortItems = computed(() =>
|
||||
</UButton>
|
||||
</UDropdownMenu>
|
||||
|
||||
<div role="group" aria-label="View" class="flex shrink-0 border border-accented">
|
||||
<div role="group" :aria-label="t('View')" class="flex shrink-0 border border-accented">
|
||||
<UButton
|
||||
v-for="option in VIEW_OPTIONS"
|
||||
:key="option.value"
|
||||
|
||||
Reference in new issue
Block a user