feat(SPA): i18n internationzalization, english and french

This commit is contained in:
fsylvain committed 2026-10-03 01:53:49 +02:00
1 parent 7f1e8e572d
commit 721311a643
88 files changed
+4438 -1148

No files matched your search

+26 -19
View File
@@ -1,4 +1,6 @@
<script setup lang="ts">
import { t } from '@/i18n'
import { computed, nextTick, onBeforeUnmount, ref, watch } from 'vue'
import { useMediaQuery } from '@vueuse/core'
import MediaThumb from '@/components/MediaThumb.vue'
@@ -55,7 +57,7 @@ const firstLoadSkeletons = computed(() =>
)
const searching = computed(() => props.query !== '')
const summary = computed(() =>
searching.value ? 'Newest first' : `Newest first · ${props.total} images`,
searching.value ? t('Newest first') : t('Newest first · {0} images', [props.total]),
)
const scrollHeight = computed(() => (props.selected ? 'max-h-32 md:max-h-49.5' : 'max-h-77'))
const showEmptyLibrary = computed(
@@ -66,7 +68,7 @@ const showNoResults = computed(
)
const showGrid = computed(() => props.status === 'ready' && props.items.length > 0)
const showLoadMore = computed(() => showGrid.value && props.hasMore && !props.selected)
const noResultsTitle = computed(() => `No images match "${props.query}"`)
const noResultsTitle = computed(() => t('No images match \u0022{0}\u0022', [props.query]))
function clearDebounce() {
if (debounceTimer !== null) {
@@ -133,10 +135,13 @@ onBeforeUnmount(clearDebounce)
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="w-full"
:ui="{ base: 'h-11 text-lg md:h-8 md:text-sm', leadingIcon: SEARCH_ICON_SIZE }"
:ui="{
base: 'h-11 text-lg md:h-8 md:text-sm',
leadingIcon: SEARCH_ICON_SIZE,
}"
>
<template v-if="searchText" #trailing>
<UButton
@@ -144,7 +149,7 @@ onBeforeUnmount(clearDebounce)
variant="link"
size="xs"
icon="i-lucide-x"
aria-label="Clear search"
:aria-label="t('Clear search')"
class="text-muted"
@click="clearSearch"
/>
@@ -159,8 +164,8 @@ onBeforeUnmount(clearDebounce)
orientation="vertical"
:close="false"
icon="i-lucide-circle-x"
title="Couldn't load your library"
description="Check your connection and try again."
:title="t('Couldn\'t load your library')"
:description="t('Check your connection and try again.')"
:ui="{ actions: 'mt-2' }"
>
<template #actions>
@@ -172,7 +177,7 @@ onBeforeUnmount(clearDebounce)
:ui="{ leadingIcon: 'size-3.5' }"
@click="emit('retry')"
>
Try again
{{ t('Try again') }}
</UButton>
</template>
</UAlert>
@@ -181,13 +186,13 @@ onBeforeUnmount(clearDebounce)
v-else-if="showEmptyLibrary"
variant="naked"
icon="i-lucide-images"
title="Your library is empty"
description="Images you upload appear here, ready to use in any article."
:title="t('Your library is empty')"
:description="t('Images you upload appear here, ready to use in any article.')"
:ui="EMPTY_STATE_UI"
>
<template #actions>
<UButton icon="i-lucide-upload" class="h-11 px-4 md:h-8" @click="emit('upload')">
Upload an image
{{ t('Upload an image') }}
</UButton>
</template>
</UEmpty>
@@ -197,7 +202,7 @@ onBeforeUnmount(clearDebounce)
variant="naked"
icon="i-lucide-search"
:title="noResultsTitle"
description="Check the spelling, or search for a shorter part of the filename."
:description="t('Check the spelling, or search for a shorter part of the filename.')"
:ui="EMPTY_STATE_UI"
>
<template #actions>
@@ -207,7 +212,7 @@ onBeforeUnmount(clearDebounce)
class="h-11 border border-accented bg-default px-4 text-highlighted ring-0 md:h-8"
@click="clearSearch"
>
Clear search
{{ t('Clear search') }}
</UButton>
</template>
</UEmpty>
@@ -259,7 +264,7 @@ onBeforeUnmount(clearDebounce)
<span
v-if="isInArticle(item)"
class="absolute bottom-1 left-1 inline-flex h-4.5 items-center bg-secondary-200 px-1.25 text-[0.6875rem] font-medium text-primary-900 dark:bg-secondary-300"
>In this article</span
>{{ t('In this article') }}</span
>
<span
v-if="isSelected(item)"
@@ -291,10 +296,12 @@ onBeforeUnmount(clearDebounce)
:icon="loadingMore ? 'i-lucide-loader-circle' : undefined"
:aria-disabled="loadingMore || undefined"
class="h-11 border border-accented bg-default px-3 text-highlighted ring-0 aria-disabled:opacity-40 md:h-8"
:ui="{ leadingIcon: loadingMore ? 'size-4 animate-spin' : 'size-4' }"
:ui="{
leadingIcon: loadingMore ? 'size-4 animate-spin' : 'size-4',
}"
@click="emit('load-more')"
>
{{ loadingMore ? 'Loading…' : 'Load more' }}
{{ loadingMore ? t('Loading…') : t('Load more') }}
</UButton>
</div>
</template>
@@ -317,7 +324,7 @@ onBeforeUnmount(clearDebounce)
</div>
</div>
<UFormField
label="Alt text (optional)"
:label="t('Alt text (optional)')"
help="Describes the image for people who use a screen reader, and shows if it doesn't load. Leave it empty if the image is only decoration."
:ui="{
label: 'font-medium text-highlighted',
@@ -327,7 +334,7 @@ onBeforeUnmount(clearDebounce)
<UInput
v-model="alt"
type="text"
placeholder="e.g. North wall of the kitchen before plastering"
:placeholder="t('e.g. North wall of the kitchen before plastering')"
class="w-full"
:ui="{ base: 'h-11 text-lg md:h-10 md:text-sm' }"
/>