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

+39 -5
View File
@@ -1,7 +1,10 @@
<script setup lang="ts">
import { t } from '@/i18n'
import { computed, ref } from 'vue'
import { useMediaQuery } from '@vueuse/core'
import { useEventListener, useMediaQuery } from '@vueuse/core'
import { colorModeOptions, useAccountMenu } from '@/composables/useAccountMenu'
import LanguagePicker from '@/components/LanguagePicker.vue'
const DESKTOP_QUERY = '(min-width: 64rem)'
const ITEM_CLASS = 'h-8 items-center py-0'
@@ -23,11 +26,35 @@ const { colorMode, name, initials, onProfile, goToProfile } = useAccountMenu(()
const isDesktop = useMediaQuery(DESKTOP_QUERY)
const open = ref(false)
const chip = ref<{ $el: HTMLElement } | null>(null)
const languagePicker = ref<{ $el: HTMLElement } | null>(null)
function focusLanguage(event: KeyboardEvent) {
const target = event.target
if (!(target instanceof HTMLElement)) return
if (target.closest('[role="menu"]') !== languagePicker.value?.$el.closest('[role="menu"]'))
return
if (target.closest('[role="combobox"]')) return
const entries = Array.from(
target
.closest('[role="menu"]')
?.querySelectorAll<HTMLElement>('[role="menuitem"], [role="menuitemcheckbox"]') ?? [],
)
const movesToLanguage =
event.key === 'End' ||
(event.key === 'ArrowDown' && target === entries[entries.length - 1]) ||
(event.key === 'ArrowUp' && target === entries[0])
if (movesToLanguage) {
event.preventDefault()
languagePicker.value?.$el.querySelector<HTMLElement>('[role="combobox"]')?.focus()
}
}
useEventListener(document, 'keydown', focusLanguage, { capture: true })
const chipActive = computed(() => open.value || onProfile.value)
const triggerAriaLabel = computed(() =>
props.collapsed ? `${name.value} — account menu` : undefined,
props.collapsed ? t('{0} — account menu', [name.value]) : undefined,
)
const chipClass = computed(() => [
@@ -59,7 +86,9 @@ const items = computed(() => [
class: 'mb-1 border-b border-default px-2 pt-2 pb-2.5',
},
{
label: 'Profile',
get label() {
return t('Profile')
},
icon: 'i-lucide-circle-user',
class: onProfile.value ? `${ITEM_CLASS} bg-elevated` : ITEM_CLASS,
onSelect: goToProfile,
@@ -79,7 +108,9 @@ const items = computed(() => [
})),
[
{
label: 'Log out',
get label() {
return t('Log out')
},
icon: 'i-lucide-log-out',
class: ITEM_CLASS,
onSelect: () => emit('logout'),
@@ -101,7 +132,7 @@ const items = computed(() => [
color="neutral"
variant="ghost"
block
title="Account"
:title="t('Account')"
:aria-expanded="chipExpanded"
:class="chipClass"
:trailing-icon="collapsed ? undefined : 'i-lucide-chevrons-up-down'"
@@ -128,5 +159,8 @@ const items = computed(() => [
<span class="truncate text-xs font-normal text-muted">{{ email }}</span>
</span>
</template>
<template #content-bottom>
<LanguagePicker ref="languagePicker" />
</template>
</UDropdownMenu>
</template>