From 9cf4c903adc2244da316aa36e5bf1a81f672f78e Mon Sep 17 00:00:00 2001 From: NeeEoo Date: Fri, 12 Apr 2024 14:11:09 +0200 Subject: [PATCH] WIP Translation --- assets/languages/en/Editors.xml | 24 ++++ assets/languages/en/Main.xml | 96 +++++++++++++ assets/languages/en/config.ini | 3 + source/funkin/backend/FunkinText.hx | 19 +-- source/funkin/backend/scripting/Script.hx | 5 + source/funkin/backend/utils/CoolUtil.hx | 7 + .../funkin/backend/utils/TranslationUtil.hx | 130 ++++-------------- .../backend/utils/translations/FormatUtil.hx | 96 +++++++++++++ .../editors/charter/CharterAutoSaveUI.hx | 10 +- .../funkin/editors/charter/CharterEventAdd.hx | 4 +- source/funkin/game/PlayState.hx | 22 +-- source/funkin/import.hx | 1 + source/funkin/menus/BetaWarningState.hx | 4 +- source/funkin/menus/FreeplayState.hx | 14 +- source/funkin/menus/MainMenuState.hx | 8 +- source/funkin/menus/ModSwitchMenu.hx | 2 +- source/funkin/menus/PauseSubState.hx | 19 ++- .../menus/PlaytestingWarningSubstate.hx | 4 +- source/funkin/menus/StoryMenuState.hx | 17 ++- .../funkin/menus/credits/CreditsCodename.hx | 9 +- source/funkin/menus/credits/CreditsMain.hx | 6 +- source/funkin/menus/ui/Alphabet.hx | 4 +- 22 files changed, 333 insertions(+), 171 deletions(-) create mode 100644 assets/languages/en/Editors.xml create mode 100644 assets/languages/en/Main.xml create mode 100644 assets/languages/en/config.ini create mode 100644 source/funkin/backend/utils/translations/FormatUtil.hx diff --git a/assets/languages/en/Editors.xml b/assets/languages/en/Editors.xml new file mode 100644 index 00000000..a681d615 --- /dev/null +++ b/assets/languages/en/Editors.xml @@ -0,0 +1,24 @@ + + + + Autosaving in {0} seconds{1} + + + + Chart Editor + + Add Event + Edit + Delete Event + + + + Character Editor + + + + Stage Editor + + + + \ No newline at end of file diff --git a/assets/languages/en/Main.xml b/assets/languages/en/Main.xml new file mode 100644 index 00000000..52479114 --- /dev/null +++ b/assets/languages/en/Main.xml @@ -0,0 +1,96 @@ + + + + Score:{0} + Misses:{0} + Combo Breaks:{0} + Accuracy:{0} - {1} + Combo:{0} + + [N/A] + F + E + D + C + B + A + S + S++ + + + + (Chart Playtesting) + Exit Game + Exit To Menu + Save & Exit Game + Save & Exit To Menu + Cancel + + UNSAVED CHANGES! + Your changes will be *lost* if you don't save them. (Can't be recovered)\n\n\nWould you like to Cancel? + + + + WEEK SCORE:{0} + TRACKS + + + + PERSONAL BEST:{0} + Solo + Opponent Mode + Co-Op Mode + Co-Op Mode (Switched) + + + + + + Resume + Restart Song + Change Controls + Change Options + Exit to menu + Exit to charter + + + Blue balled: {0} + CO-OP MODE + OPPONENT MODE + + + + + *- Public member of the main Devs!* + Total Contributions: ~{0}~ / *{1}* (~{2}%~) - Select to open GitHub account + Downloading List... + All the contributors of the engine! - Press RESET to update the list (One reset per 2 minutes). + + + Credits + The people who made this possible! + Select this to see all the contributors of the engine! + Select this to open the itch.io page of the original game to donate! + + + + + Disable Mods + + + + Commit: {0} ({1}) + [{0}] Open Mods menu + + + + WARNING + This engine is still in a *{0}* state. That means *majority of the features* are either *buggy* or *non finished*. If you find any bugs, please report them to the Codename Engine GitHub.\n\nPress {1} to continue + + + + Easy + Normal + Hard + + \ No newline at end of file diff --git a/assets/languages/en/config.ini b/assets/languages/en/config.ini new file mode 100644 index 00000000..c70c3efc --- /dev/null +++ b/assets/languages/en/config.ini @@ -0,0 +1,3 @@ +name="English" +credits="Codename Engine" +version="0.0.1" \ No newline at end of file diff --git a/source/funkin/backend/FunkinText.hx b/source/funkin/backend/FunkinText.hx index f3c6a4f4..aa3728ea 100644 --- a/source/funkin/backend/FunkinText.hx +++ b/source/funkin/backend/FunkinText.hx @@ -2,19 +2,10 @@ package funkin.backend; import flixel.text.FlxText; import flixel.util.FlxColor; -import flixel.util.FlxColor; -import funkin.backend.utils.TranslationUtil.IFormatInfo; class FunkinText extends FlxText { - public var langStrID:String = null; - private var langFormat:IFormatInfo; - - public function new(X:Float = 0, Y:Float = 0, FieldWidth:Float = 0, ?Text:String, Size:Int = 16, Border:Bool = true, ?LangStrID:String, ?Parameters:Array) { - langStrID = LangStrID; - langFormat = TranslationUtil.getUnformatted(Text, LangStrID); - - // Should still default to the normal string if the translation is not found - super(X, Y, FieldWidth, getFormattedText(Parameters), Size); + public function new(X:Float = 0, Y:Float = 0, FieldWidth:Float = 0, ?Text:String, Size:Int = 16, Border:Bool = true) { + super(X, Y, FieldWidth, Text, Size); setFormat(Paths.font("vcr.ttf"), Size, FlxColor.WHITE); if (Border) { borderStyle = OUTLINE; @@ -22,10 +13,4 @@ class FunkinText extends FlxText { borderColor = 0xFF000000; } } - - public inline function resetLang(Parameters:Array) - return this.text = getFormattedText(Parameters); - - private inline function getFormattedText(Parameters:Array) - return langFormat.format(Parameters); } \ No newline at end of file diff --git a/source/funkin/backend/scripting/Script.hx b/source/funkin/backend/scripting/Script.hx index 5f54e14d..b70f5766 100644 --- a/source/funkin/backend/scripting/Script.hx +++ b/source/funkin/backend/scripting/Script.hx @@ -94,6 +94,11 @@ class Script extends FlxBasic implements IFlxDestroyable { "EngineUtil" => funkin.backend.utils.EngineUtil, "MemoryUtil" => funkin.backend.utils.MemoryUtil, "BitmapUtil" => funkin.backend.utils.BitmapUtil, + + #if TRANSLATIONS_SUPPORT + "TranslationUtil" => funkin.backend.utils.TranslationUtil, + "translate" => funkin.backend.utils.TranslationUtil.get, + #end ]; } public static function getDefaultPreprocessors():Map { diff --git a/source/funkin/backend/utils/CoolUtil.hx b/source/funkin/backend/utils/CoolUtil.hx index 0d17ed06..97ecacc5 100644 --- a/source/funkin/backend/utils/CoolUtil.hx +++ b/source/funkin/backend/utils/CoolUtil.hx @@ -742,6 +742,13 @@ class CoolUtil return array.indexOf(element) != -1; } #end + + public static inline function repeat(str:String, times:Int) { + var r = new StringBuf(); + for(i in 0...times) + r.add(str); + return r.toString(); + } } /** diff --git a/source/funkin/backend/utils/TranslationUtil.hx b/source/funkin/backend/utils/TranslationUtil.hx index 333d94ff..f4ca9adb 100644 --- a/source/funkin/backend/utils/TranslationUtil.hx +++ b/source/funkin/backend/utils/TranslationUtil.hx @@ -7,6 +7,7 @@ import openfl.utils.Assets; import haxe.io.Path; import haxe.xml.Access; import haxe.Exception; +import funkin.backend.utils.translations.FormatUtil; /** * The class used for translations based on the XMLs inside the translations folders. @@ -14,7 +15,7 @@ import haxe.Exception; * Made by @NexIsDumb originally for the Poldhub mod. */ @:allow(funkin.backend.assets.TranslatedAssetLibrary) -class TranslationUtil +final class TranslationUtil { /** * The current language selected translation map; If the current language it's english, this map will be empty. @@ -63,7 +64,7 @@ class TranslationUtil private static inline function getDefaultNameMap():Map { return ['en' => 'English']; } - private static inline function getDefaultConfig(name:String):IniMap { + @:noUsing private static inline function getDefaultConfig(name:String):IniMap { return ["name" => getLanguageName(name), "credits" => "", "version" => "1.0.0"]; } @@ -98,16 +99,22 @@ class TranslationUtil * * If `id` is `null` then it's gonna search using `defString`. */ - public static inline function get(defString:String, ?id:String, ?params:Array):String - return getUnformatted(defString, id).format(params); + public static inline function get(?id:String, ?params:Array, ?def:String):String + return getUnformatted(id, def).format(params); - public static function getUnformatted(defString:String, ?id:String):IFormatInfo + public static inline function translate(?id:String, ?params:Array, ?def:String):String + return get(id, params, def); + + public static inline function translateDiff(?id:String, ?params:Array):String + return get("diff." + id.toLowerCase(), params, id); + + public static function getUnformatted(id:String, ?def:String):IFormatInfo { #if TRANSLATIONS_SUPPORT - if (id == null) id = defString; if (stringMap.exists(id)) return stringMap.get(id); #end - return FormatUtil.get(defString); + if(def != null) id = def; + return FormatUtil.get(id); } /** @@ -146,6 +153,8 @@ class TranslationUtil if (foundLanguages.contains(englishName)) foundLanguages.remove(englishName); foundLanguages.insert(0, englishName); + + Logs.trace("Found languages: " + foundLanguages.join(", "), "Language"); #end } @@ -163,17 +172,19 @@ class TranslationUtil for(node in xml.elements) { if (node.name == "group") // Cosmetic name parseXml(node); - else if(node.name == "text" || node.name == "trans" || node.name == "lang" || node.name == "string") + else if(["text", "trans", "lang", "string", "str"].contains(node.name)) translations.push(node); } } for(file in Paths.getFolderContent(mainPath, true).sortAlphabetically()) { - if(Path.extension(file) != "xml") continue; + if(Path.extension(file).toLowerCase() != "xml") continue; + + var afile = "assets/" + file; // Parse the XML var xml:Access = null; - try xml = new Access(Xml.parse(Assets.getText(file))) + try xml = new Access(Xml.parse(Assets.getText(afile))) catch(e) Logs.error('Error while parsing $file: ${Std.string(e)}', "Language"); if (xml == null) continue; @@ -197,9 +208,13 @@ class TranslationUtil continue; } + var shouldTrim = node.has.notrim ? node.att.notrim != "true" : true; + var value:String = node.has.string ? node.att.string : node.innerData; + value = shouldTrim ? value.trim() : value; value = value.replace("\\n", "\n").replace("\r", ""); // remove stupid windows line breaks and convert newline literals to newlines leMap.set(node.att.id, FormatUtil.get(value)); + //Logs.trace("Added " + node.att.id + " -> `" + value + "`", "Language"); } return leMap; @@ -256,99 +271,4 @@ class TranslationUtil @:noCompletion private static function get_isLanguageLoaded():Bool return Lambda.count(stringMap) > 0; -} - -/** - * The class used to format strings based on parameters. - * - * For example if the parameter list is just an `Int` which is `9`, `You have been blue balled {0} times` becomes `You have been blue balled 9 times`. - */ -class FormatUtil { - private static var cache:Map = new Map(); - - public static function get(id:String):IFormatInfo { - if (cache.exists(id)) - return cache.get(id); - - var fi:IFormatInfo = ParamFormatInfo.returnOnlyIfValid(id); - if(fi == null) fi = new StrFormatInfo(id); - cache.set(id, fi); - return fi; - } - - public inline static function clear() { - cache.clear(); - } -} - -class StrFormatInfo implements IFormatInfo { - public var string:String; - - public function new(str:String) { - this.string = str; - } - - public function format(params:Array):String { - return string; - } - - public function toString():String { - return "StrFormatInfo(" + string + ")"; - } -} - -// TODO: add support for @:({0}==1?(Hello):(World)) -class ParamFormatInfo implements IFormatInfo { - public var strings:Array = []; - public var indexes:Array = []; - - public function new(str:String) { - var i = 0; - - while (i < str.length) { - var fi = str.indexOf("{", i); // search from the start of i - - if (fi == -1) { - // if there are no more parameters, just add the rest of the string - this.strings.push(str.substring(i)); - break; - } - - var fe = str.indexOf("}", fi); - - this.strings.push(str.substring(i, fi)); - this.indexes.push(Std.parseInt(str.substring(fi+1, fe))); - i = fe + 1; - } - } - - public static function isValid(str:String):Bool { - var fi = new ParamFormatInfo(str); - return fi.indexes.length > 0; - } - public static function returnOnlyIfValid(str:String):IFormatInfo { - var fi = new ParamFormatInfo(str); - return fi.indexes.length > 0 ? fi : null; - } - - public function format(params:Array):String { - if (params == null) params = []; - - var str:String = ""; - for (i=>s in strings) { - str += s; - if (i < indexes.length) - str += params[indexes[i]]; - } - - return str; - } - - public function toString():String { - return 'ParamFormatInfo([${strings.join(", ")}] [${indexes.join(", ")}])'; - } -} - -interface IFormatInfo { - public function format(params:Array):String; } \ No newline at end of file diff --git a/source/funkin/backend/utils/translations/FormatUtil.hx b/source/funkin/backend/utils/translations/FormatUtil.hx new file mode 100644 index 00000000..5d1a0b09 --- /dev/null +++ b/source/funkin/backend/utils/translations/FormatUtil.hx @@ -0,0 +1,96 @@ +package funkin.backend.utils.translations; + +/** + * The class used to format strings based on parameters. + * + * For example if the parameter list is just an `Int` which is `9`, `You have been blue balled {0} times` becomes `You have been blue balled 9 times`. + */ +class FormatUtil { + private static var cache:Map = new Map(); + + public static function get(id:String):IFormatInfo { + if (cache.exists(id)) + return cache.get(id); + + var fi:IFormatInfo = ParamFormatInfo.returnOnlyIfValid(id); + if(fi == null) fi = new StrFormatInfo(id); + cache.set(id, fi); + return fi; + } + + public inline static function clear() { + cache.clear(); + } +} + +class StrFormatInfo implements IFormatInfo { + public var string:String; + + public function new(str:String) { + this.string = str; + } + + public function format(params:Array):String { + return string; + } + + public function toString():String { + return "StrFormatInfo(" + string + ")"; + } +} + +// TODO: add support for @:({0}==1?(Hello):(World)) +class ParamFormatInfo implements IFormatInfo { + public var strings:Array = []; + public var indexes:Array = []; + + public function new(str:String) { + var i = 0; + + while (i < str.length) { + var fi = str.indexOf("{", i); // search from the start of i + + if (fi == -1) { + // if there are no more parameters, just add the rest of the string + this.strings.push(str.substring(i)); + break; + } + + var fe = str.indexOf("}", fi); + + this.strings.push(str.substring(i, fi)); + this.indexes.push(Std.parseInt(str.substring(fi+1, fe))); + i = fe + 1; + } + } + + public static function isValid(str:String):Bool { + var fi = new ParamFormatInfo(str); + return fi.indexes.length > 0; + } + public static function returnOnlyIfValid(str:String):IFormatInfo { + var fi = new ParamFormatInfo(str); + return fi.indexes.length > 0 ? fi : null; + } + + public function format(params:Array):String { + if (params == null) params = []; + + var str:String = ""; + for (i=>s in strings) { + str += s; + if (i < indexes.length) + str += params[indexes[i]]; + } + + return str; + } + + public function toString():String { + return 'ParamFormatInfo([${strings.join(", ")}] [${indexes.join(", ")}])'; + } +} + +interface IFormatInfo { + public function format(params:Array):String; +} \ No newline at end of file diff --git a/source/funkin/editors/charter/CharterAutoSaveUI.hx b/source/funkin/editors/charter/CharterAutoSaveUI.hx index 81f207ad..73684c0f 100644 --- a/source/funkin/editors/charter/CharterAutoSaveUI.hx +++ b/source/funkin/editors/charter/CharterAutoSaveUI.hx @@ -26,7 +26,7 @@ class CharterAutoSaveUI extends UISliceSprite { icon.animation.play("icon"); icon.animation.curAnim.curFrame = 0; members.push(icon); - members.push(autosavingText = new UIText(x+12+10+4, y+8, 0, "Autosaving in 10 seconds...", 12)); + members.push(autosavingText = new UIText(x+12+10+4, y+8, 0, TU.translate("editor.autosavingIn", ["?", "..."]), 12)); progressBarBack = new FlxSprite(x + 10, y + bHeight - 20).makeGraphic(Std.int(bWidth-20), 10, 0x00000000, true); progressBarBack.drawRoundRect(0, 0, progressBarBack.width, progressBarBack.height, 4, 6, 0xFF727272, null, {smoothing: false}); @@ -68,8 +68,10 @@ class CharterAutoSaveUI extends UISliceSprite { __tween = FlxTween.num(0, 1, time, null, (v:Float) -> { if ((progress = v) < .95) { - autosavingText.text = 'Autosaving in ${Math.min(Math.round(time), 1+Math.floor(Math.abs(time-(progress*time))))} seconds'; - autosavingText.text += [for (i in 0...(Math.floor((progress*time*3)%4))) "."].join(""); + autosavingText.text = TU.translate("editor.autosavingIn", [ + Math.min(Math.round(time), 1+Math.floor(Math.abs(time-(progress*time)))), + ".".repeat(Math.floor((progress*time*3)%4)) + ]); } }); __timer = new FlxTimer(); @@ -109,7 +111,7 @@ class CharterAutoSaveUI extends UISliceSprite { } public function appearAnimation() { - autosavingText.text = "Autosaving in seconds..."; progress = 0; icon.animation.curAnim.curFrame = 0; + progress = 0; icon.animation.curAnim.curFrame = 0; for (member in [this, autosavingText, progressBar, progressBarBack]) member.color = 0xFFFFFFFF; x = -(320); alpha=0; FlxTween.cancelTweensOf(this); cancelled = false; cancelButton.visible = true; diff --git a/source/funkin/editors/charter/CharterEventAdd.hx b/source/funkin/editors/charter/CharterEventAdd.hx index 038725d3..cc4ce0bc 100644 --- a/source/funkin/editors/charter/CharterEventAdd.hx +++ b/source/funkin/editors/charter/CharterEventAdd.hx @@ -38,7 +38,7 @@ class CharterEventAdd extends UISliceSprite { curCharterEvent = null; this.step = step; this.y = (step * 40) - (bHeight / 2); - text.text = "Add event"; + text.text = TU.translate("editors.addEvent"); framesOffset = 0; x = -(bWidth = 37 + Math.ceil(text.width)); } @@ -46,7 +46,7 @@ class CharterEventAdd extends UISliceSprite { public function updateEdit(event:CharterEvent) { curCharterEvent = event; this.y = event.y; - text.text = "Edit"; + text.text = TU.translate("editors.editEvent"); framesOffset = 9; x = -(bWidth = 27 + Math.ceil(text.width) + event.bWidth); } diff --git a/source/funkin/game/PlayState.hx b/source/funkin/game/PlayState.hx index 0512f274..a3d8ae14 100644 --- a/source/funkin/game/PlayState.hx +++ b/source/funkin/game/PlayState.hx @@ -719,9 +719,9 @@ class PlayState extends MusicBeatState add(icon); } - scoreTxt = new FunkinText(healthBarBG.x + 50, healthBarBG.y + 30, Std.int(healthBarBG.width - 100), "Score:{0}", 16, "score", [songScore]); - missesTxt = new FunkinText(healthBarBG.x + 50, healthBarBG.y + 30, Std.int(healthBarBG.width - 100), "Misses:0", 16); - accuracyTxt = new FunkinText(healthBarBG.x + 50, healthBarBG.y + 30, Std.int(healthBarBG.width - 100), "Accuracy:{0} - {1}", 16, "accuracy", ["-%", "(N/A)"]); + scoreTxt = new FunkinText(healthBarBG.x + 50, healthBarBG.y + 30, Std.int(healthBarBG.width - 100), TU.translate("game.score", [songScore]), 16); + missesTxt = new FunkinText(healthBarBG.x + 50, healthBarBG.y + 30, Std.int(healthBarBG.width - 100), TU.translate("game.misses", [misses]), 16); + accuracyTxt = new FunkinText(healthBarBG.x + 50, healthBarBG.y + 30, Std.int(healthBarBG.width - 100), TU.translate("game.accuracy", ["-%", "(N/A)"]), 16); accuracyTxt.addFormat(accFormat, 0, 1); for(text in [scoreTxt, missesTxt, accuracyTxt]) { @@ -751,7 +751,7 @@ class PlayState extends MusicBeatState if (chartingMode) { WindowUtils.prefix = Charter.undos.unsaved ? "* " : ""; - WindowUtils.suffix = " (Chart Playtesting)"; + WindowUtils.suffix = TU.translate("charter.chartPlaytesting"); SaveWarning.showWarning = Charter.undos.unsaved; SaveWarning.selectionClass = CharterSelection; @@ -1141,7 +1141,7 @@ class PlayState extends MusicBeatState state.openSubState(new PlaytestingWarningSubstate(closingWindow, [ { - label: closingWindow ? "Exit Game" : "Exit To Menu", + label: closingWindow ? TU.translate("playtesting.exitGame") : TU.translate("playtesting.exitToMenu"), color: 0xFF0000, onClick: function(_) { if (!closingWindow) { @@ -1153,7 +1153,7 @@ class PlayState extends MusicBeatState } }, { - label: closingWindow ? "Save & Exit Game" : "Save & Exit To Menu", + label: closingWindow ? TU.translate("playtesting.saveAndExitGame") : TU.translate("playtesting.saveAndExitToMenu"), color: 0xFFFF00, onClick: function(_) { if (SaveWarning.saveFunc != null) SaveWarning.saveFunc(); @@ -1166,7 +1166,7 @@ class PlayState extends MusicBeatState } }, { - label: "Cancel", + label: TU.translate("playtesting.cancel"), color: 0xFFFFFF, onClick: function (_) { if (closingWindow) WindowUtils.resetClosing(); @@ -1190,15 +1190,15 @@ class PlayState extends MusicBeatState } function updateRatingStuff() { - scoreTxt.resetLang([songScore]); - missesTxt.text = '${comboBreaks ? "Combo Breaks" : "Misses"}:$misses'; + scoreTxt.text = TU.translate("game.score", [songScore]); + missesTxt.text = TU.translate(comboBreaks ? "game.comboBreaks" : "game.misses", [misses]); if (curRating == null) curRating = new ComboRating(0, "[N/A]", 0xFF888888); @:privateAccess { accFormat.format.color = curRating.color; - accuracyTxt.resetLang([accuracy < 0 ? "-%" : '${CoolUtil.quantize(accuracy * 100, 100)}%', curRating.rating]); + accuracyTxt.text = TU.translate("game.accuracy", [accuracy < 0 ? "-%" : '${CoolUtil.quantize(accuracy * 100, 100)}%', curRating.rating]); accuracyTxt._formatRanges[0].range.start = accuracyTxt.text.length - curRating.rating.length; accuracyTxt._formatRanges[0].range.end = accuracyTxt.text.length; @@ -1914,7 +1914,7 @@ class ComboRating { public function new(percent:Float, rating:String, color:FlxColor) { this.percent = percent; - this.rating = TranslationUtil.get(rating, 'rating_$rating'); + this.rating = TranslationUtil.get('game.rating.$rating', rating); this.color = color; } } diff --git a/source/funkin/import.hx b/source/funkin/import.hx index eca238fd..a83d7c8a 100644 --- a/source/funkin/import.hx +++ b/source/funkin/import.hx @@ -6,6 +6,7 @@ import funkin.backend.MusicBeatSubstate; import funkin.backend.MusicBeatGroup; import funkin.backend.FunkinSprite; import funkin.backend.utils.*; +import funkin.backend.utils.TranslationUtil as TU; import funkin.backend.system.Logs; import funkin.options.Options; import funkin.game.PlayState; diff --git a/source/funkin/menus/BetaWarningState.hx b/source/funkin/menus/BetaWarningState.hx index d436138f..fcfae487 100644 --- a/source/funkin/menus/BetaWarningState.hx +++ b/source/funkin/menus/BetaWarningState.hx @@ -13,13 +13,13 @@ class BetaWarningState extends MusicBeatState { public override function create() { super.create(); - titleAlphabet = new Alphabet(0, 0, "WARNING", true); + titleAlphabet = new Alphabet(0, 0, TU.translate("betaWarning.title"), true); titleAlphabet.screenCenter(X); add(titleAlphabet); disclaimer = new FunkinText(16, titleAlphabet.y + titleAlphabet.height + 10, FlxG.width - 32, "", 32); disclaimer.alignment = CENTER; - disclaimer.applyMarkup('This engine is still in a *${Main.releaseCycle}* state. That means *majority of the features* are either *buggy* or *non finished*. If you find any bugs, please report them to the Codename Engine GitHub.\n\nPress ENTER to continue', + disclaimer.applyMarkup(TU.translate("betaWarning.desc", [Main.releaseCycle, "ENTER"]), [ new FlxTextFormatMarkerPair(new FlxTextFormat(0xFFFF4444), "*") ] diff --git a/source/funkin/menus/FreeplayState.hx b/source/funkin/menus/FreeplayState.hx index d814b2ee..3b7d0c05 100644 --- a/source/funkin/menus/FreeplayState.hx +++ b/source/funkin/menus/FreeplayState.hx @@ -48,7 +48,7 @@ class FreeplayState extends MusicBeatState /** * Currently lerped score. Is updated to go towards `intendedScore`. */ - public var lerpScore:Int = 0; + public var lerpScore:Float = 0; /** * Destination for the currently lerped score. */ @@ -207,7 +207,7 @@ class FreeplayState extends MusicBeatState FlxG.sound.music.volume += 0.5 * elapsed; } - lerpScore = Math.floor(lerp(lerpScore, intendedScore, 0.4)); + lerpScore = lerp(lerpScore, intendedScore, 0.4); if (Math.abs(lerpScore - intendedScore) <= 10) lerpScore = intendedScore; @@ -220,7 +220,7 @@ class FreeplayState extends MusicBeatState updateOptionsAlpha(); } - scoreText.text = "PERSONAL BEST:" + lerpScore; + scoreText.text = TU.translate("freeplay.score", [Math.round(lerpScore)]); scoreBG.scale.set(Math.max(Math.max(diffText.width, scoreText.width), coopText.width) + 8, (coopText.visible ? coopText.y + coopText.height : 66)); scoreBG.updateHitbox(); scoreBG.x = FlxG.width - scoreBG.width; @@ -344,10 +344,10 @@ class FreeplayState extends MusicBeatState * Array containing all labels for Co-Op / Opponent modes. */ public var coopLabels:Array = [ - TranslationUtil.get("[TAB] Solo"), - TranslationUtil.get("[TAB] Opponent Mode"), - TranslationUtil.get("[TAB] Co-Op Mode"), - TranslationUtil.get("[TAB] Co-Op Mode (Switched)") + "[TAB] " + TU.translate("freeplay.solo"), + "[TAB] " + TU.translate("freeplay.opponentMode"), + "[TAB] " + TU.translate("freeplay.coopMode"), + "[TAB] " + TU.translate("freeplay.coopModeSwitched") ]; /** diff --git a/source/funkin/menus/MainMenuState.hx b/source/funkin/menus/MainMenuState.hx index 171f7959..3c28344f 100644 --- a/source/funkin/menus/MainMenuState.hx +++ b/source/funkin/menus/MainMenuState.hx @@ -70,7 +70,13 @@ class MainMenuState extends MusicBeatState FlxG.camera.follow(camFollow, null, 0.06); - var versionShit:FunkinText = new FunkinText(5, FlxG.height - 2, 0, 'Codename Engine v${Application.current.meta.get('version')}\nCommit ${funkin.backend.system.macros.GitCommitMacro.commitNumber} (${funkin.backend.system.macros.GitCommitMacro.commitHash})\n[TAB] Open Mods menu\n'); + var versionText = [ + 'Codename Engine v${Application.current.meta.get('version')}', + TU.translate("mainMenu.commit", [funkin.backend.system.macros.GitCommitMacro.commitNumber, funkin.backend.system.macros.GitCommitMacro.commitHash]), + TU.translate("mainMenu.openMods", ["TAB"]), + '' + ].join('\n'); + var versionShit:FunkinText = new FunkinText(5, FlxG.height - 2, 0, versionText); versionShit.y -= versionShit.height; versionShit.scrollFactor.set(); add(versionShit); diff --git a/source/funkin/menus/ModSwitchMenu.hx b/source/funkin/menus/ModSwitchMenu.hx index eb14ddcd..c3772075 100644 --- a/source/funkin/menus/ModSwitchMenu.hx +++ b/source/funkin/menus/ModSwitchMenu.hx @@ -27,7 +27,7 @@ class ModSwitchMenu extends MusicBeatSubstate { alphabets = new FlxTypedGroup(); for(mod in mods) { - var a = new Alphabet(0, 0, mod == null ? "DISABLE MODS" : mod, true); + var a = new Alphabet(0, 0, mod == null ? TU.translate("mods.disableMods") : mod, true); a.isMenuItem = true; a.scrollFactor.set(); alphabets.add(a); diff --git a/source/funkin/menus/PauseSubState.hx b/source/funkin/menus/PauseSubState.hx index 91ee482b..9f7ae38f 100644 --- a/source/funkin/menus/PauseSubState.hx +++ b/source/funkin/menus/PauseSubState.hx @@ -20,6 +20,7 @@ class PauseSubState extends MusicBeatSubstate var grpMenuShit:FlxTypedGroup; + // TODO: make it possible to translate these var menuItems:Array = ['Resume', 'Restart Song', 'Change Controls', 'Change Options', 'Exit to menu', "Exit to charter"]; var curSelected:Int = 0; @@ -69,12 +70,19 @@ class PauseSubState extends MusicBeatSubstate bg.scrollFactor.set(); add(bg); + var multiplayerInfo:String = PlayState.opponentMode ? 'pause.coopMode' : + PlayState.coopMode ? 'pause.opponentMode' : + null; + var levelInfo:FunkinText = new FunkinText(20, 15, 0, PlayState.SONG.meta.displayName, 32, false); - var levelDifficulty:FunkinText = new FunkinText(20, 15, 0, PlayState.difficulty.toUpperCase(), 32, false); - var multiplayerText:FunkinText = new FunkinText(20, 15, 0, PlayState.opponentMode ? 'OPPONENT MODE' : (PlayState.coopMode ? 'CO-OP MODE' : ''), 32, false); - var deathCounter:FunkinText = new FunkinText(20, 15, 0, "Blue balled: {0}", 32, false, "blue_balled", [PlayState.deathCounter]); + var levelDifficulty:FunkinText = new FunkinText(20, 15, 0, TU.translateDiff(PlayState.difficulty).toUpperCase(), 32, false); + var deathCounter:FunkinText = new FunkinText(20, 15, 0, TU.translate("pause.deathCounter", [PlayState.deathCounter]), 32, false); + var multiplayerText:FunkinText = null; + if(multiplayerInfo != "") + multiplayerText = new FunkinText(20, 15, 0, TU.translate(multiplayerInfo), 32, false); for(k=>label in [levelInfo, levelDifficulty, deathCounter, multiplayerText]) { + if(label == null) continue; label.scrollFactor.set(); label.updateHitbox(); label.alpha = 0; @@ -194,10 +202,7 @@ class PauseSubState extends MusicBeatSubstate { item.targetY = i - curSelected; - if (item.targetY == 0) - item.alpha = 1; - else - item.alpha = 0.6; + item.alpha = (item.targetY == 0) ? 1 : 0.6; } } } \ No newline at end of file diff --git a/source/funkin/menus/PlaytestingWarningSubstate.hx b/source/funkin/menus/PlaytestingWarningSubstate.hx index 32859705..1bd5a00f 100644 --- a/source/funkin/menus/PlaytestingWarningSubstate.hx +++ b/source/funkin/menus/PlaytestingWarningSubstate.hx @@ -40,13 +40,13 @@ class PlaytestingWarningSubstate extends MusicBeatSubstate bg.scrollFactor.set(); add(bg); - titleAlphabet = new Alphabet(0, 140, "UNSAVED CHANGES!", true); + titleAlphabet = new Alphabet(0, 140, TU.translate("playtesting.warningTitle"), true); titleAlphabet.screenCenter(X); add(titleAlphabet); disclaimer = new FunkinText(16, titleAlphabet.y + titleAlphabet.height + 70, FlxG.width - 32, "", 32); disclaimer.alignment = CENTER; - disclaimer.applyMarkup("Your changes will be *lost* if you don't save them. (Can't be recovered)\n\n\nWould you like to Cancel?", + disclaimer.applyMarkup(TU.translate("playtesting.warningDesc"), [ new FlxTextFormatMarkerPair(new FlxTextFormat(0xFFFF4444), "*") ] diff --git a/source/funkin/menus/StoryMenuState.hx b/source/funkin/menus/StoryMenuState.hx index be9c2d67..7e5cc9a8 100644 --- a/source/funkin/menus/StoryMenuState.hx +++ b/source/funkin/menus/StoryMenuState.hx @@ -48,7 +48,7 @@ class StoryMenuState extends MusicBeatState { blackBar.color = 0xFF000000; blackBar.updateHitbox(); - scoreText = new FunkinText(10, 10, 0, "SCORE: -", 36); + scoreText = new FunkinText(10, 10, 0, TU.translate("story.score", ["-"]), 36); scoreText.setFormat(Paths.font("vcr.ttf"), 32); weekTitle = new FlxText(10, 10, FlxG.width - 20, "", 32); @@ -125,7 +125,7 @@ class StoryMenuState extends MusicBeatState { super.update(elapsed); lerpScore = lerp(lerpScore, intendedScore, 0.5); - scoreText.text = 'WEEK SCORE:${Math.round(lerpScore)}'; + scoreText.text = TU.translate("story.score", [Math.round(lerpScore)]); if (canSelect) { if (leftArrow != null && leftArrow.exists) leftArrow.animation.play(controls.LEFT ? 'press' : 'idle'); @@ -164,7 +164,18 @@ class StoryMenuState extends MusicBeatState { for(k=>e in weekSprites.members) { e.targetY = k - curWeek; } - tracklist.text = 'TRACKS\n\n${[for(e in weeks[curWeek].songs) if (!e.hide) e.name.toUpperCase()].join('\n')}'; + var str = new StringBuf(); + str.add(TU.translate("story.tracks") + "\n\n"); + var len = weeks[curWeek].songs.length; + for(i=>e in weeks[curWeek].songs) { + if (!e.hide) { + str.add(e.name.toUpperCase()); + if (i != len-1) + str.add("\n"); + } + } + + tracklist.text = str.toString(); weekTitle.text = weeks[curWeek].name.getDefault(""); for(i in 0...3) diff --git a/source/funkin/menus/credits/CreditsCodename.hx b/source/funkin/menus/credits/CreditsCodename.hx index c9d1e2fd..3deb2310 100644 --- a/source/funkin/menus/credits/CreditsCodename.hx +++ b/source/funkin/menus/credits/CreditsCodename.hx @@ -17,7 +17,7 @@ class CreditsCodename extends funkin.options.OptionsScreen { public override function new() { - super("Codename Engine", "All the contributors of the engine! - Press RESET to update the list (One reset per 2 minutes)."); + super("Codename Engine", TU.translate("credits.allContributors")); tryUpdating(true); } @@ -40,7 +40,7 @@ class CreditsCodename extends funkin.options.OptionsScreen { } public function tryUpdating(forceDisplaying:Bool = false) { - updateMenuDesc("Downloading List..."); + updateMenuDesc(TU.translate("credits.downloadingList")); _canReset = false; Main.execAsync(function() { if(checkUpdate() || forceDisplaying) _downloadingSteps = 2; @@ -108,9 +108,10 @@ class CreditsCodename extends funkin.options.OptionsScreen { totalContributions = 0; for(c in Options.contributors) totalContributions += c.contributions; for(c in Options.contributors) { - var opt:GithubIconOption = new GithubIconOption(c, 'Total Contributions: ~${c.contributions}~ / *${totalContributions}* (~${FlxMath.roundDecimal(c.contributions / totalContributions * 100, 2)}%~) - Select to open GitHub account'); + var text = TU.translate("credits.totalContributions", [c.contributions, totalContributions, FlxMath.roundDecimal(c.contributions / totalContributions * 100, 2)]); + var opt:GithubIconOption = new GithubIconOption(c, text); if(Options.mainDevs.contains(c.id)) { - opt.desc += " *- Public member of the main Devs!*"; + opt.desc += TU.translate("credits.mainDev"); @:privateAccess opt.__text.color = mainDevCol; } add(opt); diff --git a/source/funkin/menus/credits/CreditsMain.hx b/source/funkin/menus/credits/CreditsMain.hx index e37af7bb..841af11e 100644 --- a/source/funkin/menus/credits/CreditsMain.hx +++ b/source/funkin/menus/credits/CreditsMain.hx @@ -35,14 +35,14 @@ class CreditsMain extends TreeMenu { selectables.push(c); } } - selectables.push(new TextOption("Codename Engine >", "Select this to see all the contributors of the engine!", function() { + selectables.push(new TextOption("Codename Engine >", TU.translate("credits.selectCodename"), function() { optionsTree.add(Type.createInstance(CreditsCodename, [])); })); - selectables.push(new TextOption("Friday Night Funkin'", "Select this to open the itch.io page of the original game to donate!", function() { + selectables.push(new TextOption("Friday Night Funkin'", TU.translate("credits.selectBase"), function() { CoolUtil.openURL("https://ninja-muffin24.itch.io/funkin"); })); - main = new OptionsScreen('Credits', 'The people who made this possible!', selectables); + main = new OptionsScreen(TU.translate("credits.name"), TU.translate("credits.madePossible"), selectables); super.create(); DiscordUtil.call("onMenuLoaded", ["Credits Menu"]); diff --git a/source/funkin/menus/ui/Alphabet.hx b/source/funkin/menus/ui/Alphabet.hx index 0de7db89..5ee79a7e 100644 --- a/source/funkin/menus/ui/Alphabet.hx +++ b/source/funkin/menus/ui/Alphabet.hx @@ -78,11 +78,11 @@ class Alphabet extends FlxSpriteGroup trace(e.details()); } } - public function new(x:Float, y:Float, text:String = "", ?bold:Bool = false, typed:Bool = false, ?transID:String, ?transParams:Array) + public function new(x:Float, y:Float, text:String = "", ?bold:Bool = false, typed:Bool = false) { super(x, y); - _finalText = this.text = TranslationUtil.get(text, transID, transParams); + _finalText = this.text = text; isBold = bold; var alphabetPath = Paths.xml("alphabet");