Index: ps/trunk/binaries/data/mods/public/gui/msgbox/msgbox.js
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/msgbox/msgbox.js (revision 21753)
+++ ps/trunk/binaries/data/mods/public/gui/msgbox/msgbox.js (nonexistent)
@@ -1,67 +0,0 @@
-/**
- * Currently limited to at most 3 buttons per message box.
- * The convention is to have "cancel" appear first.
- */
-function init(data)
-{
- // Set title
- Engine.GetGUIObjectByName("mbTitleBar").caption = data.title;
-
- // Set subject
- let mbTextObj = Engine.GetGUIObjectByName("mbText");
- mbTextObj.caption = data.message;
- if (data.font)
- mbTextObj.font = data.font;
-
- // Default behaviour
- let mbCancelHotkey = Engine.GetGUIObjectByName("mbCancelHotkey");
- mbCancelHotkey.onPress = Engine.PopGuiPage;
-
- // Calculate size
- let mbLRDiff = data.width / 2;
- let mbUDDiff = data.height / 2;
- Engine.GetGUIObjectByName("mbMain").size = "50%-" + mbLRDiff + " 50%-" + mbUDDiff + " 50%+" + mbLRDiff + " 50%+" + mbUDDiff;
-
- let captions = data.buttonCaptions || [translate("OK")];
-
- // Set button captions and visibility
- let mbButton = [];
- captions.forEach((caption, i) => {
- mbButton[i] = Engine.GetGUIObjectByName("mbButton" + (i + 1));
-
- let action = function()
- {
- if (data.callback)
- Engine.PopGuiPageCB(i);
- else
- Engine.PopGuiPage();
- };
-
- mbButton[i].caption = caption;
- mbButton[i].onPress = action;
- mbButton[i].hidden = false;
-
- // Convention: Cancel is the first button
- if (i == 0)
- mbCancelHotkey.onPress = action;
- });
-
- // Distribute buttons horizontally
- let y1 = "100%-46";
- let y2 = "100%-18";
- switch (captions.length)
- {
- case 1:
- mbButton[0].size = "18 " + y1 + " 100%-18 " + y2;
- break;
- case 2:
- mbButton[0].size = "18 " + y1 + " 50%-5 " + y2;
- mbButton[1].size = "50%+5 " + y1 + " 100%-18 " + y2;
- break;
- case 3:
- mbButton[0].size = "18 " + y1 + " 33%-5 " + y2;
- mbButton[1].size = "33%+5 " + y1 + " 66%-5 " + y2;
- mbButton[2].size = "66%+5 " + y1 + " 100%-18 " + y2;
- break;
- }
-}
Property changes on: ps/trunk/binaries/data/mods/public/gui/msgbox/msgbox.js
___________________________________________________________________
Deleted: svn:eol-style
## -1 +0,0 ##
-native
\ No newline at end of property
Deleted: svn:mime-type
## -1 +0,0 ##
-text/plain
\ No newline at end of property
Index: ps/trunk/binaries/data/mods/public/gui/msgbox/msgbox.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/msgbox/msgbox.xml (revision 21753)
+++ ps/trunk/binaries/data/mods/public/gui/msgbox/msgbox.xml (nonexistent)
@@ -1,42 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
Property changes on: ps/trunk/binaries/data/mods/public/gui/msgbox/msgbox.xml
___________________________________________________________________
Deleted: svn:eol-style
## -1 +0,0 ##
-native
\ No newline at end of property
Index: ps/trunk/binaries/data/mods/public/gui/page_msgbox.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/page_msgbox.xml (revision 21753)
+++ ps/trunk/binaries/data/mods/public/gui/page_msgbox.xml (nonexistent)
@@ -1,9 +0,0 @@
-
-
- common/modern/setup.xml
- common/modern/styles.xml
- common/modern/sprites.xml
-
- msgbox/msgbox.xml
- common/global.xml
-
Property changes on: ps/trunk/binaries/data/mods/public/gui/page_msgbox.xml
___________________________________________________________________
Deleted: svn:eol-style
## -1 +0,0 ##
-native
\ No newline at end of property
Index: ps/trunk/binaries/data/mods/mod/gui/common/functions_msgbox.js
===================================================================
--- ps/trunk/binaries/data/mods/mod/gui/common/functions_msgbox.js (nonexistent)
+++ ps/trunk/binaries/data/mods/mod/gui/common/functions_msgbox.js (revision 21754)
@@ -0,0 +1,48 @@
+// We want to pass callback functions for the different buttons in a convenient way.
+// Because passing functions accross compartment boundaries is a pain, we just store them here together with some optional arguments.
+// The messageBox page will return the code of the pressed button and the according function will be called.
+var g_MessageBoxBtnFunctions = [];
+var g_MessageBoxCallbackArgs = [];
+
+function messageBoxCallbackFunction(btnCode)
+{
+ if (btnCode !== undefined && g_MessageBoxBtnFunctions[btnCode])
+ {
+ // Cache the variables to make it possible to call a messageBox from a callback function.
+ let callbackFunction = g_MessageBoxBtnFunctions[btnCode];
+ let callbackArgs = g_MessageBoxCallbackArgs[btnCode];
+
+ g_MessageBoxBtnFunctions = [];
+ g_MessageBoxCallbackArgs = [];
+
+ if (callbackArgs !== undefined)
+ callbackFunction(callbackArgs);
+ else
+ callbackFunction();
+ return;
+ }
+
+ g_MessageBoxBtnFunctions = [];
+ g_MessageBoxCallbackArgs = [];
+};
+
+function messageBox(mbWidth, mbHeight, mbMessage, mbTitle, mbButtonCaptions, mbBtnCode, mbCallbackArgs)
+{
+ if (g_MessageBoxBtnFunctions && g_MessageBoxBtnFunctions.length)
+ {
+ warn("A messagebox was called when a previous callback function is still set, aborting!");
+ return;
+ }
+
+ g_MessageBoxBtnFunctions = mbBtnCode;
+ g_MessageBoxCallbackArgs = mbCallbackArgs || g_MessageBoxCallbackArgs;
+
+ Engine.PushGuiPage("page_msgbox.xml", {
+ "width": mbWidth,
+ "height": mbHeight,
+ "message": mbMessage,
+ "title": mbTitle,
+ "buttonCaptions": mbButtonCaptions,
+ "callback": mbBtnCode && "messageBoxCallbackFunction"
+ });
+}
Index: ps/trunk/binaries/data/mods/mod/gui/common/l10n.js
===================================================================
--- ps/trunk/binaries/data/mods/mod/gui/common/l10n.js (revision 21753)
+++ ps/trunk/binaries/data/mods/mod/gui/common/l10n.js (revision 21754)
@@ -1,184 +1,197 @@
/**
+ * Convert time in milliseconds to [HH:]mm:ss string representation.
+ *
+ * @param time Time period in milliseconds (integer)
+ * @return String representing time period
+ */
+function timeToString(time)
+{
+ return Engine.FormatMillisecondsIntoDateStringGMT(time, time < 1000 * 60 * 60 ?
+ // Translation: Time-format string. See http://userguide.icu-project.org/formatparse/datetime for a guide to the meaning of the letters.
+ translate("mm:ss") : translate("HH:mm:ss"));
+}
+
+/**
* These functions rely on the JS cache where possible and
* should be prefered over the Engine.Translate ones to optimize the performance.
*/
var g_Translations = {};
var g_PluralTranslations = {};
var g_TranslationsWithContext = {};
var g_PluralTranslationsWithContext = {};
function isTranslatableString(message)
{
return typeof message == "string" && !!message.trim();
}
/**
* Translates the specified English message into the current language.
*/
function translate(message)
{
if (!g_Translations[message])
g_Translations[message] = Engine.Translate(message);
return g_Translations[message];
}
/**
* Translates the specified English message into the current language for the specified number.
*/
function translatePlural(singularMessage, pluralMessage, number)
{
if (!g_PluralTranslations[singularMessage])
g_PluralTranslations[singularMessage] = {};
if (!g_PluralTranslations[singularMessage][number])
g_PluralTranslations[singularMessage][number] = Engine.TranslatePlural(singularMessage, pluralMessage, number);
return g_PluralTranslations[singularMessage][number];
}
/**
* Translates the specified English message into the current language for the specified context.
*/
function translateWithContext(context, message)
{
if (!g_TranslationsWithContext[context])
- g_TranslationsWithContext[context] = {}
+ g_TranslationsWithContext[context] = {};
if (!g_TranslationsWithContext[context][message])
g_TranslationsWithContext[context][message] = Engine.TranslateWithContext(context, message);
return g_TranslationsWithContext[context][message];
}
/**
* Translates the specified English message into the current language for the specified context and number.
*/
function translatePluralWithContext(context, singularMessage, pluralMessage, number)
{
if (!g_PluralTranslationsWithContext[context])
g_PluralTranslationsWithContext[context] = {};
if (!g_PluralTranslationsWithContext[context][singularMessage])
g_PluralTranslationsWithContext[context][singularMessage] = {};
if (!g_PluralTranslationsWithContext[context][singularMessage][number])
g_PluralTranslationsWithContext[context][singularMessage][number] =
Engine.TranslatePluralWithContext(context, singularMessage, pluralMessage, number);
return g_PluralTranslationsWithContext[context][singularMessage][number];
}
/**
* The input object should contain either of the following properties:
*
* • A ‘message’ property that contains a message to translate.
*
* • A ‘list’ property that contains a list of messages to translate as a
* comma-separated list of translated.
*
* Optionally, the input object may contain a ‘context’ property. In that case,
* the value of this property is used as translation context, that is, passed to
* the translateWithContext(context, message) function.
*/
function translateMessageObject(object)
{
let trans = translate;
if (object.context)
trans = msg => translateWithContext(object.context, msg);
if (object.message)
object = trans(object.message);
else if (object.list)
object = object.list.map(trans).join(translateWithContext("enumeration", ", "));
return object;
}
/**
* Translates any string value in the specified JavaScript object
* that is associated with a key included in the specified keys array.
*
* it accepts an object in the form of
*
* {
* translatedString1: "my first message",
* unTranslatedString1: "some English string",
* ignoredObject: {
* translatedString2: "my second message",
* unTranslatedString2: "some English string"
* },
* translatedObject1: {
* message: "my third singular message",
* context: "message context",
* },
* translatedObject2: {
* list: ["list", "of", "strings"],
* context: "message context",
* },
* }
*
* Together with a keys list to translate the strings and objects
* ["translatedString1", "translatedString2", "translatedObject1",
* "translatedObject2"]
*
* The result will be (f.e. in Dutch)
* {
* translatedString1: "mijn eerste bericht",
* unTranslatedString1: "some English string",
* ignoredObject: {
* translatedString2: "mijn tweede bericht",
* unTranslatedString2: "some English string"
* },
* translatedObject1: "mijn derde bericht",
* translatedObject2: "lijst, van, teksten",
* }
*
* So you see that the keys array can also contain lower-level keys,
* And that you can include objects in the keys array to translate
* them with a context, or to join a list of translations.
*
* Also, the keys array may be an object where properties are keys to translate
* and values are translation contexts to use for each key.
*/
function translateObjectKeys(object, keys)
{
if (keys instanceof Array)
{
for (let property in object)
{
if (keys.indexOf(property) > -1)
{
if (isTranslatableString(object[property]))
object[property] = translate(object[property]);
else if (object[property] instanceof Object)
object[property] = translateMessageObject(object[property]);
}
else if (object[property] instanceof Object)
translateObjectKeys(object[property], keys);
}
}
// If ‘keys’ is not an array, it is an object where keys are properties to
// translate and values are translation contexts to use for each key.
// An empty value means no context.
else
{
for (let property in object)
{
if (property in keys)
{
if (isTranslatableString(object[property]))
if (keys[property])
object[property] = translateWithContext(keys[property], object[property]);
else
object[property] = translate(object[property]);
else if (object[property] instanceof Object)
object[property] = translateMessageObject(object[property]);
}
else if (object[property] instanceof Object)
translateObjectKeys(object[property], keys);
}
}
}
Index: ps/trunk/binaries/data/mods/mod/gui/msgbox/msgbox.xml
===================================================================
--- ps/trunk/binaries/data/mods/mod/gui/msgbox/msgbox.xml (nonexistent)
+++ ps/trunk/binaries/data/mods/mod/gui/msgbox/msgbox.xml (revision 21754)
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Property changes on: ps/trunk/binaries/data/mods/mod/gui/msgbox/msgbox.xml
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Index: ps/trunk/binaries/data/mods/mod/gui/msgbox/msgbox.js
===================================================================
--- ps/trunk/binaries/data/mods/mod/gui/msgbox/msgbox.js (nonexistent)
+++ ps/trunk/binaries/data/mods/mod/gui/msgbox/msgbox.js (revision 21754)
@@ -0,0 +1,67 @@
+/**
+ * Currently limited to at most 3 buttons per message box.
+ * The convention is to have "cancel" appear first.
+ */
+function init(data)
+{
+ // Set title
+ Engine.GetGUIObjectByName("mbTitleBar").caption = data.title;
+
+ // Set subject
+ let mbTextObj = Engine.GetGUIObjectByName("mbText");
+ mbTextObj.caption = data.message;
+ if (data.font)
+ mbTextObj.font = data.font;
+
+ // Default behaviour
+ let mbCancelHotkey = Engine.GetGUIObjectByName("mbCancelHotkey");
+ mbCancelHotkey.onPress = Engine.PopGuiPage;
+
+ // Calculate size
+ let mbLRDiff = data.width / 2;
+ let mbUDDiff = data.height / 2;
+ Engine.GetGUIObjectByName("mbMain").size = "50%-" + mbLRDiff + " 50%-" + mbUDDiff + " 50%+" + mbLRDiff + " 50%+" + mbUDDiff;
+
+ let captions = data.buttonCaptions || [translate("OK")];
+
+ // Set button captions and visibility
+ let mbButton = [];
+ captions.forEach((caption, i) => {
+ mbButton[i] = Engine.GetGUIObjectByName("mbButton" + (i + 1));
+
+ let action = function()
+ {
+ if (data.callback)
+ Engine.PopGuiPageCB(i);
+ else
+ Engine.PopGuiPage();
+ };
+
+ mbButton[i].caption = caption;
+ mbButton[i].onPress = action;
+ mbButton[i].hidden = false;
+
+ // Convention: Cancel is the first button
+ if (i == 0)
+ mbCancelHotkey.onPress = action;
+ });
+
+ // Distribute buttons horizontally
+ let y1 = "100%-46";
+ let y2 = "100%-18";
+ switch (captions.length)
+ {
+ case 1:
+ mbButton[0].size = "18 " + y1 + " 100%-18 " + y2;
+ break;
+ case 2:
+ mbButton[0].size = "18 " + y1 + " 50%-5 " + y2;
+ mbButton[1].size = "50%+5 " + y1 + " 100%-18 " + y2;
+ break;
+ case 3:
+ mbButton[0].size = "18 " + y1 + " 33%-5 " + y2;
+ mbButton[1].size = "33%+5 " + y1 + " 66%-5 " + y2;
+ mbButton[2].size = "66%+5 " + y1 + " 100%-18 " + y2;
+ break;
+ }
+}
Property changes on: ps/trunk/binaries/data/mods/mod/gui/msgbox/msgbox.js
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: ps/trunk/binaries/data/mods/mod/gui/page_msgbox.xml
===================================================================
--- ps/trunk/binaries/data/mods/mod/gui/page_msgbox.xml (nonexistent)
+++ ps/trunk/binaries/data/mods/mod/gui/page_msgbox.xml (revision 21754)
@@ -0,0 +1,8 @@
+
+
+ common/modern/setup.xml
+ common/modern/styles.xml
+ common/modern/sprites.xml
+
+ msgbox/msgbox.xml
+
Property changes on: ps/trunk/binaries/data/mods/mod/gui/page_msgbox.xml
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Index: ps/trunk/binaries/data/mods/mod/l10n/messages.json
===================================================================
--- ps/trunk/binaries/data/mods/mod/l10n/messages.json (revision 21753)
+++ ps/trunk/binaries/data/mods/mod/l10n/messages.json (revision 21754)
@@ -1,45 +1,45 @@
[
{
"output": "mod-selector.pot",
"inputRoot": "..",
"project": "Pyrogenesis - Mod Selector",
"copyrightHolder": "Wildfire Games",
"rules": [
{
"extractor": "javascript",
"filemasks": [
- "gui/modmod/**.js"
+ "gui/**.js"
],
"options": {
"format": "javascript-format",
"keywords": {
"translate": [1],
"translatePlural": [1, 2],
"translateWithContext": [[1], 2],
"translatePluralWithContext": [[1], 2, 3],
"markForTranslation": [1],
"markForTranslationWithContext": [[1], 2]
},
"commentTags": [
"Translation:"
]
}
},
{
"extractor": "xml",
"filemasks": [
- "gui/modmod/**.xml"
+ "gui/**.xml"
],
"options": {
"format": "none",
"keywords": {
"translatableAttribute": {
"locationAttributes": ["id"]
},
"translate": {}
}
}
}
]
}
]
Index: ps/trunk/binaries/data/mods/public/gui/common/functions_global_object.js
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/common/functions_global_object.js (revision 21753)
+++ ps/trunk/binaries/data/mods/public/gui/common/functions_global_object.js (revision 21754)
@@ -1,158 +1,109 @@
-// We want to pass callback functions for the different buttons in a convenient way.
-// Because passing functions accross compartment boundaries is a pain, we just store them here together with some optional arguments.
-// The messageBox page will return the code of the pressed button and the according function will be called.
-var g_MessageBoxBtnFunctions = [];
-var g_MessageBoxCallbackArgs = [];
-
-var g_MessageBoxCallbackFunction = function(btnCode)
-{
- if (btnCode !== undefined && g_MessageBoxBtnFunctions[btnCode])
- {
- // Cache the variables to make it possible to call a messageBox from a callback function.
- let callbackFunction = g_MessageBoxBtnFunctions[btnCode];
- let callbackArgs = g_MessageBoxCallbackArgs[btnCode];
-
- g_MessageBoxBtnFunctions = [];
- g_MessageBoxCallbackArgs = [];
-
- if (callbackArgs !== undefined)
- callbackFunction(callbackArgs);
- else
- callbackFunction();
- return;
- }
-
- g_MessageBoxBtnFunctions = [];
- g_MessageBoxCallbackArgs = [];
-};
-
-function messageBox(mbWidth, mbHeight, mbMessage, mbTitle, mbButtonCaptions, mbBtnCode, mbCallbackArgs)
-{
- if (g_MessageBoxBtnFunctions && g_MessageBoxBtnFunctions.length)
- {
- warn("A messagebox was called when a previous callback function is still set, aborting!");
- return;
- }
-
- g_MessageBoxBtnFunctions = mbBtnCode;
- g_MessageBoxCallbackArgs = mbCallbackArgs || g_MessageBoxCallbackArgs;
-
- Engine.PushGuiPage("page_msgbox.xml", {
- "width": mbWidth,
- "height": mbHeight,
- "message": mbMessage,
- "title": mbTitle,
- "buttonCaptions": mbButtonCaptions,
- "callback": mbBtnCode && "g_MessageBoxCallbackFunction"
- });
-}
-
function openURL(url)
{
Engine.OpenURL(url);
messageBox(
600, 200,
sprintf(
translate("Opening %(url)s\n in default web browser. Please wait…"),
{ "url": url }
),
translate("Opening page")
);
}
function updateCounters()
{
let counters = [];
if (Engine.ConfigDB_GetValue("user", "overlay.fps") === "true")
// dennis-ignore: *
counters.push(sprintf(translate("FPS: %(fps)4s"), { "fps": Engine.GetFPS() }));
if (Engine.ConfigDB_GetValue("user", "overlay.realtime") === "true")
counters.push((new Date()).toLocaleTimeString());
// If game has been started
if (typeof appendSessionCounters != "undefined")
appendSessionCounters(counters);
let dataCounter = Engine.GetGUIObjectByName("dataCounter");
dataCounter.caption = counters.join("\n") + "\n";
dataCounter.hidden = !counters.length;
dataCounter.size = sprintf("%(left)s %(top)s %(right)s %(bottom)s", {
"left": "100%%-100",
"top": "40",
"right": "100%%-5",
"bottom": 40 + 14 * counters.length
});
}
/**
* Update the overlay with the most recent network warning of each client.
*/
function displayGamestateNotifications()
{
let messages = [];
let maxTextWidth = 0;
// Add network warnings
if (Engine.ConfigDB_GetValue("user", "overlay.netwarnings") == "true")
{
let netwarnings = getNetworkWarnings();
messages = messages.concat(netwarnings.messages);
maxTextWidth = Math.max(maxTextWidth, netwarnings.maxTextWidth);
}
// Resize textbox
let width = maxTextWidth + 20;
let height = 14 * messages.length;
// Position left of the dataCounter
let top = "40";
let right = Engine.GetGUIObjectByName("dataCounter").hidden ? "100%-15" : "100%-110";
let bottom = top + "+" + height;
let left = right + "-" + width;
let gameStateNotifications = Engine.GetGUIObjectByName("gameStateNotifications");
gameStateNotifications.caption = messages.join("\n");
gameStateNotifications.hidden = !messages.length;
gameStateNotifications.size = left + " " + top + " " + right + " " + bottom;
setTimeout(displayGamestateNotifications, 1000);
}
/**
* This function is called from the engine whenever starting a game fails.
*/
function cancelOnLoadGameError(msg)
{
Engine.EndGame();
Engine.SwitchGuiPage("page_pregame.xml");
if (msg)
Engine.PushGuiPage("page_msgbox.xml", {
"width": 500,
"height": 200,
"message": '[font="sans-bold-18"]' + msg + '[/font]',
"title": translate("Loading Aborted"),
"mode": 2
});
Engine.ResetCursor();
}
/**
* Also called from the C++ side when ending the game.
* The current page can be the summary screen or a message box, so it can't be moved to session/.
*/
function getReplayMetadata()
{
let extendedSimState = Engine.GuiInterfaceCall("GetExtendedSimulationState");
return {
"timeElapsed": extendedSimState.timeElapsed,
"playerStates": extendedSimState.players,
"mapSettings": Engine.GetInitAttributes().settings
};
}
Index: ps/trunk/binaries/data/mods/public/gui/common/functions_utility.js
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/common/functions_utility.js (revision 21753)
+++ ps/trunk/binaries/data/mods/public/gui/common/functions_utility.js (revision 21754)
@@ -1,239 +1,228 @@
/**
* Used for acoustic GUI notifications.
* Define the soundfile paths and specific time thresholds (avoid spam).
* And store the timestamp of last interaction for each notification.
*/
var g_SoundNotifications = {
"nick": { "soundfile": "audio/interface/ui/chat_alert.ogg", "threshold": 3000 }
};
/**
* Save setting for current instance and write setting to the user config file.
*/
function saveSettingAndWriteToUserConfig(setting, value)
{
Engine.ConfigDB_CreateValue("user", setting, value);
Engine.ConfigDB_WriteValueToFile("user", setting, value, "config/user.cfg");
}
/**
* Returns translated history and gameplay data of all civs, optionally including a mock gaia civ.
*/
function loadCivData(selectableOnly, gaia)
{
let civData = loadCivFiles(selectableOnly);
translateObjectKeys(civData, ["Name", "Description", "History", "Special"]);
if (gaia)
civData.gaia = { "Code": "gaia", "Name": translate("Gaia") };
return deepfreeze(civData);
}
// A sorting function for arrays of objects with 'name' properties, ignoring case
function sortNameIgnoreCase(x, y)
{
let lowerX = x.name.toLowerCase();
let lowerY = y.name.toLowerCase();
if (lowerX < lowerY)
return -1;
if (lowerX > lowerY)
return 1;
return 0;
}
/**
* Escape tag start and escape characters, so users cannot use special formatting.
* Also limit string length to 256 characters (not counting escape characters).
*/
function escapeText(text, limitLength = true)
{
if (!text)
return text;
if (limitLength)
text = text.substr(0, 255);
return text.replace(/\\/g, "\\\\").replace(/\[/g, "\\[");
}
function unescapeText(text)
{
if (!text)
return text;
return text.replace(/\\\\/g, "\\").replace(/\\\[/g, "\[");
}
/**
* Merge players by team to remove duplicate Team entries, thus reducing the packet size of the lobby report.
*/
function playerDataToStringifiedTeamList(playerData)
{
let teamList = {};
for (let pData of playerData)
{
let team = pData.Team === undefined ? -1 : pData.Team;
if (!teamList[team])
teamList[team] = [];
teamList[team].push(pData);
delete teamList[team].Team;
}
return escapeText(JSON.stringify(teamList), false);
}
function stringifiedTeamListToPlayerData(stringifiedTeamList)
{
let teamList = JSON.parse(unescapeText(stringifiedTeamList));
let playerData = [];
for (let team in teamList)
for (let pData of teamList[team])
{
pData.Team = team;
playerData.push(pData);
}
return playerData;
}
function translateMapTitle(mapTitle)
{
return mapTitle == "random" ? translateWithContext("map selection", "Random") : translate(mapTitle);
}
-/**
- * Convert time in milliseconds to [hh:]mm:ss string representation.
- * @param time Time period in milliseconds (integer)
- * @return String representing time period
- */
-function timeToString(time)
-{
- return Engine.FormatMillisecondsIntoDateStringGMT(time, time < 1000 * 60 * 60 ?
- translate("mm:ss") : translate("HH:mm:ss"));
-}
-
function removeDupes(array)
{
// loop backwards to make splice operations cheaper
let i = array.length;
while (i--)
if (array.indexOf(array[i]) != i)
array.splice(i, 1);
}
function singleplayerName()
{
return Engine.ConfigDB_GetValue("user", "playername.singleplayer") || Engine.GetSystemUsername();
}
function multiplayerName()
{
return Engine.ConfigDB_GetValue("user", "playername.multiplayer") || Engine.GetSystemUsername();
}
function tryAutoComplete(text, autoCompleteList)
{
if (!text.length)
return text;
var wordSplit = text.split(/\s/g);
if (!wordSplit.length)
return text;
var lastWord = wordSplit.pop();
if (!lastWord.length)
return text;
for (var word of autoCompleteList)
{
if (word.toLowerCase().indexOf(lastWord.toLowerCase()) != 0)
continue;
text = wordSplit.join(" ");
if (text.length > 0)
text += " ";
text += word;
break;
}
return text;
}
function autoCompleteNick(guiObject, playernames)
{
let text = guiObject.caption;
if (!text.length)
return;
let bufferPosition = guiObject.buffer_position;
let textTillBufferPosition = text.substring(0, bufferPosition);
let newText = tryAutoComplete(textTillBufferPosition, playernames);
guiObject.caption = newText + text.substring(bufferPosition);
guiObject.buffer_position = bufferPosition + (newText.length - textTillBufferPosition.length);
}
function clearChatMessages()
{
g_ChatMessages.length = 0;
Engine.GetGUIObjectByName("chatText").caption = "";
try {
for (let timer of g_ChatTimers)
clearTimeout(timer);
g_ChatTimers.length = 0;
} catch (e) {
}
}
/**
* Manage acoustic GUI notifications.
*
* @param {string} type - Notification type.
*/
function soundNotification(type)
{
if (Engine.ConfigDB_GetValue("user", "sound.notify." + type) != "true")
return;
let notificationType = g_SoundNotifications[type];
let timeNow = Date.now();
if (!notificationType.lastInteractionTime || timeNow > notificationType.lastInteractionTime + notificationType.threshold)
Engine.PlayUISound(notificationType.soundfile, false);
notificationType.lastInteractionTime = timeNow;
}
/**
* Horizontally spaces objects within a parent
*
* @param margin The gap, in px, between the objects
*/
function horizontallySpaceObjects(parentName, margin = 0)
{
let objects = Engine.GetGUIObjectByName(parentName).children;
for (let i = 0; i < objects.length; ++i)
{
let size = objects[i].size;
let width = size.right - size.left;
size.left = i * (width + margin) + margin;
size.right = (i + 1) * (width + margin);
objects[i].size = size;
}
}
/**
* Hide all children after a certain index
*/
function hideRemaining(parentName, start = 0)
{
let objects = Engine.GetGUIObjectByName(parentName).children;
for (let i = start; i < objects.length; ++i)
objects[i].hidden = true;
}
Index: ps/trunk/binaries/data/mods/public/l10n/messages.json
===================================================================
--- ps/trunk/binaries/data/mods/public/l10n/messages.json (revision 21753)
+++ ps/trunk/binaries/data/mods/public/l10n/messages.json (revision 21754)
@@ -1,740 +1,738 @@
[
{
"output": "public-civilizations.pot",
"inputRoot": "..",
"project": "0 A.D. — Empires Ascendant",
"copyrightHolder": "Wildfire Games",
"rules": [
{
"extractor": "json",
"filemasks": [
"simulation/data/civs/**.json"
],
"options": {
"keywords": [
"Name",
"Description",
"History",
"Special",
"AINames"
]
}
}
]
},
{
"output": "public-gui-ingame.pot",
"inputRoot": "..",
"project": "0 A.D. — Empires Ascendant",
"copyrightHolder": "Wildfire Games",
"rules": [
{
"extractor": "javascript",
"filemasks": [
"gui/session/**.js"
],
"options": {
"format": "javascript-format",
"keywords": {
"translate": [1],
"translatePlural": [1, 2],
"translateWithContext": [[1], 2],
"translatePluralWithContext": [[1], 2, 3],
"markForTranslation": [1],
"markForTranslationWithContext": [[1], 2],
"markForPluralTranslation": [1, 2]
},
"commentTags": [
"Translation:"
]
}
},
{
"extractor": "xml",
"filemasks": [
"gui/session/**.xml"
],
"options": {
"keywords": {
"translatableAttribute": {
"locationAttributes": ["id"]
},
"translate": {}
}
}
}
]
},
{
"output": "public-gui-gamesetup.pot",
"inputRoot": "..",
"project": "0 A.D. — Empires Ascendant",
"copyrightHolder": "Wildfire Games",
"rules": [
{
"extractor": "javascript",
"filemasks": [
"gui/aiconfig/**.js",
"gui/gamesetup/**.js",
"gui/loading/**.js"
],
"options": {
"format": "javascript-format",
"keywords": {
"translate": [1],
"translatePlural": [1, 2],
"translateWithContext": [[1], 2],
"translatePluralWithContext": [[1], 2, 3],
"markForTranslation": [1],
"markForTranslationWithContext": [[1], 2],
"markForPluralTranslation": [1, 2]
},
"commentTags": [
"Translation:"
]
}
},
{
"extractor": "xml",
"filemasks": [
"gui/aiconfig/**.xml",
"gui/gamesetup/**.xml",
"gui/loading/**.xml"
],
"options": {
"keywords": {
"translatableAttribute": {
"locationAttributes": ["id"]
},
"translate": {}
}
}
},
{
"extractor": "txt",
"filemasks": [
"gui/text/quotes.txt"
],
"options": {
}
}
]
},
{
"output": "public-gui-lobby.pot",
"inputRoot": "..",
"project": "0 A.D. — Empires Ascendant",
"copyrightHolder": "Wildfire Games",
"rules": [
{
"extractor": "javascript",
"filemasks": [
"gui/lobby/**.js",
"gui/prelobby/**.js"
],
"options": {
"format": "javascript-format",
"keywords": {
"translate": [1],
"translatePlural": [1, 2],
"translateWithContext": [[1], 2],
"translatePluralWithContext": [[1], 2, 3],
"markForTranslation": [1],
"markForTranslationWithContext": [[1], 2],
"markForPluralTranslation": [1, 2]
},
"commentTags": [
"Translation:"
]
}
},
{
"extractor": "xml",
"filemasks": [
"gui/lobby/**.xml",
"gui/prelobby/**.xml"
],
"options": {
"keywords": {
"translatableAttribute": {
"locationAttributes": ["id"]
},
"translate": {}
}
}
},
{
"extractor": "txt",
"filemasks": [
"gui/prelobby/Terms_of_Service.txt",
"gui/prelobby/Terms_of_Use.txt"
],
"options": {
}
}
]
},
{
"output": "public-gui-manual.pot",
"inputRoot": "..",
"project": "0 A.D. — Empires Ascendant",
"copyrightHolder": "Wildfire Games",
"rules": [
{
"extractor": "javascript",
"filemasks": [
"gui/manual/**.js"
],
"options": {
"format": "javascript-format",
"keywords": {
"translate": [1],
"translatePlural": [1, 2],
"translateWithContext": [[1], 2],
"translatePluralWithContext": [[1], 2, 3],
"markForTranslation": [1],
"markForTranslationWithContext": [[1], 2],
"markForPluralTranslation": [1, 2]
},
"commentTags": [
"Translation:"
]
}
},
{
"extractor": "xml",
"filemasks": [
"gui/manual/**.xml"
],
"options": {
"keywords": {
"translatableAttribute": {
"locationAttributes": ["id"]
},
"translate": {}
}
}
},
{
"extractor": "txt",
"filemasks": [
"gui/manual/intro.txt",
"gui/manual/userreport.txt"
],
"options": {
}
}
]
},
{
"output": "public-gui-other.pot",
"inputRoot": "..",
"project": "0 A.D. — Empires Ascendant",
"copyrightHolder": "Wildfire Games",
"rules": [
{
"extractor": "javascript",
"filemasks": [
"globalscripts/**.js",
"gui/civinfo/**.js",
"gui/common/**.js",
"gui/credits/**.js",
"gui/locale/**.js",
- "gui/msgbox/**.js",
"gui/options/**.js",
"gui/pregame/**.js",
"gui/reference/common/**.js",
"gui/reference/structree/**.js",
"gui/reference/viewer/**.js",
"gui/replaymenu/**.js",
"gui/savedgames/**.js",
"gui/splashscreen/**.js",
"gui/summary/**.js"
],
"options": {
"format": "javascript-format",
"keywords": {
"translate": [1],
"translatePlural": [1, 2],
"translateWithContext": [[1], 2],
"translatePluralWithContext": [[1], 2, 3],
"markForTranslation": [1],
"markForTranslationWithContext": [[1], 2],
"markForPluralTranslation": [1, 2]
},
"commentTags": [
"dennis-ignore:",
"Translation:"
]
}
},
{
"extractor": "xml",
"filemasks": [
"globalscripts/**.xml",
"gui/civinfo/**.xml",
"gui/common/**.xml",
"gui/credits/**.xml",
"gui/locale/**.xml",
- "gui/msgbox/**.xml",
"gui/options/**.xml",
"gui/pregame/**.xml",
"gui/reference/structree/**.xml",
"gui/reference/viewer/**.xml",
"gui/replaymenu/**.xml",
"gui/savedgames/**.xml",
"gui/splashscreen/**.xml",
"gui/summary/**.xml"
],
"options": {
"keywords": {
"translatableAttribute": {
"locationAttributes": ["id"]
},
"translate": {}
}
}
},
{
"extractor": "json",
"filemasks": [
"gui/credits/texts/**.json"
],
"options": {
"keywords": [
"Title",
"Subtitle"
]
}
},
{
"extractor": "json",
"filemasks": [
"gui/options/**.json"
],
"options": {
"keywords": [
"label",
"tooltip"
]
}
},
{
"extractor": "json",
"filemasks": [
"simulation/data/resources/**.json"
],
"options": {
"keywords": [
"description"
]
}
},
{
"extractor": "json",
"filemasks": [
"simulation/data/resources/**.json"
],
"options": {
"keywords": [
"name",
"subtypes"
],
"comments": [
"Translation: Word as used at the beginning of a sentence or as a single-word sentence."
],
"context": "firstWord"
}
},
{
"extractor": "json",
"filemasks": [
"simulation/data/resources/**.json"
],
"options": {
"keywords": [
"name",
"subtypes"
],
"comments": [
"Translation: Word as used in the middle of a sentence (which may require using lowercase for your language)."
],
"context": "withinSentence"
}
},
{
"extractor": "txt",
"filemasks": [
"gui/gamesetup/**.txt",
"gui/splashscreen/splashscreen.txt",
"gui/text/tips/**.txt"
],
"options": {
}
}
]
},
{
"output": "public-templates-units.pot",
"inputRoot": "..",
"project": "0 A.D. — Empires Ascendant",
"copyrightHolder": "Wildfire Games",
"rules": [
{
"extractor": "xml",
"filemasks": [
"simulation/templates/template_unit_*.xml",
"simulation/templates/units/**.xml"
],
"options": {
"keywords": {
"GenericName": {},
"SpecificName": {},
"History": {},
"VisibleClasses": {
"splitOnWhitespace": true
},
"Tooltip": {},
"DisabledTooltip": {},
"FormationName": {},
"FromClass": {},
"Rank": {
"tagAsContext": true
}
}
}
}
]
},
{
"output": "public-templates-buildings.pot",
"inputRoot": "..",
"project": "0 A.D. — Empires Ascendant",
"copyrightHolder": "Wildfire Games",
"rules": [
{
"extractor": "xml",
"filemasks": [
"simulation/templates/template_structure_*.xml",
"simulation/templates/structures/**.xml"
],
"options": {
"keywords": {
"GenericName": {},
"SpecificName": {},
"History": {},
"VisibleClasses": {
"splitOnWhitespace": true
},
"Tooltip": {},
"DisabledTooltip": {},
"FormationName": {},
"FromClass": {},
"Rank": {
"tagAsContext": true
}
}
}
}
]
},
{
"output": "public-templates-other.pot",
"inputRoot": "..",
"project": "0 A.D. — Empires Ascendant",
"copyrightHolder": "Wildfire Games",
"rules": [
{
"extractor": "xml",
"filemasks": {
"includeMasks": [
"simulation/templates/**.xml"
],
"excludeMasks": [
"simulation/templates/structures/**.xml",
"simulation/templates/template_structure_*.xml",
"simulation/templates/template_unit_*.xml",
"simulation/templates/units/**.xml"
]
},
"options": {
"keywords": {
"GenericName": {},
"SpecificName": {},
"History": {},
"VisibleClasses": {
"splitOnWhitespace": true
},
"Tooltip": {},
"DisabledTooltip": {},
"FormationName": {},
"FromClass": {},
"Rank": {
"tagAsContext": true
}
}
}
}
]
},
{
"output": "public-simulation-auras.pot",
"inputRoot": "..",
"project": "0 A.D. — Empires Ascendant",
"copyrightHolder": "Wildfire Games",
"rules": [
{
"extractor": "json",
"filemasks": [
"simulation/data/auras/**.json"
],
"options": {
"keywords": [
"auraName",
"auraDescription"
]
}
}
]
},
{
"output": "public-simulation-technologies.pot",
"inputRoot": "..",
"project": "0 A.D. — Empires Ascendant",
"copyrightHolder": "Wildfire Games",
"rules": [
{
"extractor": "json",
"filemasks": [
"simulation/data/technologies/**.json"
],
"options": {
"keywords": [
"specificName",
"genericName",
"description",
"tooltip",
"requirementsTooltip"
]
}
}
]
},
{
"output": "public-simulation-other.pot",
"inputRoot": "..",
"project": "0 A.D. — Empires Ascendant",
"copyrightHolder": "Wildfire Games",
"rules": [
{
"extractor": "javascript",
"filemasks": [
"simulation/ai/**.js",
"simulation/components/**.js",
"simulation/helpers/**.js"
],
"options": {
"format": "javascript-format",
"keywords": {
"translate": [1],
"translatePlural": [1, 2],
"translateWithContext": [[1], 2],
"translatePluralWithContext": [[1], 2, 3],
"markForTranslation": [1],
"markForTranslationWithContext": [[1], 2],
"markForPluralTranslation": [1, 2]
},
"commentTags": [
"Translation:"
]
}
},
{
"extractor": "json",
"filemasks": [
"simulation/data/settings/player_defaults.json"
],
"options": {
"keywords": [
"Name"
]
}
},
{
"extractor": "json",
"filemasks": [
"simulation/data/settings/game_speeds.json"
],
"options": {
"keywords": ["Title"]
}
},
{
"extractor": "json",
"filemasks": [
"simulation/data/settings/victory_conditions/*.json"
],
"options": {
"keywords": ["Title", "Description"]
}
},
{
"extractor": "json",
"filemasks": [
"simulation/data/settings/starting_resources.json"
],
"options": {
"keywords": ["Title"],
"context": "startingResources"
}
},
{
"extractor": "json",
"filemasks": [
"simulation/data/settings/trigger_difficulties.json"
],
"options": {
"keywords": ["Title", "Tooltip"]
}
},
{
"extractor": "json",
"filemasks": [
"simulation/data/settings/map_sizes.json"
],
"options": {
"keywords": [
"Name",
"Tooltip"
]
}
},
{
"extractor": "json",
"filemasks": [
"simulation/ai/**.json"
],
"options": {
"keywords": [
"name",
"description"
]
}
}
]
},
{
"output": "public-maps.pot",
"inputRoot": "..",
"project": "0 A.D. — Empires Ascendant",
"copyrightHolder": "Wildfire Games",
"rules": [
{
"extractor": "json",
"filemasks": [
"maps/random/**.json"
],
"options": {
"keywords": [
"Name",
"Description"
]
}
},
{
"extractor": "javascript",
"filemasks": [
"maps/scenarios/**.js",
"maps/skirmishes/**.js",
"maps/random/**.js"
],
"options": {
"format": "javascript-format",
"keywords": {
"markForTranslation": [1],
"markForTranslationWithContext": [[1], 2],
"markForPluralTranslation": [1, 2]
},
"commentTags": [
"Translation:"
]
}
},
{
"extractor": "xml",
"filemasks": [
"maps/scenarios/**.xml",
"maps/skirmishes/**.xml"
],
"options": {
"keywords": {
"ScriptSettings": {
"extractJson": {
"keywords": [
"Name",
"Description"
]
}
}
}
}
},
{
"extractor": "json",
"filemasks": [
"maps/random/rmbiome/**.json"
],
"options": {
"keywords": [
"Title",
"Description"
],
"context": "biome definition"
}
}
]
},
{
"output": "public-tutorials.pot",
"inputRoot": "..",
"project": "0 A.D. — Empires Ascendant",
"copyrightHolder": "Wildfire Games",
"rules": [
{
"extractor": "javascript",
"filemasks": [
"maps/tutorials/**.js"
],
"options": {
"format": "javascript-format",
"keywords": {
"markForTranslation": [1],
"markForTranslationWithContext": [[1], 2],
"markForPluralTranslation": [1, 2]
},
"commentTags": [
"Translation:"
]
}
},
{
"extractor": "xml",
"filemasks": [
"maps/tutorials/**.xml"
],
"options": {
"keywords": {
"ScriptSettings": {
"extractJson": {
"keywords": [
"Name",
"Description"
]
}
}
}
}
}
]
}
]