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
|
|
@ -38,6 +38,9 @@ const emit = defineEmits<{
|
||||||
<span style="position: absolute; left: 12px; top: 10px; color: var(--text-secondary);">🔍</span>
|
<span style="position: absolute; left: 12px; top: 10px; color: var(--text-secondary);">🔍</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Language Switcher -->
|
||||||
|
<LanguageSwitcher />
|
||||||
|
|
||||||
<!-- User Profile Dropdown -->
|
<!-- User Profile Dropdown -->
|
||||||
<UserMenu />
|
<UserMenu />
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
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>
|
||||||
9
Frontend-Learner/i18n.config.ts
Normal file
9
Frontend-Learner/i18n.config.ts
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
import th from './i18n/locales/th.json'
|
||||||
|
import en from './i18n/locales/en.json'
|
||||||
|
|
||||||
|
export default defineI18nConfig(() => ({
|
||||||
|
legacy: false,
|
||||||
|
locale: 'th',
|
||||||
|
fallbackLocale: 'th',
|
||||||
|
messages: { th, en }
|
||||||
|
}))
|
||||||
171
Frontend-Learner/i18n/locales/en.json
Normal file
171
Frontend-Learner/i18n/locales/en.json
Normal file
|
|
@ -0,0 +1,171 @@
|
||||||
|
{
|
||||||
|
"app": {
|
||||||
|
"name": "E-Learning Platform",
|
||||||
|
"title": "E-Learning System",
|
||||||
|
"systemTitle": "E-Learning System - Online Learning Platform"
|
||||||
|
},
|
||||||
|
"common": {
|
||||||
|
"loading": "Loading...",
|
||||||
|
"views": "Views",
|
||||||
|
"students": "Students",
|
||||||
|
"lessons": "Lessons",
|
||||||
|
"hours": "Hours"
|
||||||
|
},
|
||||||
|
"dashboard": {
|
||||||
|
"welcomeTitle": "Welcome back, {name}!",
|
||||||
|
"welcomeSubtitle": "Today is a great day to learn something new. Let's gain more knowledge.",
|
||||||
|
"continueLearning": "Continue Learning",
|
||||||
|
"enterLearning": "Enter Full Lesson",
|
||||||
|
"recommendedCourses": "Recommended Courses",
|
||||||
|
"currentLearning": "CURRENTLY LEARNING",
|
||||||
|
"level": "Chapter",
|
||||||
|
"progress": "PROGRESS",
|
||||||
|
"viewDetails": "View Details",
|
||||||
|
"newBadge": "New",
|
||||||
|
"popularBadge": "Popular"
|
||||||
|
},
|
||||||
|
"auth": {
|
||||||
|
"login": {
|
||||||
|
"title": "Login",
|
||||||
|
"welcome": "Welcome back! Please enter your details.",
|
||||||
|
"submitButton": "Login",
|
||||||
|
"googleLogin": "Login with Google",
|
||||||
|
"rememberMe": "Remember me",
|
||||||
|
"forgotPassword": "Forgot password?",
|
||||||
|
"noAccount": "Don't have an account?",
|
||||||
|
"registerNow": "Register"
|
||||||
|
},
|
||||||
|
"register": {
|
||||||
|
"title": "Register",
|
||||||
|
"welcome": "Welcome back! Please enter your details.",
|
||||||
|
"submitButton": "Create Account",
|
||||||
|
"hasAccount": "Already have an account?",
|
||||||
|
"loginNow": "Login",
|
||||||
|
"successMessage": "Registration successful! Please login.",
|
||||||
|
"failMessage": "Registration failed"
|
||||||
|
},
|
||||||
|
"form": {
|
||||||
|
"username": "Username",
|
||||||
|
"email": "Email",
|
||||||
|
"password": "Password",
|
||||||
|
"confirmPassword": "Confirm Password",
|
||||||
|
"prefix": "Prefix",
|
||||||
|
"firstName": "First Name",
|
||||||
|
"lastName": "Last Name",
|
||||||
|
"phone": "Phone Number",
|
||||||
|
"prefixOptions": {
|
||||||
|
"mr": "Mr.",
|
||||||
|
"mrs": "Mrs.",
|
||||||
|
"ms": "Ms."
|
||||||
|
},
|
||||||
|
"placeholders": {
|
||||||
|
"email": "student{'@'}example.com",
|
||||||
|
"password": "••••••••",
|
||||||
|
"createPassword": "Create password (min 8 chars)",
|
||||||
|
"confirmPassword": "Confirm password again",
|
||||||
|
"username": "username"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"validation": {
|
||||||
|
"required": "This field is required",
|
||||||
|
"emailInvalid": "Please enter a valid email",
|
||||||
|
"passwordLength": "Password must be at least 8 characters",
|
||||||
|
"noThai": "Thai characters are not allowed",
|
||||||
|
"noNumber": "Numbers are not allowed",
|
||||||
|
"onlyNumber": "Please enter numbers only",
|
||||||
|
"passwordMismatch": "Passwords do not match",
|
||||||
|
"loginFailed": "Please check your Email or Password again."
|
||||||
|
},
|
||||||
|
"backToHome": "Back to Home"
|
||||||
|
},
|
||||||
|
"landing": {
|
||||||
|
"header": {
|
||||||
|
"menu": {
|
||||||
|
"allCourses": "All Courses",
|
||||||
|
"discovery": "Discovery"
|
||||||
|
},
|
||||||
|
"actions": {
|
||||||
|
"login": "Login",
|
||||||
|
"getStarted": "Get Started",
|
||||||
|
"enterDashboard": "Enter Dashboard"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"hero": {
|
||||||
|
"badge": "🚀 Start your new path to success here",
|
||||||
|
"titlePart1": "Level Up Your",
|
||||||
|
"titleHighlight": "Future Skills",
|
||||||
|
"titlePart2": "With Us",
|
||||||
|
"subtitle": "The most accessible online knowledge hub. Developed by experts to help you reach your goals with confidence.",
|
||||||
|
"ctaStart": "Start Learning for Free",
|
||||||
|
"ctaBrowse": "Browse All Courses"
|
||||||
|
},
|
||||||
|
"features": {
|
||||||
|
"certificate": {
|
||||||
|
"title": "Get Certified",
|
||||||
|
"desc": "Upon course completion"
|
||||||
|
},
|
||||||
|
"anywhere": {
|
||||||
|
"title": "Learn Anywhere",
|
||||||
|
"desc": "Supports all devices"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"whyChooseUs": {
|
||||||
|
"badge": "Why Choose Us",
|
||||||
|
"title": "Designed for Your Success",
|
||||||
|
"desc": "We are not just a learning platform, but a partner to help you reach your destination.",
|
||||||
|
"items": {
|
||||||
|
"material": {
|
||||||
|
"title": "High Quality Material",
|
||||||
|
"desc": "Sharp video quality with carefully selected learning materials for easy understanding."
|
||||||
|
},
|
||||||
|
"assessment": {
|
||||||
|
"title": "Smart Assessment",
|
||||||
|
"desc": "Online Quiz system to immediately assess understanding with improvement analysis."
|
||||||
|
},
|
||||||
|
"tracking": {
|
||||||
|
"title": "Progress Tracking",
|
||||||
|
"desc": "Track your progress anytime, anywhere via a Dashboard that summarizes everything perfectly."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"footer": {
|
||||||
|
"brandDesc": "Online learning platform for future skills",
|
||||||
|
"services": {
|
||||||
|
"title": "All Services",
|
||||||
|
"onlineCourses": "Online Courses",
|
||||||
|
"onsite": "Onsite Courses",
|
||||||
|
"classSystem": "Class System",
|
||||||
|
"forOrg": "For Organizations"
|
||||||
|
},
|
||||||
|
"about": {
|
||||||
|
"title": "About Us",
|
||||||
|
"yearlyPackage": "Yearly Package",
|
||||||
|
"learningPath": "Learning Path",
|
||||||
|
"skillCheck": "Skill Check",
|
||||||
|
"articles": "Articles",
|
||||||
|
"faq": "FAQ"
|
||||||
|
},
|
||||||
|
"join": {
|
||||||
|
"title": "Join Us",
|
||||||
|
"jobs": "Careers",
|
||||||
|
"affiliate": "Affiliate Program",
|
||||||
|
"instructor": "Become an Instructor",
|
||||||
|
"aboutUs": "About Us",
|
||||||
|
"contact": "Contact Us"
|
||||||
|
},
|
||||||
|
"download": {
|
||||||
|
"title": "Download Application"
|
||||||
|
},
|
||||||
|
"consult": {
|
||||||
|
"title": "Consultation",
|
||||||
|
"addLine": "Add Line Friend"
|
||||||
|
},
|
||||||
|
"legal": {
|
||||||
|
"terms": "Terms of Service",
|
||||||
|
"privacy": "Privacy Policy",
|
||||||
|
"refund": "Refund Policy",
|
||||||
|
"copyright": "© Copyright 2019-2026 LIKE ME X CO.,LTD All rights reserved."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
171
Frontend-Learner/i18n/locales/th.json
Normal file
171
Frontend-Learner/i18n/locales/th.json
Normal file
|
|
@ -0,0 +1,171 @@
|
||||||
|
{
|
||||||
|
"app": {
|
||||||
|
"name": "แพลตฟอร์มการเรียนรู้ออนไลน์",
|
||||||
|
"title": "ระบบ E-Learning",
|
||||||
|
"systemTitle": "ระบบการเรียนรู้ออนไลน์เพื่อพัฒนาทักษะแห่งอนาคต"
|
||||||
|
},
|
||||||
|
"common": {
|
||||||
|
"loading": "กำลังโหลด...",
|
||||||
|
"views": "ยอดเข้าชม",
|
||||||
|
"students": "ผู้เรียน",
|
||||||
|
"lessons": "บทเรียน",
|
||||||
|
"hours": "ชั่วโมง"
|
||||||
|
},
|
||||||
|
"dashboard": {
|
||||||
|
"welcomeTitle": "ยินดีต้อนรับกลับ, {name}!",
|
||||||
|
"welcomeSubtitle": "วันนี้เป็นวันที่ดีสำหรับการเรียนรู้สิ่งใหม่ๆ มาเพิ่มพูนความรู้กันเถอะ",
|
||||||
|
"continueLearning": "เรียนต่อจากเดิม",
|
||||||
|
"enterLearning": "เข้าสู่บทเรียนเต็มตัว",
|
||||||
|
"recommendedCourses": "คอร์สเรียนแนะนำ",
|
||||||
|
"currentLearning": "กำลังเรียน",
|
||||||
|
"level": "บทที่",
|
||||||
|
"progress": "ความคืบหน้า",
|
||||||
|
"viewDetails": "ดูรายละเอียด",
|
||||||
|
"newBadge": "ใหม่",
|
||||||
|
"popularBadge": "ยอดนิยม"
|
||||||
|
},
|
||||||
|
"auth": {
|
||||||
|
"login": {
|
||||||
|
"title": "เข้าสู่ระบบ",
|
||||||
|
"welcome": "ยินดีต้อนรับกลับ! กรุณากรอกข้อมูลเพื่อเข้าสู่ระบบ",
|
||||||
|
"submitButton": "เข้าสู่ระบบ",
|
||||||
|
"googleLogin": "เข้าสู่ระบบด้วย Google",
|
||||||
|
"rememberMe": "จำฉันไว้ในระบบ",
|
||||||
|
"forgotPassword": "ลืมรหัสผ่าน?",
|
||||||
|
"noAccount": "ยังไม่มีบัญชีผู้ใช้?",
|
||||||
|
"registerNow": "สมัครสมาชิก"
|
||||||
|
},
|
||||||
|
"register": {
|
||||||
|
"title": "สมัครสมาชิก",
|
||||||
|
"welcome": "ยินดีต้อนรับ! กรุณากรอกข้อมูลเพื่อสร้างบัญชี",
|
||||||
|
"submitButton": "สร้างบัญชีใหม่",
|
||||||
|
"hasAccount": "มีบัญชีผู้ใช้อยู่แล้ว?",
|
||||||
|
"loginNow": "เข้าสู่ระบบ",
|
||||||
|
"successMessage": "สมัครสมาชิกสำเร็จ! กรุณาเข้าสู่ระบบ",
|
||||||
|
"failMessage": "การสมัครสมาชิกไม่สำเร็จ"
|
||||||
|
},
|
||||||
|
"form": {
|
||||||
|
"username": "ชื่อผู้ใช้",
|
||||||
|
"email": "อีเมล",
|
||||||
|
"password": "รหัสผ่าน",
|
||||||
|
"confirmPassword": "ยืนยันรหัสผ่าน",
|
||||||
|
"prefix": "คำนำหน้าชื่อ",
|
||||||
|
"firstName": "ชื่อจริง",
|
||||||
|
"lastName": "นามสกุล",
|
||||||
|
"phone": "เบอร์โทรศัพท์",
|
||||||
|
"prefixOptions": {
|
||||||
|
"mr": "นาย",
|
||||||
|
"mrs": "นาง",
|
||||||
|
"ms": "นางสาว"
|
||||||
|
},
|
||||||
|
"placeholders": {
|
||||||
|
"email": "student{'@'}example.com",
|
||||||
|
"password": "••••••••",
|
||||||
|
"createPassword": "ตั้งรหัสผ่าน (ขั้นต่ำ 8 ตัวอักษร)",
|
||||||
|
"confirmPassword": "ยืนยันรหัสผ่านอีกครั้ง",
|
||||||
|
"username": "username"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"validation": {
|
||||||
|
"required": "กรุณากรอกข้อมูลในช่องนี้",
|
||||||
|
"emailInvalid": "รูปแบบอีเมลไม่ถูกต้อง",
|
||||||
|
"passwordLength": "รหัสผ่านต้องมีความยาวอย่างน้อย 8 ตัวอักษร",
|
||||||
|
"noThai": "ไม่อนุญาตให้ใช้ภาษาไทย",
|
||||||
|
"noNumber": "ไม่อนุญาตให้ใส่ตัวเลข",
|
||||||
|
"onlyNumber": "กรุณากรอกเฉพาะตัวเลขเท่านั้น",
|
||||||
|
"passwordMismatch": "รหัสผ่านไม่ตรงกัน",
|
||||||
|
"loginFailed": "เข้าสู่ระบบไม่สำเร็จ กรุณาตรวจสอบอีเมลหรือรหัสผ่าน"
|
||||||
|
},
|
||||||
|
"backToHome": "กลับสู่หน้าหลัก"
|
||||||
|
},
|
||||||
|
"landing": {
|
||||||
|
"header": {
|
||||||
|
"menu": {
|
||||||
|
"allCourses": "คอร์สทั้งหมด",
|
||||||
|
"discovery": "ค้นหาคอร์ส"
|
||||||
|
},
|
||||||
|
"actions": {
|
||||||
|
"login": "เข้าสู่ระบบ",
|
||||||
|
"getStarted": "เริ่มต้นใช้งาน",
|
||||||
|
"enterDashboard": "เข้าสู่แดชบอร์ด"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"hero": {
|
||||||
|
"badge": "🚀 เริ่มต้นเส้นทางความสำเร็จใหม่ของคุณที่นี่",
|
||||||
|
"titlePart1": "ยกระดับ",
|
||||||
|
"titleHighlight": "ทักษะแห่งอนาคต",
|
||||||
|
"titlePart2": "ไปกับเรา",
|
||||||
|
"subtitle": "แหล่งรวมความรู้ออนไลน์ที่เข้าถึงง่ายที่สุด พัฒนาโดยผู้เชี่ยวชาญเพื่อให้คุณก้าวไปสู่เป้าหมายได้อย่างมั่นใจ",
|
||||||
|
"ctaStart": "เริ่มเรียนฟรี",
|
||||||
|
"ctaBrowse": "ดูคอร์สทั้งหมด"
|
||||||
|
},
|
||||||
|
"features": {
|
||||||
|
"certificate": {
|
||||||
|
"title": "รับใบประกาศนียบัตร",
|
||||||
|
"desc": "เมื่อเรียนจบคอร์ส"
|
||||||
|
},
|
||||||
|
"anywhere": {
|
||||||
|
"title": "เรียนได้ทุกที่",
|
||||||
|
"desc": "รองรับทุกอุปกรณ์"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"whyChooseUs": {
|
||||||
|
"badge": "ทำไมต้องเลือกเรา",
|
||||||
|
"title": "ออกแบบมาเพื่อความสำเร็จของคุณ",
|
||||||
|
"desc": "เราไม่ได้เป็นเพียงแค่แพลตฟอร์มเรียนออนไลน์ แต่เป็นพาร์ทเนอร์ที่จะช่วยผลักดันให้คุณไปถึงเป้าหมาย",
|
||||||
|
"items": {
|
||||||
|
"material": {
|
||||||
|
"title": "เนื้อหาคุณภาพสูง",
|
||||||
|
"desc": "วิดีโอคมชัด พร้อมเอกสารประกอบการเรียนที่คัดสรรมาอย่างดี เข้าใจง่าย"
|
||||||
|
},
|
||||||
|
"assessment": {
|
||||||
|
"title": "วัดผลแม่นยำ",
|
||||||
|
"desc": "ระบบแบบทดสอบออนไลน์ (Quiz) รู้ผลทันที พร้อมวิเคราะห์จุดที่ควรปรับปรุง"
|
||||||
|
},
|
||||||
|
"tracking": {
|
||||||
|
"title": "ติดตามผลได้ตลอด",
|
||||||
|
"desc": "ดูความคืบหน้าการเรียนได้ทุกที่ทุกเวลา ผ่าน Dashboard ที่สรุปทุกอย่างให้อย่างลงตัว"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"footer": {
|
||||||
|
"brandDesc": "แพลตฟอร์มการเรียนรู้ออนไลน์สำหรับทักษะแห่งอนาคต",
|
||||||
|
"services": {
|
||||||
|
"title": "บริการทั้งหมด",
|
||||||
|
"onlineCourses": "คอร์สออนไลน์",
|
||||||
|
"onsite": "คอร์สเรียนสด (Onsite)",
|
||||||
|
"classSystem": "ระบบห้องเรียน",
|
||||||
|
"forOrg": "สำหรับองค์กร"
|
||||||
|
},
|
||||||
|
"about": {
|
||||||
|
"title": "เกี่ยวกับเรา",
|
||||||
|
"yearlyPackage": "แพ็กเกจรายปี",
|
||||||
|
"learningPath": "เส้นทางการเรียนรู้",
|
||||||
|
"skillCheck": "ประเมินทักษะ",
|
||||||
|
"articles": "บทความ",
|
||||||
|
"faq": "คำถามที่พบบ่อย"
|
||||||
|
},
|
||||||
|
"join": {
|
||||||
|
"title": "ร่วมงานกับเรา",
|
||||||
|
"jobs": "สมัครงาน",
|
||||||
|
"affiliate": "โปรแกรมพันธมิตร",
|
||||||
|
"instructor": "สมัครเป็นผู้สอน",
|
||||||
|
"aboutUs": "เกี่ยวกับเรา",
|
||||||
|
"contact": "ติดต่อเรา"
|
||||||
|
},
|
||||||
|
"download": {
|
||||||
|
"title": "ดาวน์โหลดแอปพลิเคชัน"
|
||||||
|
},
|
||||||
|
"consult": {
|
||||||
|
"title": "ปรึกษาหลักสูตร",
|
||||||
|
"addLine": "แอดไลน์เพื่อน"
|
||||||
|
},
|
||||||
|
"legal": {
|
||||||
|
"terms": "เงื่อนไขการใช้งาน",
|
||||||
|
"privacy": "นโยบายความเป็นส่วนตัว",
|
||||||
|
"refund": "นโยบายการคืนเงิน",
|
||||||
|
"copyright": "© สงวนลิขสิทธิ์ 2019-2026 บริษัท ไลค์ มี เอ็กซ์ จำกัด"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,48 +1,82 @@
|
||||||
// Nuxt 3 + Quasar + Tailwind + TypeScript
|
// Nuxt 3 + Quasar + Tailwind + TypeScript
|
||||||
// Configuration for E-Learning Platform
|
// Configuration for E-Learning Platform
|
||||||
export default defineNuxtConfig({
|
export default defineNuxtConfig({
|
||||||
modules: ["nuxt-quasar-ui", "@nuxtjs/tailwindcss"],
|
compatibilityDate: '2026-01-19',
|
||||||
css: ["~/assets/css/main.css"],
|
|
||||||
typescript: {
|
modules: [
|
||||||
strict: true,
|
'nuxt-quasar-ui',
|
||||||
|
'@nuxtjs/tailwindcss',
|
||||||
|
'@nuxtjs/i18n'
|
||||||
|
],
|
||||||
|
|
||||||
|
i18n: {
|
||||||
|
strategy: 'no_prefix',
|
||||||
|
defaultLocale: 'th',
|
||||||
|
|
||||||
|
// ✅ สำคัญ: ไม่ใส่ i18n/ ซ้ำ (ฐานคือโฟลเดอร์ i18n อยู่แล้ว)
|
||||||
|
langDir: 'locales',
|
||||||
|
lazy: true,
|
||||||
|
|
||||||
|
locales: [
|
||||||
|
{ code: 'th', iso: 'th-TH', name: 'ไทย', file: 'th.json' },
|
||||||
|
{ code: 'en', iso: 'en-US', name: 'English', file: 'en.json' }
|
||||||
|
],
|
||||||
|
|
||||||
|
// ✅ ให้ใช้ config จากไฟล์นี้ด้วย (ถ้าคุณมี i18n.config.ts)
|
||||||
|
vueI18n: './i18n.config.ts',
|
||||||
|
|
||||||
|
detectBrowserLanguage: {
|
||||||
|
useCookie: true,
|
||||||
|
cookieKey: 'i18n_redirected',
|
||||||
|
redirectOn: 'root'
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
css: ['~/assets/css/main.css'],
|
||||||
|
|
||||||
|
typescript: {
|
||||||
|
strict: true
|
||||||
|
},
|
||||||
|
|
||||||
quasar: {
|
quasar: {
|
||||||
plugins: ["Notify"],
|
plugins: ['Notify'],
|
||||||
config: {
|
config: {
|
||||||
brand: {
|
brand: {
|
||||||
primary: "#4b82f7",
|
primary: '#4b82f7',
|
||||||
secondary: "#2f5ed7",
|
secondary: '#2f5ed7',
|
||||||
accent: "#44d4a8",
|
accent: '#44d4a8',
|
||||||
dark: "#0f1827",
|
dark: '#0f1827'
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
components: [
|
components: [
|
||||||
{
|
{
|
||||||
path: "~/components",
|
path: '~/components',
|
||||||
pathPrefix: false,
|
pathPrefix: false
|
||||||
},
|
}
|
||||||
],
|
],
|
||||||
|
|
||||||
app: {
|
app: {
|
||||||
head: {
|
head: {
|
||||||
htmlAttrs: {
|
htmlAttrs: {
|
||||||
lang: 'th',
|
lang: 'th'
|
||||||
},
|
},
|
||||||
title: "E-Learning System",
|
title: 'E-Learning System',
|
||||||
meta: [
|
meta: [{ name: 'viewport', content: 'width=device-width, initial-scale=1' }],
|
||||||
{ name: "viewport", content: "width=device-width, initial-scale=1" },
|
|
||||||
],
|
|
||||||
link: [
|
link: [
|
||||||
{
|
{
|
||||||
rel: "stylesheet",
|
rel: 'stylesheet',
|
||||||
href: "https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800;900&family=Prompt:wght@300;400;500;600;700;800;900&family=Sarabun:wght@300;400;500;600;700;800&display=swap",
|
href:
|
||||||
},
|
'https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800;900&family=Prompt:wght@300;400;500;600;700;800;900&family=Sarabun:wght@300;400;500;600;700;800&display=swap'
|
||||||
],
|
}
|
||||||
},
|
]
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
runtimeConfig: {
|
runtimeConfig: {
|
||||||
public: {
|
public: {
|
||||||
apiBase: process.env.NUXT_PUBLIC_API_BASE || 'http://localhost:4000/api'
|
apiBase: process.env.NUXT_PUBLIC_API_BASE || 'http://localhost:4000/api'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
|
|
|
||||||
4108
Frontend-Learner/package-lock.json
generated
4108
Frontend-Learner/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -17,6 +17,7 @@
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@nuxt/eslint-config": "^1.12.1",
|
"@nuxt/eslint-config": "^1.12.1",
|
||||||
|
"@nuxtjs/i18n": "^10.2.1",
|
||||||
"@types/node": "^22.9.1",
|
"@types/node": "^22.9.1",
|
||||||
"eslint": "^9.39.2",
|
"eslint": "^9.39.2",
|
||||||
"typescript": "^5.4.5"
|
"typescript": "^5.4.5"
|
||||||
|
|
|
||||||
1
Frontend-Learner/public/flags/en.svg
Normal file
1
Frontend-Learner/public/flags/en.svg
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 60 30"><clipPath id="a"><path d="M0 0v30h60V0z"/></clipPath><path d="M0 0v30h60V0z" fill="#012169"/><path d="M0 0l60 30m0-30L0 30" stroke="#fff" stroke-width="6"/><path d="M0 0l60 30m0-30L0 30" clip-path="url(#a)" stroke="#C8102E" stroke-width="4"/><path d="M30 0v30M0 15h60" stroke="#fff" stroke-width="10"/><path d="M30 0v30M0 15h60" stroke="#C8102E" stroke-width="6"/></svg>
|
||||||
|
After Width: | Height: | Size: 431 B |
1
Frontend-Learner/public/flags/th.svg
Normal file
1
Frontend-Learner/public/flags/th.svg
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 900 600"><rect width="900" height="600" fill="#A51931"/><rect width="900" height="400" y="100" fill="#F4F5F8"/><rect width="900" height="200" y="200" fill="#2D2A4A"/></svg>
|
||||||
|
After Width: | Height: | Size: 226 B |
9
frontend_management/public/flags/en.svg
Normal file
9
frontend_management/public/flags/en.svg
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 50 30" width="1000" height="600">
|
||||||
|
<clipPath id="t">
|
||||||
|
<path d="M25,15h25v15zv15h-25zh-25v-15zv-15h25z"/>
|
||||||
|
</clipPath>
|
||||||
|
<path d="M0,0v30h50v-30z" fill="#012169"/>
|
||||||
|
<path d="M0,0 50,30M50,0 0,30" stroke="#fff" stroke-width="6"/>
|
||||||
|
<path d="M0,0 50,30M50,0 0,30" clip-path="url(#t)" stroke="#C8102E" stroke-width="4"/>
|
||||||
|
<path d="M-1 11h22v-12h8v12h22v8h-22v12h-8v-12h-22z" fill="#C8102E" stroke="#FFF" stroke-width="2"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 477 B |
6
frontend_management/public/flags/th.svg
Normal file
6
frontend_management/public/flags/th.svg
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="900" height="600">
|
||||||
|
<rect fill="#A51931" width="900" height="600"/>
|
||||||
|
<rect fill="#F4F5F8" y="100" width="900" height="400"/>
|
||||||
|
<rect fill="#2D2A4A" y="200" width="900" height="200"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 254 B |
5
package.json
Normal file
5
package.json
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"devDependencies": {
|
||||||
|
"@nuxtjs/i18n": "^10.2.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue