feat(settings/options/language): implement language selection menu

This commit is contained in:
2026-01-14 21:20:22 +01:00
parent 5dd43c7814
commit d78abd59c9
10 changed files with 124 additions and 4 deletions

View File

@@ -1,13 +1,120 @@
<script setup lang="ts">
const { locales, locale, setLocale } = useI18n();
const store = useSettingsStore();
const confirmationModal = useConfirmationModal();
const { assets } = useAssets();
const { onRender } = useScreen();
const BUTTON_KEYS = [
"english",
"german",
"french",
"spanish",
"italian",
"japanese",
] as const;
const BUTTON_POSITIONS = [
[15, 32],
[143, 32],
[15, 80],
[143, 80],
[15, 128],
[143, 128],
] as const;
const { selected, selectorPosition } = useButtonNavigation({
buttons: {
english: [10, 27, 106, 41],
german: [138, 27, 106, 41],
french: [10, 75, 106, 41],
spanish: [138, 75, 106, 41],
italian: [10, 123, 106, 41],
japanese: [138, 123, 106, 41],
},
initialButton:
BUTTON_KEYS[locales.value.findIndex((l) => l.code === locale.value)] ??
BUTTON_KEYS[0]!,
navigation: {
english: {
right: "german",
down: "french",
},
german: {
left: "english",
down: "spanish",
},
french: {
up: "english",
right: "spanish",
down: "italian",
},
spanish: {
up: "german",
left: "french",
down: "japanese",
},
italian: {
up: "french",
right: "japanese",
},
japanese: {
up: "spanish",
left: "italian",
},
},
});
const handleCancel = () => {
store.closeSubMenu();
};
const handleConfirm = () => {
const selectedLocale = locales.value[BUTTON_KEYS.indexOf(selected.value)]!;
setLocale(selectedLocale.code);
confirmationModal.open({
text: $t(
"settings.options.language.confirmation",
{},
{ locale: selectedLocale.code },
),
onClosed: () => store.closeSubMenu(),
});
// TODO: add "timeout" to confirmationModal.open
setTimeout(() => confirmationModal.close(), 2000);
};
onRender((ctx) => {
ctx.font = "10px NDS10";
ctx.fillStyle = "#000000";
ctx.fillText("Language", 10, 20);
ctx.fillStyle = "#010101";
for (let i = 0; i < locales.value.length; i += 1) {
const [x, y] = BUTTON_POSITIONS[i]!;
const isSelected = selected.value === BUTTON_KEYS[i];
const buttonImage = isSelected
? assets.images.settings.bottomScreen.options.languageButtonActive
: assets.images.settings.bottomScreen.options.languageButton;
buttonImage.draw(ctx, x, y, isSelected ? { colored: true } : undefined);
fillTextHCentered(ctx, locales.value[i].name, x, y + 20, 96);
}
});
defineOptions({
render: () => null,
});
</script>
<template>
<CommonButtons
:y-offset="0"
b-label="Cancel"
a-label="Confirm"
@activate-b="handleCancel"
@activate-a="handleConfirm"
/>
<CommonButtonSelector :rect="selectorPosition" />
</template>

1
i18n/locales/de.json Normal file
View File

@@ -0,0 +1 @@
{}

View File

@@ -23,7 +23,8 @@
},
"language": {
"title": "Language",
"description": "Select the language to use."
"description": "Select the language to use.",
"confirmation": "Language set to English."
},
"gbaMode": {
"title": "GBA Mode",

1
i18n/locales/es.json Normal file
View File

@@ -0,0 +1 @@
{}

1
i18n/locales/fr.json Normal file
View File

@@ -0,0 +1 @@
{}

1
i18n/locales/it.json Normal file
View File

@@ -0,0 +1 @@
{}

1
i18n/locales/ja.json Normal file
View File

@@ -0,0 +1 @@
{}

View File

@@ -20,7 +20,14 @@ export default defineNuxtConfig({
},
i18n: {
strategy: "no_prefix",
locales: [{ code: "en", language: "en-US", file: "en.json" }],
locales: [
{ code: "en", language: "en-US", name: "English", file: "en.json" },
{ code: "de", language: "de-DE", name: "Deutsch", file: "de.json" },
{ code: "fr", language: "fr-FR", name: "Français", file: "fr.json" },
{ code: "es", language: "es-ES", name: "Español", file: "es.json" },
{ code: "it", language: "it-IT", name: "Italiano", file: "it.json" },
{ code: "ja", language: "ja-JP", name: "日本語", file: "ja.json" },
],
defaultLocale: "en",
},
image: {

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 B