Added language setting (#185)
* Added language setting * Allow properly changing language --------- Co-authored-by: Flashfyre <flashfireex@gmail.com>pull/189/head
parent
86da18943d
commit
95d2ad2fb4
|
@ -15,7 +15,7 @@ import { GameData, PlayerGender } from './system/game-data';
|
||||||
import StarterSelectUiHandler from './ui/starter-select-ui-handler';
|
import StarterSelectUiHandler from './ui/starter-select-ui-handler';
|
||||||
import { TextStyle, addTextObject } from './ui/text';
|
import { TextStyle, addTextObject } from './ui/text';
|
||||||
import { Moves } from "./data/enums/moves";
|
import { Moves } from "./data/enums/moves";
|
||||||
import { } from "./data/move";
|
import { allMoves } from "./data/move";
|
||||||
import { initMoves } from './data/move';
|
import { initMoves } from './data/move';
|
||||||
import { ModifierPoolType, getDefaultModifierTypeForTier, getEnemyModifierTypesForWave } from './modifier/modifier-type';
|
import { ModifierPoolType, getDefaultModifierTypeForTier, getEnemyModifierTypesForWave } from './modifier/modifier-type';
|
||||||
import AbilityBar from './ui/ability-bar';
|
import AbilityBar from './ui/ability-bar';
|
||||||
|
@ -58,6 +58,7 @@ import { UiTheme } from './enums/ui-theme';
|
||||||
import { SceneBase } from './scene-base';
|
import { SceneBase } from './scene-base';
|
||||||
import CandyBar from './ui/candy-bar';
|
import CandyBar from './ui/candy-bar';
|
||||||
import { Variant, variantData } from './data/variant';
|
import { Variant, variantData } from './data/variant';
|
||||||
|
import { Localizable } from './plugins/i18n';
|
||||||
|
|
||||||
export const bypassLogin = import.meta.env.VITE_BYPASS_LOGIN === "1";
|
export const bypassLogin = import.meta.env.VITE_BYPASS_LOGIN === "1";
|
||||||
|
|
||||||
|
@ -454,7 +455,7 @@ export default class BattleScene extends SceneBase {
|
||||||
hideOnComplete: true
|
hideOnComplete: true
|
||||||
});
|
});
|
||||||
|
|
||||||
this.reset();
|
this.reset(false, false, true);
|
||||||
|
|
||||||
const ui = new UI(this);
|
const ui = new UI(this);
|
||||||
this.uiContainer.add(ui);
|
this.uiContainer.add(ui);
|
||||||
|
@ -738,7 +739,7 @@ export default class BattleScene extends SceneBase {
|
||||||
return this.currentBattle.randSeedInt(this, range, min);
|
return this.currentBattle.randSeedInt(this, range, min);
|
||||||
}
|
}
|
||||||
|
|
||||||
reset(clearScene: boolean = false, clearData: boolean = false): void {
|
reset(clearScene: boolean = false, clearData: boolean = false, reloadI18n: boolean = false): void {
|
||||||
if (clearData)
|
if (clearData)
|
||||||
this.gameData = new GameData(this);
|
this.gameData = new GameData(this);
|
||||||
|
|
||||||
|
@ -791,7 +792,13 @@ export default class BattleScene extends SceneBase {
|
||||||
|
|
||||||
this.trainer.setTexture(`trainer_${this.gameData.gender === PlayerGender.FEMALE ? 'f' : 'm'}_back`);
|
this.trainer.setTexture(`trainer_${this.gameData.gender === PlayerGender.FEMALE ? 'f' : 'm'}_back`);
|
||||||
this.trainer.setPosition(406, 186);
|
this.trainer.setPosition(406, 186);
|
||||||
this.trainer.setVisible(true)
|
this.trainer.setVisible(true);
|
||||||
|
|
||||||
|
if (reloadI18n) {
|
||||||
|
const localizable: Localizable[] = [ ...allMoves ];
|
||||||
|
for (let item of localizable)
|
||||||
|
item.localize();
|
||||||
|
}
|
||||||
|
|
||||||
if (clearScene) {
|
if (clearScene) {
|
||||||
this.fadeOutBgm(250, false);
|
this.fadeOutBgm(250, false);
|
||||||
|
|
|
@ -24,7 +24,7 @@ import { Species } from "./enums/species";
|
||||||
import { ModifierPoolType } from "#app/modifier/modifier-type";
|
import { ModifierPoolType } from "#app/modifier/modifier-type";
|
||||||
import { Command } from "../ui/command-ui-handler";
|
import { Command } from "../ui/command-ui-handler";
|
||||||
import { Biome } from "./enums/biome";
|
import { Biome } from "./enums/biome";
|
||||||
import i18next from '../plugins/i18n';
|
import i18next, { Localizable } from '../plugins/i18n';
|
||||||
|
|
||||||
export enum MoveCategory {
|
export enum MoveCategory {
|
||||||
PHYSICAL,
|
PHYSICAL,
|
||||||
|
@ -75,7 +75,7 @@ export enum MoveFlags {
|
||||||
type MoveConditionFunc = (user: Pokemon, target: Pokemon, move: Move) => boolean;
|
type MoveConditionFunc = (user: Pokemon, target: Pokemon, move: Move) => boolean;
|
||||||
type UserMoveConditionFunc = (user: Pokemon, move: Move) => boolean;
|
type UserMoveConditionFunc = (user: Pokemon, move: Move) => boolean;
|
||||||
|
|
||||||
export default class Move {
|
export default class Move implements Localizable {
|
||||||
public id: Moves;
|
public id: Moves;
|
||||||
public name: string;
|
public name: string;
|
||||||
public type: Type;
|
public type: Type;
|
||||||
|
@ -97,14 +97,14 @@ export default class Move {
|
||||||
|
|
||||||
const i18nKey = Moves[id].split('_').filter(f => f).map((f, i) => i ? `${f[0]}${f.slice(1).toLowerCase()}` : f.toLowerCase()).join('') as unknown as string;
|
const i18nKey = Moves[id].split('_').filter(f => f).map((f, i) => i ? `${f[0]}${f.slice(1).toLowerCase()}` : f.toLowerCase()).join('') as unknown as string;
|
||||||
|
|
||||||
this.name = id ? i18next.t(`move:${i18nKey}.name`) as string : '';
|
this.name = id ? i18next.t(`move:${i18nKey}.name`).toString() : '';
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.category = category;
|
this.category = category;
|
||||||
this.moveTarget = defaultMoveTarget;
|
this.moveTarget = defaultMoveTarget;
|
||||||
this.power = power;
|
this.power = power;
|
||||||
this.accuracy = accuracy;
|
this.accuracy = accuracy;
|
||||||
this.pp = pp;
|
this.pp = pp;
|
||||||
this.effect = id ? i18next.t(`move:${i18nKey}.effect`) as string : '';
|
this.effect = id ? i18next.t(`move:${i18nKey}.effect`).toString() : '';
|
||||||
this.chance = chance;
|
this.chance = chance;
|
||||||
this.priority = priority;
|
this.priority = priority;
|
||||||
this.generation = generation;
|
this.generation = generation;
|
||||||
|
@ -119,6 +119,13 @@ export default class Move {
|
||||||
this.setFlag(MoveFlags.MAKES_CONTACT, true);
|
this.setFlag(MoveFlags.MAKES_CONTACT, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
localize() {
|
||||||
|
const i18nKey = Moves[this.id].split('_').filter(f => f).map((f, i) => i ? `${f[0]}${f.slice(1).toLowerCase()}` : f.toLowerCase()).join('') as unknown as string;
|
||||||
|
|
||||||
|
this.name = this.id ? i18next.t(`move:${i18nKey}.name`).toString() : '';
|
||||||
|
this.effect = this.id ? i18next.t(`move:${i18nKey}.effect`).toString() : '';
|
||||||
|
}
|
||||||
|
|
||||||
getAttrs(attrType: { new(...args: any[]): MoveAttr }): MoveAttr[] {
|
getAttrs(attrType: { new(...args: any[]): MoveAttr }): MoveAttr[] {
|
||||||
return this.attrs.filter(a => a instanceof attrType);
|
return this.attrs.filter(a => a instanceof attrType);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,12 +8,14 @@ import { SceneBase } from "./scene-base";
|
||||||
import { WindowVariant, getWindowVariantSuffix } from "./ui/ui-theme";
|
import { WindowVariant, getWindowVariantSuffix } from "./ui/ui-theme";
|
||||||
import { isMobile } from "./touch-controls";
|
import { isMobile } from "./touch-controls";
|
||||||
import * as Utils from "./utils";
|
import * as Utils from "./utils";
|
||||||
|
import { initI18n } from "./plugins/i18n";
|
||||||
|
|
||||||
export class LoadingScene extends SceneBase {
|
export class LoadingScene extends SceneBase {
|
||||||
constructor() {
|
constructor() {
|
||||||
super('loading');
|
super('loading');
|
||||||
|
|
||||||
Phaser.Plugins.PluginCache.register('Loader', CacheBustedLoaderPlugin, 'load');
|
Phaser.Plugins.PluginCache.register('Loader', CacheBustedLoaderPlugin, 'load');
|
||||||
|
initI18n();
|
||||||
}
|
}
|
||||||
|
|
||||||
preload() {
|
preload() {
|
||||||
|
|
|
@ -15,41 +15,52 @@ export interface MoveTranslations {
|
||||||
[key: string]: MoveTranslationEntry
|
[key: string]: MoveTranslationEntry
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface Localizable {
|
||||||
|
localize(): void;
|
||||||
|
}
|
||||||
|
|
||||||
const DEFAULT_LANGUAGE_OVERRIDE = '';
|
const DEFAULT_LANGUAGE_OVERRIDE = '';
|
||||||
|
|
||||||
/**
|
export function initI18n(): void {
|
||||||
* i18next is a localization library for maintaining and using translation resources.
|
let lang = 'en';
|
||||||
*
|
|
||||||
* Q: How do I add a new language?
|
|
||||||
* A: To add a new language, create a new folder in the locales directory with the language code.
|
|
||||||
* Each language folder should contain a file for each namespace (ex. menu.ts) with the translations.
|
|
||||||
*
|
|
||||||
* Q: How do I add a new namespace?
|
|
||||||
* A: To add a new namespace, create a new file in each language folder with the translations.
|
|
||||||
* Then update the `resources` field in the init() call and the CustomTypeOptions interface.
|
|
||||||
*/
|
|
||||||
|
|
||||||
i18next.init({
|
if (localStorage.getItem('prLang'))
|
||||||
lng: DEFAULT_LANGUAGE_OVERRIDE ? DEFAULT_LANGUAGE_OVERRIDE : 'en',
|
lang = localStorage.getItem('prLang');
|
||||||
fallbackLng: 'en',
|
|
||||||
debug: true,
|
/**
|
||||||
interpolation: {
|
* i18next is a localization library for maintaining and using translation resources.
|
||||||
escapeValue: false,
|
*
|
||||||
},
|
* Q: How do I add a new language?
|
||||||
resources: {
|
* A: To add a new language, create a new folder in the locales directory with the language code.
|
||||||
en: {
|
* Each language folder should contain a file for each namespace (ex. menu.ts) with the translations.
|
||||||
menu: enMenu,
|
*
|
||||||
move: enMove,
|
* Q: How do I add a new namespace?
|
||||||
|
* A: To add a new namespace, create a new file in each language folder with the translations.
|
||||||
|
* Then update the `resources` field in the init() call and the CustomTypeOptions interface.
|
||||||
|
*/
|
||||||
|
|
||||||
|
i18next.init({
|
||||||
|
lng: DEFAULT_LANGUAGE_OVERRIDE ? DEFAULT_LANGUAGE_OVERRIDE : lang,
|
||||||
|
fallbackLng: 'en',
|
||||||
|
debug: true,
|
||||||
|
interpolation: {
|
||||||
|
escapeValue: false,
|
||||||
},
|
},
|
||||||
it: {
|
resources: {
|
||||||
menu: itMenu,
|
en: {
|
||||||
|
menu: enMenu,
|
||||||
|
move: enMove,
|
||||||
|
},
|
||||||
|
it: {
|
||||||
|
menu: itMenu,
|
||||||
|
},
|
||||||
|
fr: {
|
||||||
|
menu: frMenu,
|
||||||
|
move: frMove,
|
||||||
|
}
|
||||||
},
|
},
|
||||||
fr: {
|
});
|
||||||
menu: frMenu,
|
}
|
||||||
move: frMove,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
// Module declared to make referencing keys in the localization files type-safe.
|
// Module declared to make referencing keys in the localization files type-safe.
|
||||||
declare module 'i18next' {
|
declare module 'i18next' {
|
||||||
|
|
|
@ -1,13 +1,17 @@
|
||||||
|
import i18next from "i18next";
|
||||||
import BattleScene from "../battle-scene";
|
import BattleScene from "../battle-scene";
|
||||||
import { hasTouchscreen } from "../touch-controls";
|
import { hasTouchscreen } from "../touch-controls";
|
||||||
import { updateWindowType } from "../ui/ui-theme";
|
import { updateWindowType } from "../ui/ui-theme";
|
||||||
import { PlayerGender } from "./game-data";
|
import { PlayerGender } from "./game-data";
|
||||||
|
import { Mode } from "#app/ui/ui";
|
||||||
|
import SettingsUiHandler from "#app/ui/settings-ui-handler";
|
||||||
|
|
||||||
export enum Setting {
|
export enum Setting {
|
||||||
Game_Speed = "GAME_SPEED",
|
Game_Speed = "GAME_SPEED",
|
||||||
Master_Volume = "MASTER_VOLUME",
|
Master_Volume = "MASTER_VOLUME",
|
||||||
BGM_Volume = "BGM_VOLUME",
|
BGM_Volume = "BGM_VOLUME",
|
||||||
SE_Volume = "SE_VOLUME",
|
SE_Volume = "SE_VOLUME",
|
||||||
|
Language = "LANGUAGE",
|
||||||
Damage_Numbers = "DAMAGE_NUMBERS",
|
Damage_Numbers = "DAMAGE_NUMBERS",
|
||||||
UI_Theme = "UI_THEME",
|
UI_Theme = "UI_THEME",
|
||||||
Window_Type = "WINDOW_TYPE",
|
Window_Type = "WINDOW_TYPE",
|
||||||
|
@ -38,6 +42,7 @@ export const settingOptions: SettingOptions = {
|
||||||
[Setting.Master_Volume]: new Array(11).fill(null).map((_, i) => i ? (i * 10).toString() : 'Mute'),
|
[Setting.Master_Volume]: new Array(11).fill(null).map((_, i) => i ? (i * 10).toString() : 'Mute'),
|
||||||
[Setting.BGM_Volume]: new Array(11).fill(null).map((_, i) => i ? (i * 10).toString() : 'Mute'),
|
[Setting.BGM_Volume]: new Array(11).fill(null).map((_, i) => i ? (i * 10).toString() : 'Mute'),
|
||||||
[Setting.SE_Volume]: new Array(11).fill(null).map((_, i) => i ? (i * 10).toString() : 'Mute'),
|
[Setting.SE_Volume]: new Array(11).fill(null).map((_, i) => i ? (i * 10).toString() : 'Mute'),
|
||||||
|
[Setting.Language]: [ 'English', 'Change' ],
|
||||||
[Setting.Damage_Numbers]: [ 'Off', 'Simple', 'Fancy' ],
|
[Setting.Damage_Numbers]: [ 'Off', 'Simple', 'Fancy' ],
|
||||||
[Setting.UI_Theme]: [ 'Default', 'Legacy' ],
|
[Setting.UI_Theme]: [ 'Default', 'Legacy' ],
|
||||||
[Setting.Window_Type]: new Array(5).fill(null).map((_, i) => (i + 1).toString()),
|
[Setting.Window_Type]: new Array(5).fill(null).map((_, i) => (i + 1).toString()),
|
||||||
|
@ -60,6 +65,7 @@ export const settingDefaults: SettingDefaults = {
|
||||||
[Setting.Master_Volume]: 5,
|
[Setting.Master_Volume]: 5,
|
||||||
[Setting.BGM_Volume]: 10,
|
[Setting.BGM_Volume]: 10,
|
||||||
[Setting.SE_Volume]: 10,
|
[Setting.SE_Volume]: 10,
|
||||||
|
[Setting.Language]: 0,
|
||||||
[Setting.Damage_Numbers]: 0,
|
[Setting.Damage_Numbers]: 0,
|
||||||
[Setting.UI_Theme]: 0,
|
[Setting.UI_Theme]: 0,
|
||||||
[Setting.Window_Type]: 0,
|
[Setting.Window_Type]: 0,
|
||||||
|
@ -77,7 +83,7 @@ export const settingDefaults: SettingDefaults = {
|
||||||
[Setting.Vibration]: 0
|
[Setting.Vibration]: 0
|
||||||
};
|
};
|
||||||
|
|
||||||
export const reloadSettings: Setting[] = [ Setting.UI_Theme ];
|
export const reloadSettings: Setting[] = [ Setting.UI_Theme, Setting.Language ];
|
||||||
|
|
||||||
export function setSetting(scene: BattleScene, setting: Setting, value: integer): boolean {
|
export function setSetting(scene: BattleScene, setting: Setting, value: integer): boolean {
|
||||||
switch (setting) {
|
switch (setting) {
|
||||||
|
@ -151,6 +157,39 @@ export function setSetting(scene: BattleScene, setting: Setting, value: integer)
|
||||||
case Setting.Vibration:
|
case Setting.Vibration:
|
||||||
scene.enableVibration = settingOptions[setting][value] !== 'Disabled' && hasTouchscreen();
|
scene.enableVibration = settingOptions[setting][value] !== 'Disabled' && hasTouchscreen();
|
||||||
break;
|
break;
|
||||||
|
case Setting.Language:
|
||||||
|
if (value) {
|
||||||
|
if (scene.ui) {
|
||||||
|
const cancelHandler = () => {
|
||||||
|
scene.ui.revertMode();
|
||||||
|
(scene.ui.getHandler() as SettingsUiHandler).setOptionCursor(Object.values(Setting).indexOf(Setting.Language), 0, true);
|
||||||
|
};
|
||||||
|
const changeLocaleHandler = (locale: string) => {
|
||||||
|
i18next.changeLanguage(locale);
|
||||||
|
localStorage.setItem('prLang', locale);
|
||||||
|
cancelHandler();
|
||||||
|
scene.reset(true, false, true);
|
||||||
|
};
|
||||||
|
scene.ui.setOverlayMode(Mode.OPTION_SELECT, {
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
label: 'English',
|
||||||
|
handler: () => changeLocaleHandler('en')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'French',
|
||||||
|
handler: () => changeLocaleHandler('fr')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Cancel',
|
||||||
|
handler: () => cancelHandler()
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -22,11 +22,13 @@ export default class SettingsUiHandler extends UiHandler {
|
||||||
private cursorObj: Phaser.GameObjects.NineSlice;
|
private cursorObj: Phaser.GameObjects.NineSlice;
|
||||||
|
|
||||||
private reloadRequired: boolean;
|
private reloadRequired: boolean;
|
||||||
|
private reloadI18n: boolean;
|
||||||
|
|
||||||
constructor(scene: BattleScene, mode?: Mode) {
|
constructor(scene: BattleScene, mode?: Mode) {
|
||||||
super(scene, mode);
|
super(scene, mode);
|
||||||
|
|
||||||
this.reloadRequired = false;
|
this.reloadRequired = false;
|
||||||
|
this.reloadI18n = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
setup() {
|
setup() {
|
||||||
|
@ -197,8 +199,11 @@ export default class SettingsUiHandler extends UiHandler {
|
||||||
|
|
||||||
if (save) {
|
if (save) {
|
||||||
this.scene.gameData.saveSetting(setting, cursor)
|
this.scene.gameData.saveSetting(setting, cursor)
|
||||||
if (reloadSettings.includes(setting))
|
if (reloadSettings.includes(setting)) {
|
||||||
this.reloadRequired = true;
|
this.reloadRequired = true;
|
||||||
|
if (setting === Setting.Language)
|
||||||
|
this.reloadI18n = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -234,7 +239,7 @@ export default class SettingsUiHandler extends UiHandler {
|
||||||
this.eraseCursor();
|
this.eraseCursor();
|
||||||
if (this.reloadRequired) {
|
if (this.reloadRequired) {
|
||||||
this.reloadRequired = false;
|
this.reloadRequired = false;
|
||||||
this.scene.reset(true);
|
this.scene.reset(true, false, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue