WIP Translation
This commit is contained in:
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<language>
|
||||
<group name="General Editor Translations">
|
||||
<str id="editor.autosavingIn">Autosaving in {0} seconds{1}</str>
|
||||
</group>
|
||||
|
||||
<group name="ChartEditor">
|
||||
<str id="charter.name">Chart Editor</str>
|
||||
|
||||
<str id="charter.addEvent">Add Event</str>
|
||||
<str id="charter.editEvent">Edit</str> <!-- Should maybe be "Edit Event" -->
|
||||
<str id="charter.deleteEvent">Delete Event</str>
|
||||
</group>
|
||||
|
||||
<group name="CharacterEditor">
|
||||
<str id="charEditor.name">Character Editor</str>
|
||||
</group>
|
||||
|
||||
<group name="StageEditor">
|
||||
<str id="stageEditor.name">Stage Editor</str>
|
||||
</group>
|
||||
|
||||
<!-- Debug Options here maybe?-->
|
||||
</language>
|
||||
@@ -0,0 +1,96 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<language>
|
||||
<group name="PlayState">
|
||||
<str id="game.score">Score:{0}</str>
|
||||
<str id="game.misses">Misses:{0}</str>
|
||||
<str id="game.comboBreaks">Combo Breaks:{0}</str>
|
||||
<str id="game.accuracy">Accuracy:{0} - {1}</str>
|
||||
<str id="game.combo">Combo:{0}</str>
|
||||
|
||||
<str id="game.rating.[N/A]">[N/A]</str>
|
||||
<str id="game.rating.F">F</str>
|
||||
<str id="game.rating.E">E</str>
|
||||
<str id="game.rating.D">D</str>
|
||||
<str id="game.rating.C">C</str>
|
||||
<str id="game.rating.B">B</str>
|
||||
<str id="game.rating.A">A</str>
|
||||
<str id="game.rating.S">S</str>
|
||||
<str id="game.rating.S++">S++</str>
|
||||
</group>
|
||||
|
||||
<group name="PlayTesting">
|
||||
<str id="playtesting.chartPlaytesting" notrim="true"> (Chart Playtesting)</str>
|
||||
<str id="playtesting.exitGame">Exit Game</str>
|
||||
<str id="playtesting.exitToMenu">Exit To Menu</str>
|
||||
<str id="playtesting.saveAndExitGame">Save & Exit Game</str>
|
||||
<str id="playtesting.saveAndExitToMenu">Save & Exit To Menu</str>
|
||||
<str id="playtesting.cancel">Cancel</str>
|
||||
|
||||
<str id="playtesting.warningTitle">UNSAVED CHANGES!</str>
|
||||
<str id="playtesting.warningDesc">Your changes will be *lost* if you don't save them. (Can't be recovered)\n\n\nWould you like to Cancel?</str>
|
||||
</group>
|
||||
|
||||
<group name="StoryMenu">
|
||||
<str id="story.score">WEEK SCORE:{0}</str>
|
||||
<str id="story.tracks">TRACKS</str>
|
||||
</group>
|
||||
|
||||
<group name="Freeplay">
|
||||
<str id="freeplay.score">PERSONAL BEST:{0}</str>
|
||||
<str id="freeplay.solo">Solo</str>
|
||||
<str id="freeplay.opponentMode">Opponent Mode</str>
|
||||
<str id="freeplay.coopMode">Co-Op Mode</str>
|
||||
<str id="freeplay.coopModeSwitched">Co-Op Mode (Switched)</str>
|
||||
</group>
|
||||
|
||||
<group name="Pause">
|
||||
<group name="PauseOptions">
|
||||
<!-- These dont work yet-->
|
||||
<str id="pause.resume">Resume</str>
|
||||
<str id="pause.restart">Restart Song</str>
|
||||
<str id="pause.changeControls">Change Controls</str>
|
||||
<str id="pause.changeOptions">Change Options</str>
|
||||
<str id="pause.exitToMenu">Exit to menu</str>
|
||||
<str id="pause.exitToCharter">Exit to charter</str>
|
||||
</group>
|
||||
|
||||
<str id="pause.deathCounter">Blue balled: {0}</str>
|
||||
<str id="pause.coopMode">CO-OP MODE</str>
|
||||
<str id="pause.opponentMode">OPPONENT MODE</str>
|
||||
</group>
|
||||
|
||||
<group name="Credits">
|
||||
<group name="CreditsCodename">
|
||||
<str id="credits.mainDev" notrim="true"> *- Public member of the main Devs!*</str>
|
||||
<str id="credits.totalContributions">Total Contributions: ~{0}~ / *{1}* (~{2}%~) - Select to open GitHub account</str>
|
||||
<str id="credits.downloadingList">Downloading List...</str>
|
||||
<str id="credits.allContributors">All the contributors of the engine! - Press RESET to update the list (One reset per 2 minutes).</str>
|
||||
</group>
|
||||
<group name="CreditsMain">
|
||||
<str id="credits.name">Credits</str>
|
||||
<str id="credits.madePossible">The people who made this possible!</str>
|
||||
<str id="credits.selectCodename">Select this to see all the contributors of the engine!</str>
|
||||
<str id="credits.selectBase">Select this to open the itch.io page of the original game to donate!</str>
|
||||
</group>
|
||||
</group>
|
||||
|
||||
<group name="Mods">
|
||||
<str id="mods.disableMods">Disable Mods</str>
|
||||
</group>
|
||||
|
||||
<group name="MainMenu">
|
||||
<str id="mainMenu.commit">Commit: {0} ({1})</str>
|
||||
<str id="mainMenu.openMods">[{0}] Open Mods menu</str>
|
||||
</group>
|
||||
|
||||
<group name="BetaWarning">
|
||||
<str id="betaWarning.title">WARNING</str>
|
||||
<str id="betaWarning.desc">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</str>
|
||||
</group>
|
||||
|
||||
<group name="Difficulties">
|
||||
<str id="diff.easy">Easy</str>
|
||||
<str id="diff.normal">Normal</str>
|
||||
<str id="diff.hard">Hard</str>
|
||||
</group>
|
||||
</language>
|
||||
@@ -0,0 +1,3 @@
|
||||
name="English"
|
||||
credits="Codename Engine"
|
||||
version="0.0.1"
|
||||
@@ -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<Dynamic>) {
|
||||
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<Dynamic>)
|
||||
return this.text = getFormattedText(Parameters);
|
||||
|
||||
private inline function getFormattedText(Parameters:Array<Dynamic>)
|
||||
return langFormat.format(Parameters);
|
||||
}
|
||||
@@ -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<String, Dynamic> {
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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<String, String> {
|
||||
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<Dynamic>):String
|
||||
return getUnformatted(defString, id).format(params);
|
||||
public static inline function get(?id:String, ?params:Array<Dynamic>, ?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<Dynamic>, ?def:String):String
|
||||
return get(id, params, def);
|
||||
|
||||
public static inline function translateDiff(?id:String, ?params:Array<Dynamic>):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<String, IFormatInfo> = 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<Dynamic>):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<String> = [];
|
||||
public var indexes:Array<Int> = [];
|
||||
|
||||
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<Dynamic>):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<Dynamic>):String;
|
||||
}
|
||||
@@ -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<String, IFormatInfo> = 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<Dynamic>):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<String> = [];
|
||||
public var indexes:Array<Int> = [];
|
||||
|
||||
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<Dynamic>):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<Dynamic>):String;
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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), "*")
|
||||
]
|
||||
|
||||
@@ -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<String> = [
|
||||
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")
|
||||
];
|
||||
|
||||
/**
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -27,7 +27,7 @@ class ModSwitchMenu extends MusicBeatSubstate {
|
||||
|
||||
alphabets = new FlxTypedGroup<Alphabet>();
|
||||
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);
|
||||
|
||||
@@ -20,6 +20,7 @@ class PauseSubState extends MusicBeatSubstate
|
||||
|
||||
var grpMenuShit:FlxTypedGroup<Alphabet>;
|
||||
|
||||
// TODO: make it possible to translate these
|
||||
var menuItems:Array<String> = ['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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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), "*")
|
||||
]
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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"]);
|
||||
|
||||
@@ -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<Dynamic>)
|
||||
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");
|
||||
|
||||
Reference in New Issue
Block a user