fix: i18n all settings labels, add ja to language select, dynamic lang options

This commit is contained in:
2026-06-10 15:42:33 +08:00
parent 4c20c6444b
commit 7c1c734572
4 changed files with 55 additions and 18 deletions

View File

@@ -3,7 +3,7 @@ import { useGameStore } from '@/stores/gameStore'
import { useI18n } from '@/composables/useI18n' import { useI18n } from '@/composables/useI18n'
const store = useGameStore() const store = useGameStore()
const { currentLang, setLang } = useI18n() const { t, currentLang, setLang } = useI18n()
const emit = defineEmits<{ const emit = defineEmits<{
close: [] close: []
@@ -11,38 +11,51 @@ const emit = defineEmits<{
const fontSizeOptions = [20, 24, 28, 32] const fontSizeOptions = [20, 24, 28, 32]
const bgAlphaOptions = [0, 0.3, 0.5, 0.7, 0.9] const bgAlphaOptions = [0, 0.3, 0.5, 0.7, 0.9]
const langLabels: Record<string, string> = {
zh: '中文',
en: 'English',
ja: '日本語',
ko: '한국어',
fr: 'Français',
de: 'Deutsch',
es: 'Español',
pt: 'Português',
}
</script> </script>
<template> <template>
<div class="settings-overlay" @click.self="emit('close')" @keydown.escape="emit('close')"> <div class="settings-overlay" @click.self="emit('close')" @keydown.escape="emit('close')">
<div class="settings-panel"> <div class="settings-panel">
<h2 class="settings-title">设置</h2> <h2 class="settings-title">{{ t('ui.settings') }}</h2>
<div class="settings-body"> <div class="settings-body">
<div class="setting-row"> <div class="setting-row" v-if="store.storyLocales.languages.length > 1">
<span class="setting-label">语言</span> <span class="setting-label">{{ t('ui.language') }}</span>
<select :value="currentLang" @change="setLang(($event.target as HTMLSelectElement).value as 'zh' | 'en')"> <select :value="currentLang" @change="setLang(($event.target as HTMLSelectElement).value)">
<option value="zh">中文</option> <option v-for="lang in store.storyLocales.languages" :key="lang" :value="lang">
<option value="en">English</option> {{ langLabels[lang] || lang.toUpperCase() }}
</option>
</select> </select>
</div> </div>
<div class="setting-row"> <div class="setting-row">
<span class="setting-label">字幕字号</span> <span class="setting-label">{{ t('ui.subtitleSize') }}</span>
<select :value="store.subFontSize" @change="store.setSubFontSize(+($event.target as HTMLSelectElement).value)"> <select :value="store.subFontSize" @change="store.setSubFontSize(+($event.target as HTMLSelectElement).value)">
<option v-for="s in fontSizeOptions" :key="s" :value="s">{{ s }}px</option> <option v-for="s in fontSizeOptions" :key="s" :value="s">{{ s }}px</option>
</select> </select>
</div> </div>
<div class="setting-row"> <div class="setting-row">
<span class="setting-label">字幕背景</span> <span class="setting-label">{{ t('ui.subtitleBg') }}</span>
<select :value="store.subBgAlpha" @change="store.setSubBgAlpha(+($event.target as HTMLSelectElement).value)"> <select :value="store.subBgAlpha" @change="store.setSubBgAlpha(+($event.target as HTMLSelectElement).value)">
<option :value="0"></option> <option :value="0">{{ t('ui.none') }}</option>
<option v-for="a in bgAlphaOptions.filter(v => v > 0)" :key="a" :value="a">{{ (a * 100) + '%' }}</option> <option v-for="a in bgAlphaOptions.filter(v => v > 0)" :key="a" :value="a">{{ (a * 100) + '%' }}</option>
</select> </select>
</div> </div>
<div class="setting-row"> <div class="setting-row">
<span class="setting-label">QTE 时限放宽 (×1.5)</span> <span class="setting-label">{{ t('ui.qteTimeRelax') }}</span>
<label class="toggle"> <label class="toggle">
<input type="checkbox" :checked="store.qteTimeRelax" @change="store.setQteTimeRelax(($event.target as HTMLInputElement).checked)" /> <input type="checkbox" :checked="store.qteTimeRelax" @change="store.setQteTimeRelax(($event.target as HTMLInputElement).checked)" />
<span class="toggle-slider"></span> <span class="toggle-slider"></span>
@@ -50,7 +63,7 @@ const bgAlphaOptions = [0, 0.3, 0.5, 0.7, 0.9]
</div> </div>
<div class="setting-row"> <div class="setting-row">
<span class="setting-label">QTE 按键简化仅空格</span> <span class="setting-label">{{ t('ui.qteSingleKey') }}</span>
<label class="toggle"> <label class="toggle">
<input type="checkbox" :checked="store.qteSingleKey" @change="store.setQteSingleKey(($event.target as HTMLInputElement).checked)" /> <input type="checkbox" :checked="store.qteSingleKey" @change="store.setQteSingleKey(($event.target as HTMLInputElement).checked)" />
<span class="toggle-slider"></span> <span class="toggle-slider"></span>
@@ -58,7 +71,7 @@ const bgAlphaOptions = [0, 0.3, 0.5, 0.7, 0.9]
</div> </div>
<div class="setting-row"> <div class="setting-row">
<span class="setting-label">防误触延迟 (0.5s)</span> <span class="setting-label">{{ t('ui.antiMistap') }}</span>
<label class="toggle"> <label class="toggle">
<input type="checkbox" :checked="store.antiMistap" @change="store.setAntiMistap(($event.target as HTMLInputElement).checked)" /> <input type="checkbox" :checked="store.antiMistap" @change="store.setAntiMistap(($event.target as HTMLInputElement).checked)" />
<span class="toggle-slider"></span> <span class="toggle-slider"></span>
@@ -66,7 +79,7 @@ const bgAlphaOptions = [0, 0.3, 0.5, 0.7, 0.9]
</div> </div>
<div class="setting-row"> <div class="setting-row">
<span class="setting-label">可暂停 (P)</span> <span class="setting-label">{{ t('ui.pauseEnabled') }}</span>
<label class="toggle"> <label class="toggle">
<input type="checkbox" :checked="store.pauseEnabled" @change="store.setPauseEnabled(($event.target as HTMLInputElement).checked)" /> <input type="checkbox" :checked="store.pauseEnabled" @change="store.setPauseEnabled(($event.target as HTMLInputElement).checked)" />
<span class="toggle-slider"></span> <span class="toggle-slider"></span>
@@ -74,7 +87,7 @@ const bgAlphaOptions = [0, 0.3, 0.5, 0.7, 0.9]
</div> </div>
</div> </div>
<button class="settings-close" @click="emit('close')">关闭</button> <button class="settings-close" @click="emit('close')">{{ t('ui.close') }}</button>
</div> </div>
</div> </div>
</template> </template>

View File

@@ -26,6 +26,14 @@
"achievements": "Achievements", "achievements": "Achievements",
"gallery": "Gallery", "gallery": "Gallery",
"noAutoSave": "No auto save yet", "noAutoSave": "No auto save yet",
"autoSaveHint": "Game auto-saves to slot 0 at each scene change" "autoSaveHint": "Game auto-saves to slot 0 at each scene change",
"language": "Language",
"subtitleSize": "Subtitle Size",
"subtitleBg": "Subtitle BG",
"qteTimeRelax": "QTE Time Relax",
"qteSingleKey": "QTE Single Key",
"antiMistap": "Anti Mistap",
"pauseEnabled": "Pause Enabled",
"none": "None"
} }
} }

View File

@@ -26,6 +26,14 @@
"achievements": "実績", "achievements": "実績",
"gallery": "ギャラリー", "gallery": "ギャラリー",
"noAutoSave": "オートセーブがありません", "noAutoSave": "オートセーブがありません",
"autoSaveHint": "シーン切替時にスロット0に自動保存されます" "autoSaveHint": "シーン切替時にスロット0に自動保存されます",
"language": "言語",
"subtitleSize": "字幕サイズ",
"subtitleBg": "字幕背景",
"qteTimeRelax": "QTE時間緩和",
"qteSingleKey": "QTE単一キー",
"antiMistap": "誤操作防止",
"pauseEnabled": "一時停止有効",
"none": "なし"
} }
} }

View File

@@ -26,6 +26,14 @@
"achievements": "成就", "achievements": "成就",
"gallery": "画廊", "gallery": "画廊",
"noAutoSave": "暂无自动存档", "noAutoSave": "暂无自动存档",
"autoSaveHint": "游戏会在每次场景切换时自动保存到槽位 0" "autoSaveHint": "游戏会在每次场景切换时自动保存到槽位 0",
"language": "语言",
"subtitleSize": "字幕字号",
"subtitleBg": "字幕背景",
"qteTimeRelax": "QTE 时限放宽",
"qteSingleKey": "QTE 按键简化",
"antiMistap": "防误触延迟",
"pauseEnabled": "可暂停",
"none": "无"
} }
} }