forked from akanyan/STARTLINER
feat: internationalization
This commit is contained in:
@ -12,6 +12,9 @@ import { invoke } from '../../invoke';
|
||||
import { usePkgStore, usePrfStore } from '../../stores';
|
||||
import { Feature } from '../../types';
|
||||
import { hasFeature, pkgKey } from '../../util';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const pkgs = usePkgStore();
|
||||
const prf = usePrfStore();
|
||||
@ -60,14 +63,18 @@ load();
|
||||
<template>
|
||||
<OptionCategory title="Aime">
|
||||
<OptionRow
|
||||
title="Aime type"
|
||||
tooltip="Additional Aime plugins can be downloaded from the package store."
|
||||
:title="t('cfg.aime.type')"
|
||||
:tooltip="
|
||||
t('cfg.segatools.installTooltip', {
|
||||
thing: t('cfg.aime.modules'),
|
||||
})
|
||||
"
|
||||
>
|
||||
<Select
|
||||
v-model="prf.current!.data.sgt.aime"
|
||||
:options="[
|
||||
{ title: 'hardware', value: 'Disabled' },
|
||||
{ title: 'segatools built-in emulation', value: 'BuiltIn' },
|
||||
{ title: t('cfg.hardware'), value: 'Disabled' },
|
||||
{ title: t('cfg.segatools.builtIn'), value: 'BuiltIn' },
|
||||
...pkgs.byFeature(Feature.Aime).map((p) => {
|
||||
return {
|
||||
title: pkgKey(p),
|
||||
@ -83,8 +90,8 @@ load();
|
||||
></Select>
|
||||
</OptionRow>
|
||||
<OptionRow
|
||||
title="Aime code"
|
||||
tooltip="Only applicable with the segatools built-in emulation or with compatible third-party packages"
|
||||
:title="t('cfg.aime.code')"
|
||||
:tooltip="t('cfg.aime.codeTooltip')"
|
||||
v-if="prf.current!.data.sgt.aime !== 'Disabled'"
|
||||
>
|
||||
<InputText
|
||||
@ -97,7 +104,7 @@ load();
|
||||
/>
|
||||
</OptionRow>
|
||||
<div v-if="prf.current!.data.sgt.aime?.hasOwnProperty('AMNet')">
|
||||
<OptionRow title="Server name">
|
||||
<OptionRow :title="t('cfg.aime.serverName')">
|
||||
<InputText
|
||||
class="shrink"
|
||||
size="small"
|
||||
@ -106,7 +113,7 @@ load();
|
||||
v-model="prf.current!.data.sgt.amnet.name"
|
||||
/>
|
||||
</OptionRow>
|
||||
<OptionRow title="Server address">
|
||||
<OptionRow :title="t('cfg.network.address')">
|
||||
<InputText
|
||||
class="shrink"
|
||||
size="small"
|
||||
@ -116,22 +123,21 @@ load();
|
||||
/>
|
||||
</OptionRow>
|
||||
<OptionRow
|
||||
title="Use AiMeDB for physical cards"
|
||||
tooltip="Whether physical cards should use AiMeDB to retrieve access codes. If the game is using a hosted network, enable this option to load the same account data/profile as you would get on a physical cab."
|
||||
:title="t('cfg.aime.aimedb')"
|
||||
:tooltip="t('cfg.aime.aimedbTooltip')"
|
||||
>
|
||||
<ToggleSwitch v-model="prf.current!.data.sgt.amnet.physical" />
|
||||
</OptionRow>
|
||||
</div>
|
||||
<OptionRow
|
||||
title="Aime serial port"
|
||||
tooltip="Ports can be checked in Devices and Printers or at googlechromelabs.github.io/serial-terminal
|
||||
For AIC Pico, the AIME port should be selected."
|
||||
:title="t('cfg.aime.serialPort')"
|
||||
:tooltip="t('cfg.aime.serialPortTooltip')"
|
||||
v-if="prf.current!.data.sgt.aime === 'Disabled'"
|
||||
>
|
||||
<Select
|
||||
v-model="prf.current!.data.sgt.aime_port"
|
||||
:options="[
|
||||
{ title: 'default', value: null },
|
||||
{ title: t('default'), value: null },
|
||||
...Object.entries(coms ?? {}).map(([title, value]) => {
|
||||
return {
|
||||
title,
|
||||
@ -139,7 +145,7 @@ load();
|
||||
};
|
||||
}),
|
||||
]"
|
||||
placeholder="default"
|
||||
:placeholder="t('default')"
|
||||
option-label="title"
|
||||
option-value="value"
|
||||
></Select>
|
||||
|
@ -8,11 +8,14 @@ import OptionCategory from '../OptionCategory.vue';
|
||||
import OptionRow from '../OptionRow.vue';
|
||||
import { invoke } from '../../invoke';
|
||||
import { usePrfStore } from '../../stores';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const capabilities: Ref<string[]> = ref([]);
|
||||
const displayList: Ref<{ title: string; value: string }[]> = ref([
|
||||
{
|
||||
title: 'Primary',
|
||||
title: t('cfg.display.primary'),
|
||||
value: 'default',
|
||||
},
|
||||
]);
|
||||
@ -25,7 +28,7 @@ const extraDisplayOptionsDisabled = computed(() => {
|
||||
const loadDisplays = () => {
|
||||
const newList = [
|
||||
{
|
||||
title: 'Primary',
|
||||
title: t('cfg.display.primary'),
|
||||
value: 'default',
|
||||
},
|
||||
];
|
||||
@ -74,7 +77,7 @@ const canSkipPrimarySwitch = game === 'ongeki';
|
||||
<OptionCategory title="Display">
|
||||
<OptionRow
|
||||
v-if="capabilities.includes('display')"
|
||||
title="Target display"
|
||||
:title="t('cfg.display.target')"
|
||||
>
|
||||
<Select
|
||||
v-model="prf.current!.data.display.target"
|
||||
@ -108,7 +111,7 @@ const canSkipPrimarySwitch = game === 'ongeki';
|
||||
v-model="prf.current!.data.display.rez[1]"
|
||||
/>
|
||||
</OptionRow>
|
||||
<OptionRow title="Display mode">
|
||||
<OptionRow :title="t('cfg.display.mode')">
|
||||
<SelectButton
|
||||
v-model="prf.current!.data.display.mode"
|
||||
:options="[
|
||||
@ -122,7 +125,7 @@ const canSkipPrimarySwitch = game === 'ongeki';
|
||||
/>
|
||||
</OptionRow>
|
||||
<OptionRow
|
||||
title="Display rotation"
|
||||
:title="t('cfg.display.rotation')"
|
||||
v-if="capabilities.includes('display')"
|
||||
>
|
||||
<SelectButton
|
||||
@ -130,12 +133,18 @@ const canSkipPrimarySwitch = game === 'ongeki';
|
||||
:options="
|
||||
isVertical
|
||||
? [
|
||||
{ title: 'Portrait', value: 90 },
|
||||
{ title: 'Portrait (flipped)', value: 270 },
|
||||
{ title: t('cfg.display.portrait'), value: 90 },
|
||||
{
|
||||
title: `${t('cfg.display.portrait')} (${t('cfg.display.flipped')})`,
|
||||
value: 270,
|
||||
},
|
||||
]
|
||||
: [
|
||||
{ title: 'Landscape', value: 0 },
|
||||
{ title: 'Landscape (flipped)', value: 180 },
|
||||
{ title: t('cfg.display.landscape'), value: 0 },
|
||||
{
|
||||
title: `${t('cfg.display.landscape')} (${t('cfg.display.flipped')})`,
|
||||
value: 180,
|
||||
},
|
||||
]
|
||||
"
|
||||
:allow-empty="true"
|
||||
@ -147,7 +156,7 @@ const canSkipPrimarySwitch = game === 'ongeki';
|
||||
<OptionRow
|
||||
v-if="capabilities.includes('display')"
|
||||
class="number-input"
|
||||
title="Refresh Rate"
|
||||
:title="t('cfg.display.refreshRate')"
|
||||
>
|
||||
<InputNumber
|
||||
v-if="game === 'ongeki'"
|
||||
@ -173,9 +182,9 @@ const canSkipPrimarySwitch = game === 'ongeki';
|
||||
/>
|
||||
</OptionRow>
|
||||
<OptionRow
|
||||
title="Borderless fullscreen"
|
||||
:title="t('cfg.display.borderlessFullscreen')"
|
||||
v-if="capabilities.includes('display')"
|
||||
tooltip="Match display resolution with the game."
|
||||
:tooltip="t('cfg.display.borderlessFullscreenTooltip')"
|
||||
>
|
||||
<ToggleSwitch
|
||||
:disabled="
|
||||
@ -186,7 +195,7 @@ const canSkipPrimarySwitch = game === 'ongeki';
|
||||
/>
|
||||
</OptionRow>
|
||||
<OptionRow
|
||||
title="Skip switching primary display"
|
||||
:title="t('cfg.display.dontSwitchPrimary')"
|
||||
v-if="
|
||||
capabilities.includes('display') &&
|
||||
prf.current?.data.display.target !== 'default' &&
|
||||
@ -194,7 +203,7 @@ const canSkipPrimarySwitch = game === 'ongeki';
|
||||
displayList.length > 2) &&
|
||||
canSkipPrimarySwitch
|
||||
"
|
||||
dangerous-tooltip="Only enable this option if switching the primary display causes issues. The monitors must have a matching refresh rate."
|
||||
:dangerous-tooltip="t('cfg.display.dontSwitchPrimaryTooltip')"
|
||||
>
|
||||
<ToggleSwitch
|
||||
:disabled="extraDisplayOptionsDisabled"
|
||||
@ -202,7 +211,7 @@ const canSkipPrimarySwitch = game === 'ongeki';
|
||||
/>
|
||||
</OptionRow>
|
||||
<OptionRow
|
||||
title="Display index"
|
||||
:title="t('cfg.display.index')"
|
||||
class="number-input"
|
||||
v-if="
|
||||
capabilities.includes('display') &&
|
||||
|
@ -5,27 +5,27 @@ import KeyboardKey from '../KeyboardKey.vue';
|
||||
import OptionCategory from '../OptionCategory.vue';
|
||||
import OptionRow from '../OptionRow.vue';
|
||||
import { usePrfStore } from '../../stores';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const prf = usePrfStore();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<OptionCategory title="Keyboard">
|
||||
<OptionRow
|
||||
title="Enable"
|
||||
tooltip="Only applicable if the IO module is set to segatools built-in (keyboard) or a compatible third-party module (like mu3io.NET)"
|
||||
>
|
||||
<OptionCategory :title="t('cfg.keyboard.title')">
|
||||
<OptionRow :title="t('enable')" :tooltip="t('cfg.keyboard.tooltip')">
|
||||
<ToggleSwitch v-model="prf.current!.data.keyboard!.data.enabled" />
|
||||
</OptionRow>
|
||||
<OptionRow
|
||||
title="Lever mode"
|
||||
:title="t('cfg.keyboard.leverMode')"
|
||||
v-if="prf.current!.data.keyboard!.game === 'Ongeki'"
|
||||
>
|
||||
<SelectButton
|
||||
v-model="prf.current!.data.keyboard!.data.use_mouse"
|
||||
:options="[
|
||||
{ title: 'XInput', value: false },
|
||||
{ title: 'Mouse', value: true },
|
||||
{ title: t('cfg.keyboard.mouse'), value: true },
|
||||
]"
|
||||
:allow-empty="false"
|
||||
option-label="title"
|
||||
|
@ -4,18 +4,24 @@ import FileEditor from '../FileEditor.vue';
|
||||
import OptionCategory from '../OptionCategory.vue';
|
||||
import OptionRow from '../OptionRow.vue';
|
||||
import { usePrfStore } from '../../stores';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const prf = usePrfStore();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<OptionCategory title="Misc">
|
||||
<OptionRow title="OpenSSL bug workaround for Intel ≥10th gen">
|
||||
<OptionCategory :title="t('cfg.misc.title')">
|
||||
<OptionRow
|
||||
:title="t('cfg.misc.intel')"
|
||||
:dangerous-tooltip="t('cfg.misc.intelTooltip')"
|
||||
>
|
||||
<ToggleSwitch v-model="prf.current!.data.sgt.intel" />
|
||||
</OptionRow>
|
||||
<OptionRow
|
||||
title="More segatools options"
|
||||
tooltip="Advanced options not covered by STARTLINER"
|
||||
:title="t('cfg.misc.other')"
|
||||
:tooltip="t('cfg.misc.otherTooltip')"
|
||||
>
|
||||
<!-- <Button icon="pi pi-refresh" size="small" /> -->
|
||||
<FileEditor filename="segatools-base.ini" />
|
||||
|
@ -6,18 +6,21 @@ import FilePicker from '../FilePicker.vue';
|
||||
import OptionCategory from '../OptionCategory.vue';
|
||||
import OptionRow from '../OptionRow.vue';
|
||||
import { usePrfStore } from '../../stores';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const prf = usePrfStore();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<OptionCategory title="Network">
|
||||
<OptionRow title="Network type">
|
||||
<OptionCategory :title="t('cfg.network.title')">
|
||||
<OptionRow :title="t('cfg.network.type')">
|
||||
<SelectButton
|
||||
v-model="prf.current!.data.network.network_type"
|
||||
:options="[
|
||||
{ title: 'Remote', value: 'Remote' },
|
||||
{ title: 'Local (ARTEMiS)', value: 'Artemis' },
|
||||
{ title: t('cfg.network.remote'), value: 'Remote' },
|
||||
{ title: t('cfg.network.localArtemis'), value: 'Artemis' },
|
||||
]"
|
||||
:allow-empty="false"
|
||||
option-label="title"
|
||||
@ -25,8 +28,8 @@ const prf = usePrfStore();
|
||||
/>
|
||||
</OptionRow>
|
||||
<OptionRow
|
||||
v-if="prf.current!.data.network.network_type == 'Artemis'"
|
||||
title="ARTEMiS path"
|
||||
v-if="prf.current!.data.network.network_type === 'Artemis'"
|
||||
:title="t('cfg.network.artemisPath')"
|
||||
>
|
||||
<FilePicker
|
||||
:directory="false"
|
||||
@ -47,7 +50,7 @@ const prf = usePrfStore();
|
||||
</OptionRow> -->
|
||||
<OptionRow
|
||||
v-if="prf.current!.data.network.network_type == 'Remote'"
|
||||
title="Server address"
|
||||
:title="t('cfg.network.address')"
|
||||
>
|
||||
<InputText
|
||||
class="shrink"
|
||||
@ -58,7 +61,7 @@ const prf = usePrfStore();
|
||||
/> </OptionRow
|
||||
><OptionRow
|
||||
v-if="prf.current!.data.network.network_type == 'Remote'"
|
||||
title="Keychip"
|
||||
:title="t('cfg.network.keychip')"
|
||||
>
|
||||
<InputText
|
||||
class="shrink"
|
||||
@ -67,7 +70,7 @@ const prf = usePrfStore();
|
||||
placeholder="A123-01234567890"
|
||||
v-model="prf.current!.data.network.keychip"
|
||||
/> </OptionRow
|
||||
><OptionRow title="Subnet">
|
||||
><OptionRow :title="t('cfg.network.subnet')">
|
||||
<InputText
|
||||
class="shrink"
|
||||
size="small"
|
||||
@ -76,7 +79,7 @@ const prf = usePrfStore();
|
||||
v-model="prf.current!.data.network.subnet"
|
||||
/>
|
||||
</OptionRow>
|
||||
<OptionRow title="Address suffix">
|
||||
<OptionRow :title="t('cfg.network.addrSuffix')">
|
||||
<InputNumber
|
||||
class="shrink"
|
||||
size="small"
|
||||
|
@ -11,6 +11,9 @@ import { invoke } from '../../invoke';
|
||||
import { usePkgStore, usePrfStore } from '../../stores';
|
||||
import { Feature } from '../../types';
|
||||
import { pkgKey } from '../../util';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const prf = usePrfStore();
|
||||
const pkgs = usePkgStore();
|
||||
@ -54,10 +57,10 @@ const checkSegatoolsIni = async (target: string) => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<OptionCategory title="General">
|
||||
<OptionCategory :title="t('cfg.segatools.general')">
|
||||
<OptionRow
|
||||
:title="names.exe"
|
||||
tooltip="STARTLINER expects unpacked executables put into otherwise clean data."
|
||||
:tooltip="t('cfg.segatools.targetTooltip')"
|
||||
>
|
||||
<FilePicker
|
||||
:directory="false"
|
||||
@ -104,7 +107,11 @@ const checkSegatoolsIni = async (target: string) => {
|
||||
</OptionRow>
|
||||
<OptionRow
|
||||
:title="names.hook"
|
||||
tooltip="Hooks can be downloaded from the package store."
|
||||
:tooltip="
|
||||
t('cfg.segatools.installTooltip', {
|
||||
thing: t('cfg.segatools.hooks'),
|
||||
})
|
||||
"
|
||||
>
|
||||
<Select
|
||||
v-model="prf.current!.data.sgt.hook"
|
||||
@ -126,7 +133,11 @@ const checkSegatoolsIni = async (target: string) => {
|
||||
</OptionRow>
|
||||
<OptionRow
|
||||
:title="names.io"
|
||||
tooltip="IO plugins can be downloaded from the package store."
|
||||
:tooltip="
|
||||
t('cfg.segatools.installTooltip', {
|
||||
thing: t('cfg.segatools.ioModules'),
|
||||
})
|
||||
"
|
||||
>
|
||||
<Select
|
||||
v-model="prf.current!.data.sgt.io2"
|
||||
|
@ -1,92 +1,43 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue';
|
||||
import SelectButton from 'primevue/selectbutton';
|
||||
import ToggleSwitch from 'primevue/toggleswitch';
|
||||
import OptionCategory from '../OptionCategory.vue';
|
||||
import OptionRow from '../OptionRow.vue';
|
||||
import { useClientStore } from '../../stores';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const client = useClientStore();
|
||||
|
||||
const offlineModel = computed({
|
||||
get() {
|
||||
return client.offlineMode;
|
||||
},
|
||||
async set(value: boolean) {
|
||||
await client.setOfflineMode(value);
|
||||
},
|
||||
});
|
||||
|
||||
const updatesModel = computed({
|
||||
get() {
|
||||
return client.enableAutoupdates;
|
||||
},
|
||||
async set(value: boolean) {
|
||||
await client.setAutoupdates(value);
|
||||
},
|
||||
});
|
||||
|
||||
const verboseModel = computed({
|
||||
get() {
|
||||
return client.verbose;
|
||||
},
|
||||
async set(value: boolean) {
|
||||
await client.setVerbose(value);
|
||||
},
|
||||
});
|
||||
|
||||
const themeModel = computed({
|
||||
get() {
|
||||
return client.theme;
|
||||
},
|
||||
async set(value: 'light' | 'dark' | 'system') {
|
||||
await client.setTheme(value);
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<OptionCategory title="STARTLINER">
|
||||
<OptionRow title="UI scaling">
|
||||
<SelectButton
|
||||
v-model="client.scaleModel"
|
||||
:options="[
|
||||
{ title: 'S', value: 's' },
|
||||
{ title: 'M', value: 'm' },
|
||||
{ title: 'L', value: 'l' },
|
||||
{ title: 'XL', value: 'xl' },
|
||||
]"
|
||||
:allow-empty="false"
|
||||
option-label="title"
|
||||
option-value="value"
|
||||
<OptionRow
|
||||
:title="t('cfg.startliner.offlineMode')"
|
||||
:tooltip="`${t('cfg.startliner.offlineModeTooltip')} ${t('cfg.afterRestart')}`"
|
||||
>
|
||||
<ToggleSwitch
|
||||
:model-value="client.offlineMode"
|
||||
@update:model-value="
|
||||
async (v) => await client.setOfflineMode(v)
|
||||
"
|
||||
/>
|
||||
</OptionRow>
|
||||
<OptionRow
|
||||
title="Offline mode"
|
||||
tooltip="Disables the package store. Applies after a restart."
|
||||
>
|
||||
<ToggleSwitch v-model="offlineModel" />
|
||||
</OptionRow>
|
||||
<OptionRow title="Enable automatic updates">
|
||||
<ToggleSwitch v-model="updatesModel" />
|
||||
<OptionRow :title="t('cfg.startliner.autoUpdate')">
|
||||
<ToggleSwitch
|
||||
:model-value="client.enableAutoupdates"
|
||||
@update:model-value="
|
||||
async (v) => await client.setAutoupdates(v)
|
||||
"
|
||||
></ToggleSwitch>
|
||||
</OptionRow>
|
||||
<OptionRow
|
||||
title="Enable detailed logs"
|
||||
tooltip="Applies after a restart."
|
||||
:title="t('cfg.startliner.verbose')"
|
||||
:tooltip="t('cfg.afterRestart')"
|
||||
>
|
||||
<ToggleSwitch v-model="verboseModel" />
|
||||
</OptionRow>
|
||||
<OptionRow title="Theme">
|
||||
<SelectButton
|
||||
v-model="themeModel"
|
||||
:options="[
|
||||
{ title: 'System', value: 'system' },
|
||||
{ title: 'Light', value: 'light' },
|
||||
{ title: 'Dark', value: 'dark' },
|
||||
]"
|
||||
:allow-empty="false"
|
||||
option-label="title"
|
||||
option-value="value"
|
||||
<ToggleSwitch
|
||||
:model-value="client.verbose"
|
||||
@update:model-value="async (v) => await client.setVerbose(v)"
|
||||
/>
|
||||
</OptionRow>
|
||||
</OptionCategory>
|
||||
|
Reference in New Issue
Block a user