|
1 | 1 | <script setup lang="ts">
|
2 |
| -import { useI18n } from 'vue-i18n' |
3 |
| -import { Button } from '@/components/ui/button' |
4 |
| -import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from '@/components/ui/dropdown-menu' |
5 |
| -import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select' |
6 |
| -import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card' |
7 |
| -import { Globe } from 'lucide-vue-next' |
8 |
| -import { router } from '@inertiajs/vue3' |
9 |
| -import { usePage } from '@inertiajs/vue3' |
10 |
| -import { useLocale } from '@/composables/useLocale' |
11 |
| -import { computed, watch } from 'vue' |
| 2 | +import { Button } from '@/components/ui/button'; |
| 3 | +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; |
| 4 | +import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from '@/components/ui/dropdown-menu'; |
| 5 | +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; |
| 6 | +import { useLocale } from '@/composables/useLocale'; |
| 7 | +import { router, usePage } from '@inertiajs/vue3'; |
| 8 | +import { Globe } from 'lucide-vue-next'; |
| 9 | +import { computed, watch } from 'vue'; |
| 10 | +import { useI18n } from 'vue-i18n'; |
12 | 11 |
|
13 | 12 | interface Props {
|
14 |
| - display?: 'dropdown' | 'select' | 'cards' |
| 13 | + display?: 'dropdown' | 'select' | 'cards'; |
15 | 14 | }
|
16 | 15 |
|
17 | 16 | withDefaults(defineProps<Props>(), {
|
18 |
| - display: 'dropdown' |
19 |
| -}) |
| 17 | + display: 'dropdown', |
| 18 | +}); |
20 | 19 |
|
21 |
| -const { locale, t } = useI18n() |
22 |
| -const page = usePage() |
23 |
| -const { initializeLocale } = useLocale() |
| 20 | +const { locale, t } = useI18n(); |
| 21 | +const page = usePage(); |
| 22 | +const { initializeLocale } = useLocale(); |
24 | 23 |
|
25 | 24 | const languages = [
|
26 |
| - { code: 'en', name: 'English', flag: '🇺🇸' }, |
27 |
| - { code: 'fr', name: 'Français', flag: '🇫🇷' }, |
28 |
| -] |
| 25 | + { code: 'en', name: 'English', flag: '🇺🇸' }, |
| 26 | + { code: 'fr', name: 'Français', flag: '🇫🇷' }, |
| 27 | +]; |
29 | 28 |
|
30 |
| -const currentLanguage = computed(() => |
31 |
| - languages.find(lang => lang.code === locale.value) || languages[0] |
32 |
| -) |
| 29 | +const currentLanguage = computed(() => languages.find((lang) => lang.code === locale.value) || languages[0]); |
33 | 30 |
|
34 | 31 | watch(locale, async (newLocale, oldLocale) => {
|
35 |
| - if (newLocale !== oldLocale && oldLocale) { |
36 |
| - await syncLocaleWithBackend(newLocale) |
37 |
| - } |
38 |
| -}) |
| 32 | + if (newLocale !== oldLocale && oldLocale) { |
| 33 | + await syncLocaleWithBackend(newLocale); |
| 34 | + } |
| 35 | +}); |
39 | 36 |
|
40 | 37 | const syncLocaleWithBackend = async (langCode: string) => {
|
41 |
| - const isAuthenticated = (page.props as any)?.auth?.user |
42 |
| - const routeName = isAuthenticated ? 'language.update' : 'language.update.guest' |
| 38 | + const isAuthenticated = (page.props as any)?.auth?.user; |
| 39 | + const routeName = isAuthenticated ? 'language.update' : 'language.update.guest'; |
43 | 40 |
|
44 |
| - try { |
45 |
| - await router.patch(route(routeName), { locale: langCode }, { |
46 |
| - preserveState: true, |
47 |
| - preserveScroll: true, |
48 |
| - onSuccess: () => { |
49 |
| - }, |
50 |
| - onError: () => { |
51 |
| - initializeLocale() |
52 |
| - } |
53 |
| - }) |
54 |
| - } catch (error) { |
55 |
| - initializeLocale() |
56 |
| - } |
57 |
| -} |
| 41 | + try { |
| 42 | + await router.patch( |
| 43 | + route(routeName), |
| 44 | + { locale: langCode }, |
| 45 | + { |
| 46 | + preserveState: true, |
| 47 | + preserveScroll: true, |
| 48 | + onSuccess: () => {}, |
| 49 | + onError: () => { |
| 50 | + initializeLocale(); |
| 51 | + }, |
| 52 | + }, |
| 53 | + ); |
| 54 | + } catch (error) { |
| 55 | + initializeLocale(); |
| 56 | + } |
| 57 | +}; |
58 | 58 |
|
59 | 59 | const switchLanguage = async (langCode: string) => {
|
60 |
| - locale.value = langCode |
61 |
| -} |
| 60 | + locale.value = langCode; |
| 61 | +}; |
62 | 62 | </script>
|
63 | 63 |
|
64 | 64 | <template>
|
65 |
| - <!-- Dropdown Display (Default) --> |
66 |
| - <DropdownMenu v-if="display === 'dropdown'"> |
67 |
| - <DropdownMenuTrigger as-child> |
68 |
| - <Button variant="ghost" size="icon" class="h-8 w-8 p-0"> |
69 |
| - <Globe class="h-4 w-4 text-foreground" /> |
70 |
| - <span class="sr-only">{{ t('common.switchLanguage') }}</span> |
71 |
| - </Button> |
72 |
| - </DropdownMenuTrigger> |
73 |
| - <DropdownMenuContent align="end"> |
74 |
| - <DropdownMenuItem |
75 |
| - v-for="language in languages" |
76 |
| - :key="language.code" |
77 |
| - @click="switchLanguage(language.code)" |
78 |
| - :class="{ 'bg-accent': language.code === currentLanguage.code }" |
79 |
| - > |
80 |
| - <span class="mr-2">{{ language.flag }}</span> |
81 |
| - {{ language.name }} |
82 |
| - </DropdownMenuItem> |
83 |
| - </DropdownMenuContent> |
84 |
| - </DropdownMenu> |
| 65 | + <!-- Dropdown Display (Default) --> |
| 66 | + <DropdownMenu v-if="display === 'dropdown'"> |
| 67 | + <DropdownMenuTrigger as-child> |
| 68 | + <Button variant="ghost" size="icon" class="h-8 w-8 p-0"> |
| 69 | + <Globe class="h-4 w-4 text-foreground" /> |
| 70 | + <span class="sr-only">{{ t('common.switchLanguage') }}</span> |
| 71 | + </Button> |
| 72 | + </DropdownMenuTrigger> |
| 73 | + <DropdownMenuContent align="end"> |
| 74 | + <DropdownMenuItem |
| 75 | + v-for="language in languages" |
| 76 | + :key="language.code" |
| 77 | + @click="switchLanguage(language.code)" |
| 78 | + :class="{ 'bg-accent': language.code === currentLanguage.code }" |
| 79 | + > |
| 80 | + <span class="mr-2">{{ language.flag }}</span> |
| 81 | + {{ language.name }} |
| 82 | + </DropdownMenuItem> |
| 83 | + </DropdownMenuContent> |
| 84 | + </DropdownMenu> |
85 | 85 |
|
86 |
| - <!-- Select Display --> |
87 |
| - <Select v-else-if="display === 'select'" v-model="locale"> |
88 |
| - <SelectTrigger class="w-[180px]"> |
89 |
| - <SelectValue class="text-foreground"> |
90 |
| - <span class="flex items-center gap-2"> |
91 |
| - <span>{{ currentLanguage.flag }}</span> |
92 |
| - <span class="text-foreground">{{ currentLanguage.name }}</span> |
93 |
| - </span> |
94 |
| - </SelectValue> |
95 |
| - </SelectTrigger> |
96 |
| - <SelectContent> |
97 |
| - <SelectItem |
98 |
| - v-for="language in languages" |
99 |
| - :key="language.code" |
100 |
| - :value="language.code" |
101 |
| - > |
102 |
| - <span class="flex items-center gap-2"> |
103 |
| - <span>{{ language.flag }}</span> |
104 |
| - <span>{{ language.name }}</span> |
105 |
| - </span> |
106 |
| - </SelectItem> |
107 |
| - </SelectContent> |
108 |
| - </Select> |
| 86 | + <!-- Select Display --> |
| 87 | + <Select v-else-if="display === 'select'" v-model="locale"> |
| 88 | + <SelectTrigger class="w-[180px]"> |
| 89 | + <SelectValue class="text-foreground"> |
| 90 | + <span class="flex items-center gap-2"> |
| 91 | + <span>{{ currentLanguage.flag }}</span> |
| 92 | + <span class="text-foreground">{{ currentLanguage.name }}</span> |
| 93 | + </span> |
| 94 | + </SelectValue> |
| 95 | + </SelectTrigger> |
| 96 | + <SelectContent> |
| 97 | + <SelectItem v-for="language in languages" :key="language.code" :value="language.code"> |
| 98 | + <span class="flex items-center gap-2"> |
| 99 | + <span>{{ language.flag }}</span> |
| 100 | + <span>{{ language.name }}</span> |
| 101 | + </span> |
| 102 | + </SelectItem> |
| 103 | + </SelectContent> |
| 104 | + </Select> |
109 | 105 |
|
110 |
| - <!-- Card Display --> |
111 |
| - <Card v-else-if="display === 'cards'"> |
112 |
| - <CardHeader> |
113 |
| - <CardTitle class="flex items-center gap-2"> |
114 |
| - <Globe class="h-5 w-5" /> |
115 |
| - {{ t('settings.language.title') }} |
116 |
| - </CardTitle> |
117 |
| - <CardDescription> |
118 |
| - {{ t('settings.language.description') }} |
119 |
| - </CardDescription> |
120 |
| - </CardHeader> |
121 |
| - <CardContent> |
122 |
| - <div class="grid gap-3"> |
123 |
| - <Button |
124 |
| - v-for="language in languages" |
125 |
| - :key="language.code" |
126 |
| - @click="switchLanguage(language.code)" |
127 |
| - variant="outline" |
128 |
| - :class="[ |
129 |
| - 'justify-start', |
130 |
| - language.code === currentLanguage.code |
131 |
| - ? 'border-primary bg-primary/5' |
132 |
| - : 'hover:bg-muted' |
133 |
| - ]" |
134 |
| - > |
135 |
| - <span class="mr-3 text-lg">{{ language.flag }}</span> |
136 |
| - <div class="flex items-center justify-between w-full"> |
137 |
| - <span class="font-medium">{{ language.name }}</span> |
138 |
| - <span v-if="language.code === currentLanguage.code" class="text-xs text-muted-foreground"> |
139 |
| - {{ t('settings.language.currentLanguage') }} |
140 |
| - </span> |
141 |
| - </div> |
142 |
| - </Button> |
143 |
| - </div> |
144 |
| - </CardContent> |
145 |
| - </Card> |
| 106 | + <!-- Card Display --> |
| 107 | + <Card v-else-if="display === 'cards'"> |
| 108 | + <CardHeader> |
| 109 | + <CardTitle class="flex items-center gap-2"> |
| 110 | + <Globe class="h-5 w-5" /> |
| 111 | + {{ t('settings.language.title') }} |
| 112 | + </CardTitle> |
| 113 | + <CardDescription> |
| 114 | + {{ t('settings.language.description') }} |
| 115 | + </CardDescription> |
| 116 | + </CardHeader> |
| 117 | + <CardContent> |
| 118 | + <div class="grid gap-3"> |
| 119 | + <Button |
| 120 | + v-for="language in languages" |
| 121 | + :key="language.code" |
| 122 | + @click="switchLanguage(language.code)" |
| 123 | + variant="outline" |
| 124 | + :class="['justify-start', language.code === currentLanguage.code ? 'border-primary bg-primary/5' : 'hover:bg-muted']" |
| 125 | + > |
| 126 | + <span class="mr-3 text-lg">{{ language.flag }}</span> |
| 127 | + <div class="flex w-full items-center justify-between"> |
| 128 | + <span class="font-medium">{{ language.name }}</span> |
| 129 | + <span v-if="language.code === currentLanguage.code" class="text-xs text-muted-foreground"> |
| 130 | + {{ t('settings.language.currentLanguage') }} |
| 131 | + </span> |
| 132 | + </div> |
| 133 | + </Button> |
| 134 | + </div> |
| 135 | + </CardContent> |
| 136 | + </Card> |
146 | 137 | </template>
|
0 commit comments