feat(i18n): add localized content for game navbar

This commit is contained in:
neilchen0812 committed 2026-09-22 00:57:39 +09:30
1 parent 013a5acaa7
commit 4a43df9dd9
4 files changed
+38 -19

No files matched your search

@@ -1,4 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { useI18n } from 'vue-i18n'
import { onMounted } from 'vue' import { onMounted } from 'vue'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import { useToast } from 'vue-toastification' import { useToast } from 'vue-toastification'
@@ -8,6 +9,7 @@ import { openBugReport } from '../../utils/formbricks'
import { useSession } from '../../store/session' import { useSession } from '../../store/session'
import useUserProfile from '../../store/userProfile' import useUserProfile from '../../store/userProfile'
const { t } = useI18n()
const userStore = useUserProfile() const userStore = useUserProfile()
const sessionStore = useSession() const sessionStore = useSession()
const router = useRouter() const router = useRouter()
@@ -21,7 +23,7 @@ const handleLogout = async () => {
sessionStore.reset() sessionStore.reset()
router.push({ name: 'login' }) router.push({ name: 'login' })
} catch (err) { } catch (err) {
toast.error('登出失敗') toast.error(t('game_nav.sign_out_failed'))
console.error(err) console.error(err)
} }
} }
@@ -35,7 +37,7 @@ onMounted(async () => {
try { try {
await userStore.loadUserProfile() await userStore.loadUserProfile()
} catch (err) { } catch (err) {
toast.error('無法讀取使用者資料') toast.error(t('game_nav.load_user_profile_failed'))
console.error(err) console.error(err)
} }
}) })
@@ -67,7 +69,7 @@ onMounted(async () => {
{{ userStore.username }} {{ userStore.username }}
</p> </p>
<button <button
title="Survey" :title="t('game_nav.survey')"
target="_blank" target="_blank"
class="md:h-5 md:w-5 px-1.5 w-auto" class="md:h-5 md:w-5 px-1.5 w-auto"
@click="openSurvey" @click="openSurvey"
@@ -76,30 +78,30 @@ onMounted(async () => {
:icon="['fas', 'file-invoice']" :icon="['fas', 'file-invoice']"
class="text-text-primary inline" class="text-text-primary inline"
/> />
<span class="text-text sm:hidden px-2">Survey</span>
</button> </button>
<RouterLink <RouterLink
title="LeaderBoard" :title="t('game_nav.leaderboard')"
to="/leaderboard" to="/leaderboard"
class="md:h-5 md:w-5 px-1.5 w-auto" class="md:h-5 md:w-5 px-1.5 w-auto"
> >
<font-awesome-icon :icon="['fas', 'trophy']" class="text-text-primary" /> <font-awesome-icon :icon="['fas', 'trophy']" class="text-text-primary" />
<span class="text-text sm:hidden px-2">Leader Board</span>
</RouterLink> </RouterLink>
<RouterLink title="Map" to="/map" class="md:h-5 md:w-5 px-1.5 w-auto"> <RouterLink
:title="t('game_nav.map')"
to="/map"
class="md:h-5 md:w-5 px-1.5 w-auto"
>
<font-awesome-icon :icon="['fas', 'map']" class="text-text-primary" /> <font-awesome-icon :icon="['fas', 'map']" class="text-text-primary" />
<span class="text-text sm:hidden px-2">Map</span>
</RouterLink> </RouterLink>
<button <button
title="Bug Report" :title="t('game_nav.bug_report')"
@click="openBugReport" @click="openBugReport"
class="md:h-5 md:w-5 px-1.5 w-auto" class="md:h-5 md:w-5 px-1.5 w-auto"
> >
<font-awesome-icon :icon="['fas', 'bug']" class="text-text-primary" /> <font-awesome-icon :icon="['fas', 'bug']" class="text-text-primary" />
<span class="text-text sm:hidden px-2">Bug Report</span>
</button> </button>
<button <button
title="Sign Out" :title="t('game_nav.sign_out')"
@click="handleLogout" @click="handleLogout"
class="md:h-5 md:w-5 px-1.5 w-auto" class="md:h-5 md:w-5 px-1.5 w-auto"
> >
@@ -107,6 +109,5 @@ onMounted(async () => {
:icon="['fas', 'arrow-right-from-bracket']" :icon="['fas', 'arrow-right-from-bracket']"
class="text-text-primary" class="text-text-primary"
/> />
<span class="text-text sm:hidden px-2">Sign Out</span>
</button> </button>
</template> </template>
@@ -24,7 +24,7 @@ const scrollToSection = (sectionId: string) => {
@click="scrollToSection('intro')" @click="scrollToSection('intro')"
style="font-size: 2vh" style="font-size: 2vh"
> >
{{ t('nav.intro') }} {{ t('landing_nav.intro') }}
</button> </button>
<button <button
@@ -33,7 +33,7 @@ const scrollToSection = (sectionId: string) => {
@click="scrollToSection('feature')" @click="scrollToSection('feature')"
style="font-size: 2vh" style="font-size: 2vh"
> >
{{ t('nav.features') }} {{ t('landing_nav.features') }}
</button> </button>
<button <button
@@ -42,7 +42,7 @@ const scrollToSection = (sectionId: string) => {
@click="scrollToSection('about')" @click="scrollToSection('about')"
style="font-size: 2vh" style="font-size: 2vh"
> >
{{ t('nav.about') }} {{ t('landing_nav.about') }}
</button> </button>
<button <button
@@ -51,7 +51,7 @@ const scrollToSection = (sectionId: string) => {
@click="scrollToSection('contact')" @click="scrollToSection('contact')"
style="font-size: 2vh" style="font-size: 2vh"
> >
{{ t('nav.contact') }} {{ t('landing_nav.contact') }}
</button> </button>
<RouterLink <RouterLink
@@ -60,11 +60,11 @@ const scrollToSection = (sectionId: string) => {
class="text-text inline-block font-bold whitespace-nowrap pt-1 px-2 hover:text-text-primary" class="text-text inline-block font-bold whitespace-nowrap pt-1 px-2 hover:text-text-primary"
style="font-size: 2vh" style="font-size: 2vh"
> >
{{ t('nav.login') }} {{ t('landing_nav.login') }}
</RouterLink> </RouterLink>
<a <a
:title="t('nav.report_bug')" :title="t('landing_nav.report_bug')"
:href="bugReportUrl" :href="bugReportUrl"
target="_blank" target="_blank"
class="h-5 w-5" class="h-5 w-5"
+9
View File
@@ -65,5 +65,14 @@
"invalid_password": "Invalid password", "invalid_password": "Invalid password",
"username_taken": "Username is already taken", "username_taken": "Username is already taken",
"email_taken": "Email is already taken" "email_taken": "Email is already taken"
},
"game_nav": {
"survey": "Survey",
"leaderboard": "Leaderboard",
"map": "Map",
"bug_report": "Bug Report",
"sign_out": "Sign Out",
"sign_out_failed": "Sign Out Failed",
"load_user_profile_failed": "Failed to Load User Profile"
} }
} }
+10 -1
View File
@@ -4,7 +4,7 @@
"traditional_chinese": "繁體中文", "traditional_chinese": "繁體中文",
"english": "English" "english": "English"
}, },
"nav": { "landing_nav": {
"intro": "前言", "intro": "前言",
"features": "特色", "features": "特色",
"about": "關於", "about": "關於",
@@ -65,5 +65,14 @@
"invalid_password": "無效的密碼", "invalid_password": "無效的密碼",
"username_taken": "帳號名稱已被使用", "username_taken": "帳號名稱已被使用",
"email_taken": "電子郵件已被使用" "email_taken": "電子郵件已被使用"
},
"game_nav": {
"survey": "問卷",
"leaderboard": "排行榜",
"map": "地圖",
"bug_report": "回報錯誤",
"sign_out": "登出",
"sign_out_failed": "登出失敗",
"load_user_profile_failed": "無法讀取使用者資料"
} }
} }