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 { TextStyle, addTextObject } from './ui/text';
|
||||
import { Moves } from "./data/enums/moves";
|
||||
import { } from "./data/move";
|
||||
import { allMoves } from "./data/move";
|
||||
import { initMoves } from './data/move';
|
||||
import { ModifierPoolType, getDefaultModifierTypeForTier, getEnemyModifierTypesForWave } from './modifier/modifier-type';
|
||||
import AbilityBar from './ui/ability-bar';
|
||||
|
@ -58,6 +58,7 @@ import { UiTheme } from './enums/ui-theme';
|
|||
import { SceneBase } from './scene-base';
|
||||
import CandyBar from './ui/candy-bar';
|
||||
import { Variant, variantData } from './data/variant';
|
||||
import { Localizable } from './plugins/i18n';
|
||||
|
||||
export const bypassLogin = import.meta.env.VITE_BYPASS_LOGIN === "1";
|
||||
|
||||
|
@ -454,7 +455,7 @@ export default class BattleScene extends SceneBase {
|
|||
hideOnComplete: true
|
||||
});
|
||||
|
||||
this.reset();
|
||||
this.reset(false, false, true);
|
||||
|
||||
const ui = new UI(this);
|
||||
this.uiContainer.add(ui);
|
||||
|
@ -738,7 +739,7 @@ export default class BattleScene extends SceneBase {
|
|||
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)
|
||||
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.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) {
|
||||
this.fadeOutBgm(250, false);
|
||||
|
|
|
@ -24,7 +24,7 @@ import { Species } from "./enums/species";
|
|||
import { ModifierPoolType } from "#app/modifier/modifier-type";
|
||||
import { Command } from "../ui/command-ui-handler";
|
||||
import { Biome } from "./enums/biome";
|
||||
import i18next from '../plugins/i18n';
|
||||
import i18next, { Localizable } from '../plugins/i18n';
|
||||
|
||||
export enum MoveCategory {
|
||||
PHYSICAL,
|
||||
|
@ -75,7 +75,7 @@ export enum MoveFlags {
|
|||
type MoveConditionFunc = (user: Pokemon, target: 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 name: string;
|
||||
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;
|
||||
|
||||
this.name = id ? i18next.t(`move:${i18nKey}.name`) as string : '';
|
||||
this.name = id ? i18next.t(`move:${i18nKey}.name`).toString() : '';
|
||||
this.type = type;
|
||||
this.category = category;
|
||||
this.moveTarget = defaultMoveTarget;
|
||||
this.power = power;
|
||||
this.accuracy = accuracy;
|
||||
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.priority = priority;
|
||||
this.generation = generation;
|
||||
|
@ -119,6 +119,13 @@ export default class Move {
|
|||
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[] {
|
||||
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 { isMobile } from "./touch-controls";
|
||||
import * as Utils from "./utils";
|
||||
import { initI18n } from "./plugins/i18n";
|
||||
|
||||
export class LoadingScene extends SceneBase {
|
||||
constructor() {
|
||||
super('loading');
|
||||
|
||||
Phaser.Plugins.PluginCache.register('Loader', CacheBustedLoaderPlugin, 'load');
|
||||
initI18n();
|
||||
}
|
||||
|
||||
preload() {
|
||||
|
|
|
@ -15,41 +15,52 @@ export interface MoveTranslations {
|
|||
[key: string]: MoveTranslationEntry
|
||||
}
|
||||
|
||||
export interface Localizable {
|
||||
localize(): void;
|
||||
}
|
||||
|
||||
const DEFAULT_LANGUAGE_OVERRIDE = '';
|
||||
|
||||
/**
|
||||
* i18next is a localization library for maintaining and using translation resources.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
export function initI18n(): void {
|
||||
let lang = 'en';
|
||||
|
||||
i18next.init({
|
||||
lng: DEFAULT_LANGUAGE_OVERRIDE ? DEFAULT_LANGUAGE_OVERRIDE : 'en',
|
||||
fallbackLng: 'en',
|
||||
debug: true,
|
||||
interpolation: {
|
||||
escapeValue: false,
|
||||
},
|
||||
resources: {
|
||||
en: {
|
||||
menu: enMenu,
|
||||
move: enMove,
|
||||
if (localStorage.getItem('prLang'))
|
||||
lang = localStorage.getItem('prLang');
|
||||
|
||||
/**
|
||||
* i18next is a localization library for maintaining and using translation resources.
|
||||
*
|
||||
* 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({
|
||||
lng: DEFAULT_LANGUAGE_OVERRIDE ? DEFAULT_LANGUAGE_OVERRIDE : lang,
|
||||
fallbackLng: 'en',
|
||||
debug: true,
|
||||
interpolation: {
|
||||
escapeValue: false,
|
||||
},
|
||||
it: {
|
||||
menu: itMenu,
|
||||
resources: {
|
||||
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.
|
||||
declare module 'i18next' {
|
||||
|
|
|
@ -1,13 +1,17 @@
|
|||
import i18next from "i18next";
|
||||
import BattleScene from "../battle-scene";
|
||||
import { hasTouchscreen } from "../touch-controls";
|
||||
import { updateWindowType } from "../ui/ui-theme";
|
||||
import { PlayerGender } from "./game-data";
|
||||
import { Mode } from "#app/ui/ui";
|
||||
import SettingsUiHandler from "#app/ui/settings-ui-handler";
|
||||
|
||||
export enum Setting {
|
||||
Game_Speed = "GAME_SPEED",
|
||||
Master_Volume = "MASTER_VOLUME",
|
||||
BGM_Volume = "BGM_VOLUME",
|
||||
SE_Volume = "SE_VOLUME",
|
||||
Language = "LANGUAGE",
|
||||
Damage_Numbers = "DAMAGE_NUMBERS",
|
||||
UI_Theme = "UI_THEME",
|
||||
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.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.Language]: [ 'English', 'Change' ],
|
||||
[Setting.Damage_Numbers]: [ 'Off', 'Simple', 'Fancy' ],
|
||||
[Setting.UI_Theme]: [ 'Default', 'Legacy' ],
|
||||
[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.BGM_Volume]: 10,
|
||||
[Setting.SE_Volume]: 10,
|
||||
[Setting.Language]: 0,
|
||||
[Setting.Damage_Numbers]: 0,
|
||||
[Setting.UI_Theme]: 0,
|
||||
[Setting.Window_Type]: 0,
|
||||
|
@ -77,7 +83,7 @@ export const settingDefaults: SettingDefaults = {
|
|||
[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 {
|
||||
switch (setting) {
|
||||
|
@ -151,6 +157,39 @@ export function setSetting(scene: BattleScene, setting: Setting, value: integer)
|
|||
case Setting.Vibration:
|
||||
scene.enableVibration = settingOptions[setting][value] !== 'Disabled' && hasTouchscreen();
|
||||
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;
|
||||
|
|
|
@ -22,11 +22,13 @@ export default class SettingsUiHandler extends UiHandler {
|
|||
private cursorObj: Phaser.GameObjects.NineSlice;
|
||||
|
||||
private reloadRequired: boolean;
|
||||
private reloadI18n: boolean;
|
||||
|
||||
constructor(scene: BattleScene, mode?: Mode) {
|
||||
super(scene, mode);
|
||||
|
||||
this.reloadRequired = false;
|
||||
this.reloadI18n = false;
|
||||
}
|
||||
|
||||
setup() {
|
||||
|
@ -197,8 +199,11 @@ export default class SettingsUiHandler extends UiHandler {
|
|||
|
||||
if (save) {
|
||||
this.scene.gameData.saveSetting(setting, cursor)
|
||||
if (reloadSettings.includes(setting))
|
||||
if (reloadSettings.includes(setting)) {
|
||||
this.reloadRequired = true;
|
||||
if (setting === Setting.Language)
|
||||
this.reloadI18n = true;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -234,7 +239,7 @@ export default class SettingsUiHandler extends UiHandler {
|
|||
this.eraseCursor();
|
||||
if (this.reloadRequired) {
|
||||
this.reloadRequired = false;
|
||||
this.scene.reset(true);
|
||||
this.scene.reset(true, false, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue