i18n implemented

This commit is contained in:
2026-10-03 23:45:04 +02:00
parent 2ccea34bb9
commit d95ed40053
55 changed files with 2952 additions and 301 deletions
+38 -34
View File
@@ -25,21 +25,22 @@ interface ListedUser {
const route = useRoute()
const router = useRouter()
const { t } = useI18n()
const TYPE_OPTIONS = [
{ value: 'image', label: 'Bilder', icon: 'ph:image-fill' },
{ value: 'video', label: 'Videos', icon: 'ph:video-camera-fill' },
{ value: 'audio', label: 'Audio', icon: 'ph:music-note-fill' },
{ value: 'youtube', label: 'YouTube', icon: 'simple-icons:youtube' },
{ value: 'twitch', label: 'Twitch', icon: 'simple-icons:twitch' },
{ value: 'link', label: 'Links', icon: 'ph:link-fill' },
{ value: 'image', labelKey: 'filters.images', icon: 'ph:image-fill' },
{ value: 'video', labelKey: 'filters.videos', icon: 'ph:video-camera-fill' },
{ value: 'audio', labelKey: 'filters.audio', icon: 'ph:music-note-fill' },
{ value: 'youtube', labelKey: null, icon: 'simple-icons:youtube' },
{ value: 'twitch', labelKey: null, icon: 'simple-icons:twitch' },
{ value: 'link', labelKey: 'filters.links', icon: 'ph:link-fill' },
] as const
const DAY_OPTIONS = [
{ value: '1', label: 'Heute' },
{ value: '7', label: '7 Tage' },
{ value: '30', label: '30 Tage' },
{ value: '365', label: 'Letztes Jahr' },
{ value: '1', labelKey: 'filters.today' },
{ value: '7', labelKey: 'filters.days7' },
{ value: '30', labelKey: 'filters.days30' },
{ value: '365', labelKey: 'filters.lastYear' },
] as const
const open = ref(false)
@@ -79,7 +80,10 @@ const daysModel = computed<string>({
})
const daysOption = computed(() => DAY_OPTIONS.find(d => d.value === daysModel.value))
const typeLabel = (value: string) => TYPE_OPTIONS.find(t => t.value === value)?.label ?? value
const typeLabel = (value: string) => {
const option = TYPE_OPTIONS.find(o => o.value === value)
return option ? (option.labelKey ? t(option.labelKey) : option.value) : value
}
const typeIcon = (value: string) => TYPE_OPTIONS.find(t => t.value === value)?.icon ?? 'ph:image-fill'
const activeCount = computed(() =>
@@ -111,36 +115,36 @@ function clearFilters() {
<PopoverTrigger as-child>
<Button variant="outline" size="sm" class="gap-1.5">
<Icon name="ph:sliders-horizontal-fill" class="size-4" />
Filter
{{ $t('filters.filter') }}
<Badge v-if="activeCount" variant="secondary" class="ml-0.5 px-1.5 text-xs">{{ activeCount }}</Badge>
</Button>
</PopoverTrigger>
<PopoverContent class="w-72" align="start">
<FieldGroup class="gap-4">
<Field>
<FieldLabel>Typ</FieldLabel>
<FieldLabel>{{ $t('filters.type') }}</FieldLabel>
<ToggleGroup v-model="selectedTypes" type="multiple" variant="outline" :spacing="2" class="flex-wrap justify-start">
<ToggleGroupItem
v-for="t in TYPE_OPTIONS"
:key="t.value"
:value="t.value"
:aria-label="t.label"
v-for="o in TYPE_OPTIONS"
:key="o.value"
:value="o.value"
:aria-label="typeLabel(o.value)"
class="gap-1.5 rounded-md px-2.5"
>
<Icon :name="t.icon" class="size-4" />
{{ t.label }}
<Icon :name="o.icon" class="size-4" />
{{ typeLabel(o.value) }}
</ToggleGroupItem>
</ToggleGroup>
</Field>
<Field>
<FieldLabel>Uploader</FieldLabel>
<FieldLabel>{{ $t('filters.uploader') }}</FieldLabel>
<Popover v-model:open="uploaderOpen">
<PopoverTrigger as-child>
<Button variant="outline" role="combobox" :aria-expanded="uploaderOpen" class="w-full justify-between font-normal">
<span class="flex items-center gap-1.5 truncate">
<Icon name="ph:user-fill" class="size-4 shrink-0 text-muted-foreground" />
<span :style="selectedUser?.color ? { color: selectedUser.color } : undefined" class="truncate">
{{ selectedUser?.name ?? 'Alle Uploader' }}
{{ selectedUser?.name ?? $t('filters.allUploaders') }}
</span>
</span>
<Icon name="ph:caret-up-down-fill" class="size-4 shrink-0 text-muted-foreground" />
@@ -148,13 +152,13 @@ function clearFilters() {
</PopoverTrigger>
<PopoverContent class="w-64 p-0">
<Command>
<CommandInput placeholder="Nutzer suchen…" />
<CommandInput :placeholder="$t('filters.searchUser')" />
<CommandList>
<CommandEmpty>Kein Nutzer gefunden.</CommandEmpty>
<CommandEmpty>{{ $t('filters.noUser') }}</CommandEmpty>
<CommandGroup>
<CommandItem value="alle" class="gap-2" @select="selectUser(null)">
<Icon name="ph:check-fill" :class="cn('size-4', !uploaderId ? 'opacity-100' : 'opacity-0')" />
Alle Uploader
{{ $t('filters.allUploaders') }}
</CommandItem>
<CommandItem
v-for="u in uploaders"
@@ -187,19 +191,19 @@ function clearFilters() {
</Popover>
</Field>
<Field>
<FieldLabel>Zeitraum</FieldLabel>
<FieldLabel>{{ $t('filters.period') }}</FieldLabel>
<Select v-model="daysModel">
<SelectTrigger class="w-full">
<SelectValue placeholder="Alle" />
<SelectValue :placeholder="$t('filters.allTime')" />
</SelectTrigger>
<SelectContent>
<SelectItem value="all">Gesamter Zeitraum</SelectItem>
<SelectItem v-for="d in DAY_OPTIONS" :key="d.value" :value="d.value">{{ d.label }}</SelectItem>
<SelectItem value="all">{{ $t('filters.allTime') }}</SelectItem>
<SelectItem v-for="d in DAY_OPTIONS" :key="d.value" :value="d.value">{{ $t(d.labelKey) }}</SelectItem>
</SelectContent>
</Select>
</Field>
<Button variant="ghost" size="sm" :disabled="!activeCount" class="self-start" @click="clearFilters">
Zurücksetzen
{{ $t('common.reset') }}
</Button>
</FieldGroup>
</PopoverContent>
@@ -211,7 +215,7 @@ function clearFilters() {
<button
type="button"
class="text-muted-foreground transition-colors hover:text-foreground"
aria-label="Tag-Filter entfernen"
:aria-label="$t('filters.removeTag')"
@click="setQuery({ tag: undefined })"
>
<Icon name="ph:x-fill" class="size-3.5" />
@@ -223,7 +227,7 @@ function clearFilters() {
<button
type="button"
class="text-muted-foreground transition-colors hover:text-foreground"
:aria-label="`Typ-Filter ${typeLabel(t)} entfernen`"
:aria-label="$t('filters.removeType', { label: typeLabel(t) })"
@click="selectedTypes = selectedTypes.filter(v => v !== t)"
>
<Icon name="ph:x-fill" class="size-3.5" />
@@ -235,7 +239,7 @@ function clearFilters() {
<button
type="button"
class="text-muted-foreground transition-colors hover:text-foreground"
aria-label="Uploader-Filter entfernen"
:aria-label="$t('filters.removeUploader')"
@click="setQuery({ uploader: undefined })"
>
<Icon name="ph:x-fill" class="size-3.5" />
@@ -243,11 +247,11 @@ function clearFilters() {
</span>
<span v-if="daysOption" class="inline-flex items-center gap-1.5 rounded-sm bg-muted px-2.5 py-1 text-sm">
<Icon name="ph:calendar-fill" class="size-3.5" />
{{ daysOption.label }}
{{ daysOption ? $t(daysOption.labelKey) : '' }}
<button
type="button"
class="text-muted-foreground transition-colors hover:text-foreground"
aria-label="Zeitraum-Filter entfernen"
:aria-label="$t('filters.removePeriod')"
@click="setQuery({ days: undefined })"
>
<Icon name="ph:x-fill" class="size-3.5" />