feat: Implement internationalization (i18n) with language switching and establish core backend services and frontend pages for course management.
This commit is contained in:
parent
6a05e6fdb6
commit
dbf62feea9
13 changed files with 3195 additions and 1463 deletions
89
Frontend-Learner/components/common/LanguageSwitcher.vue
Normal file
89
Frontend-Learner/components/common/LanguageSwitcher.vue
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
<script setup lang="ts">
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
const { locale, setLocale } = useI18n()
|
||||
|
||||
// Language options
|
||||
const languages = [
|
||||
{ code: 'th', label: 'TH', fullLabel: 'ไทย', flagSrc: '/flags/th.svg' },
|
||||
{ code: 'en', label: 'EN', fullLabel: 'English', flagSrc: '/flags/en.svg' }
|
||||
]
|
||||
|
||||
// Get current language object
|
||||
const currentLang = computed(() =>
|
||||
languages.find(l => l.code === locale.value) || languages[0]
|
||||
)
|
||||
|
||||
// Change language function
|
||||
const changeLanguage = (langCode: string) => {
|
||||
setLocale(langCode)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<q-btn
|
||||
rounded
|
||||
flat
|
||||
no-caps
|
||||
class="text-slate-700 dark:text-slate-200"
|
||||
:aria-label="$t('app.title') || 'Change Language'"
|
||||
>
|
||||
<div class="flex items-center gap-2">
|
||||
<img
|
||||
:src="currentLang.flagSrc"
|
||||
alt="flag"
|
||||
class="w-5 h-5 rounded-full object-cover border border-slate-200 dark:border-slate-600"
|
||||
/>
|
||||
<span class="font-bold">{{ currentLang.label }}</span>
|
||||
<q-icon name="arrow_drop_down" />
|
||||
</div>
|
||||
|
||||
<!-- Tooltip -->
|
||||
<q-tooltip>ภาษา / Language</q-tooltip>
|
||||
|
||||
<!-- Dropdown Menu -->
|
||||
<q-menu
|
||||
auto-close
|
||||
transition-show="jump-down"
|
||||
transition-hide="jump-up"
|
||||
class="rounded-xl shadow-lg border border-slate-100 bg-white dark:bg-slate-800 dark:border-slate-700"
|
||||
>
|
||||
<q-list style="min-width: 150px" class="py-2">
|
||||
<q-item
|
||||
v-for="lang in languages"
|
||||
:key="lang.code"
|
||||
clickable
|
||||
v-close-popup
|
||||
:active="locale === lang.code"
|
||||
active-class="bg-blue-50 text-blue-600 dark:bg-blue-900/30 dark:text-blue-400"
|
||||
class="text-black dark:text-white hover:bg-slate-50 dark:hover:bg-slate-700/50 transition-colors"
|
||||
@click="changeLanguage(lang.code)"
|
||||
>
|
||||
<q-item-section avatar>
|
||||
<img
|
||||
:src="lang.flagSrc"
|
||||
alt="flag"
|
||||
class="w-6 h-6 rounded-full object-cover border border-slate-200 dark:border-slate-600"
|
||||
/>
|
||||
</q-item-section>
|
||||
<q-item-section>
|
||||
<span :class="{ 'font-bold': locale === lang.code }">{{ lang.fullLabel }}</span>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
</q-list>
|
||||
</q-menu>
|
||||
</q-btn>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
/* Optional: adjust Quasar overrides if needed */
|
||||
</style>
|
||||
|
||||
<style scoped>
|
||||
.font-emoji {
|
||||
font-family: "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
||||
}
|
||||
|
||||
/* Tooltip directive placeholder if not globally available,
|
||||
though usually handled by a library like Floating Vue or simple title attr */
|
||||
</style>
|
||||
Loading…
Add table
Add a link
Reference in a new issue