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
+
+ 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 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");