Ticket #67: internationalization.patch
File internationalization.patch, 507.9 KB (added by , 11 years ago) |
---|
-
new file inaries/data/localization/.tx/config
diff --git a/binaries/data/localization/.tx/config b/binaries/data/localization/.tx/config new file mode 100644 index 0000000..9695d34
- + 1 [main] 2 host = https://www.transifex.com 3 4 [0ad.engine] 5 file_filter = <lang>.engine.po 6 source_file = engine.pot 7 source_lang = en 8 -
new file inaries/data/mods/public/globalscripts/localization.js
diff --git a/binaries/data/mods/public/globalscripts/localization.js b/binaries/data/mods/public/globalscripts/localization.js new file mode 100644 index 0000000..158f9e4
- + 1 // Localizes (translates) any string value in the specified JavaScript object that is associated with a key included in 2 // the specified keys array. 3 function localizeObjectKeys(object, keys) { 4 for (property in object) 5 { 6 if (keys.indexOf(property) > -1) 7 { 8 if (object[property] != "" && object[property] !== undefined) 9 { 10 object[property] = Engine.localize(object[property]); 11 } 12 } 13 else 14 { 15 // From http://stackoverflow.com/a/7390612/939364 16 var variableType = ({}).toString.call(object[property]).match(/\s([a-zA-Z]+)/)[1].toLowerCase(); 17 if (variableType === "object" || variableType == "array") 18 { 19 localizeObjectKeys(object[property], keys); 20 } 21 } 22 } 23 } -
new file inaries/data/mods/public/globalscripts/sprintf.js
diff --git a/binaries/data/mods/public/globalscripts/sprintf.js b/binaries/data/mods/public/globalscripts/sprintf.js new file mode 100644 index 0000000..320b061
- + 1 /** 2 sprintf() for JavaScript 0.7-beta1 3 http://www.diveintojavascript.com/projects/javascript-sprintf 4 5 Copyright (c) Alexandru Marasteanu <alexaholic [at) gmail (dot] com> 6 All rights reserved. 7 8 Redistribution and use in source and binary forms, with or without 9 modification, are permitted provided that the following conditions are met: 10 * Redistributions of source code must retain the above copyright 11 notice, this list of conditions and the following disclaimer. 12 * Redistributions in binary form must reproduce the above copyright 13 notice, this list of conditions and the following disclaimer in the 14 documentation and/or other materials provided with the distribution. 15 * Neither the name of sprintf() for JavaScript nor the 16 names of its contributors may be used to endorse or promote products 17 derived from this software without specific prior written permission. 18 19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 20 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 DISCLAIMED. IN NO EVENT SHALL Alexandru Marasteanu BE LIABLE FOR ANY 23 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 26 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 30 31 Changelog: 32 2010.09.06 - 0.7-beta1 33 - features: vsprintf, support for named placeholders 34 - enhancements: format cache, reduced global namespace pollution 35 36 2010.05.22 - 0.6: 37 - reverted to 0.4 and fixed the bug regarding the sign of the number 0 38 Note: 39 Thanks to Raphael Pigulla <raph (at] n3rd [dot) org> (http://www.n3rd.org/) 40 who warned me about a bug in 0.5, I discovered that the last update was 41 a regress. I appologize for that. 42 43 2010.05.09 - 0.5: 44 - bug fix: 0 is now preceeded with a + sign 45 - bug fix: the sign was not at the right position on padded results (Kamal Abdali) 46 - switched from GPL to BSD license 47 48 2007.10.21 - 0.4: 49 - unit test and patch (David Baird) 50 51 2007.09.17 - 0.3: 52 - bug fix: no longer throws exception on empty paramenters (Hans Pufal) 53 54 2007.09.11 - 0.2: 55 - feature: added argument swapping 56 57 2007.04.03 - 0.1: 58 - initial release 59 **/ 60 61 var sprintf = (function() { 62 function get_type(variable) { 63 return Object.prototype.toString.call(variable).slice(8, -1).toLowerCase(); 64 } 65 function str_repeat(input, multiplier) { 66 for (var output = []; multiplier > 0; output[--multiplier] = input) {/* do nothing */} 67 return output.join(''); 68 } 69 70 var str_format = function() { 71 if (!str_format.cache.hasOwnProperty(arguments[0])) { 72 str_format.cache[arguments[0]] = str_format.parse(arguments[0]); 73 } 74 return str_format.format.call(null, str_format.cache[arguments[0]], arguments); 75 }; 76 77 str_format.format = function(parse_tree, argv) { 78 var cursor = 1, tree_length = parse_tree.length, node_type = '', arg, output = [], i, k, match, pad, pad_character, pad_length; 79 for (i = 0; i < tree_length; i++) { 80 node_type = get_type(parse_tree[i]); 81 if (node_type === 'string') { 82 output.push(parse_tree[i]); 83 } 84 else if (node_type === 'array') { 85 match = parse_tree[i]; // convenience purposes only 86 if (match[2]) { // keyword argument 87 arg = argv[cursor]; 88 for (k = 0; k < match[2].length; k++) { 89 if (!arg.hasOwnProperty(match[2][k])) { 90 throw(sprintf(Engine.localize('[sprintf] property "%s" does not exist'), match[2][k])); 91 } 92 arg = arg[match[2][k]]; 93 } 94 } 95 else if (match[1]) { // positional argument (explicit) 96 arg = argv[match[1]]; 97 } 98 else { // positional argument (implicit) 99 arg = argv[cursor++]; 100 } 101 102 if (/[^s]/.test(match[8]) && (get_type(arg) != 'number')) { 103 throw(sprintf(Engine.localize('[sprintf] expecting number but found %s'), get_type(arg))); 104 } 105 switch (match[8]) { 106 case 'b': arg = arg.toString(2); break; 107 case 'c': arg = String.fromCharCode(arg); break; 108 case 'd': arg = parseInt(arg, 10); break; 109 case 'e': arg = match[7] ? arg.toExponential(match[7]) : arg.toExponential(); break; 110 case 'f': arg = match[7] ? parseFloat(arg).toFixed(match[7]) : parseFloat(arg); break; 111 case 'o': arg = arg.toString(8); break; 112 case 's': arg = ((arg = String(arg)) && match[7] ? arg.substring(0, match[7]) : arg); break; 113 case 'u': arg = Math.abs(arg); break; 114 case 'x': arg = arg.toString(16); break; 115 case 'X': arg = arg.toString(16).toUpperCase(); break; 116 } 117 arg = (/[def]/.test(match[8]) && match[3] && arg >= 0 ? '+'+ arg : arg); 118 pad_character = match[4] ? match[4] == '0' ? '0' : match[4].charAt(1) : ' '; 119 pad_length = match[6] - String(arg).length; 120 pad = match[6] ? str_repeat(pad_character, pad_length) : ''; 121 output.push(match[5] ? arg + pad : pad + arg); 122 } 123 } 124 return output.join(''); 125 }; 126 127 str_format.cache = {}; 128 129 str_format.parse = function(fmt) { 130 var _fmt = fmt, match = [], parse_tree = [], arg_names = 0; 131 while (_fmt) { 132 if ((match = /^[^\x25]+/.exec(_fmt)) !== null) { 133 parse_tree.push(match[0]); 134 } 135 else if ((match = /^\x25{2}/.exec(_fmt)) !== null) { 136 parse_tree.push('%'); 137 } 138 else if ((match = /^\x25(?:([1-9]\d*)\$|\(([^\)]+)\))?(\+)?(0|'[^$])?(-)?(\d+)?(?:\.(\d+))?([b-fosuxX])/.exec(_fmt)) !== null) { 139 if (match[2]) { 140 arg_names |= 1; 141 var field_list = [], replacement_field = match[2], field_match = []; 142 if ((field_match = /^([a-z_][a-z_\d]*)/i.exec(replacement_field)) !== null) { 143 field_list.push(field_match[1]); 144 while ((replacement_field = replacement_field.substring(field_match[0].length)) !== '') { 145 if ((field_match = /^\.([a-z_][a-z_\d]*)/i.exec(replacement_field)) !== null) { 146 field_list.push(field_match[1]); 147 } 148 else if ((field_match = /^\[(\d+)\]/.exec(replacement_field)) !== null) { 149 field_list.push(field_match[1]); 150 } 151 else { 152 throw(Engine.localize('[sprintf] huh?')); 153 } 154 } 155 } 156 else { 157 throw(Engine.localize('[sprintf] huh?')); 158 } 159 match[2] = field_list; 160 } 161 else { 162 arg_names |= 2; 163 } 164 if (arg_names === 3) { 165 throw(Engine.localize('[sprintf] mixing positional and named placeholders is not (yet) supported')); 166 } 167 parse_tree.push(match); 168 } 169 else { 170 throw(Engine.localize('[sprintf] huh?')); 171 } 172 _fmt = _fmt.substring(match[0].length); 173 } 174 return parse_tree; 175 }; 176 177 return str_format; 178 })(); 179 180 var vsprintf = function(fmt, argv) { 181 argv.unshift(fmt); 182 return sprintf.apply(null, argv); 183 }; -
binaries/data/mods/public/gui/aiconfig/aiconfig.js
diff --git a/binaries/data/mods/public/gui/aiconfig/aiconfig.js b/binaries/data/mods/public/gui/aiconfig/aiconfig.js index 76e6e20..796bcc2 100644
a b function init(settings) 5 5 { 6 6 g_Callback = settings.callback; 7 7 8 localizeObjectKeys(settings.ais, ["name", "description"]); 8 9 g_AIs = [ 9 {id: "", data: {name: "None", description: "AI will be disabled for this player."}}10 {id: "", data: {name: Engine.localizeWithContext("ai", "None"), description: Engine.localize("AI will be disabled for this player.")}} 10 11 ].concat(settings.ais); 11 12 12 13 var aiSelection = getGUIObjectByName("aiSelection"); 13 aiSelection.list = [ ai.data.namefor each (ai in g_AIs) ];14 aiSelection.list = [ Engine.localize(ai.data.name) for each (ai in g_AIs) ]; 14 15 15 16 var selected = 0; 16 17 for (var i = 0; i < g_AIs.length; ++i) … … function init(settings) 24 25 aiSelection.selected = selected; 25 26 26 27 var aiDiff = getGUIObjectByName("aiDifficulty"); 27 aiDiff.list = [ "Sandbox", "Easy", "Medium", "Hard", "Very Hard"];28 aiDiff.list = [Engine.localize("Sandbox"), Engine.localize("Easy"), Engine.localize("Medium"), Engine.localize("Hard"), Engine.localize("Very Hard")]; 28 29 aiDiff.selected = settings.difficulty; 29 30 } 30 31 -
binaries/data/mods/public/gui/aiconfig/aiconfig.xml
diff --git a/binaries/data/mods/public/gui/aiconfig/aiconfig.xml b/binaries/data/mods/public/gui/aiconfig/aiconfig.xml index 19cf728..830b37c 100644
a b 9 9 10 10 <object type="image" style="StoneDialog" size="50%-200 40%-140 50%+200 40%+180"> 11 11 12 <object style="TitleText" type="text" size="50%-128 -16 50%+128 16">AI Configuration</object> 12 <object style="TitleText" type="text" size="50%-128 -16 50%+128 16"> 13 <localizableAttribute id="caption">AI Configuration</localizableAttribute> 14 </object> 13 15 14 16 <object size="50%-128 30 50%+128 80"> 15 17 <object type="text" style="RightLabelText" size="-10 0 90 50%"> 16 AI Player18 <localizableAttribute id="caption">AI Player</localizableAttribute> 17 19 </object> 18 20 19 21 <object name="aiSelection" type="dropdown" style="StoneDropDown" size="50%-24 0 50%+136 28"> … … 21 23 </object> 22 24 23 25 <object type="text" style="RightLabelText" size="-10 35 90 50%+35"> 24 AI Difficulty26 <localizableAttribute id="caption">AI Difficulty</localizableAttribute> 25 27 </object> 26 28 27 29 <object name="aiDifficulty" type="dropdown" style="StoneDropDown" size="50%-24 35 50%+136 63"> … … 37 39 </object> 38 40 39 41 <object type="button" style="StoneButton" size="50%-144 100%-60 50%-16 100%-32"> 40 OK42 <localizableAttribute id="caption">OK</localizableAttribute> 41 43 <action on="Press">returnAI();</action> 42 44 </object> 43 45 44 46 <object type="button" style="StoneButton" size="50%+16 100%-60 50%+144 100%-32"> 45 Cancel47 <localizableAttribute id="caption">Cancel</localizableAttribute> 46 48 <action on="Press">Engine.PopGuiPage();</action> 47 49 </object> 48 50 </object> -
binaries/data/mods/public/gui/civinfo/civinfo.js
diff --git a/binaries/data/mods/public/gui/civinfo/civinfo.js b/binaries/data/mods/public/gui/civinfo/civinfo.js index d283cd8..6b1edc9 100644
a b function selectCiv(code) 82 82 var civInfo = g_CivData[code]; 83 83 84 84 if(!civInfo) 85 error( "Error loading civ data for \""+code+"\"");85 error(sprintf(Engine.localizeWithContext("civinfo", "Error loading civ data for \"%(code)s\""), { code: code })); 86 86 87 87 // Update civ gameplay display 88 getGUIObjectByName("civGameplayHeading").caption = heading(civInfo.Name+" Gameplay", 16); 89 88 getGUIObjectByName("civGameplayHeading").caption = heading(sprintf(Engine.localizeWithContext("civinfo", "%(civilization)s Gameplay"), { civilization: civInfo.Name }), 16); 90 89 91 90 // Bonuses 92 var bonusCaption = heading( "Civilization Bonus"+(civInfo.CivBonuses.length == 1 ? "" : "es"), 12) + '\n';91 var bonusCaption = heading(Engine.localizePluralWithContext("civinfo", "Civilization Bonus", "Civilization Bonuses", civInfo.CivBonuses.length), 12) + '\n'; 93 92 94 93 for(var i = 0; i < civInfo.CivBonuses.length; ++i) 95 94 { … … function selectCiv(code) 97 96 + civInfo.CivBonuses[i].History + '" tooltip_style="civInfoTooltip"]\n ' + civInfo.CivBonuses[i].Description + '\n[/color]'; 98 97 } 99 98 100 bonusCaption += heading( "Team Bonus"+(civInfo.TeamBonuses.length == 1 ? "" : "es"), 12) + '\n';99 bonusCaption += heading(Engine.localizePluralWithContext("civinfo", "Team Bonus", "Team Bonuses", civInfo.TeamBonuses.length), 12) + '\n'; 101 100 102 101 for(var i = 0; i < civInfo.TeamBonuses.length; ++i) 103 102 { … … function selectCiv(code) 109 108 110 109 111 110 // Special techs / buildings 112 var techCaption = heading( "Special Technologies", 12) + '\n';111 var techCaption = heading(Engine.localize("Special Technologies"), 12) + '\n'; 113 112 114 113 for(var i = 0; i < civInfo.Factions.length; ++i) 115 114 { … … function selectCiv(code) 121 120 } 122 121 } 123 122 124 techCaption += heading( "Special Building"+(civInfo.Structures.length == 1 ? "" : "s"), 12) + '\n';123 techCaption += heading(Engine.localizePluralWithContext("civinfo", "Special Building", "Special Buildings", civInfo.Structures.length), 12) + '\n'; 125 124 126 125 for(var i = 0; i < civInfo.Structures.length; ++i) 127 126 { … … function selectCiv(code) 133 132 134 133 135 134 // Heroes 136 var heroCaption = heading( "Heroes", 12) + '\n';135 var heroCaption = heading(Engine.localizeWithContext("civinfo", "Heroes"), 12) + '\n'; 137 136 138 137 for(var i = 0; i < civInfo.Factions.length; ++i) 139 138 { … … function selectCiv(code) 150 149 151 150 152 151 // Update civ history display 153 getGUIObjectByName("civHistoryHeading").caption = heading( "History of the " + civInfo.Name, 16);152 getGUIObjectByName("civHistoryHeading").caption = heading(sprintf(Engine.localizeWithContext("civinfo", "History of the %(civilization)s"), { civilization: civInfo.Name }), 16); 154 153 getGUIObjectByName("civHistoryText").caption = civInfo.History; 155 154 } -
binaries/data/mods/public/gui/civinfo/civinfo.xml
diff --git a/binaries/data/mods/public/gui/civinfo/civinfo.xml b/binaries/data/mods/public/gui/civinfo/civinfo.xml index 2651364..dcbd084 100644
a b 12 12 13 13 <object type="image" style="StoneDialog" size="50%-466 50%-316 50%+466 50%+316"> 14 14 15 <object style="TitleText" type="text" size="50%-128 -16 50%+128 16">Civilizations</object> 15 <object style="TitleText" type="text" size="50%-128 -16 50%+128 16"> 16 <localizableAttribute id="caption">Civilizations</localizableAttribute> 17 </object> 16 18 17 19 <!-- Civ selection --> 18 20 <object size="25 10 100% 30"> … … 23 25 textcolor="white" 24 26 text_align="left" 25 27 size="50%-320 10 50%-96 48"> 26 Civilization Selection28 <localizableAttribute id="caption">Civilization Selection</localizableAttribute> 27 29 </object> 28 30 29 31 <object name="civSelection" type="dropdown" style="StoneDropDown" size="50%-96 10 50%+96 40"> … … 112 114 type="button" 113 115 style="StoneButton" 114 116 size="100%-164 100%-52 100%-24 100%-24" 115 >Close 117 > 118 <localizableAttribute id="caption">Close</localizableAttribute> 116 119 <action on="Press"> 117 120 <![CDATA[ 118 121 Engine.PopGuiPage(); -
binaries/data/mods/public/gui/common/functions_civinfo.js
diff --git a/binaries/data/mods/public/gui/common/functions_civinfo.js b/binaries/data/mods/public/gui/common/functions_civinfo.js index f1495d4..7665de9 100644
a b function loadCivData() 14 14 for each (var filename in civFiles) 15 15 { // Parse data if valid file 16 16 var data = parseJSONData(filename); 17 localizeObjectKeys(data, ["Name", "Description", "History", "Special"]); 17 18 civData[data.Code] = data; 18 19 } 19 20 -
binaries/data/mods/public/gui/common/functions_global_object.js
diff --git a/binaries/data/mods/public/gui/common/functions_global_object.js b/binaries/data/mods/public/gui/common/functions_global_object.js index a030587..04a4da7 100644
a b function messageBox (mbWidth, mbHeight, mbMessage, mbTitle, mbMode, mbButtonCapt 27 27 28 28 // ==================================================================== 29 29 30 var g_FpsDisplayString = Engine.localize("FPS: %(fps)s") 30 31 function updateFPS() 31 32 { 32 getGUIObjectByName("fpsCounter").caption = "FPS: " + getFPS();33 getGUIObjectByName("fpsCounter").caption = sprintf(g_FpsDisplayString, { fps: getFPS() }); 33 34 } -
binaries/data/mods/public/gui/common/functions_utility.js
diff --git a/binaries/data/mods/public/gui/common/functions_utility.js b/binaries/data/mods/public/gui/common/functions_utility.js index 1c1a049..a0ac0a3 100644
a b 5 5 6 6 // ==================================================================== 7 7 8 var g_localizedTimeFormat = Engine.localize("HH:mm:ss"); 9 8 10 function getRandom(randomMin, randomMax) 9 11 { 10 12 // Returns a random whole number in a min..max range. … … function parseJSONData(pathname) 64 66 var rawData = readFile(pathname); 65 67 if (!rawData) 66 68 { 67 error( "Failed to read file: "+pathname);69 error(sprintf(Engine.localize("Failed to read file: %(path)s"), { path: pathname })); 68 70 } 69 71 else 70 72 { … … function parseJSONData(pathname) 73 75 // TODO: Need more info from the parser on why it failed: line number, position, etc! 74 76 data = JSON.parse(rawData); 75 77 if (!data) 76 error( "Failed to parse JSON data in: "+pathname+" (check for valid JSON data)");78 error(sprintf(Engine.localize("Failed to parse JSON data in: %(path)s (check for valid JSON data)"), { path: pathname })); 77 79 78 80 79 81 } 80 82 catch(err) 81 83 { 82 error( err.toString()+": parsing JSON data in "+pathname);84 error(sprintf(Engine.localize("%(error)s: parsing JSON data in %(path)s"), { error: err.toString(), path: pathname })); 83 85 } 84 86 } 85 87 … … function parseJSONFromDataFile(filename) 141 143 var path = "simulation/data/"+filename; 142 144 var rawData = readFile(path); 143 145 if (!rawData) 144 error( "Failed to read file: "+path);146 error(sprintf(Engine.localize("Failed to read file: %(path)s"), { path: path })); 145 147 146 148 try 147 149 { … … function parseJSONFromDataFile(filename) 152 154 } 153 155 catch(err) 154 156 { 155 error( err.toString()+": parsing JSON data in "+path);157 error(sprintf(Engine.localize("%(error)s: parsing JSON data in %(path)s"), { error: err.toString(), path: path })); 156 158 } 157 159 158 160 return undefined; … … function initPlayerDefaults() 167 169 168 170 var data = parseJSONFromDataFile("player_defaults.json"); 169 171 if (!data || !data.PlayerData) 170 error( "Failed to parse player defaults in player_defaults.json (check for valid JSON data)");172 error(Engine.localize("Failed to parse player defaults in player_defaults.json (check for valid JSON data)")); 171 173 else 174 { 175 localizeObjectKeys(data.PlayerData, ["Name"]) 172 176 defaults = data.PlayerData; 177 } 173 178 174 179 return defaults; 175 180 } … … function initMapSizes() 187 192 188 193 var data = parseJSONFromDataFile("map_sizes.json"); 189 194 if (!data || !data.Sizes) 190 error( "Failed to parse map sizes in map_sizes.json (check for valid JSON data)");195 error(Engine.localize("Failed to parse map sizes in map_sizes.json (check for valid JSON data)")); 191 196 else 192 197 { 198 localizeObjectKeys(data, ["Name", "LongName"]); 193 199 for (var i = 0; i < data.Sizes.length; ++i) 194 200 { 195 201 sizes.names.push(data.Sizes[i].LongName); … … function initGameSpeeds() 216 222 217 223 var data = parseJSONFromDataFile("game_speeds.json"); 218 224 if (!data || !data.Speeds) 219 error( "Failed to parse game speeds in game_speeds.json (check for valid JSON data)");225 error(Engine.localize("Failed to parse game speeds in game_speeds.json (check for valid JSON data)")); 220 226 else 221 227 { 228 localizeObjectKeys(data, ["Name"]); 222 229 for (var i = 0; i < data.Speeds.length; ++i) 223 230 { 224 231 gameSpeeds.names.push(data.Speeds[i].Name); … … function iColorToString(color) 254 261 */ 255 262 function timeToString(time) 256 263 { 257 var hours = Math.floor(time / 1000 / 60 / 60); 258 var minutes = Math.floor(time / 1000 / 60) % 60; 259 var seconds = Math.floor(time / 1000) % 60; 260 return hours + ':' + (minutes < 10 ? '0' + minutes : minutes) + ':' + (seconds < 10 ? '0' + seconds : seconds); 264 return Engine.formatMillisecondsIntoDateString(time, g_localizedTimeFormat); 261 265 } 262 266 263 267 // ==================================================================== -
binaries/data/mods/public/gui/common/functions_utility_error.js
diff --git a/binaries/data/mods/public/gui/common/functions_utility_error.js b/binaries/data/mods/public/gui/common/functions_utility_error.js index 17254b3..13e8572 100644
a b function cancelOnError(msg) 19 19 width: 500, 20 20 height: 200, 21 21 message: '[font="serif-bold-18"]' + msg + '[/font]', 22 title: "Loading Aborted",22 title: Engine.localize("Loading Aborted"), 23 23 mode: 2 24 24 }); 25 25 } -
binaries/data/mods/public/gui/common/functions_utility_list.js
diff --git a/binaries/data/mods/public/gui/common/functions_utility_list.js b/binaries/data/mods/public/gui/common/functions_utility_list.js index 0f3050c..43d911e 100644
a b 11 11 function removeItem (objectName, pos) 12 12 { 13 13 if (getGUIObjectByName (objectName) == null) 14 Engine.Console_Write ( "removeItem(): " + objectName + " not found.");14 Engine.Console_Write (sprintf(Engine.localize("%(functionName)s: %(object)s not found."), { functionName: "removeItem()", object: objectName })); 15 15 16 16 var list = getGUIObjectByName (objectName).list; 17 17 var selected = getGUIObjectByName (objectName).selected; … … function removeItem (objectName, pos) 41 41 function addItem (objectName, pos, value) 42 42 { 43 43 if (getGUIObjectByName (objectName) == null) 44 Engine.Console_Write ( "addItem(): " + objectName + " not found.");44 Engine.Console_Write (sprintf(Engine.localize("%(functionName)s: %(object)s not found."), { functionName: "addItem()", object: objectName })); 45 45 46 46 var list = getGUIObjectByName (objectName).list; 47 47 var selected = getGUIObjectByName (objectName).selected; … … function addItem (objectName, pos, value) 66 66 function pushItem (objectName, value) 67 67 { 68 68 if (getGUIObjectByName (objectName) == null) 69 Engine.Console_Write ( "pushItem(): " + objectName + " not found.");69 Engine.Console_Write (sprintf(Engine.localize("%(functionName)s: %(object)s not found."), { functionName: "pushItem()", object: objectName })); 70 70 71 71 var list = getGUIObjectByName (objectName).list; 72 72 list.push (value); … … function pushItem (objectName, value) 81 81 function popItem (objectName) 82 82 { 83 83 if (getGUIObjectByName (objectName) == null) 84 Engine.Console_Write ( "popItem(): " + objectName + " not found.");84 Engine.Console_Write (sprintf(Engine.localize("%(functionName)s: %(object)s not found."), { functionName: "popItem()", object: objectName })); 85 85 86 86 var selected = getGUIObjectByName (objectName).selected; 87 87 removeItem(objectName, getNumItems(objectName)-1); … … function popItem (objectName) 98 98 function getNumItems (objectName) 99 99 { 100 100 if (getGUIObjectByName (objectName) == null) 101 Engine.Console_Write ( "getNumItems(): " + objectName + " not found.");101 Engine.Console_Write (sprintf(Engine.localize("%(functionName)s: %(object)s not found."), { functionName: "getNumItems()", object: objectName })); 102 102 103 103 var list = getGUIObjectByName(objectName).list; 104 104 return list.length; … … function getNumItems (objectName) 110 110 function getItemValue (objectName, pos) 111 111 { 112 112 if (getGUIObjectByName (objectName) == null) 113 Engine.Console_Write ( "getItemValue(): " + objectName + " not found.");113 Engine.Console_Write (sprintf(Engine.localize("%(functionName)s: %(object)s not found."), { functionName: "getItemValue()", object: objectName })); 114 114 115 115 var list = getGUIObjectByName(objectName).list; 116 116 return list[pos]; … … function getItemValue (objectName, pos) 122 122 function getCurrItemValue (objectName) 123 123 { 124 124 if (getGUIObjectByName (objectName) == null) 125 Engine.Console_Write ( "getCurrItemValue(): " + objectName + " not found.");125 Engine.Console_Write (sprintf(Engine.localize("%(functionName)s: %(object)s not found."), { functionName: "getCurrItemValue()", object: objectName })); 126 126 127 127 if (getGUIObjectByName(objectName).selected == -1) 128 128 return ""; … … function getCurrItemValue (objectName) 137 137 function setCurrItemValue (objectName, string) 138 138 { 139 139 if (getGUIObjectByName(objectName) == null) { 140 Engine.Console_Write ( "setCurrItemValue(): " + objectName + " not found.");140 Engine.Console_Write (sprintf(Engine.localize("%(functionName)s: %(object)s not found."), { functionName: "setCurrItemValue()", object: objectName })); 141 141 return -1; 142 142 } 143 143 … … function setCurrItemValue (objectName, string) 157 157 } 158 158 159 159 // Return -2 if failed to find value in list. 160 Engine.Console_Write ( "Requested string '" + string + "' not found in " + objectName + "'s list.");160 Engine.Console_Write (sprintf(Engine.localize("Requested string '%(string)s' not found in %(object)s's list."), { string: string, object: objectName })); 161 161 return -2; 162 162 } 163 163 -
binaries/data/mods/public/gui/common/functions_utility_loadsave.js
diff --git a/binaries/data/mods/public/gui/common/functions_utility_loadsave.js b/binaries/data/mods/public/gui/common/functions_utility_loadsave.js index 769a667..edf5b87 100644
a b function sortDecreasingDate(a, b) 3 3 return b.metadata.time - a.metadata.time; 4 4 } 5 5 6 function twoDigits(n)7 {8 return n < 10 ? "0" + n : n;9 }10 11 6 function generateLabel(metadata) 12 7 { 13 var t = new Date(metadata.time*1000); 14 15 var date = t.getFullYear()+"-"+twoDigits(1+t.getMonth())+"-"+twoDigits(t.getDate()); 16 var time = twoDigits(t.getHours())+":"+twoDigits(t.getMinutes())+":"+twoDigits(t.getSeconds()); 17 return "["+date+" "+time+"] "+metadata.initAttributes.map+(metadata.description ? " - "+metadata.description : ""); 8 var dateTimeString = Engine.formatMillisecondsIntoDateString(metadata.time, Engine.localize("yyyy-MM-dd HH:mm:ss")); 9 if (metadata.description) 10 { 11 return sprintf(Engine.localize("[%(date)s] %(map)s - %(description)s"), { date: dateTimeString, map: metadata.initAttributes.map, description: metadata.description }); 12 } 13 else 14 { 15 return sprintf(Engine.localize("[%(date)s] %(map)s"), { date: dateTimeString, map: metadata.initAttributes.map }); 16 } 18 17 } -
binaries/data/mods/public/gui/common/functions_utility_music.js
diff --git a/binaries/data/mods/public/gui/common/functions_utility_music.js b/binaries/data/mods/public/gui/common/functions_utility_music.js index f9631d8..129b261 100644
a b function newRandomSound(soundType, soundSubType, soundPrePath) 53 53 var soundArray = buildDirEntList(randomSoundPath, "*" + soundSubType + "*", false); 54 54 if (soundArray.length == 0) 55 55 { 56 Engine.Console_Write ( "Failed to find sounds matching '*"+soundSubType+"*'");56 Engine.Console_Write (sprintf(Engine.localize("Failed to find sounds matching '*%(subtype)s*'"), { soundSubType: subtype })); 57 57 return undefined; 58 58 } 59 59 // Get a random number within the sound's range. … … function newRandomSound(soundType, soundSubType, soundPrePath) 75 75 return new AmbientSound(randomSoundPath); 76 76 break; 77 77 case "effect": 78 Engine.Console_Write( "am loading effect '*"+randomSoundPath+"*'");78 Engine.Console_Write(sprintf(Engine.localize("am loading effect '*%(path)s*'"), { path: randomSoundPath })); 79 79 break; 80 80 default: 81 81 break; -
binaries/data/mods/public/gui/common/music.js
diff --git a/binaries/data/mods/public/gui/common/music.js b/binaries/data/mods/public/gui/common/music.js index 843f3af..20a0d6f 100644
a b Music.prototype.updateState = function() 108 108 break; 109 109 110 110 default: 111 warn( "Music.updateState(): Unknown music state: " + this.currentState);111 warn(sprintf(Engine.localize("%(functionName)s: Unknown music state: %(state)s"), { functionName: "Music.updateState()", state: this.currentState })); 112 112 break; 113 113 } 114 114 } … … Music.prototype.storeTracks = function(civMusic) 131 131 132 132 if (type === undefined) 133 133 { 134 warn( "Music.storeTracks(): Unrecognized music type: " + music.Type);134 warn(sprintf(Engine.localize("%(functionName)s: Unrecognized music type: %(musicType)s"), { functionName: "Music.storeTracks()", musicType: music.Type })); 135 135 continue; 136 136 } 137 137 -
binaries/data/mods/public/gui/common/network.js
diff --git a/binaries/data/mods/public/gui/common/network.js b/binaries/data/mods/public/gui/common/network.js index 081d0f0..2f946e0 100644
a b function getDisconnectReason(id) 3 3 // Must be kept in sync with source/network/NetHost.h 4 4 switch (id) 5 5 { 6 case 0: return "Unknown reason";7 case 1: return "Unexpected shutdown";8 case 2: return "Incorrect network protocol version";9 case 3: return "Game has already started";10 default: return "[Invalid value "+id+"]";6 case 0: return Engine.localize("Unknown reason"); 7 case 1: return Engine.localize("Unexpected shutdown"); 8 case 2: return Engine.localize("Incorrect network protocol version"); 9 case 3: return Engine.localize("Game has already started"); 10 default: return sprintf(Engine.localize("[Invalid value %(id)s]"), { id: id }); 11 11 } 12 12 } 13 13 … … function reportDisconnect(reason) 16 16 var reasontext = getDisconnectReason(reason); 17 17 18 18 messageBox(400, 200, 19 "Lost connection to the server.\n\nReason: " + reasontext + ".",20 "Disconnected", 2);19 Engine.localize("Lost connection to the server.") + "\n\n" + sprintf(Engine.localize("Reason: %(reason)s."), { reason: reasontext }), 20 Engine.localize("Disconnected"), 2); 21 21 } -
binaries/data/mods/public/gui/common/timer.js
diff --git a/binaries/data/mods/public/gui/common/timer.js b/binaries/data/mods/public/gui/common/timer.js index 5391ba7..8cf9a61 100644
a b function updateTimers() 45 45 t[1](); 46 46 } catch (e) { 47 47 var stack = e.stack.trimRight().replace(/^/mg, ' '); // indent the stack trace 48 error( "Error in timer: "+e+"\n"+stack+"\n");48 error(sprintf(Engine.localize("Error in timer: %(error)s"), { error: e })+"\n"+stack+"\n"); 49 49 } 50 50 delete g_Timers[id]; 51 51 } -
binaries/data/mods/public/gui/gamesetup/gamesetup.js
diff --git a/binaries/data/mods/public/gui/gamesetup/gamesetup.js b/binaries/data/mods/public/gui/gamesetup/gamesetup.js index 6ce3102..3e8850f 100644
a b const DEFAULT_NETWORKED_MAP = "Acropolis 01"; 4 4 const DEFAULT_OFFLINE_MAP = "Acropolis 01"; 5 5 6 6 // TODO: Move these somewhere like simulation\data\game_types.json, Atlas needs them too 7 const VICTORY_TEXT = [ "Conquest", "None"];7 const VICTORY_TEXT = [Engine.localize("Conquest"), Engine.localizeWithContext("victory", "None")]; 8 8 const VICTORY_DATA = ["conquest", "endless"]; 9 9 const VICTORY_DEFAULTIDX = 0; 10 const POPULATION_CAP = ["50", "100", "150", "200", "250", "300", "Unlimited"];10 const POPULATION_CAP = ["50", "100", "150", "200", "250", "300", Engine.localize("Unlimited")]; 11 11 const POPULATION_CAP_DATA = [50, 100, 150, 200, 250, 300, 10000]; 12 12 const POPULATION_CAP_DEFAULTIDX = 5; 13 const STARTING_RESOURCES = [ "Very Low", "Low", "Medium", "High", "Very High", "Deathmatch"];13 const STARTING_RESOURCES = [Engine.localize("Very Low"), Engine.localize("Low"), Engine.localize("Medium"), Engine.localize("High"), Engine.localize("Very High"), Engine.localize("Deathmatch")]; 14 14 const STARTING_RESOURCES_DATA = [100, 300, 500, 1000, 3000, 50000]; 15 15 const STARTING_RESOURCES_DEFAULTIDX = 1; 16 16 // Max number of players for any map … … var g_CivData = {}; 49 49 50 50 var g_MapFilters = []; 51 51 52 var g_randomCivilizationString = "[color=\"orange\"]" + Engine.localizeWithContext("civilization", "Random") 53 52 54 // Warn about the AI's nonexistent naval map support. 53 var g_NavalWarning = "\n\n[font=\"serif-bold-12\"][color=\"orange\"]Warning:[/color][/font] \ 54 The AI does not support naval maps and may cause severe performance issues. \ 55 Naval maps are recommended to be played with human opponents only."; 55 var g_warning = "[font=\"serif-bold-12\"][color=\"orange\"]" + Engine.localize("Warning:") + "[/color][/font]" 56 var g_NavalWarning = "\n\n" + sprintf(Engine.localize("%(warning)s The AI does not support naval maps and may cause severe performance issues. Naval maps are recommended to be played with human opponents only."), { warning: g_warning }); 56 57 57 58 // To prevent the display locking up while we load the map metadata, 58 59 // we'll start with a 'loading' message and switch to the main screen in the … … function init(attribs) 78 79 g_IsController = false; 79 80 break; 80 81 default: 81 error( "Unexpected 'type' in gamesetup init: "+attribs.type);82 error(sprintf(Engine.localize("Unexpected 'type' in gamesetup init: %(unexpectedType)s"), { unexpectedType: attribs.type })); 82 83 } 83 84 } 84 85 … … function initMain() 107 108 108 109 // Init map types 109 110 var mapTypes = getGUIObjectByName("mapTypeSelection"); 110 mapTypes.list = [ "Scenario","Skirmish","Random"];111 mapTypes.list = [Engine.localize("Scenario"), Engine.localizeWithContext("map", "Skirmish"), Engine.localizeWithContext("map", "Random")]; 111 112 mapTypes.list_data = ["scenario","skirmish","random"]; 112 113 113 114 // Setup map filters - will appear in order they are added 114 addFilter(" Default", function(settings) { return settings && !keywordTestOR(settings.Keywords, ["naval", "demo", "hidden"]); });115 addFilter(" Naval Maps", function(settings) { return settings && keywordTestAND(settings.Keywords, ["naval"]); });116 addFilter(" Demo Maps", function(settings) { return settings && keywordTestAND(settings.Keywords, ["demo"]); });117 addFilter(" All Maps", function(settings) { return true; });115 addFilter("default", Engine.localize("Default"), function(settings) { return settings && !keywordTestOR(settings.Keywords, ["naval", "demo", "hidden"]); }); 116 addFilter("naval", Engine.localize("Naval Maps"), function(settings) { return settings && keywordTestAND(settings.Keywords, ["naval"]); }); 117 addFilter("demo", Engine.localize("Demo Maps"), function(settings) { return settings && keywordTestAND(settings.Keywords, ["demo"]); }); 118 addFilter("all", Engine.localize("All Maps"), function(settings) { return true; }); 118 119 119 120 // Populate map filters dropdown 120 121 var mapFilters = getGUIObjectByName("mapFilterSelection"); 121 mapFilters.list = getFilters(); 122 g_GameAttributes.mapFilter = "Default"; 122 mapFilters.list = getFilterNames(); 123 mapFilters.list_data = getFilterIds(); 124 g_GameAttributes.mapFilter = "default"; 123 125 124 126 // Setup controls for host only 125 127 if (g_IsController) … … function initMain() 287 289 288 290 // Populate team dropdowns 289 291 var team = getGUIObjectByName("playerTeam["+i+"]"); 290 team.list = [ "None", "1", "2", "3", "4"];292 team.list = [Engine.localizeWithContext("team", "None"), "1", "2", "3", "4"]; 291 293 team.list_data = [-1, 0, 1, 2, 3]; 292 294 team.selected = 0; 293 295 … … function initCivNameList() 447 449 var civListCodes = [ civ.code for each (civ in civList) ]; 448 450 449 451 // Add random civ to beginning of list 450 civListNames.unshift( "[color=\"orange\"]Random");452 civListNames.unshift(g_randomCivilizationString); 451 453 civListCodes.unshift("random"); 452 454 453 455 // Update the dropdowns … … function initMapNameList() 480 482 break; 481 483 482 484 default: 483 error( "initMapNameList: Unexpected map type '"+g_GameAttributes.mapType+"'");485 error(sprintf(Engine.localize("initMapNameList: Unexpected map type '%(mapType)s'"), { mapType: g_GameAttributes.mapType })); 484 486 return; 485 487 } 486 488 … … function initMapNameList() 498 500 // Alphabetically sort the list, ignoring case 499 501 mapList.sort(sortNameIgnoreCase); 500 502 if (g_GameAttributes.mapType == "random") 501 mapList.unshift({ "name": "[color=\"orange\"] Random[/color]", "file": "random" });503 mapList.unshift({ "name": "[color=\"orange\"]" + Engine.localizeWithContext("map", "Random") + "[/color]", "file": "random" }); 502 504 503 505 var mapListNames = [ map.name for each (map in mapList) ]; 504 506 var mapListFiles = [ map.file for each (map in mapList) ]; … … function loadMapData(name) 529 531 case "scenario": 530 532 case "skirmish": 531 533 g_MapData[name] = Engine.LoadMapSettings(name); 534 localizeObjectKeys(g_MapData[name], ["Name", "Description"]); 532 535 break; 533 536 534 537 case "random": 535 538 if (name == "random") 536 g_MapData[name] = {settings : {"Name" : "Random", "Description" : "Randomly selects a map from the list"}}; 539 { 540 g_MapData[name] = { settings: { "Name": Engine.localizeWithContext("map", "Random"), "Description": Engine.localize("Randomly selects a map from the list") } }; 541 } 537 542 else 543 { 538 544 g_MapData[name] = parseJSONData(name+".json"); 545 localizeObjectKeys(g_MapData[name], ["Name", "Description"]); 546 } 539 547 break; 540 548 541 549 default: 542 error( "loadMapData: Unexpected map type '"+g_GameAttributes.mapType+"'");550 error(sprintf(Engine.localize("loadMapData: Unexpected map type '%(mapType)s'"), { mapType: g_GameAttributes.mapType })); 543 551 return undefined; 544 552 } 545 553 } … … function selectNumPlayers(num) 620 628 if (g_IsNetworked) 621 629 Engine.AssignNetworkPlayer(player, ""); 622 630 else 623 g_PlayerAssignments = { "local": { "name": "You", "player": 1, "civ": "", "team": -1} };631 g_PlayerAssignments = { "local": { "name": Engine.localize("You"), "player": 1, "civ": "", "team": -1} }; 624 632 } 625 633 } 626 634 … … function selectMapType(type) 674 682 break; 675 683 676 684 default: 677 error( "selectMapType: Unexpected map type '"+g_GameAttributes.mapType+"'");685 error(sprintf(Engine.localize("selectMapType: Unexpected map type '%(mapType)s'"), { mapType: g_GameAttributes.mapType })); 678 686 return; 679 687 } 680 688 … … function selectMapType(type) 683 691 updateGameAttributes(); 684 692 } 685 693 686 function selectMapFilter( filterName)694 function selectMapFilter(id) 687 695 { 688 696 // Avoid recursion 689 697 if (g_IsInGuiUpdate) … … function selectMapFilter(filterName) 693 701 if (g_IsNetworked && !g_IsController) 694 702 return; 695 703 696 g_GameAttributes.mapFilter = filterName;704 g_GameAttributes.mapFilter = id; 697 705 698 706 initMapNameList(); 699 707 … … function selectMap(name) 721 729 // Copy any new settings 722 730 g_GameAttributes.map = name; 723 731 g_GameAttributes.script = mapSettings.Script; 724 if ( mapData !== "Random")732 if (g_GameAttributes.map !== "random") 725 733 for (var prop in mapSettings) 726 734 g_GameAttributes.settings[prop] = mapSettings[prop]; 727 735 … … function selectMap(name) 737 745 // Reset player assignments on map change 738 746 if (!g_IsNetworked) 739 747 { // Slot 1 740 g_PlayerAssignments = { "local": { "name": "You", "player": 1, "civ": "", "team": -1} };748 g_PlayerAssignments = { "local": { "name": Engine.localize("You"), "player": 1, "civ": "", "team": -1} }; 741 749 } 742 750 else 743 751 { … … function launchGame() 759 767 { 760 768 if (g_IsNetworked && !g_IsController) 761 769 { 762 error( "Only host can start game");770 error(Engine.localize("Only host can start game")); 763 771 return; 764 772 } 765 773 … … function launchGame() 812 820 usedName++; 813 821 814 822 // Assign civ specific names to AI players 823 chosenName = Engine.localize(chosenName); 815 824 if (usedName) 816 g_GameAttributes.settings.PlayerData[i].Name = chosenName + " " + romanNumbers[usedName+1];825 g_GameAttributes.settings.PlayerData[i].Name = sprintf(Engine.localize("%(playerName)s %(romanNumber)s"), { playerName: chosenName, romanNumber: romanNumbers[usedName+1]}); 817 826 else 818 827 g_GameAttributes.settings.PlayerData[i].Name = chosenName; 819 828 } … … function onGameAttributesChange() 862 871 // Update some controls for clients 863 872 if (!g_IsController) 864 873 { 865 getGUIObjectByName("mapFilterText").caption = g_GameAttributes.mapFilter; 874 var mapFilderSelection = getGUIObjectByName("mapFilterText"); 875 var mapFilterId = mapFilderSelection.list_data.indexOf(g_GameAttributes.mapFilter); 876 getGUIObjectByName("mapFilterText").caption = mapFilderSelection.list[mapFilterId]; 866 877 var mapTypeSelection = getGUIObjectByName("mapTypeSelection"); 867 878 var idx = mapTypeSelection.list_data.indexOf(g_GameAttributes.mapType); 868 879 getGUIObjectByName("mapTypeText").caption = mapTypeSelection.list[idx]; … … function onGameAttributesChange() 900 911 var speedIdx = (g_GameAttributes.gameSpeed !== undefined && g_GameSpeeds.speeds.indexOf(g_GameAttributes.gameSpeed) != -1) ? g_GameSpeeds.speeds.indexOf(g_GameAttributes.gameSpeed) : g_GameSpeeds["default"]; 901 912 var victoryIdx = (VICTORY_DATA.indexOf(mapSettings.GameType) != -1 ? VICTORY_DATA.indexOf(mapSettings.GameType) : VICTORY_DEFAULTIDX); 902 913 enableCheats.checked = (g_GameAttributes.settings.CheatsEnabled === undefined || !g_GameAttributes.settings.CheatsEnabled ? false : true) 903 enableCheatsText.caption = (enableCheats.checked ? "Yes" : "No");914 enableCheatsText.caption = (enableCheats.checked ? Engine.localize("Yes") : Engine.localize("No")); 904 915 gameSpeedText.caption = g_GameSpeeds.names[speedIdx]; 905 916 populationCap.selected = (POPULATION_CAP_DATA.indexOf(mapSettings.PopulationCap) != -1 ? POPULATION_CAP_DATA.indexOf(mapSettings.PopulationCap) : POPULATION_CAP_DEFAULTIDX); 906 917 populationCapText.caption = POPULATION_CAP[populationCap.selected]; … … function onGameAttributesChange() 934 945 populationCapText.hidden = true; 935 946 startingResourcesText.hidden = true; 936 947 937 mapSizeText.caption = "Map size:";948 mapSizeText.caption = Engine.localize("Map size:"); 938 949 mapSize.selected = sizeIdx; 939 revealMapText.caption = "Reveal map:";950 revealMapText.caption = Engine.localize("Reveal map:"); 940 951 revealMap.checked = (mapSettings.RevealMap ? true : false); 941 952 942 victoryConditionText.caption = "Victory condition:";953 victoryConditionText.caption = Engine.localize("Victory condition:"); 943 954 victoryCondition.selected = victoryIdx; 944 lockTeamsText.caption = "Teams locked:";955 lockTeamsText.caption = Engine.localize("Teams locked:"); 945 956 lockTeams.checked = (mapSettings.LockTeams ? true : false); 946 957 } 947 958 else … … function onGameAttributesChange() 959 970 960 971 numPlayersText.caption = numPlayers; 961 972 mapSizeText.caption = g_MapSizes.names[sizeIdx]; 962 revealMapText.caption = (mapSettings.RevealMap ? "Yes" : "No");973 revealMapText.caption = (mapSettings.RevealMap ? Engine.localize("Yes") : Engine.localize("No")); 963 974 victoryConditionText.caption = VICTORY_TEXT[victoryIdx]; 964 lockTeamsText.caption = (mapSettings.LockTeams ? "Yes" : "No");975 lockTeamsText.caption = (mapSettings.LockTeams ? Engine.localize("Yes") : Engine.localize("No")); 965 976 } 966 977 967 978 break; … … function onGameAttributesChange() 1035 1046 startingResourcesText.hidden = false; 1036 1047 1037 1048 numPlayersText.caption = numPlayers; 1038 mapSizeText.caption = "Default";1039 revealMapText.caption = (mapSettings.RevealMap ? "Yes" : "No");1049 mapSizeText.caption = Engine.localize("Default"); 1050 revealMapText.caption = (mapSettings.RevealMap ? Engine.localize("Yes") : Engine.localize("No")); 1040 1051 victoryConditionText.caption = VICTORY_TEXT[victoryIdx]; 1041 lockTeamsText.caption = (mapSettings.LockTeams ? "Yes" : "No");1052 lockTeamsText.caption = (mapSettings.LockTeams ? Engine.localize("Yes") : Engine.localize("No")); 1042 1053 getGUIObjectByName("populationCap").selected = POPULATION_CAP_DEFAULTIDX; 1043 1054 1044 1055 break; 1045 1056 1046 1057 default: 1047 error( "onGameAttributesChange: Unexpected map type '"+g_GameAttributes.mapType+"'");1058 error(sprintf(Engine.localize("onGameAttributesChange: Unexpected map type '%(mapType)s'"), { mapType: g_GameAttributes.mapType })); 1048 1059 return; 1049 1060 } 1050 1061 … … function onGameAttributesChange() 1052 1063 getGUIObjectByName("mapInfoName").caption = getMapDisplayName(mapName); 1053 1064 1054 1065 // Load the description from the map file, if there is one 1055 var description = mapSettings.Description || "Sorry, no description available.";1066 var description = mapSettings.Description || Engine.localize("Sorry, no description available."); 1056 1067 1057 if (g_GameAttributes.mapFilter == " Naval Maps")1068 if (g_GameAttributes.mapFilter == "naval") 1058 1069 description += g_NavalWarning; 1059 1070 1060 1071 // Describe the number of players 1061 var playerString = numPlayers + " " + (numPlayers == 1 ? "player" : "players") + ". ";1072 var playerString = sprintf(Engine.localizePlural("%(number)s player. %(description)s", "%(number)s players. %(description)s", numPlayers), { number: numPlayers, description: description }); 1062 1073 1063 1074 for (var i = 0; i < MAX_PLAYERS; ++i) 1064 1075 { … … function onGameAttributesChange() 1097 1108 pTeam.hidden = true; 1098 1109 // Set text values 1099 1110 if (civ == "random") 1100 pCivText.caption = "[color=\"orange\"]Random";1111 pCivText.caption = g_randomCivilizationString; 1101 1112 else 1102 1113 pCivText.caption = g_CivData[civ].Name; 1103 1114 pTeamText.caption = (team !== undefined && team >= 0) ? team+1 : "-"; … … function onGameAttributesChange() 1114 1125 } 1115 1126 } 1116 1127 1117 getGUIObjectByName("mapInfoDescription").caption = playerString + description;1128 getGUIObjectByName("mapInfoDescription").caption = playerString; 1118 1129 1119 1130 g_IsInGuiUpdate = false; 1120 1131 … … function updatePlayerList() 1178 1189 } 1179 1190 // Give AI a different color so it stands out 1180 1191 aiAssignments[ai.id] = hostNameList.length; 1181 hostNameList.push("[color=\"70 150 70 255\"] AI: " + ai.data.name);1192 hostNameList.push("[color=\"70 150 70 255\"]" + sprintf(Engine.localize("AI: %(ai)s"), { ai: Engine.localize(ai.data.name) })); 1182 1193 hostGuidList.push("ai:" + ai.id); 1183 1194 } 1184 1195 1185 1196 noAssignment = hostNameList.length; 1186 hostNameList.push("[color=\"140 140 140 255\"] Unassigned");1197 hostNameList.push("[color=\"140 140 140 255\"]" + Engine.localize("Unassigned")); 1187 1198 hostGuidList.push(""); 1188 1199 1189 1200 for (var i = 0; i < MAX_PLAYERS; ++i) … … function updatePlayerList() 1210 1221 if (aiId in aiAssignments) 1211 1222 selection = aiAssignments[aiId]; 1212 1223 else 1213 warn( "AI \""+aiId+"\" not present. Defaulting to unassigned.");1224 warn(sprintf(Engine.localize("AI \"%(id)s\" not present. Defaulting to unassigned."), { id: aiId })); 1214 1225 } 1215 1226 1216 1227 if (!selection) … … function addChatMessage(msg) 1385 1396 switch (msg.type) 1386 1397 { 1387 1398 case "connect": 1388 formatted = '[font="serif-bold-13"][color="'+ color +'"]' + username + '[/color][/font] [color="gold"]has joined[/color]'; 1399 var formattedUsername = '[font="serif-bold-13"][color="'+ color +'"]' + username + '[/color][/font][color="gold"]' 1400 formatted = '[color="gold"]' + sprintf(Engine.localize("%(username)s has joined"), { username: formattedUsername }); 1389 1401 break; 1390 1402 1391 1403 case "disconnect": 1392 formatted = '[font="serif-bold-13"][color="'+ color +'"]' + username + '[/color][/font] [color="gold"]has left[/color]'; 1404 var formattedUsername = '[font="serif-bold-13"][color="'+ color +'"]' + username + '[/color][/font][color="gold"]' 1405 formatted = '[color="gold"]' + sprintf(Engine.localize("%(username)s has left"), { username: formattedUsername }); 1393 1406 break; 1394 1407 1395 1408 case "message": 1396 formatted = '[font="serif-bold-13"]<[color="'+ color +'"]' + username + '[/color]>[/font] ' + message; 1409 var formattedUsername = '[color="'+ color +'"]' + username + '[/color]' 1410 var formattedUsernamePrefix = '[font="serif-bold-13"]' + sprintf(Engine.localize("<%(username)s>"), { username: formattedUsername }) + '[/font]' 1411 formatted = sprintf(Engine.localize("%(username)s %(message)s"), { username: formattedUsernamePrefix, message: message }); 1397 1412 break; 1398 1413 1399 1414 default: 1400 error( "Invalid chat message '" + uneval(msg) + "'");1415 error(sprintf(Engine.localize("Invalid chat message '%(message)s'"), { message: uneval(msg) })); 1401 1416 return; 1402 1417 } 1403 1418 … … function toggleMoreOptions() 1415 1430 // Basic map filters API 1416 1431 1417 1432 // Add a new map list filter 1418 function addFilter( name, filterFunc)1433 function addFilter(id, name, filterFunc) 1419 1434 { 1420 1435 if (filterFunc instanceof Object) 1421 1436 { // Basic validity test 1422 1437 var newFilter = {}; 1438 newFilter.id = id; 1423 1439 newFilter.name = name; 1424 1440 newFilter.filter = filterFunc; 1425 1441 … … function addFilter(name, filterFunc) 1427 1443 } 1428 1444 else 1429 1445 { 1430 error( "Invalid map filter: "+name);1446 error(sprintf(Engine.localize("Invalid map filter: %(name)s"), { name: name })); 1431 1447 } 1432 1448 } 1433 1449 1450 // Get array of map filter IDs 1451 function getFilterIds() 1452 { 1453 var filters = []; 1454 for (var i = 0; i < g_MapFilters.length; ++i) 1455 filters.push(g_MapFilters[i].id); 1456 1457 return filters; 1458 } 1459 1434 1460 // Get array of map filter names 1435 function getFilter s()1461 function getFilterNames() 1436 1462 { 1437 1463 var filters = []; 1438 1464 for (var i = 0; i < g_MapFilters.length; ++i) … … function getFilters() 1442 1468 } 1443 1469 1444 1470 // Test map filter on given map settings object 1445 function testFilter( name, mapSettings)1471 function testFilter(id, mapSettings) 1446 1472 { 1447 1473 for (var i = 0; i < g_MapFilters.length; ++i) 1448 if (g_MapFilters[i]. name == name)1474 if (g_MapFilters[i].id == id) 1449 1475 return g_MapFilters[i].filter(mapSettings); 1450 1476 1451 error( "Invalid map filter: "+name);1477 error(sprintf(Engine.localize("Invalid map filter: %(id)s"), { id: id })); 1452 1478 return false; 1453 1479 } 1454 1480 -
binaries/data/mods/public/gui/gamesetup/gamesetup.xml
diff --git a/binaries/data/mods/public/gui/gamesetup/gamesetup.xml b/binaries/data/mods/public/gui/gamesetup/gamesetup.xml index 157afc5..a6e49d9 100644
a b 12 12 <object type="image" style="StoneWindow" size="0 0 100% 100%"> 13 13 14 14 <object style="TitleText" type="text" size="50%-128 4 50%+128 36"> 15 Match Setup15 <localizableAttribute id="caption">Match Setup</localizableAttribute> 16 16 </object> 17 17 18 18 <object type="image" style="StoneDialog" size="50%-190 50%-80 50%+190 50%+80" name="loadingWindow"> 19 19 20 20 <object type="text" style="TitleText" size="50%-128 0%-16 50%+128 16"> 21 Loading21 <localizableAttribute id="caption">Loading</localizableAttribute> 22 22 </object> 23 23 24 24 <object type="text" style="CenteredLabelText"> 25 Loading map data. Please wait...25 <localizableAttribute id="caption">Loading map data. Please wait...</localizableAttribute> 26 26 </object> 27 27 28 28 </object> … … 38 38 39 39 <!-- Number of Players--> 40 40 <object size="0 0 150 28"> 41 <object size="0 0 100% 100%" type="text" style="RightLabelText">Number of players:</object> 41 <object size="0 0 100% 100%" type="text" style="RightLabelText"> 42 <localizableAttribute id="caption">Number of players:</localizableAttribute> 43 </object> 42 44 </object> 43 45 44 46 <!-- Number of Players--> … … 48 50 type="dropdown" 49 51 style="StoneDropDown" 50 52 size="0 0 100% 28" 51 tooltip_style="onscreenToolTip" 52 tooltip="Select number of players.">53 tooltip_style="onscreenToolTip"> 54 <localizableAttribute id="tooltip">Select number of players.</localizableAttribute> 53 55 <action on="SelectionChange">selectNumPlayers(this.list_data[this.selected]);</action> 54 56 </object> 55 57 </object> … … 59 61 <!-- Player assignments --> 60 62 <object size="24 59 100%-440 358" type="image" sprite="BackgroundIndentFillDark" name="playerAssignmentsPannel"> 61 63 <object size="0 6 100% 30"> 62 <object name="playerNameHeading" type="text" style="CenteredLabelText" size="0 0 25% 100%">Player Name</object> 63 <object name="playerPlacementHeading" type="text" style="CenteredLabelText" size="25%+5 0 55% 100%">Player Placement</object> 64 <object name="playerCivHeading" type="text" style="CenteredLabelText" size="55%+65 0 85% 100%">Civilization</object> 64 <object name="playerNameHeading" type="text" style="CenteredLabelText" size="0 0 25% 100%"> 65 <localizableAttribute id="caption">Player Name</localizableAttribute> 66 </object> 67 <object name="playerPlacementHeading" type="text" style="CenteredLabelText" size="25%+5 0 55% 100%"> 68 <localizableAttribute id="caption">Player Placement</localizableAttribute> 69 </object> 70 <object name="playerCivHeading" type="text" style="CenteredLabelText" size="55%+65 0 85% 100%"> 71 <localizableAttribute id="caption">Civilization</localizableAttribute> 72 </object> 65 73 <object name="civInfoButton" 66 74 type="button" 67 75 sprite="iconInfoGold" 68 76 sprite_over="iconInfoWhite" 69 77 size="85%-8 0 85%+8 16" 70 78 tooltip_style="onscreenToolTip" 71 tooltip="View civilization info"72 79 > 80 <localizableAttribute id="tooltip">View civilization info</localizableAttribute> 73 81 <action on="Press"><![CDATA[ 74 82 Engine.PushGuiPage("page_civinfo.xml"); 75 83 ]]></action> 76 84 </object> 77 <object name="playerTeamHeading" type="text" style="CenteredLabelText" size="85%+5 0 100%-5 100%">Team</object> 85 <object name="playerTeamHeading" type="text" style="CenteredLabelText" size="85%+5 0 100%-5 100%"> 86 <localizableAttribute id="caption">Team</localizableAttribute> 87 </object> 78 88 </object> 79 89 <object size="1 36 100%-1 100%"> 80 90 <repeat count="8"> 81 91 <object name="playerBox[n]" size="0 0 100% 32" hidden="true"> 82 92 <object name="playerColour[n]" type="image" size="0 0 100% 100%"/> 83 93 <object name="playerName[n]" type="text" style="CenteredLabelText" size="0 2 25% 30"/> 84 <object name="playerAssignment[n]" type="dropdown" style="StoneDropDown" size="25%+5 2 55% 30" tooltip_style="onscreenToolTip" tooltip="Select player."/> 94 <object name="playerAssignment[n]" type="dropdown" style="StoneDropDown" size="25%+5 2 55% 30" tooltip_style="onscreenToolTip"> 95 <localizableAttribute id="tooltip">Select player.</localizableAttribute> 96 </object> 85 97 <object name="playerConfig[n]" type="button" style="StoneButton" size="55%+5 6 55%+60 26" 86 98 tooltip_style="onscreenToolTip" 87 tooltip="Configure AI settings."88 99 font="serif-bold-stroke-12" 89 >Settings</object> 90 <object name="playerCiv[n]" type="dropdown" style="StoneDropDown" size="55%+65 2 85% 30" tooltip_style="onscreenToolTip" tooltip="Select player's civilization."/> 100 > 101 <localizableAttribute id="caption">Settings</localizableAttribute> 102 <localizableAttribute id="tooltip">Configure AI settings.</localizableAttribute> 103 </object> 104 <object name="playerCiv[n]" type="dropdown" style="StoneDropDown" size="55%+65 2 85% 30" tooltip_style="onscreenToolTip"> 105 <localizableAttribute id="tooltip">Select player's civilization.</localizableAttribute> 106 </object> 91 107 <object name="playerCivText[n]" type="text" style="CenteredLabelText" size="55%+65 0 85% 30"/> 92 <object name="playerTeam[n]" type="dropdown" style="StoneDropDown" size="85%+5 2 100%-5 30" tooltip_style="onscreenToolTip" tooltip="Select player's team."/> 108 <object name="playerTeam[n]" type="dropdown" style="StoneDropDown" size="85%+5 2 100%-5 30" tooltip_style="onscreenToolTip"> 109 <localizableAttribute id="tooltip">Select player's team.</localizableAttribute> 110 </object> 93 111 <object name="playerTeamText[n]" type="text" style="CenteredLabelText" size="85%+5 0 100%-5 100%"/> 94 112 </object> 95 113 </repeat> … … 100 118 101 119 102 120 <object size="100%-425 363 100%-325 455" name="mapTypeSelectionTooltip"> 103 <object type="text" style="RightLabelText" size="0 0 100% 30">Match Type:</object> 104 <object type="text" style="RightLabelText" size="0 32 100% 62">Map Filter:</object> 105 <object type="text" style="RightLabelText" size="0 64 100% 94">Select Map:</object> 106 <object type="text" style="RightLabelText" size="0 96 100% 126">Map Size:</object> 121 <object type="text" style="RightLabelText" size="0 0 100% 30"> 122 <localizableAttribute id="caption">Match Type:</localizableAttribute> 123 </object> 124 <object type="text" style="RightLabelText" size="0 32 100% 62"> 125 <localizableAttribute id="caption">Map Filter:</localizableAttribute> 126 </object> 127 <object type="text" style="RightLabelText" size="0 64 100% 94"> 128 <localizableAttribute id="caption">Select Map:</localizableAttribute> 129 </object> 130 <object type="text" style="RightLabelText" size="0 96 100% 126"> 131 <localizableAttribute id="caption">Map Size:</localizableAttribute> 132 </object> 107 133 </object> 108 134 109 135 <object size="100%-327 363 100%-25 423" name="mapFilterSelectionTooltip"> … … 117 143 type="dropdown" 118 144 style="StoneDropDown" 119 145 size="100%-325 363 100%-25 391" 120 tooltip_style="onscreenToolTip" 121 tooltip="Select a map type.">146 tooltip_style="onscreenToolTip"> 147 <localizableAttribute id="tooltip">Select a map type.</localizableAttribute> 122 148 <action on="SelectionChange">selectMapType(this.list_data[this.selected]);</action> 123 149 </object> 124 150 … … 126 152 type="dropdown" 127 153 style="StoneDropDown" 128 154 size="100%-325 395 100%-25 423" 129 tooltip_style="onscreenToolTip" 130 tooltip="Select a map filter.">131 <action on="SelectionChange">selectMapFilter(this.list [this.selected]);</action>155 tooltip_style="onscreenToolTip"> 156 <localizableAttribute id="tooltip">Select a map filter.</localizableAttribute> 157 <action on="SelectionChange">selectMapFilter(this.list_data[this.selected]);</action> 132 158 </object> 133 159 134 160 <object size="100%-325 427 100%-25 455" name="mapSelectionPannel" z="55"> … … 137 163 style="StoneDropDown" 138 164 type="dropdown" 139 165 size="0 0 100% 100%" 140 tooltip_style="onscreenToolTip" 141 tooltip="Select a map to play on.">166 tooltip_style="onscreenToolTip"> 167 <localizableAttribute id="tooltip">Select a map to play on.</localizableAttribute> 142 168 <action on="SelectionChange">selectMap(this.list_data[this.selected]);</action> 143 169 </object> 144 170 145 171 </object> 146 172 147 <object name="mapSize" size="100%-325 459 100%-25 487" type="dropdown" style="StoneDropDown" hidden="true" tooltip_style="onscreenToolTip" tooltip="Select map size. (Larger sizes may reduce performance.)"/> 173 <object name="mapSize" size="100%-325 459 100%-25 487" type="dropdown" style="StoneDropDown" hidden="true" tooltip_style="onscreenToolTip"> 174 <localizableAttribute id="tooltip">Select map size. (Larger sizes may reduce performance.)</localizableAttribute> 175 </object> 148 176 149 177 <!-- Map Preview --> 150 178 <object type="image" sprite="BackgroundIndentFillDark" name="gamePreviewBox" size="100%-426 57 100%-24 359"> … … 168 196 style="StoneButton" 169 197 size="100%-120 0 100% 28" 170 198 tooltip_style="onscreenToolTip" 171 tooltip="See more game options"172 199 > 173 More Options 200 <localizableAttribute id="caption">More Options</localizableAttribute> 201 <localizableAttribute id="tooltip">See more game options</localizableAttribute> 174 202 <action on="Press">toggleMoreOptions();</action> 175 203 </object> 176 204 … … 180 208 <!-- More Options --> 181 209 <object name="moreOptions" type="image" sprite="StoneWindow" size="50%-200 50%-150 50%+200 50%+155" z="70" hidden="true"> 182 210 <object style="TitleText" type="text" size="50%-128 11 50%+128 27"> 183 More Options211 <localizableAttribute id="caption">More Options</localizableAttribute> 184 212 </object> 185 213 186 214 <object size="14 38 94% 66"> 187 215 <object size="0 0 40% 28"> 188 <object size="0 0 100% 100%" type="text" style="RightLabelText">Game Speed:</object> 216 <object size="0 0 100% 100%" type="text" style="RightLabelText"> 217 <localizableAttribute id="caption">Game Speed:</localizableAttribute> 218 </object> 189 219 </object> 190 220 <object name="gameSpeedText" size="40% 0 100% 100%" type="text" style="LeftLabelText"/> 191 <object name="gameSpeed" size="40% 0 100% 28" type="dropdown" style="StoneDropDown" hidden="true" tooltip_style="onscreenToolTip" tooltip="Select game speed."/> 221 <object name="gameSpeed" size="40% 0 100% 28" type="dropdown" style="StoneDropDown" hidden="true" tooltip_style="onscreenToolTip"> 222 <localizableAttribute id="tooltip">Select game speed.</localizableAttribute> 223 </object> 192 224 </object> 193 225 194 226 <object size="14 68 94% 96"> 195 227 <object size="0 0 40% 28"> 196 <object size="0 0 100% 100%" type="text" style="RightLabelText">Victory Condition:</object> 228 <object size="0 0 100% 100%" type="text" style="RightLabelText"> 229 <localizableAttribute id="caption">Victory Condition:</localizableAttribute> 230 </object> 197 231 </object> 198 232 <object name="victoryConditionText" size="40% 0 100% 100%" type="text" style="LeftLabelText"/> 199 <object name="victoryCondition" size="40% 0 100% 28" type="dropdown" style="StoneDropDown" hidden="true" tooltip_style="onscreenToolTip" tooltip="Select victory condition."/> 233 <object name="victoryCondition" size="40% 0 100% 28" type="dropdown" style="StoneDropDown" hidden="true" tooltip_style="onscreenToolTip"> 234 <localizableAttribute id="tooltip">Select victory condition.</localizableAttribute> 235 </object> 200 236 </object> 201 237 202 238 <object size="14 98 94% 126"> 203 239 <object size="0 0 40% 28"> 204 <object size="0 0 100% 100%" type="text" style="RightLabelText">Population Cap:</object> 240 <object size="0 0 100% 100%" type="text" style="RightLabelText"> 241 <localizableAttribute id="caption">Population Cap:</localizableAttribute> 242 </object> 205 243 </object> 206 244 <object name="populationCapText" size="40% 0 100% 100%" type="text" style="LeftLabelText"/> 207 <object name="populationCap" size="40% 0 100% 28" type="dropdown" style="StoneDropDown" hidden="true" tooltip_style="onscreenToolTip" tooltip="Select population cap."/> 245 <object name="populationCap" size="40% 0 100% 28" type="dropdown" style="StoneDropDown" hidden="true" tooltip_style="onscreenToolTip"> 246 <localizableAttribute id="tooltip">Select population cap.</localizableAttribute> 247 </object> 208 248 </object> 209 249 210 250 <object size="14 128 94% 156"> 211 251 <object size="0 0 40% 28"> 212 <object size="0 0 100% 100%" type="text" style="RightLabelText">Starting Resources:</object> 252 <object size="0 0 100% 100%" type="text" style="RightLabelText"> 253 <localizableAttribute id="caption">Starting Resources:</localizableAttribute> 254 </object> 213 255 </object> 214 256 <object name="startingResourcesText" size="40% 0 100% 100%" type="text" style="LeftLabelText"/> 215 <object name="startingResources" size="40% 0 100% 28" type="dropdown" style="StoneDropDown" hidden="true" tooltip_style="onscreenToolTip" tooltip="Select the game's starting resources."/> 257 <object name="startingResources" size="40% 0 100% 28" type="dropdown" style="StoneDropDown" hidden="true" tooltip_style="onscreenToolTip"> 258 <localizableAttribute id="tooltip">Select the game's starting resources.</localizableAttribute> 259 </object> 216 260 </object> 217 261 218 262 <object size="14 158 94% 246"> 219 263 <object size="0 0 40% 28"> 220 <object size="0 0 100% 100%" type="text" style="RightLabelText">Reveal Map:</object> 264 <object size="0 0 100% 100%" type="text" style="RightLabelText"> 265 <localizableAttribute id="caption">Reveal Map:</localizableAttribute> 266 </object> 221 267 </object> 222 268 <object size="0 30 40% 58"> 223 <object size="0 0 100% 100%" type="text" style="RightLabelText">Teams Locked:</object> 269 <object size="0 0 100% 100%" type="text" style="RightLabelText"> 270 <localizableAttribute id="caption">Teams Locked:</localizableAttribute> 271 </object> 224 272 </object> 225 273 <object size="0 60 40% 88" name="enableCheatsDesc" hidden="true"> 226 <object size="0 0 100% 100%" type="text" style="RightLabelText">Cheats:</object> 274 <object size="0 0 100% 100%" type="text" style="RightLabelText"> 275 <localizableAttribute id="caption">Cheats:</localizableAttribute> 276 </object> 227 277 </object> 228 278 229 279 <object size="40% 0 100% 28"> 230 280 <object name="revealMapText" size="0 0 100% 100%" type="text" style="LeftLabelText"/> 231 <object name="revealMap" size="4 50%-8 20 50%+8" type="checkbox" style="StoneCrossBox" hidden="true" tooltip_style="onscreenToolTip" tooltip="Toggle reveal map."/> 281 <object name="revealMap" size="4 50%-8 20 50%+8" type="checkbox" style="StoneCrossBox" hidden="true" tooltip_style="onscreenToolTip"> 282 <localizableAttribute id="tooltip">Toggle reveal map.</localizableAttribute> 283 </object> 232 284 </object> 233 285 <object size="40% 30 100% 58"> 234 286 <object name="lockTeamsText" size="0 0 100% 100%" type="text" style="LeftLabelText"/> 235 <object name="lockTeams" size="4 50%-8 20 50%+8" type="checkbox" style="StoneCrossBox" hidden="true" tooltip_style="onscreenToolTip" tooltip="Toggle locked teams."/> 287 <object name="lockTeams" size="4 50%-8 20 50%+8" type="checkbox" style="StoneCrossBox" hidden="true" tooltip_style="onscreenToolTip"> 288 <localizableAttribute id="tooltip">Toggle locked teams.</localizableAttribute> 289 </object> 236 290 </object> 237 291 <object size="40% 60 100% 88"> 238 292 <object name="enableCheatsText" size="0 0 100% 100%" type="text" style="LeftLabelText" hidden="true"/> 239 <object name="enableCheats" size="4 50%-8 20 50%+8" type="checkbox" style="StoneCrossBox" hidden="true" tooltip_style="onscreenToolTip" tooltip="Toggle the usability of cheats."/> 293 <object name="enableCheats" size="4 50%-8 20 50%+8" type="checkbox" style="StoneCrossBox" hidden="true" tooltip_style="onscreenToolTip"> 294 <localizableAttribute id="tooltip">Toggle the usability of cheats.</localizableAttribute> 295 </object> 240 296 </object> 241 297 </object> 242 298 … … 247 303 style="StoneButton" 248 304 size="50%-70 248 50%+70 274" 249 305 tooltip_style="onscreenToolTip" 250 tooltip="Close more game options window"251 306 > 252 OK 307 <localizableAttribute id="caption">OK</localizableAttribute> 308 <localizableAttribute id="tooltip">Close more game options window</localizableAttribute> 253 309 <action on="Press">toggleMoreOptions();</action> 254 310 </object> 255 311 <!-- End More Options --> … … 279 335 sprite="BackgroundTranslucent" 280 336 hidden="true" 281 337 size="100%-700 100%-56 100%-312 100%-24" 282 >[Tooltip text]</object> 338 > 339 <localizableAttribute id="caption">[Tooltip text]</localizableAttribute> 340 </object> 283 341 284 342 <!-- Start Button --> 285 343 <object … … 288 346 style="StoneButton" 289 347 size="100%-308 100%-52 100%-168 100%-24" 290 348 tooltip_style="onscreenToolTip" 291 tooltip="Start a new game with the current settings."292 349 enabled="false" 293 350 > 294 Start game! 351 <localizableAttribute id="caption">Start game!</localizableAttribute> 352 <localizableAttribute id="tooltip">Start a new game with the current settings.</localizableAttribute> 295 353 <action on="Press">launchGame();</action> 296 354 </object> 297 355 … … 302 360 style="StoneButton" 303 361 size="100%-164 100%-52 100%-24 100%-24" 304 362 tooltip_style="onscreenToolTip" 305 tooltip="Return to the main menu."306 363 > 307 Main menu 364 <localizableAttribute id="caption">Main menu</localizableAttribute> 365 <localizableAttribute id="tooltip">Return to the main menu.</localizableAttribute> 308 366 <action on="Press"> 309 367 <![CDATA[ 310 368 cancelSetup(); -
binaries/data/mods/public/gui/gamesetup/gamesetup_mp.js
diff --git a/binaries/data/mods/public/gui/gamesetup/gamesetup_mp.js b/binaries/data/mods/public/gui/gamesetup/gamesetup_mp.js index a27c993..27fb66e 100644
a b function init(multiplayerGameType) 18 18 getGUIObjectByName("pageHost").hidden = false; 19 19 break; 20 20 default: 21 error( "Unrecognised multiplayer game type : " + multiplayerGameType);21 error(sprintf(Engine.localize("Unrecognised multiplayer game type: %(gameType)s"), { gameType: multiplayerGameType })); 22 22 break; 23 23 } 24 24 } … … function startConnectionStatus(type) 35 35 g_GameType = type; 36 36 g_IsConnecting = true; 37 37 g_IsRejoining = false; 38 getGUIObjectByName("connectionStatus").caption = "Connecting to server...";38 getGUIObjectByName("connectionStatus").caption = Engine.localize("Connecting to serverâ¦"); 39 39 } 40 40 41 41 function onTick() … … function onTick() 49 49 if (!message) 50 50 break; 51 51 52 log( "Net message: "+uneval(message));52 log(sprintf(Engine.localize("Net message: %(message)s"), { message: uneval(message) })); 53 53 54 54 // If we're rejoining an active game, we don't want to actually display 55 55 // the game setup screen, so perform similar processing to gamesetup.js … … function onTick() 67 67 return; 68 68 69 69 default: 70 error( "Unrecognised netstatus type "+message.status);70 error(sprintf(Engine.localize("Unrecognised netstatus type %(netType)s"), { netType: message.status })); 71 71 break; 72 72 } 73 73 break; … … function onTick() 93 93 break; 94 94 95 95 default: 96 error( "Unrecognised net message type "+message.type);96 error(sprintf(Engine.localize("Unrecognised net message type %(messageType)s"), { messageType: message.type })); 97 97 } 98 98 } 99 99 else … … function onTick() 106 106 switch (message.status) 107 107 { 108 108 case "connected": 109 getGUIObjectByName("connectionStatus").caption = "Registering with server...";109 getGUIObjectByName("connectionStatus").caption = Engine.localize("Registering with serverâ¦"); 110 110 break; 111 111 112 112 case "authenticated": 113 113 if (message.rejoining) 114 114 { 115 getGUIObjectByName("connectionStatus").caption = "Game has already started - rejoining...";115 getGUIObjectByName("connectionStatus").caption = Engine.localize("Game has already started, rejoiningâ¦"); 116 116 g_IsRejoining = true; 117 117 return; // we'll process the game setup messages in the next tick 118 118 } … … function onTick() 128 128 return; 129 129 130 130 default: 131 error( "Unrecognised netstatus type "+message.status);131 error(sprintf(Engine.localize("Unrecognised netstatus type %(netType)s"), { netType: message.status })); 132 132 break; 133 133 } 134 134 break; 135 135 default: 136 error( "Unrecognised net message type "+message.type);136 error(sprintf(Engine.localize("Unrecognised net message type %(messageType)s"), { messageType: message.type })); 137 137 break; 138 138 } 139 139 } … … function startHost(playername, servername) 156 156 { 157 157 cancelSetup(); 158 158 messageBox(400, 200, 159 "Cannot host game: " + e.message + ".",160 "Error", 2);159 sprintf(Engine.localize("Cannot host game: %(message)s."), { message: e.message }), 160 Engine.localize("Error"), 2); 161 161 return false; 162 162 } 163 163 … … function startJoin(playername, ip) 177 177 { 178 178 cancelSetup(); 179 179 messageBox(400, 200, 180 "Cannot join game: " + e.message + ".",181 "Error", 2);180 sprintf(Engine.localize("Cannot join game: %(message)s."), { message: e.message }), 181 Engine.localize("Error"), 2); 182 182 return false; 183 183 } 184 184 -
binaries/data/mods/public/gui/gamesetup/gamesetup_mp.xml
diff --git a/binaries/data/mods/public/gui/gamesetup/gamesetup_mp.xml b/binaries/data/mods/public/gui/gamesetup/gamesetup_mp.xml index c8b4be8..a69ce49 100644
a b 16 16 </action> 17 17 18 18 <object style="TitleText" type="text" size="50%-128 0%-16 50%+128 16"> 19 Multiplayer19 <localizableAttribute id="caption">Multiplayer</localizableAttribute> 20 20 </object> 21 21 22 22 <object name="pageJoin" size="0 32 100% 100%" hidden="true"> 23 23 24 24 <object type="text" style="CenteredLabelText" size="0 0 400 30"> 25 Joining an existing game.25 <localizableAttribute id="caption">Joining an existing game.</localizableAttribute> 26 26 </object> 27 27 28 28 <object type="text" size="0 40 200 70" style="RightLabelText"> 29 Player name:29 <localizableAttribute id="caption">Player name:</localizableAttribute> 30 30 </object> 31 31 32 32 <object name="joinPlayerName" type="input" size="210 40 100%-32 64" style="StoneInput"> … … 36 36 </object> 37 37 38 38 <object type="text" size="0 80 200 110" style="RightLabelText"> 39 Server Hostname or IP:39 <localizableAttribute id="caption">Server Hostname or IP:</localizableAttribute> 40 40 </object> 41 41 42 42 <object name="joinServer" type="input" size="210 80 100%-32 104" style="StoneInput"> … … 46 46 </object>3 100%-33 103 100%-3 47 47 48 48 <object hotkey="confirm" type="button" size="50%-144 100%-60 50%-16 100%-32" style="StoneButton"> 49 Continue49 <localizableAttribute id="caption">Continue</localizableAttribute> 50 50 <action on="Press"> 51 51 var joinPlayerName = getGUIObjectByName("joinPlayerName").caption; 52 52 var joinServer = getGUIObjectByName("joinServer").caption; … … 62 62 <object name="pageHost" size="0 32 100% 100%" hidden="true"> 63 63 64 64 <object type="text" style="CenteredLabelText" size="0 0 400 30"> 65 Set up your server to host.65 <localizableAttribute id="caption">Set up your server to host.</localizableAttribute> 66 66 </object> 67 67 68 68 <object type="text" size="0 40 200 70" style="RightLabelText"> 69 Player name:69 <localizableAttribute id="caption">Player name:</localizableAttribute> 70 70 </object> 71 71 72 72 <object name="hostPlayerName" type="input" size="210 40 100%-32 64" style="StoneInput"> … … 77 77 78 78 <object hidden="true"> <!-- TODO: restore this when the server name is actually used --> 79 79 <object type="text" size="0 80 200 110" style="RightLabelText"> 80 Server name:80 <localizableAttribute id="caption">Server name:</localizableAttribute> 81 81 </object> 82 82 83 83 <object name="hostServerName" type="input" size="210 80 100%-32 104" style="StoneInput"> … … 88 88 </object> 89 89 90 90 <object type="button" size="50%-144 100%-60 50%-16 100%-32" style="StoneButton"> 91 Continue91 <localizableAttribute id="caption">Continue</localizableAttribute> 92 92 <action on="Press"> 93 93 var hostPlayerName = getGUIObjectByName("hostPlayerName").caption; 94 94 Engine.SaveMPConfig(hostPlayerName, Engine.GetDefaultMPServer()); … … 103 103 </object> 104 104 105 105 <object type="button" style="StoneButton" size="50%+16 100%-60 50%+144 100%-32"> 106 Cancel106 <localizableAttribute id="caption">Cancel</localizableAttribute> 107 107 <action on="Press">cancelSetup();</action> 108 108 </object> 109 109 110 110 <object name="pageConnecting" hidden="true"> 111 111 <object name="connectionStatus" type="text" style="CenteredLabelText" size="0 100 100% 120"> 112 [Connection status]112 <localizableAttribute id="caption">[Connection status]</localizableAttribute> 113 113 </object> 114 114 </object> 115 115 -
binaries/data/mods/public/gui/loading/loading.js
diff --git a/binaries/data/mods/public/gui/loading/loading.js b/binaries/data/mods/public/gui/loading/loading.js index 182d86c..51d0047 100644
a b function init(data) 15 15 { 16 16 // Set tip text 17 17 var tipTextFilePath = tipTextLoadingArray[getRandom (0, tipTextLoadingArray.length-1)]; 18 var tipText = readFile(tipTextFilePath);18 var tipText = Engine.localizeLines(readFile(tipTextFilePath)); 19 19 20 20 if (tipText) 21 21 { … … function init(data) 34 34 } 35 35 else 36 36 { 37 error( "Failed to find any matching tips for the loading screen.")37 error(Engine.localize("Failed to find any matching tips for the loading screen.")) 38 38 } 39 39 40 40 // janwas: main loop now sets progress / description, but that won't … … function init(data) 48 48 { 49 49 case "skirmish": 50 50 case "scenario": 51 loadingMapName.caption = "Loading \"" + mapName + "\"";51 loadingMapName.caption = sprintf(Engine.localize("Loading \"%(map)s\""), {map: mapName}); 52 52 break; 53 53 54 54 case "random": 55 loadingMapName.caption = "Generating \"" + mapName + "\"";55 loadingMapName.caption = sprintf(Engine.localize("Generating \"%(map)s\""), {map: mapName}); 56 56 break; 57 57 58 58 default: 59 error( "Unknown map type: " + data.attribs.mapType);59 error(sprintf(Engine.localize("Unknown map type: %(mapType)s"), { mapType: data.attribs.mapType })); 60 60 } 61 61 } 62 62 … … function init(data) 65 65 66 66 // Pick a random quote of the day (each line is a separate tip). 67 67 var quoteArray = readFileLines("gui/text/quotes.txt"); 68 getGUIObjectByName("quoteText").caption = quoteArray[getRandom(0, quoteArray.length-1)];68 getGUIObjectByName("quoteText").caption = Engine.localize(quoteArray[getRandom(0, quoteArray.length-1)]); 69 69 } 70 70 71 71 // ==================================================================== -
binaries/data/mods/public/gui/loading/loading.xml
diff --git a/binaries/data/mods/public/gui/loading/loading.xml b/binaries/data/mods/public/gui/loading/loading.xml index 7ad8c38..35dbedb 100644
a b 44 44 45 45 <!-- LOADING SCREEN QUOTE (needs increased z value to overcome the transparent area of the tip image above it --> 46 46 <object size="50%-448 50%+230 50%+448 100%-16" z="20"> 47 <object name="quoteTitleText" size="0 0 100% 30" type="text" style="LoadingTitleText">Quote of the Day:</object> 47 <object name="quoteTitleText" size="0 0 100% 30" type="text" style="LoadingTitleText"> 48 <localizableAttribute id="caption">Quote of the Day:</localizableAttribute> 49 </object> 48 50 <object name="quoteText" size="0 30 100% 100%" type="text" style="LoadingText"></object> 49 51 </object> 50 52 </object> -
new file inaries/data/mods/public/gui/locale/locale.js
diff --git a/binaries/data/mods/public/gui/locale/locale.js b/binaries/data/mods/public/gui/locale/locale.js new file mode 100644 index 0000000..74e1020
- + 1 function init() 2 { 3 var languageList = getGUIObjectByName("languageList"); 4 languageList.list = Engine.GetSupportedLocaleDisplayNames(); 5 languageList.list_data = Engine.GetSupportedLocaleCodes(); 6 languageList.selected = Engine.GetCurrentLocaleIndex(); 7 } 8 9 function cancelSetup() 10 { 11 Engine.PopGuiPage(); 12 } 13 14 function saveSelectedLocale() 15 { 16 var languageList = getGUIObjectByName("languageList"); 17 Engine.SetLocale(languageList.list_data[languageList.selected]); 18 Engine.PopGuiPage(); 19 } -
new file inaries/data/mods/public/gui/locale/locale.xml
diff --git a/binaries/data/mods/public/gui/locale/locale.xml b/binaries/data/mods/public/gui/locale/locale.xml new file mode 100644 index 0000000..9b9cf7d
- + 1 <?xml version="1.0" encoding="utf-8"?> 2 3 <objects> 4 5 <script file="gui/common/functions_global_object.js"/> 6 <script file="gui/locale/locale.js"/> 7 8 <!-- Add a translucent black background to fade out the menu page --> 9 <object type="image" z="0" sprite="bkTranslucent"/> 10 11 <object type="image" style="StoneDialog" size="50%-190 50%-100 50%+190 50%+100"> 12 13 <object style="TitleText" type="text" size="50%-128 0%-16 50%+128 16"> 14 <localizableAttribute id="caption">Language</localizableAttribute> 15 </object> 16 17 <object size="0 32 100% 100%"> 18 <object type="text" size="0 0 140 30" style="RightLabelText"> 19 <localizableAttribute id="caption">Language:</localizableAttribute> 20 </object> 21 22 <object name="languageList" 23 type="dropdown" 24 style="StoneDropDown" 25 size="150 0 100%-32 28"> 26 </object> 27 28 <object type="text" size="30 40 100%-30 100" style="LeftLabelText"> 29 <localizableAttribute id="caption">Note: Restart the game for these changes to take effect.</localizableAttribute> 30 </object> 31 32 <object type="button" size="50%-154 100%-60 50%+10 100%-32" style="StoneButton"> 33 <localizableAttribute id="caption">Accept</localizableAttribute> 34 <action on="Press">saveSelectedLocale();</action> 35 </object> 36 </object> 37 38 <object type="button" style="StoneButton" size="50%+26 100%-60 50%+154 100%-32"> 39 <localizableAttribute id="caption">Cancel</localizableAttribute> 40 <action on="Press">cancelSetup();</action> 41 </object> 42 43 </object> 44 45 </objects> -
binaries/data/mods/public/gui/manual/manual.js
diff --git a/binaries/data/mods/public/gui/manual/manual.js b/binaries/data/mods/public/gui/manual/manual.js index 0d6ad6e..b385202 100644
a b var closeCallback; 2 2 3 3 function init(data) 4 4 { 5 getGUIObjectByName("mainText").caption = readFile("gui/manual/" + data.page + ".txt");5 getGUIObjectByName("mainText").caption = Engine.localizeLines(readFile("gui/manual/" + data.page + ".txt")); 6 6 closeCallback = data.closeCallback; 7 7 } 8 8 -
binaries/data/mods/public/gui/manual/manual.xml
diff --git a/binaries/data/mods/public/gui/manual/manual.xml b/binaries/data/mods/public/gui/manual/manual.xml index eff09d8..f48fca8 100644
a b 8 8 <object type="image" z="0" style="TranslucentPanel"/> 9 9 10 10 <object type="image" style="StoneDialog" size="50%-466 50%-316 50%+466 50%+316"> 11 <object type="text" style="TitleText" size="50%-128 0%-16 50%+128 16">Manual</object> 11 <object type="text" style="TitleText" size="50%-128 0%-16 50%+128 16"> 12 <localizableAttribute id="caption">Manual</localizableAttribute> 13 </object> 12 14 13 15 <object type="image" sprite="BackgroundTranslucent" size="20 20 100%-20 100%-58"> 14 16 <object name="mainText" type="text" style="textPanel"/> 15 17 </object> 16 <object type="button" style="StoneButton" size="100%-308 100%-52 100%-168 100%-24"> 17 Online Manual 18 19 <object type="button" style="StoneButton" size="100%-308 100%-52 100%-168 100%-24"> 20 <localizableAttribute id="caption">Online Manual</localizableAttribute> 18 21 <action on="Press"><![CDATA[ 19 22 var url = "http://trac.wildfiregames.com/wiki/0adManual"; 20 23 Engine.OpenURL(url); 21 24 messageBox(450, 200, "Opening "+url+"\n in default web browser. Please wait...", "Opening page", 2); 22 25 ]]></action> 23 26 </object> 24 27 <object type="button" style="StoneButton" tooltip_style="snToolTip" size="100%-164 100%-52 100%-24 100%-24"> 25 Close28 <localizableAttribute id="caption">Close</localizableAttribute> 26 29 <action on="Press"><![CDATA[closeManual();]]></action> 27 30 </object> 28 31 </object> -
new file inaries/data/mods/public/gui/msgbox/msgbox.js
diff --git a/binaries/data/mods/public/gui/msgbox/msgbox.js b/binaries/data/mods/public/gui/msgbox/msgbox.js new file mode 100644 index 0000000..d410a20
- + 1 function init(data) 2 { 3 var mbMainObj = getGUIObjectByName("mbMain"); 4 var mbTitleObj = getGUIObjectByName("mbTitleBar"); 5 var mbTextObj = getGUIObjectByName("mbText"); 6 7 var mbButton1Obj = getGUIObjectByName("mbButton1"); 8 var mbButton2Obj = getGUIObjectByName("mbButton2"); 9 var mbButton3Obj = getGUIObjectByName("mbButton3"); 10 11 // Calculate size 12 var mbLRDiff = data.width / 2; // Message box left/right difference from 50% of screen 13 var mbUDDiff = data.height / 2; // Message box up/down difference from 50% of screen 14 15 var mbSizeString = "50%-" + mbLRDiff + " 50%-" + mbUDDiff + " 50%+" + mbLRDiff + " 50%+" + mbUDDiff; 16 17 mbMainObj.size = mbSizeString; 18 19 // Texts 20 mbTitleObj.caption = data.title; 21 mbTextObj.caption = data.message; 22 23 if (data.font) 24 mbTextObj.font = data.font; 25 26 // Message box modes 27 // There is a number of standard modes, and if none of these is used (mbMode == 0), the button captions will be 28 // taken from the array mbButtonCaptions; there currently is a maximum of three buttons. 29 switch (data.mode) 30 { 31 case 1: 32 // Simple Yes/No question box 33 data.buttonCaptions = [Engine.localize("Yes"), Engine.localize("No")]; 34 break; 35 case 2: 36 // Okay-only box 37 data.buttonCaptions = [Engine.localize("OK")]; 38 break; 39 case 3: 40 // Retry/Abort/Ignore box (will we ever need this?!) 41 data.buttonCaptions = [Engine.localize("Retry"), Engine.localize("Ignore"), Engine.localize("Abort")]; 42 default: 43 break; 44 } 45 46 // Buttons 47 var codes = data.buttonCode; 48 if (data.buttonCaptions.length >= 1) 49 { 50 mbButton1Obj.caption = data.buttonCaptions[0]; 51 mbButton1Obj.onPress = function () { Engine.PopGuiPage(); if (codes && codes[0]) codes[0](); } 52 mbButton1Obj.hidden = false; 53 } 54 if (data.buttonCaptions.length >= 2) 55 { 56 mbButton2Obj.caption = data.buttonCaptions[1]; 57 mbButton2Obj.onPress = function () { Engine.PopGuiPage(); if (codes && codes[1]) codes[1](); } 58 mbButton2Obj.hidden = false; 59 } 60 if (data.buttonCaptions.length >= 3) 61 { 62 mbButton3Obj.caption = data.buttonCaptions[2]; 63 mbButton3Obj.onPress = function () { Engine.PopGuiPage(); if (codes && codes[2]) codes[2](); } 64 mbButton3Obj.hidden = false; 65 } 66 67 switch (data.buttonCaptions.length) 68 { 69 case 1: 70 mbButton1Obj.size = "50%-64 100%-76 50%+64 100%-48"; 71 break; 72 case 2: 73 mbButton1Obj.size = "50%-144 100%-76 50%-16 100%-48"; 74 mbButton2Obj.size = "50%+16 100%-76 50%+144 100%-48"; 75 break; 76 case 3: 77 mbButton1Obj.size = "10% 100%-76 30% 100%-48"; 78 mbButton2Obj.size = "40% 100%-76 60% 100%-48"; 79 mbButton3Obj.size = "70% 100%-76 90% 100%-48"; 80 break; 81 } 82 } -
binaries/data/mods/public/gui/msgbox/msgbox.xml
diff --git a/binaries/data/mods/public/gui/msgbox/msgbox.xml b/binaries/data/mods/public/gui/msgbox/msgbox.xml index 9e05a0a..508de2d 100644
a b 1 1 <?xml version="1.0" encoding="utf-8"?> 2 2 3 3 <objects> 4 <script><![CDATA[ 5 function init(data) 6 { 7 var mbMainObj = getGUIObjectByName("mbMain"); 8 var mbTitleObj = getGUIObjectByName("mbTitleBar"); 9 var mbTextObj = getGUIObjectByName("mbText"); 10 11 var mbButton1Obj = getGUIObjectByName("mbButton1"); 12 var mbButton2Obj = getGUIObjectByName("mbButton2"); 13 var mbButton3Obj = getGUIObjectByName("mbButton3"); 14 15 // Calculate size 16 var mbLRDiff = data.width / 2; // Message box left/right difference from 50% of screen 17 var mbUDDiff = data.height / 2; // Message box up/down difference from 50% of screen 18 19 var mbSizeString = "50%-" + mbLRDiff + " 50%-" + mbUDDiff + " 50%+" + mbLRDiff + " 50%+" + mbUDDiff; 20 21 mbMainObj.size = mbSizeString; 22 23 // Texts 24 mbTitleObj.caption = data.title; 25 mbTextObj.caption = data.message; 26 27 if (data.font) 28 mbTextObj.font = data.font; 29 30 // Message box modes 31 // There is a number of standard modes, and if none of these is used (mbMode == 0), the button captions will be 32 // taken from the array mbButtonCaptions; there currently is a maximum of three buttons. 33 switch (data.mode) 34 { 35 case 1: 36 // Simple Yes/No question box 37 data.buttonCaptions = ["Yes", "No"]; 38 break; 39 case 2: 40 // Okay-only box 41 data.buttonCaptions = ["OK"]; 42 break; 43 case 3: 44 // Retry/Abort/Ignore box (will we ever need this?!) 45 data.buttonCaptions = ["Retry", "Ignore", "Abort"]; 46 default: 47 break; 48 } 49 50 // Buttons 51 var codes = data.buttonCode; 52 if (data.buttonCaptions.length >= 1) 53 { 54 mbButton1Obj.caption = data.buttonCaptions[0]; 55 mbButton1Obj.onPress = function () { Engine.PopGuiPage(); if (codes && codes[0]) codes[0](); } 56 mbButton1Obj.hidden = false; 57 } 58 if (data.buttonCaptions.length >= 2) 59 { 60 mbButton2Obj.caption = data.buttonCaptions[1]; 61 mbButton2Obj.onPress = function () { Engine.PopGuiPage(); if (codes && codes[1]) codes[1](); } 62 mbButton2Obj.hidden = false; 63 } 64 if (data.buttonCaptions.length >= 3) 65 { 66 mbButton3Obj.caption = data.buttonCaptions[2]; 67 mbButton3Obj.onPress = function () { Engine.PopGuiPage(); if (codes && codes[2]) codes[2](); } 68 mbButton3Obj.hidden = false; 69 } 70 71 switch (data.buttonCaptions.length) 72 { 73 case 1: 74 mbButton1Obj.size = "50%-64 100%-76 50%+64 100%-48"; 75 break; 76 case 2: 77 mbButton1Obj.size = "50%-144 100%-76 50%-16 100%-48"; 78 mbButton2Obj.size = "50%+16 100%-76 50%+144 100%-48"; 79 break; 80 case 3: 81 mbButton1Obj.size = "10% 100%-76 30% 100%-48"; 82 mbButton2Obj.size = "40% 100%-76 60% 100%-48"; 83 mbButton3Obj.size = "70% 100%-76 90% 100%-48"; 84 break; 85 } 86 } 87 ]]></script> 4 <script file="gui/msgbox/msgbox.js"/> 88 5 89 6 <object hotkey="leave"> 90 7 <action on="Press">Engine.PopGuiPage();</action> -
binaries/data/mods/public/gui/options/options.xml
diff --git a/binaries/data/mods/public/gui/options/options.xml b/binaries/data/mods/public/gui/options/options.xml index 6870c15..fa1d768 100644
a b 13 13 <script file="gui/session/music.js"/> 14 14 <script file="gui/options/options.js"/> 15 15 16 16 <!-- Add a translucent black background to fade out the menu page --> 17 17 <object type="image" z="0" style="TranslucentPanel"/> 18 18 19 19 <!-- Settings Window --> 20 20 <object name="options" type="image" style="StonePanelLight" size="50%-190 50%-120 50%+190 50%+120"> 21 21 22 23 Game Options22 <object style="StoneDialogTitleBar" type="text" size="50%-128 0%-16 50%+128 16"> 23 <localizableAttribute id="caption">Game Options</localizableAttribute> 24 24 </object> 25 25 26 26 <object size="50%-190 50%-80 50%+140 50%+95"> 27 27 28 <!-- Settings / shadows --> 29 <object size="0 10 100%-80 35" type="text" style="RightLabelText" ghost="true">Enable Shadows</object> 30 <object name="shadowsCheckbox" size="100%-56 15 100%-30 40" type="checkbox" style="StoneCrossBox" checked="true"> 31 <action on="Load">this.checked = Engine.Renderer_GetShadowsEnabled();</action> 32 <action on="Press">Engine.Renderer_SetShadowsEnabled(this.checked);</action> 33 </object> 28 <!-- Settings / shadows --> 29 <object size="0 10 100%-80 35" type="text" style="RightLabelText" ghost="true"> 30 <localizableAttribute id="caption">Enable Shadows</localizableAttribute> 31 </object> 32 <object name="shadowsCheckbox" size="100%-56 15 100%-30 40" type="checkbox" style="StoneCrossBox" checked="true"> 33 <action on="Load">this.checked = Engine.Renderer_GetShadowsEnabled();</action> 34 <action on="Press">Engine.Renderer_SetShadowsEnabled(this.checked);</action> 35 </object> 34 36 35 <!-- Settings / Shadow PCF --> 36 <object size="0 35 100%-80 60" type="text" style="RightLabelText" ghost="true">Enable Shadow Filtering</object> 37 <object name="shadowPCFCheckbox" size="100%-56 40 100%-30 65" type="checkbox" style="StoneCrossBox" checked="true"> 38 <action on="Load">this.checked = Engine.Renderer_GetShadowPCFEnabled();</action> 39 <action on="Press">Engine.Renderer_SetShadowPCFEnabled(this.checked);</action> 40 </object> 37 <!-- Settings / Shadow PCF --> 38 <object size="0 35 100%-80 60" type="text" style="RightLabelText" ghost="true"> 39 <localizableAttribute id="caption">Enable Shadow Filtering</localizableAttribute> 40 </object> 41 <object name="shadowPCFCheckbox" size="100%-56 40 100%-30 65" type="checkbox" style="StoneCrossBox" checked="true"> 42 <action on="Load">this.checked = Engine.Renderer_GetShadowPCFEnabled();</action> 43 <action on="Press">Engine.Renderer_SetShadowPCFEnabled(this.checked);</action> 44 </object> 41 45 42 46 <!-- Settings / Water --> 43 47 <!-- <object size="0 60 100%-80 85" type="text" style="RightLabelText" ghost="true">Enable Water Reflections</object> … … 46 50 <action on="Press">Engine.Renderer_SetWaterNormalEnabled(this.checked);</action> 47 51 </object>--> 48 52 49 <!-- Settings / Music--> 50 <object size="0 60 100%-80 85" type="text" style="RightLabelText" ghost="true">Enable Music</object> 51 <object size="100%-56 65 100%-30 90" type="checkbox" style="StoneCrossBox" checked="true"> 52 <action on="Press">if (this.checked) startMusic(); else stopMusic();</action> 53 </object> 53 <!-- Settings / Music--> 54 <object size="0 60 100%-80 85" type="text" style="RightLabelText" ghost="true"> 55 <localizableAttribute id="caption">Enable Music</localizableAttribute> 56 </object> 57 <object size="100%-56 65 100%-30 90" type="checkbox" style="StoneCrossBox" checked="true"> 58 <action on="Press">if (this.checked) startMusic(); else stopMusic();</action> 59 </object> 54 60 55 61 <!-- Settings / Dev Overlay --> 56 62 <!-- <object size="0 110 100%-80 135" type="text" style="RightLabelText" ghost="true">Developer Overlay</object> 57 63 <object size="100%-56 115 100%-30 140" type="checkbox" style="StoneCrossBox" checked="false"> 58 64 <action on="Press">toggleDeveloperOverlay();</action> 59 65 </object>--> 60 66 </object> 61 67 62 63 Cancel68 <object type="button" style="StoneButton" size="50%-64 100%-64 50%+64 100%-32"> 69 <localizableAttribute id="caption">Cancel</localizableAttribute> 64 70 <action on="Press"><![CDATA[Engine.PopGuiPage();]]></action> 65 71 </object> 66 72 67 73 </object> 68 74 </objects> -
new file inaries/data/mods/public/gui/page_locale.xml
diff --git a/binaries/data/mods/public/gui/page_locale.xml b/binaries/data/mods/public/gui/page_locale.xml new file mode 100644 index 0000000..ac75bc1
- + 1 <?xml version="1.0" encoding="utf-8"?> 2 <page> 3 <include>common/setup.xml</include> 4 <include>common/styles.xml</include> 5 <include>common/sprite1.xml</include> 6 <include>common/common_sprites.xml</include> 7 <include>common/common_styles.xml</include> 8 9 <include>locale/locale.xml</include> 10 11 <include>common/global.xml</include> 12 </page> -
binaries/data/mods/public/gui/pregame/mainmenu.js
diff --git a/binaries/data/mods/public/gui/pregame/mainmenu.js b/binaries/data/mods/public/gui/pregame/mainmenu.js index 43d1f4a..4a69503 100644
a b function formatUserReportStatus(status) 103 103 var d = status.split(/:/, 3); 104 104 105 105 if (d[0] == "disabled") 106 return "disabled";106 return Engine.localize("disabled"); 107 107 108 108 if (d[0] == "connecting") 109 return "connecting to server";109 return Engine.localize("connecting to server"); 110 110 111 111 if (d[0] == "sending") 112 112 { 113 113 var done = d[1]; 114 return "uploading (" + Math.floor(100*done) + "%)";114 return sprintf(Engine.localize("uploading (%f%%)"), Math.floor(100*done)); 115 115 } 116 116 117 117 if (d[0] == "completed") 118 118 { 119 119 var httpCode = d[1]; 120 120 if (httpCode == 200) 121 return "upload succeeded";121 return Engine.localize("upload succeeded"); 122 122 else 123 return "upload failed (" + httpCode + ")";123 return sprintf(Engine.localize("upload failed (%{errorCode}s)"), { errorCode: httpCode }); 124 124 } 125 125 126 126 if (d[0] == "failed") 127 127 { 128 128 var errCode = d[1]; 129 129 var errMessage = d[2]; 130 return "upload failed (" + errMessage + ")";130 return sprintf(Engine.localize("upload failed (%{errorMessage}s)"), { errorMessage: errMessage }); 131 131 } 132 132 133 return "unknown";133 return Engine.localize("unknown"); 134 134 } 135 135 136 136 var lastTickTime = new Date; … … function onTick() 166 166 messageBox( 167 167 600, 168 168 300, 169 "[font=\"serif-bold-16\"][color=\"200 20 20\"]Warning:[/color] You appear to be using non-shader (fixed function) graphics. This option will be removed in a future 0 A.D. release, to allow for more advanced graphics features. We advise upgrading your graphics card to a more recent, shader-compatible model.\n\nPlease press \"Read More\" for more information or \"Ok\" to continue.", 170 "WARNING!", 169 "[font=\"serif-bold-16\"]" + 170 sprintf(Engine.localize("%{startWarning}sWarning:%{endWarning}s You appear to be using non-shader (fixed function) graphics. This option will be removed in a future 0 A.D. release, to allow for more advanced graphics features. We advise upgrading your graphics card to a more recent, shader-compatible model."), { startWarning: "[color=\"200 20 20\"]", endWarning: "[/color]"}) + 171 "\n\n" + 172 Engine.localize("Please press \"Read More\" for more information or \"OK\" to continue."), 173 Engine.localize("WARNING!"), 171 174 0, 172 [ "Ok", "Read More"],175 [Engine.localize("OK"), Engine.localize("Read More")], 173 176 [null, function() { Engine.OpenURL("http://www.wildfiregames.com/forum/index.php?showtopic=16734"); }] 174 177 ); 175 178 } … … function blendSubmenuIntoMain(topPosition, bottomPosition) 264 267 bottomSprite.size = "100%-2 " + (bottomPosition) + " 100% 100%"; 265 268 } 266 269 270 function getBuildString() 271 { 272 return sprintf(Engine.localize("Build: %(buildDate)s (%(revision)s)"), { buildDate: Engine.GetBuildTimestamp(0), revision: Engine.GetBuildTimestamp(2) }); 273 } 274 267 275 /* 268 276 * FUNCTIONS BELOW DO NOT WORK YET 269 277 */ … … function blendSubmenuIntoMain(topPosition, bottomPosition) 319 327 // guiUnHide ("pg"); 320 328 // } 321 329 //} 330 331 function exitGamePressed() 332 { 333 closeMenu(); 334 var btCaptions = [Engine.localize("Yes"), Engine.localize("No")]; 335 var btCode = [exit, null]; 336 messageBox(400, 200, Engine.localize("Are you sure you want to quit 0 A.D.?"), Engine.localize("Confirmation"), 0, btCaptions, btCode); 337 } 338 339 function pressedScenarioEditorButton() 340 { 341 closeMenu(); 342 // Start Atlas 343 if (Engine.AtlasIsAvailable()) 344 Engine.RestartInAtlas(); 345 else 346 messageBox(400, 200, Engine.localize("The scenario editor is not available or failed to load."), Engine.localize("Error"), 2); 347 } -
binaries/data/mods/public/gui/pregame/mainmenu.xml
diff --git a/binaries/data/mods/public/gui/pregame/mainmenu.xml b/binaries/data/mods/public/gui/pregame/mainmenu.xml index 837f6bf..d8f9a20 100644
a b 91 91 <object 92 92 type="text" 93 93 style="userReportText" 94 >[font="serif-bold-16"]Help improve 0 A.D.![/font] 95 96 You can automatically send us anonymous feedback that will help us fix bugs, and improve performance and compatibility. 94 > 95 <attribute id="caption"> 96 <keep>[font="serif-bold-16"]</keep> 97 <localize>Help improve 0 A.D.!</localize> 98 <keep>[/font]\n\n</keep> 99 <localize>You can automatically send us anonymous feedback that will help us fix bugs, and improve performance and compatibility.</localize> 100 </attribute> 97 101 </object> 98 102 <object type="button" style="StoneButton" size="8 100%-36 146 100%-8"> 99 Enable feedback103 <localizableAttribute id="caption">Enable feedback</localizableAttribute> 100 104 <action on="Press">EnableUserReport(true);</action> 101 105 </object> 102 106 <object type="button" style="StoneButton" size="100%-146 100%-36 100%-8 100%-8"> 103 Technical details107 <localizableAttribute id="caption">Technical details</localizableAttribute> 104 108 <action on="Press">Engine.PushGuiPage("page_manual.xml", { "page": "userreport" });</action> 105 109 </object> 106 110 </object> … … You can automatically send us anonymous feedback that will help us fix bugs, and 115 119 name="userReportEnabledText" 116 120 type="text" 117 121 style="userReportText" 118 >[font="serif-bold-16"]Thank you for helping improve 0 A.D.![/font] 119 120 Anonymous feedback is currently enabled. 121 Status: $status. 122 </object> 122 > 123 <attribute id="caption"> 124 <keep>[font="serif-bold-16"]</keep> 125 <localize>Thank you for helping improve 0 A.D.!</localize> 126 <keep>[/font]\n\n</keep> 127 <localize>Anonymous feedback is currently enabled.</localize> 128 <keep>\n</keep> 129 <localize>Status: $status.</localize> 130 </attribute> 131 </object> 123 132 124 133 <object type="button" style="StoneButton" size="8 100%-36 146 100%-8"> 125 Disable feedback134 <localizableAttribute id="caption">Disable feedback</localizableAttribute> 126 135 <action on="Press">EnableUserReport(false);</action> 127 136 </object> 128 137 <object type="button" style="StoneButton" size="100%-146 100%-36 100%-8 100%-8"> 129 Technical details138 <localizableAttribute id="caption">Technical details</localizableAttribute> 130 139 <action on="Press">Engine.PushGuiPage("page_manual.xml", { "page": "userreport" });</action> 131 140 </object> 132 141 </object> … … Status: $status. 157 166 type="image" 158 167 size="0 4 100%-4 100%-4" 159 168 tooltip_style="pgToolTip" 160 tooltip="The 0 A.D. Game Manual."161 169 hidden="true" 162 170 > 163 171 <object name="subMenuSinglePlayerButton" … … Status: $status. 165 173 style="StoneButtonFancy" 166 174 size="0 0 100% 28" 167 175 tooltip_style="pgToolTip" 168 tooltip="Click here to start a new single player game."169 176 > 170 Matches 177 <localizableAttribute id="caption">Matches</localizableAttribute> 178 <localizableAttribute id="tooltip">Click here to start a new single player game.</localizableAttribute> 171 179 <action on="Press"> 172 180 Engine.SwitchGuiPage("page_gamesetup.xml", { type: "offline" }); 173 181 </action> … … Status: $status. 178 186 style="StoneButtonFancy" 179 187 size="0 32 100% 60" 180 188 tooltip_style="pgToolTip" 181 tooltip="Relive history through historical military campaigns. [NOT YET IMPLEMENTED]"182 189 enabled="false" 183 190 > 184 Campaigns 191 <localizableAttribute id="caption">Campaigns</localizableAttribute> 192 <localizableAttribute id="tooltip">Relive history through historical military campaigns. [NOT YET IMPLEMENTED]</localizableAttribute> 185 193 <action on="Press"> 186 194 closeMenu(); 187 195 <![CDATA[ … … Status: $status. 196 204 style="StoneButtonFancy" 197 205 size="0 64 100% 92" 198 206 tooltip_style="pgToolTip" 199 tooltip="Click here to load a saved game."200 207 > 201 Load Game 208 <localizableAttribute id="caption">Load Game</localizableAttribute> 209 <localizableAttribute id="tooltip">Click here to load a saved game.</localizableAttribute> 202 210 <action on="Press"> 203 211 closeMenu(); 204 212 Engine.PushGuiPage("page_loadgame.xml", { type: "offline" }); … … Status: $status. 212 220 type="image" 213 221 size="0 4 100%-4 100%-4" 214 222 tooltip_style="pgToolTip" 215 tooltip="The 0 A.D. Game Manual"216 223 hidden="true" 217 224 > 218 225 <object name="subMenuMultiplayerJoinButton" … … Status: $status. 220 227 style="StoneButtonFancy" 221 228 size="0 0 100% 28" 222 229 tooltip_style="pgToolTip" 223 tooltip="Joining an existing multiplayer game."224 230 > 225 Join Game 231 <localizableAttribute id="caption">Join Game</localizableAttribute> 232 <localizableAttribute id="tooltip">Joining an existing multiplayer game.</localizableAttribute> 226 233 <action on="Press"> 227 234 closeMenu(); 228 235 // Open Multiplayer connection window with join option. … … Status: $status. 235 242 style="StoneButtonFancy" 236 243 size="0 32 100% 60" 237 244 tooltip_style="pgToolTip" 238 tooltip="Host a multiplayer game.\n\nRequires UDP port 20595 to be open."239 245 > 240 Host Game 246 <localizableAttribute id="caption">Host Game</localizableAttribute> 247 <localizableAttribute id="tooltip">Host a multiplayer game.\n\nRequires UDP port 20595 to be open.</localizableAttribute> 241 248 <action on="Press"> 242 249 closeMenu(); 243 250 // Open Multiplayer connection window with host option. … … Status: $status. 251 258 type="image" 252 259 size="0 4 100%-4 100%-4" 253 260 tooltip_style="pgToolTip" 254 tooltip="The 0 A.D. Game Manual"255 261 hidden="true" 256 262 > 257 263 <object name="submenuOptionsButton" … … Status: $status. 259 265 type="button" 260 266 size="0 0 100% 28" 261 267 tooltip_style="pgToolTip" 262 tooltip="Adjust game settings. [NOT YET IMPLEMENTED]"263 268 enabled="false" 264 269 > 265 Options 270 <localizableAttribute id="caption">Options</localizableAttribute> 271 <localizableAttribute id="tooltip">Adjust game settings. [NOT YET IMPLEMENTED]</localizableAttribute> 266 272 <action on="Press"> 267 273 closeMenu(); 268 274 <![CDATA[ … … Status: $status. 272 278 </action> 273 279 </object> 274 280 275 <object name="submenu EditorButton"281 <object name="submenuLocaleButton" 276 282 style="StoneButtonFancy" 277 283 type="button" 278 284 size="0 32 100% 60" 279 285 tooltip_style="pgToolTip" 280 tooltip="Open the Atlas Scenario Editor in a new window. You can run this more reliably by starting the game with the command-line argument "-editor"."281 286 > 282 Scenario Editor 287 <localizableAttribute id="caption">Language</localizableAttribute> 288 <localizableAttribute id="tooltip">Choose the language of the game.</localizableAttribute> 283 289 <action on="Press"> 284 closeMenu();285 290 <![CDATA[ 286 // Start Atlas 287 if (Engine.AtlasIsAvailable()) 288 Engine.RestartInAtlas(); 289 else 290 messageBox(400, 200, "The scenario editor is not available or failed to load.", "Error", 2); 291 closeMenu(); 292 Engine.PushGuiPage("page_locale.xml"); 291 293 ]]> 292 294 </action> 293 295 </object> 296 297 <object name="submenuEditorButton" 298 style="StoneButtonFancy" 299 type="button" 300 size="0 64 100% 92" 301 tooltip_style="pgToolTip" 302 > 303 <localizableAttribute id="caption">Scenario Editor</localizableAttribute> 304 <localizableAttribute id="tooltip">Open the Atlas Scenario Editor in a new window. You can run this more reliably by starting the game with the command-line argument "-editor".</localizableAttribute> 305 <action on="Press"> 306 pressedScenarioEditorButton(); 307 </action> 308 </object> 294 309 </object> 295 310 </object><!-- end of submenu --> 296 311 … … Status: $status. 338 353 style="StoneButtonFancy" 339 354 size="4 4 100%-4 32" 340 355 tooltip_style="pgToolTip" 341 tooltip="The 0 A.D. Game Manual"342 356 > 343 Learn To Play 357 <localizableAttribute id="caption">Learn To Play</localizableAttribute> 358 <localizableAttribute id="tooltip">The 0 A.D. Game Manual</localizableAttribute> 344 359 <action on="Press"> 345 360 closeMenu(); 346 361 <![CDATA[ … … Status: $status. 355 370 type="button" 356 371 size="4 36 100%-4 64" 357 372 tooltip_style="pgToolTip" 358 tooltip="Challenge the computer player to a single player match."359 373 > 360 Single Player 374 <localizableAttribute id="caption">Single Player</localizableAttribute> 375 <localizableAttribute id="tooltip">Challenge the computer player to a single player match.</localizableAttribute> 361 376 <action on="Press"> 362 377 closeMenu(); 363 378 openMenu("submenuSinglePlayer", (this.parent.size.top+this.size.top), (this.size.bottom-this.size.top), 3); … … Status: $status. 370 385 type="button" 371 386 size="4 68 100%-4 96" 372 387 tooltip_style="pgToolTip" 373 tooltip="Fight against one or more human players in a multiplayer game."374 388 > 375 Multiplayer 389 <localizableAttribute id="caption">Multiplayer</localizableAttribute> 390 <localizableAttribute id="tooltip">Fight against one or more human players in a multiplayer game.</localizableAttribute> 376 391 <action on="Press"> 377 392 closeMenu(); 378 393 openMenu("submenuMultiplayer", (this.parent.size.top+this.size.top), (this.size.bottom-this.size.top), 2); … … Status: $status. 385 400 type="button" 386 401 size="4 100 100%-4 128" 387 402 tooltip_style="pgToolTip" 388 tooltip="Game options and scenario design tools."389 403 > 390 Tools <![CDATA[&]]> Options 404 <localizableAttribute id="caption">Tools & Options</localizableAttribute> 405 <localizableAttribute id="tooltip">Game options and scenario design tools.</localizableAttribute> 391 406 <action on="Press"> 392 407 closeMenu(); 393 openMenu("submenuToolsAndOptions", (this.parent.size.top+this.size.top), (this.size.bottom-this.size.top), 2);408 openMenu("submenuToolsAndOptions", (this.parent.size.top+this.size.top), (this.size.bottom-this.size.top), 3); 394 409 </action> 395 410 </object> 396 411 … … Status: $status. 400 415 type="button" 401 416 size="4 132 100%-4 160" 402 417 tooltip_style="pgToolTip" 403 tooltip="Learn about the many civilizations featured in 0 A.D."404 418 > 405 History 419 <localizableAttribute id="caption">History</localizableAttribute> 420 <localizableAttribute id="tooltip">Learn about the many civilizations featured in 0 A.D.</localizableAttribute> 406 421 <action on="Press"> 407 422 closeMenu(); 408 423 <![CDATA[ … … Status: $status. 417 432 style="StoneButtonFancy" 418 433 size="4 164 100%-4 192" 419 434 tooltip_style="pgToolTip" 420 tooltip="Exit Game"421 435 > 422 Exit 423 <action on="Press"> 424 closeMenu(); 425 <![CDATA[ 426 var btCaptions = ["Yes", "No"]; 427 var btCode = [exit, null]; 428 messageBox(400, 200, "Are you sure you want to quit 0 A.D.?", "Confirmation", 0, btCaptions, btCode); 429 ]]> 430 </action> 436 <localizableAttribute id="caption">Exit</localizableAttribute> 437 <localizableAttribute id="tooltip">Exit Game</localizableAttribute> 438 <action on="Press">exitGamePressed();</action> 431 439 </object> 432 440 </object> 433 441 … … Status: $status. 445 453 size="8 8 100%-8 100%-36" 446 454 ghost="true" 447 455 > 448 [font="serif-bold-16"]Alpha XIV: Naukratis<!-- IMPORTANT: remember to update session/session.xml in sync with this -->[/font] 449 450 WARNING: This is an early development version of the game. Many features have not been added yet. 451 452 Get involved at: play0ad.com 456 <!-- IMPORTANT: remember to update session/session.xml in sync with this â --> 457 <attribute id="caption"> 458 <keep>[font="serif-bold-16"]</keep> 459 <localize>Alpha XIV: Naukratis</localize> 460 <keep>[/font]\n\n</keep> 461 <localize>WARNING: This is an early development version of the game. Many features have not been added yet.</localize> 462 <keep>\n\n</keep> 463 <localize>Get involved at: play0ad.com</localize> 464 </attribute> 453 465 </object> 454 466 455 467 <!-- FUNDRAISER --> 456 468 <object type="button" 457 469 style="StoneButton" 458 470 tooltip_style="pgToolTip" 459 tooltip="Click to view fundraiser information."460 471 size="8 100%-108 100%-8 100%-80" 461 472 > 462 Fundraiser 473 <localizableAttribute id="caption">Fundraiser</localizableAttribute> 474 <localizableAttribute id="tooltip">Click to view fundraiser information.</localizableAttribute> 463 475 <action on="Press"><![CDATA[ 464 476 closeMenu(); 465 477 Engine.PushGuiPage("page_splashscreen.xml", { "page": "splashscreen" }); … … Get involved at: play0ad.com 470 482 <object type="button" 471 483 style="StoneButton" 472 484 tooltip_style="pgToolTip" 473 tooltip="Click to open play0ad.com in your web browser."474 485 size="8 100%-72 50%-4 100%-44" 475 486 > 476 Website 487 <localizableAttribute id="caption">Website</localizableAttribute> 488 <localizableAttribute id="tooltip">Click to open play0ad.com in your web browser.</localizableAttribute> 477 489 <action on="Press"><![CDATA[ 478 490 var url = "http://play0ad.com/"; 479 491 Engine.OpenURL(url); … … Get involved at: play0ad.com 484 496 <object type="button" 485 497 style="StoneButton" 486 498 tooltip_style="pgToolTip" 487 tooltip="Click to open the 0 A.D. IRC chat in your browser. (#0ad on webchat.quakenet.org)"488 499 size="50%+4 100%-72 100%-8 100%-44" 489 500 > 490 Chat 501 <localizableAttribute id="caption">Chat</localizableAttribute> 502 <localizableAttribute id="tooltip">Click to open the 0 A.D. IRC chat in your browser. (#0ad on webchat.quakenet.org)</localizableAttribute> 491 503 <action on="Press"><![CDATA[ 492 504 var url = "http://webchat.quakenet.org/?channels=0ad"; 493 505 Engine.OpenURL(url); … … Get involved at: play0ad.com 498 510 <object type="button" 499 511 style="StoneButton" 500 512 tooltip_style="pgToolTip" 501 tooltip="Click to visit 0 A.D. Trac to report a bug, crash, or error"502 513 size="8 100%-36 100%-8 100%-8" 503 514 > 504 Report a Bug 515 <localizableAttribute id="caption">Report a Bug</localizableAttribute> 516 <localizableAttribute id="tooltip">Click to visit 0 A.D. Trac to report a bug, crash, or error</localizableAttribute> 505 517 <action on="Press"><![CDATA[ 506 518 var url = "http://trac.wildfiregames.com/wiki/ReportingErrors/"; 507 519 Engine.OpenURL(url); … … Get involved at: play0ad.com 530 542 style="MediumTitleText" 531 543 ghost="true" 532 544 size="50%-128 32 50%+128 48" 533 >WILDFIRE GAMES</object> 545 > 546 <localizableAttribute id="caption">WILDFIRE GAMES</localizableAttribute> 547 </object> 534 548 </object> 535 549 536 550 <!-- VERSION --> … … Get involved at: play0ad.com 540 554 ghost="true" 541 555 size="50%-128 100%-36 50%+128 100%" 542 556 > 543 <action on="Load"> <![CDATA[544 this.caption = "Build: " + buildTime(0) + " - " + buildTime(2);545 ]]></action>557 <action on="Load"> 558 this.caption = getBuildString(); 559 </action> 546 560 </object> 547 561 </object> 548 562 </object> -
binaries/data/mods/public/gui/savedgames/load.js
diff --git a/binaries/data/mods/public/gui/savedgames/load.js b/binaries/data/mods/public/gui/savedgames/load.js index 3201421..a21376b3 100644
a b function init() 5 5 var savedGames = Engine.GetSavedGames(); 6 6 if (savedGames.length == 0) 7 7 { 8 gameSelection.list = [ "No saved games found"];8 gameSelection.list = [Engine.localize("No saved games found")]; 9 9 gameSelection.selected = 0; 10 10 getGUIObjectByName("loadGameButton").enabled = false; 11 11 getGUIObjectByName("deleteGameButton").enabled = false; … … function loadGame() 32 32 { 33 33 // Probably the file wasn't found 34 34 // Show error and refresh saved game list 35 error( "Could not load saved game '"+gameID+"'");35 error(sprintf(Engine.localize("Could not load saved game '%(id)s'"), { id: gameID })); 36 36 init(); 37 37 } 38 38 else … … function deleteGame() 53 53 var gameID = gameSelection.list_data[gameSelection.selected]; 54 54 55 55 // Ask for confirmation 56 var btCaptions = [ "Yes", "No"];56 var btCaptions = [Engine.localize("Yes"), Engine.localize("No")]; 57 57 var btCode = [function(){ reallyDeleteGame(gameID); }, null]; 58 58 messageBox(500, 200, "\""+gameLabel+"\"\nSaved game will be permanently deleted, are you sure?", "DELETE", 0, btCaptions, btCode); 59 messageBox(500, 200, sprintf(Engine.localize("\"%(label)s\""), { label: gameLabel }) + "\n" + Engine.localize("Saved game will be permanently deleted, are you sure?"), Engine.localize("DELETE"), 0, btCaptions, btCode); 59 60 } 60 61 61 62 function reallyDeleteGame(gameID) 62 63 { 63 64 if (!Engine.DeleteSavedGame(gameID)) 64 65 error("Could not delete saved game '"+gameID+"'"); 66 error(sprintf(Engine.localize("Could not delete saved game '%(id)s'"), { id: gameID })); 65 67 66 68 // Run init again to refresh saved game list 67 69 init(); -
binaries/data/mods/public/gui/savedgames/load.xml
diff --git a/binaries/data/mods/public/gui/savedgames/load.xml b/binaries/data/mods/public/gui/savedgames/load.xml index 81f245e..c280d72 100644
a b 12 12 <object type="image" style="StoneDialog" size="50%-300 50%-200 50%+300 50%+200"> 13 13 14 14 <object type="text" style="TitleText" size="50%-128 0%-16 50%+128 16"> 15 Load Game15 <localizableAttribute id="caption">Load Game</localizableAttribute> 16 16 </object> 17 17 18 18 <object name="gameSelection" … … 22 22 </object> 23 23 24 24 <object name="loadGameButton" type="button" size="0%+25 100%-60 33%+10 100%-32" style="StoneButton"> 25 Load25 <localizableAttribute id="caption">Load</localizableAttribute> 26 26 <action on="Press">loadGame();</action> 27 27 </object> 28 28 29 29 <object name="deleteGameButton" type="button" size="33%+20 100%-60 66%-15 100%-32" style="StoneButton"> 30 Delete30 <localizableAttribute id="caption">Delete</localizableAttribute> 31 31 <action on="Press">deleteGame();</action> 32 32 </object> 33 33 34 34 <object type="button" style="StoneButton" size="66%-5 100%-60 100%-25 100%-32"> 35 Cancel35 <localizableAttribute id="caption">Cancel</localizableAttribute> 36 36 <action on="Press">Engine.PopGuiPage();</action> 37 37 </object> 38 38 -
binaries/data/mods/public/gui/savedgames/save.js
diff --git a/binaries/data/mods/public/gui/savedgames/save.js b/binaries/data/mods/public/gui/savedgames/save.js index d734655..2cae368 100644
a b function init(data) 30 30 var savedGames = Engine.GetSavedGames(); 31 31 if (savedGames.length == 0) 32 32 { 33 gameSelection.list = [ "No saved games found"];33 gameSelection.list = [Engine.localize("No saved games found")]; 34 34 gameSelection.selected = -1; 35 35 return; 36 36 } … … function saveGame() 59 59 if (gameSelection.selected != -1) 60 60 { 61 61 // Ask for confirmation 62 var btCaptions = [ "Yes", "No"];62 var btCaptions = [Engine.localize("Yes"), Engine.localize("No")]; 63 63 var btCode = [function(){ reallySaveGame(name, desc, false); }, null]; 64 messageBox(500, 200, "\""+gameLabel+"\"\nSaved game will be permanently overwritten, are you sure?", "OVERWRITE SAVE", 0, btCaptions, btCode);64 messageBox(500, 200, sprintf(Engine.localize("\"%(label)s\""), { label: gameLabel }) + "\n" + Engine.localize("Saved game will be permanently overwritten, are you sure?"), Engine.localize("OVERWRITE SAVE"), 0, btCaptions, btCode); 65 65 } 66 66 else 67 67 reallySaveGame(name, desc, true); … … function deleteGame() 91 91 var gameID = gameSelection.list_data[gameSelection.selected]; 92 92 93 93 // Ask for confirmation 94 var btCaptions = [ "Yes", "No"];94 var btCaptions = [Engine.localize("Yes"), Engine.localize("No")]; 95 95 var btCode = [function(){ reallyDeleteGame(gameID); }, null]; 96 messageBox(500, 200, "\""+gameLabel+"\"\nSaved game will be permanently deleted, are you sure?", "DELETE", 0, btCaptions, btCode);96 messageBox(500, 200, sprintf(Engine.localize("\"%(label)s\""), { label: gameLabel }) + "\n" + Engine.localize("Saved game will be permanently deleted, are you sure?"), Engine.localize("DELETE"), 0, btCaptions, btCode); 97 97 } 98 98 99 99 function reallyDeleteGame(gameID) 100 100 { 101 101 if (!Engine.DeleteSavedGame(gameID)) 102 error( "Could not delete saved game '"+gameID+"'");102 error(sprintf(Engine.localize("Could not delete saved game '%(id)s'"), { id: gameID })); 103 103 104 104 // Run init again to refresh saved game list 105 105 init(); -
binaries/data/mods/public/gui/savedgames/save.xml
diff --git a/binaries/data/mods/public/gui/savedgames/save.xml b/binaries/data/mods/public/gui/savedgames/save.xml index 70d24e9..7cebc88 100644
a b 12 12 <object type="image" style="StoneDialog" size="50%-300 50%-200 50%+300 50%+200"> 13 13 <object type="image" z="0" sprite="BackgroundTranslucent"/> 14 14 <object type="text" style="TitleText" size="50%-128 0%-16 50%+128 16"> 15 Save Game15 <localizableAttribute id="caption">Save Game</localizableAttribute> 16 16 </object> 17 17 18 18 <object name="gameSelection" 19 19 style="StoneList" 20 20 type="list" 21 22 21 size="24 24 100%-24 100%-124"> 23 22 <action on="selectionchange"> 24 23 selectDescription(); 25 24 </action> 26 25 </object> 27 26 28 <object size="24 100%-124 100%-24 100%-100" name="descLabel" type="text" style="LeftLabelText">Description:</object> 27 <object size="24 100%-124 100%-24 100%-100" name="descLabel" type="text" style="LeftLabelText"> 28 <localizableAttribute id="caption">Description:</localizableAttribute> 29 </object> 29 30 30 31 <object name="saveGameDesc" size="24 100%-96 100%-24 100%-72" type="input" style="StoneInput"/> 31 32 32 33 <object name="saveButton" type="button" size="0%+25 100%-60 33%+10 100%-32" style="StoneButton"> 33 Save34 <localizableAttribute id="caption">Save</localizableAttribute> 34 35 <action on="Press">saveGame();</action> 35 36 </object> 36 37 37 38 <object name="deleteGameButton" type="button" size="33%+20 100%-60 66%-15 100%-32" style="StoneButton"> 38 Delete39 <localizableAttribute id="caption">Delete</localizableAttribute> 39 40 <action on="Press">deleteGame();</action> 40 41 </object> 41 42 42 43 <object type="button" style="StoneButton" size="66%-5 100%-60 100%-25 100%-32"> 43 Cancel44 <localizableAttribute id="caption">Cancel</localizableAttribute> 44 45 <action on="Press">closeSave(true);</action> 45 46 </object> 46 47 -
binaries/data/mods/public/gui/session/input.js
diff --git a/binaries/data/mods/public/gui/session/input.js b/binaries/data/mods/public/gui/session/input.js index 301a808..4596427 100644
a b function updateBuildingPlacementPreview() 135 135 elevationBonus: placementSupport.attack.elevationBonus, 136 136 }; 137 137 var averageRange = Engine.GuiInterfaceCall("GetAverageRangeForBuildings",cmd); 138 placementSupport.tooltipMessage = "Basic range: "+Math.round(cmd.range/4)+"\nAverage bonus range: "+Math.round((averageRange - cmd.range)/4);138 placementSupport.tooltipMessage = sprintf(Engine.localize("Basic range: %(range)s"), { range: Math.round(cmd.range/4) }) + "\n" + sprintf(Engine.localize("Average bonus range: %(range)s"), { range: Math.round((averageRange - cmd.range)/4) }); 139 139 } 140 140 return true; 141 141 } … … function getActionInfo(action, target) 243 243 data.command = "garrison"; 244 244 data.target = target; 245 245 cursor = "action-garrison"; 246 tooltip = "Current garrison: " + targetState.garrisonHolder.entities.length 247 + "/" + targetState.garrisonHolder.capacity; 246 tooltip = sprintf(Engine.localize("Current garrison: %(garrisoned)s/%(capacity)s"), { 247 garrisoned: targetState.garrisonHolder.entities.length, 248 capacity: targetState.garrisonHolder.capacity 249 }); 248 250 if (targetState.garrisonHolder.entities.length >= targetState.garrisonHolder.capacity) 249 251 tooltip = "[color=\"orange\"]" + tooltip + "[/color]"; 250 252 } … … function getActionInfo(action, target) 293 295 data.target = traderData.secondMarket; 294 296 data.source = traderData.firstMarket; 295 297 cursor = "action-setup-trade-route"; 296 tooltip = "Right-click to establish a default route for new traders.";298 tooltip = Engine.localize("Right-click to establish a default route for new traders."); 297 299 if (trader) 298 tooltip += "\n Gain (metal): " + getTradingTooltip(gain);300 tooltip += "\n" + sprintf(Engine.localize("Gain (metal): %(gain)s"), { gain: getTradingTooltip(gain) }); 299 301 else // Foundation or cannot produce traders 300 tooltip += "\n Expected gain (metal): " + getTradingTooltip(gain);302 tooltip += "\n" + sprintf(Engine.localize("Expected gain (metal): %(gain)s"), { gain: getTradingTooltip(gain) }); 301 303 } 302 304 } 303 305 … … function getActionInfo(action, target) 335 337 case "garrison": 336 338 if (hasClass(entState, "Unit") && targetState.garrisonHolder && (playerOwned || mutualAllyOwned)) 337 339 { 338 var tooltip = "Current garrison: " + targetState.garrisonHolder.entities.length 339 + "/" + targetState.garrisonHolder.capacity; 340 var tooltip = sprintf(Engine.localize("Current garrison: %(garrisoned)s/%(capacity)s"), { 341 garrisoned: targetState.garrisonHolder.entities.length, 342 capacity: targetState.garrisonHolder.capacity 343 }); 340 344 if (targetState.garrisonHolder.entities.length >= targetState.garrisonHolder.capacity) 341 345 tooltip = "[color=\"orange\"]" + tooltip + "[/color]"; 342 346 var allowedClasses = targetState.garrisonHolder.allowedClasses; … … function getActionInfo(action, target) 362 366 switch (tradingDetails.type) 363 367 { 364 368 case "is first": 365 tooltip = "Origin trade market.";369 tooltip = Engine.localize("Origin trade market."); 366 370 if (tradingDetails.hasBothMarkets) 367 tooltip += "\nGain (" + tradingDetails.goods + "): " + getTradingTooltip(tradingDetails.gain); 371 tooltip += "\n" + sprintf(Engine.localize("Gain (%(goods)s): %(gain)s"), { 372 goods: tradingDetails.goods, 373 gain: getTradingTooltip(tradingDetails.gain) 374 }); 368 375 else 369 tooltip += "\n Right-click on another market to set it as a destination trade market."376 tooltip += "\n" + Engine.localize("Right-click on another market to set it as a destination trade market.") 370 377 break; 371 378 case "is second": 372 tooltip = "Destination trade market.\nGain (" + tradingDetails.goods + "): " + getTradingTooltip(tradingDetails.gain); 379 tooltip = Engine.localize("Destination trade market.") + "\n" + sprintf(Engine.localize("Gain (%(goods)s): %(gain)s"), { 380 goods: tradingDetails.goods, 381 gain: getTradingTooltip(tradingDetails.gain) 382 }); 373 383 break; 374 384 case "set first": 375 tooltip = "Right-click to set as origin trade market";385 tooltip = Engine.localize("Right-click to set as origin trade market"); 376 386 break; 377 387 case "set second": 378 tooltip = "Right-click to set as destination trade market.\nGain (" + tradingDetails.goods + "): " + getTradingTooltip(tradingDetails.gain); 388 tooltip = Engine.localize("Right-click to set as destination trade market.") + "\n" + sprintf(Engine.localize("Gain (%(goods)s): %(gain)s"), { 389 goods: tradingDetails.goods, 390 gain: getTradingTooltip(tradingDetails.gain) 391 }); 379 392 break; 380 393 } 381 394 return {"possible": true, "tooltip": tooltip}; … … function tryPlaceBuilding(queued) 552 565 { 553 566 if (placementSupport.mode !== "building") 554 567 { 555 error("[tryPlaceBuilding] Called while in '"+placementSupport.mode+"' placement mode instead of 'building'"); 568 error(sprintf(Engine.localize("[%(functionName)s] Called while in '%(mode)s' placement mode instead of 'building'"), { 569 functionName: "tryPlaceBuilding", 570 mode: placementSupport.mode 571 })); 556 572 return false; 557 573 } 558 574 … … function tryPlaceWall(queued) 593 609 { 594 610 if (placementSupport.mode !== "wall") 595 611 { 596 error("[tryPlaceWall] Called while in '" + placementSupport.mode + "' placement mode; expected 'wall' mode"); 612 error(sprintf(Engine.localize("[%(functionName)s] Called while in '%(mode)s' placement mode; expected 'wall' mode"), { 613 functionName: "tryPlaceWall", 614 mode: placementSupport.mode 615 })); 597 616 return false; 598 617 } 599 618 600 619 var wallPlacementInfo = updateBuildingPlacementPreview(); // entities making up the wall (wall segments, towers, ...) 601 620 if (!(wallPlacementInfo === false || typeof(wallPlacementInfo) === "object")) 602 621 { 603 error("[tryPlaceWall] Unexpected return value from updateBuildingPlacementPreview: '" + uneval(placementInfo) + "'; expected either 'false' or 'object'"); 622 error(sprintf(Engine.localize("[%(functionName)s] Unexpected return value from %(function2Name)s: '%(value)s'; expected either 'false' or 'object'"), { 623 functionName: "tryPlaceWall", 624 function2Name: "updateBuildingPlacementPreview", 625 value: uneval(placementInfo) 626 })); 604 627 return false; 605 628 } 606 629 … … function handleInputBeforeGui(ev, hoveredObject) 932 955 } 933 956 else 934 957 { 935 placementSupport.tooltipMessage = "Cannot build wall here!";958 placementSupport.tooltipMessage = Engine.localize("Cannot build wall here!"); 936 959 } 937 960 938 961 updateBuildingPlacementPreview(); -
binaries/data/mods/public/gui/session/menu.js
diff --git a/binaries/data/mods/public/gui/session/menu.js b/binaries/data/mods/public/gui/session/menu.js index 0046f64..9d209d1 100644
a b function resignMenuButton() 133 133 closeMenu(); 134 134 closeOpenDialogs(); 135 135 pauseGame(); 136 var btCaptions = [ "Yes", "No"];136 var btCaptions = [Engine.localize("Yes"), Engine.localize("No")]; 137 137 var btCode = [resignGame, resumeGame]; 138 messageBox(400, 200, "Are you sure you want to resign?", "Confirmation", 0, btCaptions, btCode);138 messageBox(400, 200, Engine.localize("Are you sure you want to resign?"), Engine.localize("Confirmation"), 0, btCaptions, btCode); 139 139 } 140 140 141 141 function exitMenuButton() … … function exitMenuButton() 143 143 closeMenu(); 144 144 closeOpenDialogs(); 145 145 pauseGame(); 146 var btCaptions = [ "Yes", "No"];146 var btCaptions = [Engine.localize("Yes"), Engine.localize("No")]; 147 147 var btCode = [leaveGame, resumeGame]; 148 messageBox(400, 200, "Are you sure you want to quit?", "Confirmation", 0, btCaptions, btCode);148 messageBox(400, 200, Engine.localize("Are you sure you want to quit?"), Engine.localize("Confirmation"), 0, btCaptions, btCode); 149 149 } 150 150 151 151 function openDeleteDialog(selection) … … function openDeleteDialog(selection) 158 158 Engine.PostNetworkCommand({"type": "delete-entities", "entities": selection}); 159 159 }; 160 160 161 var btCaptions = [ "Yes", "No"];161 var btCaptions = [Engine.localize("Yes"), Engine.localize("No")]; 162 162 var btCode = [deleteSelectedEntities, resumeGame]; 163 163 164 messageBox(400, 200, "Destroy everything currently selected?", "Delete", 0, btCaptions, btCode);164 messageBox(400, 200, Engine.localize("Destroy everything currently selected?"), Engine.localize("Delete"), 0, btCaptions, btCode); 165 165 } 166 166 167 167 // Menu functions … … function openDiplomacy() 264 264 getGUIObjectByName("diplomacyPlayerName["+(i-1)+"]").caption = "[color=\"" + playerColor + "\"]" + players[i].name + "[/color]"; 265 265 getGUIObjectByName("diplomacyPlayerCiv["+(i-1)+"]").caption = g_CivData[players[i].civ].Name; 266 266 267 getGUIObjectByName("diplomacyPlayerTeam["+(i-1)+"]").caption = (players[i].team < 0) ? "None": players[i].team+1;267 getGUIObjectByName("diplomacyPlayerTeam["+(i-1)+"]").caption = (players[i].team < 0) ? Engine.localizeWithContext("team", "None") : players[i].team+1; 268 268 269 269 if (i != we) 270 getGUIObjectByName("diplomacyPlayerTheirs["+(i-1)+"]").caption = (players[i].isAlly[we] ? "Ally" : (players[i].isNeutral[we] ? "Neutral" : "Enemy"));270 getGUIObjectByName("diplomacyPlayerTheirs["+(i-1)+"]").caption = (players[i].isAlly[we] ? Engine.localize("Ally") : (players[i].isNeutral[we] ? Engine.localize("Neutral") : Engine.localize("Enemy"))); 271 271 272 272 // Don't display the options for ourself, or if we or the other player aren't active anymore 273 273 if (i == we || players[we].state != "active" || players[i].state != "active") … … function openDiplomacy() 328 328 if (setting == "ally") 329 329 { 330 330 if (players[we].isAlly[i]) 331 button.caption = "x";331 button.caption = Engine.localize("x"); 332 332 else 333 333 button.caption = ""; 334 334 } 335 335 else if (setting == "neutral") 336 336 { 337 337 if (players[we].isNeutral[i]) 338 button.caption = "x";338 button.caption = Engine.localize("x"); 339 339 else 340 340 button.caption = ""; 341 341 } 342 342 else // "enemy" 343 343 { 344 344 if (players[we].isEnemy[i]) 345 button.caption = "x";345 button.caption = Engine.localize("x"); 346 346 else 347 347 button.caption = ""; 348 348 } 349 350 349 button.onpress = (function(e){ return function() { setDiplomacy(e) } })({"player": i, "to": setting}); 351 350 button.hidden = false; 352 351 } … … function openManual() 421 420 function toggleDeveloperOverlay() 422 421 { 423 422 var devCommands = getGUIObjectByName("devCommands"); 424 var text = devCommands.hidden ? "opened." : "closed."; 425 submitChatDirectly("The Developer Overlay was " + text); 423 if (devCommands.hidden) 424 { 425 submitChatDirectly(Engine.localize("The Developer Overlay was opened.")); 426 } 427 else 428 { 429 submitChatDirectly(Engine.localize("The Developer Overlay was closed.")); 430 } 426 431 // Update the options dialog 427 432 getGUIObjectByName("developerOverlayCheckbox").checked = devCommands.hidden; 428 433 devCommands.hidden = !devCommands.hidden; … … function closeOpenDialogs() 439 444 function formatTributeTooltip(player, resource, amount) 440 445 { 441 446 var playerColor = player.color.r + " " + player.color.g + " " + player.color.b; 442 return "Tribute " + amount + " " + resource + " to [color=\"" + playerColor + "\"]" + player.name + 443 "[/color]. Shift-click to tribute " + (amount < 500 ? 500 : amount + 500) + "."; 447 return sprintf(Engine.localize("Tribute %(resourceAmount)s %(resourceType)s to %(playerName)s. Shift-click to tribute %(greaterAmount)s."), { 448 resourceAmount: amount, 449 resourceType: resource, 450 playerName: "[color=\"" + playerColor + "\"]" + player.name + "[/color]", 451 greaterAmount: (amount < 500 ? 500 : amount + 500) 452 }); 444 453 } -
binaries/data/mods/public/gui/session/messages.js
diff --git a/binaries/data/mods/public/gui/session/messages.js b/binaries/data/mods/public/gui/session/messages.js index 708d053..f84a213 100644
a b function getCheatsData() 19 19 { 20 20 var currentCheat = parseJSONData("simulation/data/cheats/"+fileName+".json"); 21 21 if (Object.keys(cheats).indexOf(currentCheat.Name) !== -1) 22 warn( "Cheat name '"+currentCheat.Name+"' is already present");22 warn(sprintf(Engine.localize("Cheat name '%(name)s' is already present"), { name: currentCheat.Name })); 23 23 else 24 24 cheats[currentCheat.Name] = currentCheat.Data; 25 25 } … … function displayNotifications() 141 141 // Messages 142 142 function handleNetMessage(message) 143 143 { 144 log( "Net message: " + uneval(message));144 log(sprintf(Engine.localize("Net message: %(message)s"), { message: uneval(message) })); 145 145 146 146 switch (message.type) 147 147 { … … function handleNetMessage(message) 154 154 switch (message.status) 155 155 { 156 156 case "waiting_for_players": 157 obj.caption = "Waiting for other players to connect...";157 obj.caption = Engine.localize("Waiting for other players to connect..."); 158 158 obj.hidden = false; 159 159 break; 160 160 case "join_syncing": 161 obj.caption = "Synchronising gameplay with other players...";161 obj.caption = Engine.localize("Synchronising gameplay with other players..."); 162 162 obj.hidden = false; 163 163 break; 164 164 case "active": … … function handleNetMessage(message) 166 166 obj.hidden = true; 167 167 break; 168 168 case "connected": 169 obj.caption = "Connected to the server.";169 obj.caption = Engine.localize("Connected to the server."); 170 170 obj.hidden = false; 171 171 break; 172 172 case "authenticated": 173 obj.caption = "Connection to the server has been authenticated.";173 obj.caption = Engine.localize("Connection to the server has been authenticated."); 174 174 obj.hidden = false; 175 175 break; 176 176 case "disconnected": 177 177 g_Disconnected = true; 178 obj.caption = "Connection to the server has been lost.\n\nThe game has ended.";178 obj.caption = Engine.localize("Connection to the server has been lost.") + "\n\n" + Engine.localize("The game has ended."); 179 179 obj.hidden = false; 180 180 break; 181 181 default: 182 error( "Unrecognised netstatus type "+message.status);182 error(sprintf(Engine.localize("Unrecognised netstatus type %(netType)s"), { netType: message.status })); 183 183 break; 184 184 } 185 185 break; … … function handleNetMessage(message) 225 225 break; 226 226 227 227 default: 228 error( "Unrecognised net message type "+message.type);228 error(sprintf(Engine.localize("Unrecognised net message type %(messageType)s"), { messageType: message.type })); 229 229 } 230 230 } 231 231 … … function addChatMessage(msg, playerAssignments) 307 307 308 308 var playerColor, username; 309 309 310 // No prefixby default. May be set by parseChatCommands().311 msg. prefix= "";310 // No context by default. May be set by parseChatCommands(). 311 msg.context = ""; 312 312 313 313 if (playerAssignments[msg.guid]) 314 314 { … … function addChatMessage(msg, playerAssignments) 335 335 else 336 336 { 337 337 playerColor = "255 255 255"; 338 username = "Unknown player";338 username = Engine.localize("Unknown player"); 339 339 } 340 340 341 341 var message = escapeText(msg.text); … … function addChatMessage(msg, playerAssignments) 345 345 switch (msg.type) 346 346 { 347 347 case "connect": 348 formatted = "[color=\"" + playerColor + "\"]" + username + "[/color] has joined the game.";348 formatted = sprintf(Engine.localize("%(player)s has joined the game."), { player: "[color=\"" + playerColor + "\"]" + username + "[/color]" }); 349 349 break; 350 350 case "disconnect": 351 formatted = "[color=\"" + playerColor + "\"]" + username + "[/color] has left the game.";351 formatted = sprintf(Engine.localize("%(player)s has left the game."), { player: "[color=\"" + playerColor + "\"]" + username + "[/color]" }); 352 352 break; 353 353 case "defeat": 354 354 // In singleplayer, the local player is "You". "You has" is incorrect. 355 var verb = (!g_IsNetworked && msg.player == Engine.GetPlayerID()) ? "have" : "has"; 356 formatted = "[color=\"" + playerColor + "\"]" + username + "[/color] " + verb + " been defeated."; 355 if (!g_IsNetworked && msg.player == Engine.GetPlayerID()) 356 { 357 formatted = Engine.localize("You have been defeated."); 358 } 359 else 360 { 361 formatted = sprintf(Engine.localize("%(player)s has been defeated."), { player: "[color=\"" + playerColor + "\"]" + username + "[/color]" }); 362 } 357 363 break; 358 364 case "diplomacy": 359 365 var status = (msg.status == "ally" ? "allied" : (msg.status == "enemy" ? "at war" : "neutral")); … … function addChatMessage(msg, playerAssignments) 361 367 { 362 368 username= escapeText(g_Players[msg.player1].name); 363 369 playerColor = g_Players[msg.player1].color.r + " " + g_Players[msg.player1].color.g + " " + g_Players[msg.player1].color.b; 364 formatted = "You are now "+status+" with [color=\"" + playerColor + "\"]"+username + "[/color]."; 370 if (msg.status == "ally") 371 { 372 formatted = sprintf(Engine.localize("You are now allied with %(player)s."), { player: "[color=\"" + playerColor + "\"]" + username + "[/color]" }); 373 } 374 else if (msg.status == "enemy") 375 { 376 formatted = sprintf(Engine.localize("You are now at war with %(player)s."), { player: "[color=\"" + playerColor + "\"]" + username + "[/color]" }); 377 } 378 else 379 { 380 formatted = sprintf(Engine.localize("You are now neutral with %(player)s."), { player: "[color=\"" + playerColor + "\"]" + username + "[/color]" }); 381 } 365 382 } 366 383 else if (msg.player1 == Engine.GetPlayerID()) 367 384 { 368 385 username= escapeText(g_Players[msg.player].name); 369 386 playerColor = g_Players[msg.player].color.r + " " + g_Players[msg.player].color.g + " " + g_Players[msg.player].color.b; 370 formatted = "[color=\"" + playerColor + "\"]" + username + "[/color] is now " + status + " with you." 387 if (msg.status == "ally") 388 { 389 formatted = sprintf(Engine.localize("%(player)s is now allied with you."), { player: "[color=\"" + playerColor + "\"]" + username + "[/color]" }); 390 } 391 else if (msg.status == "enemy") 392 { 393 formatted = sprintf(Engine.localize("%(player)s is now at war with you."), { player: "[color=\"" + playerColor + "\"]" + username + "[/color]" }); 394 } 395 else 396 { 397 formatted = sprintf(Engine.localize("%(player)s is now neutral with you."), { player: "[color=\"" + playerColor + "\"]" + username + "[/color]" }); 398 } 371 399 } 372 400 else // No need for other players to know of this. 373 401 return; … … function addChatMessage(msg, playerAssignments) 387 415 if (amounts.length > 1) 388 416 { 389 417 var lastAmount = amounts.pop(); 390 amounts = amounts.join(", ") + " and " + lastAmount; 418 amounts = sprintf(Engine.localize("%(previousAmounts)s and %(lastAmount)s"), { 419 previousAmounts: amounts.join(Engine.localize(", ")), 420 lastAmount: lastAmount 421 }); 391 422 } 392 423 393 formatted = "[color=\"" + playerColor + "\"]" + username + "[/color] has sent you " + amounts + "."; 424 formatted = sprintf(Engine.localize("%(player)s has sent you %(amounts)s."), { 425 player: "[color=\"" + playerColor + "\"]" + username + "[/color]", 426 amounts: amounts 427 }); 394 428 break; 395 429 case "attack": 396 430 if (msg.player != Engine.GetPlayerID()) … … function addChatMessage(msg, playerAssignments) 405 439 406 440 if (msg.action) 407 441 { 408 Engine.Console_Write(msg.prefix + "* " + username + " " + message); 409 formatted = msg.prefix + "* [color=\"" + playerColor + "\"]" + username + "[/color] " + message; 442 if (msg.context !== "") 443 { 444 Engine.Console_Write(sprintf(Engine.localize("(%(context)s) * %(user)s %(message)s"), { 445 context: msg.context, 446 user: username, 447 message: message 448 })); 449 formatted = sprintf(Engine.localize("(%(context)s) * %(user)s %(message)s"), { 450 context: msg.context, 451 user: "[color=\"" + playerColor + "\"]" + username + "[/color]", 452 message: message 453 }); 454 } 455 else 456 { 457 Engine.Console_Write(sprintf(Engine.localize("* %(user)s %(message)s"), { 458 user: username, 459 message: message 460 })); 461 formatted = sprintf(Engine.localize("* %(user)s %(message)s"), { 462 user: "[color=\"" + playerColor + "\"]" + username + "[/color]", 463 message: message 464 }); 465 } 410 466 } 411 467 else 412 468 { 413 Engine.Console_Write(msg.prefix + "<" + username + "> " + message); 414 formatted = msg.prefix + "<[color=\"" + playerColor + "\"]" + username + "[/color]> " + message; 469 var userTag = sprintf(Engine.localize("<%(user)s>"), { user: username }) 470 var formattedUserTag = sprintf(Engine.localize("<%(user)s>"), { user: "[color=\"" + playerColor + "\"]" + username + "[/color]" }) 471 if (msg.context !== "") 472 { 473 Engine.Console_Write(sprintf(Engine.localize("(%(context)s) %(userTag)s %(message)s"), { 474 context: msg.context, 475 userTag: userTag, 476 message: message 477 })); 478 formatted = sprintf(Engine.localize("(%(context)s) %(userTag)s %(message)s"), { 479 context: msg.context, 480 userTag: formattedUserTag, 481 message: message 482 }); 483 } 484 else 485 { 486 Engine.Console_Write(sprintf(Engine.localize("%(userTag)s %(message)s"), { userTag: userTag, message: message})); 487 formatted = sprintf(Engine.localize("%(userTag)s %(message)s"), { userTag: formattedUserTag, message: message}); 488 } 415 489 } 416 490 break; 417 491 default: 418 error( "Invalid chat message '" + uneval(msg) + "'");492 error(sprintf(Engine.localize("Invalid chat message '%(message)s'"), { message: uneval(msg) })); 419 493 return; 420 494 } 421 495 … … function parseChatCommands(msg, playerAssignments) 457 531 { 458 532 case "/all": 459 533 // Resets values that 'team' or 'enemy' may have set. 460 msg. prefix= "";534 msg.context = ""; 461 535 msg.hide = false; 462 536 recurse = true; 463 537 break; … … function parseChatCommands(msg, playerAssignments) 468 542 if (g_Players[Engine.GetPlayerID()].team != g_Players[sender].team) 469 543 msg.hide = true; 470 544 else 471 msg. prefix = "(Team) ";545 msg.context = Engine.localize("Team"); 472 546 } 473 547 else 474 548 msg.hide = true; … … function parseChatCommands(msg, playerAssignments) 481 555 if (g_Players[Engine.GetPlayerID()].team == g_Players[sender].team && sender != Engine.GetPlayerID()) 482 556 msg.hide = true; 483 557 else 484 msg. prefix = "(Enemy) ";558 msg.context = Engine.localize("Enemy"); 485 559 } 486 560 recurse = true; 487 561 break; … … function parseChatCommands(msg, playerAssignments) 501 575 var playerName = g_Players[Engine.GetPlayerID()].name; 502 576 if (matched.length && (matched == playerName || sender == Engine.GetPlayerID())) 503 577 { 504 msg. prefix = "(Private) ";578 msg.context = Engine.localize("Private"); 505 579 msg.text = trimmed.substr(matched.length + 1); 506 580 msg.hide = false; // Might override team message hiding. 507 581 return; -
binaries/data/mods/public/gui/session/selection_details.js
diff --git a/binaries/data/mods/public/gui/session/selection_details.js b/binaries/data/mods/public/gui/session/selection_details.js index c454fe0..ae16124 100644
a b 1 var localizedFish = Engine.localize("Fish"); 2 var localizedFood = Engine.localize("Food"); 3 var localizedFruit = Engine.localize("Fruit"); 4 var localizedGrain = Engine.localize("Grain"); 5 var localizedMeat = Engine.localize("Meat"); 6 var localizedMetal = Engine.localize("Metal"); 7 var localizedOre = Engine.localize("Ore"); 8 var localizedRock = Engine.localize("Rock"); 9 var localizedRuins = Engine.localize("Ruins"); 10 var localizedStone = Engine.localize("Stone"); 11 var localizedTreasure = Engine.localize("Treasure"); 12 var localizedTree = Engine.localize("Tree"); 13 var localizedWood = Engine.localize("Wood"); 14 1 15 function layoutSelectionSingle() 2 16 { 3 17 getGUIObjectByName("detailsAreaSingle").hidden = false; … … function layoutSelectionMultiple() 10 24 getGUIObjectByName("detailsAreaSingle").hidden = true; 11 25 } 12 26 27 function getLocalizedResourceName(resourceCode) 28 { 29 switch(resourceCode) 30 { 31 case "food": return localizedFood; 32 case "meat": return localizedMeat; 33 case "metal": return localizedMetal; 34 case "ore": return localizedOre; 35 case "rock": return localizedRock; 36 case "ruins": return localizedRuins; 37 case "stone": return localizedStone; 38 case "treasure": return localizedTreasure; 39 case "tree": return localizedTree; 40 case "wood": return localizedWood; 41 case "fruit": return localizedFruit; 42 case "grain": return localizedGrain; 43 case "fish": return localizedFish; 44 default: 45 warn(sprintf(Engine.localize("Internationalization: unexpected resource type found with code â%(resource)sâ. This resource type must be internationalized."), { resource: resourceCode })); 46 return resourceCode; // It should never get here. 47 } 48 } 49 50 function getResourceTypeDisplayName(resourceType) 51 { 52 var resourceCode = resourceType["generic"]; 53 var displayName = ""; 54 if (resourceCode == "treasure") 55 { 56 displayName = getLocalizedResourceName(resourceType["specific"]); 57 } 58 else 59 { 60 displayName = getLocalizedResourceName(resourceCode); 61 } 62 return displayName; 63 } 64 13 65 // Fills out information that most entities have 14 66 function displaySingle(entState, template) 15 67 { … … function displaySingle(entState, template) 18 70 var genericName = template.name.generic != template.name.specific? template.name.generic : ""; 19 71 // If packed, add that to the generic name (reduces template clutter) 20 72 if (genericName && template.pack && template.pack.state == "packed") 21 genericName += " -- Packed";73 genericName = sprintf(Engine.localize("%(genericName)s â Packed"), { genericName: genericName }); 22 74 var playerState = g_Players[entState.player]; 23 75 24 76 var civName = g_CivData[playerState.civ].Name; … … function displaySingle(entState, template) 30 82 // Indicate disconnected players by prefixing their name 31 83 if (g_Players[entState.player].offline) 32 84 { 33 playerName = "[OFFLINE] " + playerName;85 playerName = sprintf(Engine.localize("[OFFLINE] %(player)s"), { player: playerName }); 34 86 } 35 87 36 88 // Rank 37 89 if (entState.identity && entState.identity.rank && entState.identity.classes) 38 90 { 39 getGUIObjectByName("rankIcon").tooltip = entState.identity.rank + " Rank";91 getGUIObjectByName("rankIcon").tooltip = sprintf(Engine.localize("%(rank)s Rank"), { rank: entState.identity.rank }); 40 92 getGUIObjectByName("rankIcon").sprite = getRankIconSprite(entState); 41 93 getGUIObjectByName("rankIcon").hidden = false; 42 94 } … … function displaySingle(entState, template) 54 106 healthSize.rright = 100*Math.max(0, Math.min(1, entState.hitpoints / entState.maxHitpoints)); 55 107 unitHealthBar.size = healthSize; 56 108 57 var hitpoints = Math.ceil(entState.hitpoints) + " / " + entState.maxHitpoints; 58 getGUIObjectByName("healthStats").caption = hitpoints; 109 getGUIObjectByName("healthStats").caption = sprintf(Engine.localize("%(hitpoints)s / %(maxHitpoints)s"), { 110 hitpoints: Math.ceil(entState.hitpoints), 111 maxHitpoints: entState.maxHitpoints 112 }); 59 113 getGUIObjectByName("healthSection").hidden = false; 60 114 } 61 115 else … … function displaySingle(entState, template) 84 138 85 139 var experience = "[font=\"serif-bold-13\"]Experience: [/font]" + Math.floor(entState.promotion.curr); 86 140 if (entState.promotion.curr < entState.promotion.req) 87 experience += " / " + entState.promotion.req; 88 getGUIObjectByName("experience").tooltip = experience; 141 { 142 getGUIObjectByName("experience").tooltip = sprintf(Engine.localize("%(experience)s %(current)s / %(required)s"), { 143 experience: "[font=\"serif-bold-13\"]" + Engine.localize("Experience:") + "[/font]", 144 current: Math.floor(entState.promotion.curr), 145 required: entState.promotion.req 146 }); 147 } 148 else 149 { 150 getGUIObjectByName("experience").tooltip = sprintf(Engine.localize("%(experience)s %(current)s"), { 151 experience: "[font=\"serif-bold-13\"]" + Engine.localize("Experience:") + "[/font]", 152 current: Math.floor(entState.promotion.curr) 153 }); 154 } 89 155 getGUIObjectByName("experience").hidden = false; 90 156 } 91 157 else … … function displaySingle(entState, template) 96 162 // Resource stats 97 163 if (entState.resourceSupply) 98 164 { 99 var resources = entState.resourceSupply.isInfinite ? "\u221E" : // Infinity symbol 100 Math.ceil(+entState.resourceSupply.amount) + " / " + entState.resourceSupply.max; 101 var resourceType = entState.resourceSupply.type["generic"]; 102 if (resourceType == "treasure") 103 resourceType = entState.resourceSupply.type["specific"]; 165 var resources = entState.resourceSupply.isInfinite ? Engine.localize("â") : // Infinity symbol 166 sprintf(Engine.localize("%(amount)s / %(max)s"), { amount: Math.ceil(+entState.resourceSupply.amount), max: entState.resourceSupply.max }); 167 var resourceType = getResourceTypeDisplayName(entState.resourceSupply.type); 104 168 105 169 var unitResourceBar = getGUIObjectByName("resourceBar"); 106 170 var resourceSize = unitResourceBar.size; … … function displaySingle(entState, template) 108 172 resourceSize.rright = entState.resourceSupply.isInfinite ? 100 : 109 173 100 * Math.max(0, Math.min(1, +entState.resourceSupply.amount / +entState.resourceSupply.max)); 110 174 unitResourceBar.size = resourceSize; 111 getGUIObjectByName("resourceLabel").caption = toTitleCase(resourceType) + ":";175 getGUIObjectByName("resourceLabel").caption = sprintf(Engine.localize("%(resource)s:"), { resource: resourceType }); 112 176 getGUIObjectByName("resourceStats").caption = resources; 113 177 114 178 if (entState.hitpoints) … … function displaySingle(entState, template) 132 196 getGUIObjectByName("resourceCarryingIcon").hidden = false; 133 197 getGUIObjectByName("resourceCarryingText").hidden = false; 134 198 getGUIObjectByName("resourceCarryingIcon").sprite = "stretched:session/icons/resources/"+carried.type+".png"; 135 getGUIObjectByName("resourceCarryingText").caption = carried.amount + " / " + carried.max;199 getGUIObjectByName("resourceCarryingText").caption = sprintf(Engine.localize("%(amount)s / %(max)s"), { amount: carried.amount, max: carried.max }); 136 200 getGUIObjectByName("resourceCarryingIcon").tooltip = ""; 137 201 } 138 202 // Use the same indicators for traders … … function displaySingle(entState, template) 147 211 if (entState.trader.goods.amount.market2Gain) 148 212 totalGain += entState.trader.goods.amount.market2Gain; 149 213 getGUIObjectByName("resourceCarryingText").caption = totalGain; 150 getGUIObjectByName("resourceCarryingIcon").tooltip = "Gain: " + getTradingTooltip(entState.trader.goods.amount);214 getGUIObjectByName("resourceCarryingIcon").tooltip = sprintf(Engine.localize("Gain: %(amount)s"), { amount: getTradingTooltip(entState.trader.goods.amount) }); 151 215 } 152 216 // And for number of workers 153 217 else if (entState.foundation) … … function displaySingle(entState, template) 156 220 getGUIObjectByName("resourceCarryingText").hidden = false; 157 221 getGUIObjectByName("resourceCarryingIcon").sprite = "stretched:session/icons/repair.png"; 158 222 getGUIObjectByName("resourceCarryingText").caption = entState.foundation.numBuilders + " "; 159 getGUIObjectByName("resourceCarryingIcon").tooltip = "Number of builders";223 getGUIObjectByName("resourceCarryingIcon").tooltip = Engine.localize("Number of builders"); 160 224 } 161 225 else if (entState.resourceSupply && (!entState.resourceSupply.killBeforeGather || !entState.hitpoints)) 162 226 { 163 227 getGUIObjectByName("resourceCarryingIcon").hidden = false; 164 228 getGUIObjectByName("resourceCarryingText").hidden = false; 165 229 getGUIObjectByName("resourceCarryingIcon").sprite = "stretched:session/icons/repair.png"; 166 getGUIObjectByName("resourceCarryingText").caption = entState.resourceSupply.gatherers.length + " / " + entState.resourceSupply.maxGatherers+ " ";167 getGUIObjectByName("resourceCarryingIcon").tooltip = "Current/max gatherers";230 getGUIObjectByName("resourceCarryingText").caption = sprintf(Engine.localize("%(amount)s / %(max)s"), { amount: entState.resourceSupply.gatherers.length, max: entState.resourceSupply.maxGatherers }) + " "; 231 getGUIObjectByName("resourceCarryingIcon").tooltip = Engine.localize("Current/max gatherers"); 168 232 } 169 233 else 170 234 { … … function displaySingle(entState, template) 179 243 180 244 if (genericName) 181 245 { 182 getGUIObjectByName("generic").caption = "(" + genericName + ")";246 getGUIObjectByName("generic").caption = sprintf(Engine.localize("(%(genericName)s)"), { genericName: genericName }); 183 247 } 184 248 else 185 249 { … … function displaySingle(entState, template) 209 273 getGUIObjectByName("icon").sprite = "bkFillBlack"; 210 274 } 211 275 276 var armorLabel = "[font=\"serif-bold-13\"]" + Engine.localize("Armor:") + "[/font]" 277 var armorString = sprintf(Engine.localize("%(label)s %(details)s"), { label: armorLabel, details: armorTypeDetails(entState.armour) }); 278 212 279 // Attack and Armor 213 var type = "";214 var attack = "[font=\"serif-bold-13\"]"+type+"Attack:[/font] " + damageTypeDetails(entState.attack);215 280 if (entState.attack) 216 281 { 217 type = entState.attack.type + " "; 218 219 // Show max attack range if ranged attack, also convert to tiles (4m per tile) 282 var attack; 283 var label = "[font=\"serif-bold-13\"]" + getAttackTypeLabel(entState.attack.type) + "[/font]" 220 284 if (entState.attack.type == "Ranged") 221 285 { 286 // Show max attack range if ranged attack, also convert to tiles (4m per tile) 222 287 var realRange = entState.attack.elevationAdaptedRange; 223 288 var range = entState.attack.maxRange; 224 attack += ", [font=\"serif-bold-13\"]Range:[/font] " + 225 Math.round(range/4); 289 var rangeLabel = "[font=\"serif-bold-13\"]" + Engine.localize("Range:") + "[/font]" 226 290 227 291 if (Math.round((realRange - range)/4) > 0) 228 292 { 229 attack += " (+" + Math.round((realRange - range)/4) + ")"; 293 attack = sprintf(Engine.localize("%(label)s %(details)s, %(rangeLabel)s %(range)s (%(relative)s)"), { 294 label: label, 295 details: damageTypeDetails(entState.attack), 296 rangeLabel: rangeLabel, 297 range: Math.round(range/4), 298 relative: "+" + Math.round((realRange - range)/4) 299 }); 230 300 } 231 301 else if (Math.round((realRange - range)/4) < 0) 232 302 { 233 attack += " (" + Math.round((realRange - range)/4) + ")"; 303 attack = sprintf(Engine.localize("%(label)s %(details)s, %(rangeLabel)s %(range)s"), { 304 label: label, 305 details: damageTypeDetails(entState.attack), 306 rangeLabel: rangeLabel, 307 range: Math.round(range/4), 308 relative: Math.round((realRange - range)/4) 309 }); 234 310 } // don't show when it's 0 235 311 else 312 { 313 attack = sprintf(Engine.localize("%(label)s %(details)s, %(rangeLabel)s %(range)s"), { 314 label: label, 315 details: damageTypeDetails(entState.attack), 316 rangeLabel: rangeLabel, 317 range: Math.round(range/4) 318 }); 319 } 236 320 } 321 else 322 { 323 attack = sprintf(Engine.localize("%(label)s %(details)s"), { 324 label: label, 325 details: damageTypeDetails(entState.attack) 326 }); 327 } 328 getGUIObjectByName("attackAndArmorStats").tooltip = attack + "\n" + armorString; 329 } 330 else 331 { 332 getGUIObjectByName("attackAndArmorStats").tooltip = armorString; 237 333 } 238 239 getGUIObjectByName("attackAndArmorStats").tooltip = attack + "\n[font=\"serif-bold-13\"]Armor:[/font] " + armorTypeDetails(entState.armour);240 334 241 335 // Icon Tooltip 242 336 var iconTooltip = ""; … … function displayMultiple(selection, template) 280 374 healthSize.rtop = 100-100*Math.max(0, Math.min(1, averageHealth / maxHealth)); 281 375 unitHealthBar.size = healthSize; 282 376 283 var hitpoints = "[font=\"serif-bold-13\"]Hitpoints [/font]" + averageHealth + " / " + maxHealth; 377 var hitpointsLabel = "[font=\"serif-bold-13\"]" + Engine.localize("Hitpoints:") + "[/font]" 378 var hitpoints = sprintf(Engine.localize("%(label)s %(current)s / %(max)s"), { label: hitpointsLabel, current: averageHealth, max: maxHealth }); 284 379 var healthMultiple = getGUIObjectByName("healthMultiple"); 285 380 healthMultiple.tooltip = hitpoints; 286 381 healthMultiple.hidden = false; -
binaries/data/mods/public/gui/session/session.js
diff --git a/binaries/data/mods/public/gui/session/session.js b/binaries/data/mods/public/gui/session/session.js index 365753e..71a4130 100644
a b var g_CivData = {}; 9 9 var g_GameSpeeds = {}; 10 10 var g_CurrentSpeed; 11 11 12 var g_PlayerAssignments = { "local": { "name": "You", "player": 1 } };12 var g_PlayerAssignments = { "local": { "name": Engine.localize("You"), "player": 1 } }; 13 13 14 14 // Cache dev-mode settings that are frequently or widely used 15 15 var g_DevSettings = { … … function GetEntityState(entId) 61 61 62 62 // Cache TemplateData 63 63 var g_TemplateData = {}; // {id:template} 64 var g_TemplateDataWithoutLocalization = {}; 64 65 65 66 66 67 function GetTemplateData(templateName) … … function GetTemplateData(templateName) 68 69 if (!(templateName in g_TemplateData)) 69 70 { 70 71 var template = Engine.GuiInterfaceCall("GetTemplateData", templateName); 72 localizeObjectKeys(template, ["specific", "generic", "tooltip"]); 71 73 g_TemplateData[templateName] = template; 72 74 } 73 75 74 76 return g_TemplateData[templateName]; 75 77 } 76 78 79 function GetTemplateDataWithoutLocalization(templateName) 80 { 81 if (!(templateName in g_TemplateDataWithoutLocalization)) 82 { 83 var template = Engine.GuiInterfaceCall("GetTemplateData", templateName); 84 g_TemplateDataWithoutLocalization[templateName] = template; 85 } 86 87 return g_TemplateDataWithoutLocalization[templateName]; 88 } 89 77 90 // Cache TechnologyData 78 91 var g_TechnologyData = {}; // {id:template} 79 92 … … function GetTechnologyData(technologyName) 82 95 if (!(technologyName in g_TechnologyData)) 83 96 { 84 97 var template = Engine.GuiInterfaceCall("GetTechnologyData", technologyName); 98 localizeObjectKeys(template, ["specific", "generic", "description", "tooltip", "requirementsTooltip"]); 85 99 g_TechnologyData[technologyName] = template; 86 100 } 87 101 … … function init(initData, hotloadData) 112 126 113 127 // Cache civ data 114 128 g_CivData = loadCivData(); 115 g_CivData["gaia"] = { "Code": "gaia", "Name": "Gaia"};129 g_CivData["gaia"] = { "Code": "gaia", "Name": Engine.localize("Gaia") }; 116 130 117 131 g_GameSpeeds = initGameSpeeds(); 118 132 g_CurrentSpeed = Engine.GetSimRate(); … … function leaveGame() 218 232 var gameResult; 219 233 if (g_Disconnected) 220 234 { 221 gameResult = "You have been disconnected."235 gameResult = Engine.localize("You have been disconnected."); 222 236 } 223 237 else if (playerState.state == "won") 224 238 { 225 gameResult = "You have won the battle!";239 gameResult = Engine.localize("You have won the battle!"); 226 240 } 227 241 else if (playerState.state == "defeated") 228 242 { 229 gameResult = "You have been defeated...";243 gameResult = Engine.localize("You have been defeated..."); 230 244 } 231 245 else // "active" 232 246 { 233 gameResult = "You have abandoned the game.";247 gameResult = Engine.localize("You have abandoned the game."); 234 248 235 249 // Tell other players that we have given up and been defeated 236 250 Engine.PostNetworkCommand({ … … function checkPlayerState() 356 370 if (Engine.IsAtlasRunning()) 357 371 { 358 372 // If we're in Atlas, we can't leave the game 359 var btCaptions = [ "OK"];373 var btCaptions = [Engine.localize("OK")]; 360 374 var btCode = [null]; 361 var message = "Press OK to continue";375 var message = Engine.localize("Press OK to continue"); 362 376 } 363 377 else 364 378 { 365 var btCaptions = [ "Yes", "No"];379 var btCaptions = [Engine.localize("Yes"), Engine.localize("No")]; 366 380 var btCode = [leaveGame, null]; 367 var message = "Do you want to quit?";381 var message = Engine.localize("Do you want to quit?"); 368 382 } 369 messageBox(400, 200, message, "DEFEATED!", 0, btCaptions, btCode);383 messageBox(400, 200, message, Engine.localize("DEFEATED!"), 0, btCaptions, btCode); 370 384 } 371 385 else if (playerState.state == "won") 372 386 { … … function checkPlayerState() 382 396 if (Engine.IsAtlasRunning()) 383 397 { 384 398 // If we're in Atlas, we can't leave the game 385 var btCaptions = [ "OK"];399 var btCaptions = [Engine.localize("OK")]; 386 400 var btCode = [null]; 387 var message = "Press OK to continue";401 var message = Engine.localize("Press OK to continue"); 388 402 } 389 403 else 390 404 { 391 var btCaptions = [ "Yes", "No"];405 var btCaptions = [Engine.localize("Yes"), Engine.localize("No")]; 392 406 var btCode = [leaveGame, null]; 393 var message = "Do you want to quit?";407 var message = Engine.localize("Do you want to quit?"); 394 408 } 395 messageBox(400, 200, message, "VICTORIOUS!", 0, btCaptions, btCode);409 messageBox(400, 200, message, Engine.localize("VICTORIOUS!"), 0, btCaptions, btCode); 396 410 } 397 411 } 398 412 } … … function updateHero() 473 487 474 488 // Setup tooltip 475 489 var tooltip = "[font=\"serif-bold-16\"]" + template.name.specific + "[/font]"; 476 tooltip += "\n[font=\"serif-bold-13\"]Health:[/font] " + heroState.hitpoints + "/" + heroState.maxHitpoints; 477 tooltip += "\n[font=\"serif-bold-13\"]" + (heroState.attack ? heroState.attack.type + " " : "") 478 + "Attack:[/font] " + damageTypeDetails(heroState.attack); 479 // Show max attack range if ranged attack, also convert to tiles (4m per tile) 490 var healthLabel = "[font=\"serif-bold-13\"]" + Engine.localize("Health:") + "[/font]"; 491 tooltip += "\n" + sprintf(Engine.localize("%(label)s %(current)s / %(max)s"), { label: healthLabel, current: heroState.hitpoints, max: heroState.maxHitpoints }); 492 var attackLabel = "[font=\"serif-bold-13\"]" + getAttackTypeLabel(heroState.attack.type) + "[/font]"; 480 493 if (heroState.attack && heroState.attack.type == "Ranged") 481 tooltip += ", [font=\"serif-bold-13\"]Range:[/font] " + Math.round(heroState.attack.maxRange/4); 494 { 495 var rangeLabel = "[font=\"serif-bold-13\"]" + Engine.localize("Range:") + "[/font]"; 496 // Show max attack range if ranged attack, also convert to tiles (4m per tile) 497 tooltip += "\n" + sprintf(Engine.localize("%(attackLabel)s %(details)s, %(rangeLabel)s %(range)s"), { attackLabel: attackLabel, details: damageTypeDetails(heroState.attack), rangeLabel: rangeLabel, range: Math.round(heroState.attack.maxRange/4) }); 498 } 499 else 500 { 501 tooltip += "\n" + sprintf(Engine.localize("%(label)s %(details)s"), { label: attackLabel, details: damageTypeDetails(heroState.armour) }); 502 } 482 503 483 tooltip += "\n[font=\"serif-bold-13\"]Armor:[/font] " + damageTypeDetails(heroState.armour); 504 var armorLabel = "[font=\"serif-bold-13\"]" + Engine.localize("Armor:") + "[/font]"; 505 tooltip += "\n" + sprintf(Engine.localize("%(label)s %(details)s"), { label: armorLabel, details: damageTypeDetails(heroState.attack) }); 484 506 tooltip += "\n" + template.tooltip; 485 507 486 508 heroButton.tooltip = tooltip; … … function updateResearchDisplay() 626 648 function updateTimeElapsedCounter() 627 649 { 628 650 var simState = GetSimState(); 629 var speed = g_CurrentSpeed != 1.0 ? " (" + g_CurrentSpeed + "x)" : "";630 651 var timeElapsedCounter = getGUIObjectByName("timeElapsedCounter"); 631 timeElapsedCounter.caption = timeToString(simState.timeElapsed) + speed; 652 if (g_CurrentSpeed != 1.0) 653 { 654 timeElapsedCounter.caption = sprintf(Engine.localize("%(time)s (%(speed)sx)"), { time: timeToString(simState.timeElapsed), speed: Engine.formatDecimalNumberIntoString(g_CurrentSpeed) }); 655 } 656 else 657 { 658 timeElapsedCounter.caption = timeToString(simState.timeElapsed); 659 } 632 660 } 633 661 634 662 // Toggles the display of status bars for all of the player's entities. … … function playRandomAmbient(type) 668 696 break; 669 697 670 698 default: 671 Engine.Console_Write( "Unrecognized ambient type: " + type);699 Engine.Console_Write(sprintf(Engine.localize("Unrecognized ambient type: %(ambientType)s"), { ambientType: type })); 672 700 break; 673 701 } 674 702 } … … function stopAmbient() 682 710 currentAmbient = null; 683 711 } 684 712 } 713 714 function getBuildString() 715 { 716 return sprintf(Engine.localize("Build: %(buildDate)s (%(revision)s)"), { buildDate: Engine.GetBuildTimestamp(0), revision: Engine.GetBuildTimestamp(2) }); 717 } 718 719 function showTimeWarpMessageBox() 720 { 721 messageBox(500, 250, Engine.localize("Note: time warp mode is a developer option, and not intended for use over long periods of time. Using it incorrectly may cause the game to run out of memory or crash."), Engine.localize("Time warp mode"), 2); 722 } -
binaries/data/mods/public/gui/session/session.xml
diff --git a/binaries/data/mods/public/gui/session/session.xml b/binaries/data/mods/public/gui/session/session.xml index d5b3353..6656de8 100644
a b 251 251 toggleDeveloperOverlay(); 252 252 </action> 253 253 254 <object size="0 0 100%-18 16" type="text" style="devCommandsText">Control all units</object> 254 <object size="0 0 100%-18 16" type="text" style="devCommandsText"> 255 <localizableAttribute id="caption">Control all units</localizableAttribute> 256 </object> 255 257 <object size="100%-16 0 100% 16" type="checkbox" name="devControlAll" style="StoneCrossBox"> 256 258 <action on="Press"> 257 259 g_DevSettings.controlAll = this.checked; … … 259 261 </action> 260 262 </object> 261 263 262 <object size="0 16 100%-18 32" type="text" style="devCommandsText">Change perspective</object> 264 <object size="0 16 100%-18 32" type="text" style="devCommandsText"> 265 <localizableAttribute id="caption">Change perspective</localizableAttribute> 266 </object> 263 267 <object size="100%-16 16 100% 32" type="checkbox" style="StoneCrossBox"> 264 268 <action on="Press">getGUIObjectByName("viewPlayer").hidden = !this.checked;</action> 265 269 </object> 266 270 267 <object size="0 32 100%-18 48" type="text" style="devCommandsText">Display selection state</object> 271 <object size="0 32 100%-18 48" type="text" style="devCommandsText"> 272 <localizableAttribute id="caption">Display selection state</localizableAttribute> 273 </object> 268 274 <object size="100%-16 32 100% 48" type="checkbox" name="devDisplayState" style="StoneCrossBox"/> 269 275 270 <object size="0 48 100%-18 64" type="text" style="devCommandsText">Pathfinder overlay</object> 276 <object size="0 48 100%-18 64" type="text" style="devCommandsText"> 277 <localizableAttribute id="caption">Pathfinder overlay</localizableAttribute> 278 </object> 271 279 <object size="100%-16 48 100% 64" type="checkbox" style="StoneCrossBox"> 272 280 <action on="Press">Engine.GuiInterfaceCall("SetPathfinderDebugOverlay", this.checked);</action> 273 281 </object> 274 282 275 <object size="0 64 100%-18 80" type="text" style="devCommandsText">Obstruction overlay</object> 283 <object size="0 64 100%-18 80" type="text" style="devCommandsText"> 284 <localizableAttribute id="caption">Obstruction overlay</localizableAttribute> 285 </object> 276 286 <object size="100%-16 64 100% 80" type="checkbox" style="StoneCrossBox"> 277 287 <action on="Press">Engine.GuiInterfaceCall("SetObstructionDebugOverlay", this.checked);</action> 278 288 </object> 279 289 280 <object size="0 80 100%-18 96" type="text" style="devCommandsText">Unit motion overlay</object> 290 <object size="0 80 100%-18 96" type="text" style="devCommandsText"> 291 <localizableAttribute id="caption">Unit motion overlay</localizableAttribute> 292 </object> 281 293 <object size="100%-16 80 100% 96" type="checkbox" style="StoneCrossBox"> 282 294 <action on="Press">g_Selection.SetMotionDebugOverlay(this.checked);</action> 283 295 </object> 284 296 285 <object size="0 96 100%-18 112" type="text" style="devCommandsText">Range overlay</object> 297 <object size="0 96 100%-18 112" type="text" style="devCommandsText"> 298 <localizableAttribute id="caption">Range overlay</localizableAttribute> 299 </object> 286 300 <object size="100%-16 96 100% 112" type="checkbox" style="StoneCrossBox"> 287 301 <action on="Press">Engine.GuiInterfaceCall("SetRangeDebugOverlay", this.checked);</action> 288 302 </object> 289 303 290 <object size="0 112 100%-18 128" type="text" style="devCommandsText">Bounding box overlay</object> 304 <object size="0 112 100%-18 128" type="text" style="devCommandsText"> 305 <localizableAttribute id="caption">Bounding box overlay</localizableAttribute> 306 </object> 291 307 <object size="100%-16 112 100% 128" type="checkbox" style="StoneCrossBox"> 292 308 <action on="Press">Engine.SetBoundingBoxDebugOverlay(this.checked);</action> 293 309 </object> 294 310 295 <object size="0 128 100%-18 144" type="text" style="devCommandsText">Restrict camera</object> 311 <object size="0 128 100%-18 144" type="text" style="devCommandsText"> 312 <localizableAttribute id="caption">Restrict camera</localizableAttribute> 313 </object> 296 314 <object size="100%-16 128 100% 144" type="checkbox" style="StoneCrossBox" checked="true"> 297 315 <action on="Press">Engine.GameView_SetConstrainCameraEnabled(this.checked);</action> 298 316 </object> 299 317 300 <object size="0 144 100%-18 160" type="text" style="devCommandsText">Reveal map</object> 318 <object size="0 144 100%-18 160" type="text" style="devCommandsText"> 319 <localizableAttribute id="caption">Reveal map</localizableAttribute> 320 </object> 301 321 <object size="100%-16 144 100% 160" type="checkbox" name="devCommandsRevealMap" style="StoneCrossBox"> 302 322 <action on="Press">Engine.PostNetworkCommand({"type": "reveal-map", "enable": this.checked});</action> 303 323 </object> 304 324 305 <object size="0 160 100%-18 176" type="text" style="devCommandsText">Enable time warp</object> 325 <object size="0 160 100%-18 176" type="text" style="devCommandsText"> 326 <localizableAttribute id="caption">Enable time warp</localizableAttribute> 327 </object> 306 328 <object size="100%-16 160 100% 176" type="checkbox" name="devTimeWarp" style="StoneCrossBox"> 307 329 <action on="Press"> 308 330 if (this.checked) 309 messageBox(500, 250, "Note: time warp mode is a developer option, and not intended\nfor use over long periods of time. Using it incorrectly may\ncause the game to run out of memory or crash.", "Time warp mode", 2);331 showTimeWarpMessageBox(); 310 332 Engine.EnableTimeWarpRecording(this.checked ? 10 : 0);</action> 311 333 </object> 312 334 313 <object size="0 176 100%-18 192" type="text" style="devCommandsText">Promote selected units</object> 335 <object size="0 176 100%-18 192" type="text" style="devCommandsText"> 336 <localizableAttribute id="caption">Promote selected units</localizableAttribute> 337 </object> 314 338 <object size="100%-16 176 100% 192" type="button" style="StoneCrossBox"> 315 339 <action on="Press">Engine.PostNetworkCommand({"type": "promote", "entities": g_Selection.toList()});</action> 316 340 </object> … … 335 359 z="0" 336 360 > 337 361 <object size="0 0 100% 100%" type="image" sprite="devCommandsBackground" ghost="true" z="0"/> 338 <object size="50%-128 50%-20 50%+128 50%+20" type="text" style="PauseText" ghost="true" z="0">Game Paused</object> 339 <object size="50%-128 50%+20 50%+128 50%+30" type="text" style="PauseMessageText" ghost="true" z="0">Click to Resume Game</object> 362 <object size="50%-128 50%-20 50%+128 50%+20" type="text" style="PauseText" ghost="true" z="0"> 363 <localizableAttribute id="caption">Game Paused</localizableAttribute> 364 </object> 365 <object size="50%-128 50%+20 50%+128 50%+30" type="text" style="PauseMessageText" ghost="true" z="0"> 366 <localizableAttribute id="caption">Click to Resume Game</localizableAttribute> 367 </object> 340 368 <action on="Press">togglePause();</action> 341 369 </object> 342 370 … … 363 391 </object> 364 392 365 393 <object size="16 100%-40 30%+16 100%-12" type="button" style="StoneButton"> 366 Send367 <action on="Press">submitChatInput();</action>394 <localizableAttribute id="caption">Send</localizableAttribute> 395 <action on="Press">submitChatInput();</action> 368 396 </object> 369 397 370 398 <object size="30%+24 100%-40 60%+24 100%-12" type="button" style="StoneButton"> 371 Cancel372 <action on="Press">closeChat();</action>399 <localizableAttribute id="caption">Cancel</localizableAttribute> 400 <action on="Press">closeChat();</action> 373 401 </object> 374 402 <object name="toggleTeamChat" size="60%+32 100%-34 60%+48 100%-6" type="checkbox" style="StoneCrossBox"/> 375 403 <object size="60%+48 100%-40 100% 100%-12" type="text" style="LeftLabelText"> … … 386 414 hidden="true" 387 415 sprite="StoneDialog" 388 416 > 389 <object type="text" style="TitleText" size="50%-96 -16 50%+96 16">Diplomacy</object> 417 <object type="text" style="TitleText" size="50%-96 -16 50%+96 16"> 418 <localizableAttribute id="caption">Diplomacy</localizableAttribute> 419 </object> 390 420 391 421 <object name="diplomacyHeader" size="32 32 100%-32 64"> 392 <object name="diplomacyHeaderName" size="0 0 150 100%" type="text" style="chatPanel" ghost="true" caption="Name"/> 393 <object name="diplomacyHeaderCiv" size="150 0 250 100%" type="text" style="chatPanel" ghost="true" caption="Civilization"/> 394 <object name="diplomacyHeaderTeam" size="250 0 300 100%" type="text" style="chatPanel" ghost="true" caption="Team"/> 395 <object name="diplomacyHeaderTheirs" size="300 0 360 100%" type="text" style="chatPanel" ghost="true" caption="Theirs"/> 396 <object name="diplomacyHeaderAlly" size="100%-180 0 100%-160 100%" type="text" style="chatPanel" caption="A" tooltip="Ally" tooltip_style="sessionToolTipBold"/> 397 <object name="diplomacyHeaderNeutral" size="100%-160 0 100%-140 100%" type="text" style="chatPanel" caption="N" tooltip="Neutral" tooltip_style="sessionToolTipBold"/> 398 <object name="diplomacyHeaderEnemy" size="100%-140 0 100%-120 100%" type="text" style="chatPanel" caption="E" tooltip="Enemy" tooltip_style="sessionToolTipBold"/> 399 <object name="diplomacyHeaderTribute" size="100%-110 0 100% 100%" type="text" style="chatPanel" caption="Tribute"/> 422 <object name="diplomacyHeaderName" size="0 0 150 100%" type="text" style="chatPanel" ghost="true"> 423 <localizableAttribute id="caption">Name</localizableAttribute> 424 </object> 425 <object name="diplomacyHeaderCiv" size="150 0 250 100%" type="text" style="chatPanel" ghost="true"> 426 <localizableAttribute id="caption">Civilization</localizableAttribute> 427 </object> 428 <object name="diplomacyHeaderTeam" size="250 0 300 100%" type="text" style="chatPanel" ghost="true"> 429 <localizableAttribute id="caption">Team</localizableAttribute> 430 </object> 431 <object name="diplomacyHeaderTheirs" size="300 0 360 100%" type="text" style="chatPanel" ghost="true"> 432 <localizableAttribute id="caption">Theirs</localizableAttribute> 433 </object> 434 <object name="diplomacyHeaderAlly" size="100%-180 0 100%-160 100%" type="text" style="chatPanel" tooltip_style="sessionToolTipBold"> 435 <localizableAttribute id="caption">A</localizableAttribute> 436 <localizableAttribute id="tooltip">Ally</localizableAttribute> 437 </object> 438 <object name="diplomacyHeaderNeutral" size="100%-160 0 100%-140 100%" type="text" style="chatPanel" tooltip_style="sessionToolTipBold"> 439 <localizableAttribute id="caption">N</localizableAttribute> 440 <localizableAttribute id="tooltip">Neutral</localizableAttribute> 441 </object> 442 <object name="diplomacyHeaderEnemy" size="100%-140 0 100%-120 100%" type="text" style="chatPanel" tooltip_style="sessionToolTipBold"> 443 <localizableAttribute id="caption">E</localizableAttribute> 444 <localizableAttribute id="tooltip">Enemy</localizableAttribute> 445 </object> 446 <object name="diplomacyHeaderTribute" size="100%-110 0 100% 100%" type="text" style="chatPanel"> 447 <localizableAttribute id="caption">Tribute</localizableAttribute> 448 </object> 400 449 </object> 401 450 402 451 <object size="32 64 100%-32 384"> … … 445 494 hidden="true" 446 495 z="200" 447 496 > 448 <object type="text" style="TitleText" size="50%-96 -16 50%+96 16">Settings</object> 497 <object type="text" style="TitleText" size="50%-96 -16 50%+96 16"> 498 <localizableAttribute id="caption">Settings</localizableAttribute> 499 </object> 449 500 450 501 <object style="TranslucentPanelThinBorder" 451 502 type="image" 452 503 size="32 32 100%-32 100%-70" 453 504 > 454 505 <!-- Settings / shadows --> 455 <object size="0 10 100%-80 35" type="text" style="RightLabelText" ghost="true">Enable Shadows</object> 506 <object size="0 10 100%-80 35" type="text" style="RightLabelText" ghost="true"> 507 <localizableAttribute id="caption">Enable Shadows</localizableAttribute> 508 </object> 456 509 <object name="shadowsCheckbox" size="100%-56 15 100%-30 40" type="checkbox" style="StoneCrossBox" checked="true"> 457 510 <action on="Load">this.checked = Engine.Renderer_GetShadowsEnabled();</action> 458 511 <action on="Press">Engine.Renderer_SetShadowsEnabled(this.checked);</action> 459 512 </object> 460 513 461 514 <!-- Settings / Shadow PCF --> 462 <object size="0 35 100%-80 60" type="text" style="RightLabelText" ghost="true">Enable Shadow Filtering</object> 515 <object size="0 35 100%-80 60" type="text" style="RightLabelText" ghost="true"> 516 <localizableAttribute id="caption">Enable Shadow Filtering</localizableAttribute> 517 </object> 463 518 <object name="shadowPCFCheckbox" size="100%-56 40 100%-30 65" type="checkbox" style="StoneCrossBox" checked="true"> 464 519 <action on="Load">this.checked = Engine.Renderer_GetShadowPCFEnabled();</action> 465 520 <action on="Press">Engine.Renderer_SetShadowPCFEnabled(this.checked);</action> 466 521 </object> 467 522 468 523 <!-- Settings / Water Normals --> 469 <object size="0 60 100%-80 85" type="text" style="RightLabelText" ghost="true">Water - HQ Waviness</object> 524 <object size="0 60 100%-80 85" type="text" style="RightLabelText" ghost="true"> 525 <localizableAttribute id="caption">Water - HQ Waviness</localizableAttribute> 526 </object> 470 527 <object name="waterNormalCheckox" size="100%-56 65 100%-30 90" type="checkbox" style="StoneCrossBox" checked="true"> 471 528 <action on="Load">this.checked = Engine.Renderer_GetWaterNormalEnabled();</action> 472 529 <action on="Press">Engine.Renderer_SetWaterNormalEnabled(this.checked);</action> 473 530 </object> 474 531 475 532 <!-- Settings / Real Depth --> 476 <object size="0 85 100%-80 110" type="text" style="RightLabelText" ghost="true">Water - Use Actual Depth</object> 533 <object size="0 85 100%-80 110" type="text" style="RightLabelText" ghost="true"> 534 <localizableAttribute id="caption">Water - Use Actual Depth</localizableAttribute> 535 </object> 477 536 <object name="waterRealDepthCheckbox" size="100%-56 90 100%-30 115" type="checkbox" style="StoneCrossBox" checked="true"> 478 537 <action on="Load">this.checked = Engine.Renderer_GetWaterRealDepthEnabled();</action> 479 538 <action on="Press">Engine.Renderer_SetWaterRealDepthEnabled(this.checked);</action> 480 539 </object> 481 540 482 541 <!-- Settings / Reflection --> 483 <object size="0 110 100%-80 135" type="text" style="RightLabelText" ghost="true">Water - Enable Reflections</object> 542 <object size="0 110 100%-80 135" type="text" style="RightLabelText" ghost="true"> 543 <localizableAttribute id="caption">Water - Enable Reflections</localizableAttribute> 544 </object> 484 545 <object name="waterReflectionCheckbox" size="100%-56 115 100%-30 140" type="checkbox" style="StoneCrossBox" checked="true"> 485 546 <action on="Load">this.checked = Engine.Renderer_GetWaterReflectionEnabled();</action> 486 547 <action on="Press">Engine.Renderer_SetWaterReflectionEnabled(this.checked);</action> 487 548 </object> 488 549 489 550 <!-- Settings / Refraction --> 490 <object size="0 135 100%-80 160" type="text" style="RightLabelText" ghost="true">Water - Enable Refraction</object> 551 <object size="0 135 100%-80 160" type="text" style="RightLabelText" ghost="true"> 552 <localizableAttribute id="caption">Water - Enable Refraction</localizableAttribute> 553 </object> 491 554 <object name="waterRefractionCheckbox" size="100%-56 140 100%-30 165" type="checkbox" style="StoneCrossBox" checked="true"> 492 555 <action on="Load">this.checked = Engine.Renderer_GetWaterRefractionEnabled();</action> 493 556 <action on="Press">Engine.Renderer_SetWaterRefractionEnabled(this.checked);</action> 494 557 </object> 495 558 496 559 <!-- Settings / Foam --> 497 <object size="0 160 100%-80 185" type="text" style="RightLabelText" ghost="true">Water - Enable Shore Foam</object> 560 <object size="0 160 100%-80 185" type="text" style="RightLabelText" ghost="true"> 561 <localizableAttribute id="caption">Water - Enable Shore Foam</localizableAttribute> 562 </object> 498 563 <object name="waterFoamCheckbox" size="100%-56 165 100%-30 190" type="checkbox" style="StoneCrossBox" checked="true"> 499 564 <action on="Load">this.checked = Engine.Renderer_GetWaterFoamEnabled();</action> 500 565 <action on="Press">Engine.Renderer_SetWaterFoamEnabled(this.checked);</action> 501 566 </object> 502 567 503 568 <!-- Settings / Waves --> 504 <object size="0 185 100%-80 210" type="text" style="RightLabelText" ghost="true">Water - Enable Shore Waves</object> 569 <object size="0 185 100%-80 210" type="text" style="RightLabelText" ghost="true"> 570 <localizableAttribute id="caption">Water - Enable Shore Waves</localizableAttribute> 571 </object> 505 572 <object name="waterCoastalWavesCheckbox" size="100%-56 190 100%-30 215" type="checkbox" style="StoneCrossBox" checked="true"> 506 573 <action on="Load">this.checked = Engine.Renderer_GetWaterCoastalWavesEnabled();</action> 507 574 <action on="Press">Engine.Renderer_SetWaterCoastalWavesEnabled(this.checked);</action> 508 575 </object> 509 576 510 577 <!-- Settings / Shadows --> 511 <object size="0 210 100%-80 235" type="text" style="RightLabelText" ghost="true">Water - Use Surface Shadows</object> 578 <object size="0 210 100%-80 235" type="text" style="RightLabelText" ghost="true"> 579 <localizableAttribute id="caption">Water - Use Surface Shadows</localizableAttribute> 580 </object> 512 581 <object name="waterShadowsCheckbox" size="100%-56 215 100%-30 240" type="checkbox" style="StoneCrossBox" checked="true"> 513 582 <action on="Load">if (Engine.Renderer_GetWaterShadowEnabled()) this.checked = true; else this.checked = false;</action> 514 583 <action on="Press">Engine.Renderer_SetWaterShadowEnabled(this.checked);</action> 515 584 </object> 516 585 517 586 <!-- Settings / Particles --> 518 <object size="0 235 100%-80 260" type="text" style="RightLabelText" ghost="true">Enable Particles</object> 587 <object size="0 235 100%-80 260" type="text" style="RightLabelText" ghost="true"> 588 <localizableAttribute id="caption">Enable Particles</localizableAttribute> 589 </object> 519 590 <object name="particlesCheckbox" size="100%-56 240 100%-30 265" type="checkbox" style="StoneCrossBox" checked="true"> 520 591 <action on="Load">this.checked = Engine.Renderer_GetParticlesEnabled();</action> 521 592 <action on="Press">Engine.Renderer_SetParticlesEnabled(this.checked);</action> 522 593 </object> 523 594 524 595 <!-- Settings / Unit Silhouettes --> 525 <object size="0 260 100%-80 285" type="text" style="RightLabelText" ghost="true">Enable Unit Silhouettes</object> 596 <object size="0 260 100%-80 285" type="text" style="RightLabelText" ghost="true"> 597 <localizableAttribute id="caption">Enable Unit Silhouettes</localizableAttribute> 598 </object> 526 599 <object name="silhouettesCheckbox" size="100%-56 265 100%-30 290" type="checkbox" style="StoneCrossBox" checked="true"> 527 600 <action on="Load">this.checked = Engine.Renderer_GetSilhouettesEnabled();</action> 528 601 <action on="Press">Engine.Renderer_SetSilhouettesEnabled(this.checked);</action> 529 602 </object> 530 603 531 604 <!-- Settings / Music--> 532 <object size="0 285 100%-80 310" type="text" style="RightLabelText" ghost="true">Enable Music</object> 605 <object size="0 285 100%-80 310" type="text" style="RightLabelText" ghost="true"> 606 <localizableAttribute id="caption">Enable Music</localizableAttribute> 607 </object> 533 608 <object name="musicCheckbox" size="100%-56 290 100%-30 315" type="checkbox" style="StoneCrossBox" checked="true"> 534 609 <action on="Press">if (this.checked) global.music.start(); else global.music.stop();</action> 535 610 </object> 536 611 537 612 <!-- Settings / Dev Overlay --> 538 <object size="0 310 100%-80 335" type="text" style="RightLabelText" ghost="true">Developer Overlay</object> 613 <object size="0 310 100%-80 335" type="text" style="RightLabelText" ghost="true"> 614 <localizableAttribute id="caption">Developer Overlay</localizableAttribute> 615 </object> 539 616 <object name="developerOverlayCheckbox" size="100%-56 315 100%-30 340" type="checkbox" style="StoneCrossBox" checked="false"> 540 617 <action on="Press">toggleDeveloperOverlay();</action> 541 618 </object> … … 567 644 size="10 0 45% 100%" 568 645 > 569 646 <!-- Food --> 570 <object size="0 0 90 100%" type="image" style="resourceCounter" tooltip="Food" tooltip_style="sessionToolTipBold"> 647 <object size="0 0 90 100%" type="image" style="resourceCounter" tooltip_style="sessionToolTipBold"> 648 <localizableAttribute id="tooltip">Food</localizableAttribute> 571 649 <object size="0 -4 40 36" type="image" sprite="stretched:session/icons/resources/food.png" ghost="true"/> 572 650 <object size="32 0 100% 100%-2" type="text" style="resourceText" name="resourceFood"/> 573 651 </object> 574 652 575 653 <!-- Wood --> 576 <object size="90 0 180 100%" type="image" style="resourceCounter" tooltip="Wood" tooltip_style="sessionToolTipBold"> 654 <object size="90 0 180 100%" type="image" style="resourceCounter" tooltip_style="sessionToolTipBold"> 655 <localizableAttribute id="tooltip">Wood</localizableAttribute> 577 656 <object size="0 -4 40 36" type="image" sprite="stretched:session/icons/resources/wood.png" ghost="true"/> 578 657 <object size="32 0 100% 100%-2" type="text" style="resourceText" name="resourceWood"/> 579 658 </object> 580 659 581 660 <!-- Stone --> 582 <object size="180 0 270 100%" type="image" style="resourceCounter" tooltip="Stone" tooltip_style="sessionToolTipBold"> 661 <object size="180 0 270 100%" type="image" style="resourceCounter" tooltip_style="sessionToolTipBold"> 662 <localizableAttribute id="tooltip">Stone</localizableAttribute> 583 663 <object size="0 -4 40 36" type="image" sprite="stretched:session/icons/resources/stone.png" ghost="true"/> 584 664 <object size="32 0 100% 100%-2" type="text" style="resourceText" name="resourceStone"/> 585 665 </object> 586 666 587 667 <!-- Metal --> 588 <object size="270 0 360 100%" type="image" style="resourceCounter" tooltip="Metal" tooltip_style="sessionToolTipBold"> 668 <object size="270 0 360 100%" type="image" style="resourceCounter" tooltip_style="sessionToolTipBold"> 669 <localizableAttribute id="tooltip">Metal</localizableAttribute> 589 670 <object size="0 -4 40 36" type="image" sprite="stretched:session/icons/resources/metal.png" ghost="true"/> 590 671 <object size="32 0 100% 100%-2" type="text" style="resourceText" name="resourceMetal"/> 591 672 </object> 592 673 593 674 <!-- Population --> 594 <object size="360 0 450 100%" type="image" style="resourceCounter" tooltip="Population (current / limit)" tooltip_style="sessionToolTipBold"> 675 <object size="360 0 450 100%" type="image" style="resourceCounter" tooltip_style="sessionToolTipBold"> 676 <localizableAttribute id="tooltip">Population (current / limit)</localizableAttribute> 595 677 <object size="0 -4 40 34" type="image" sprite="stretched:session/icons/resources/population.png" ghost="true"/> 596 678 <object size="32 0 100% 100%-2" type="text" style="resourceText" name="resourcePop"/> 597 679 </object> … … 603 685 <object size="50%-48 -26 50%+48 70" name="civIcon" type="image" tooltip_style="sessionToolTipBold"/> 604 686 605 687 <!-- Switch the view perspective to another player's (largely for AI development) --> 606 <object size="50%+50 5 50%+150 100%-5" name="viewPlayer" type="dropdown" hidden="true" style="StoneDropDown" tooltip_style="sessionToolTipBold" tooltip="Choose player to view"> 607 <action on="SelectionChange">selectViewPlayer(this.selected);</action> 688 <object size="50%+50 5 50%+150 100%-5" name="viewPlayer" type="dropdown" hidden="true" style="StoneDropDown" tooltip_style="sessionToolTipBold"> 689 <localizableAttribute id="tooltip">Choose player to view</localizableAttribute> 690 <action on="SelectionChange">selectViewPlayer(this.selected);</action> 608 691 </object> 609 692 610 693 <!-- ================================ ================================ --> … … 619 702 620 703 <!-- Displays Alpha name and number --> 621 704 <object size="50%+48 0 100%-226 100%" name="alphaLabel" type="text" style="CenteredLabelText" text_valign="top" ghost="true"> 622 ALPHA XIV : Naukratis<!-- IMPORTANT: remember to update pregame/mainmenu.xml in sync with this --> 705 <!-- IMPORTANT: remember to update pregame/mainmenu.xml in sync with â --> 706 <localizableAttribute id="caption">ALPHA XIV : Naukratis</localizableAttribute> 623 707 624 708 <!-- Displays build date and revision number--> 625 709 <object size="50%-128 0 50%+128 100%-2" name="buildTimeLabel" type="text" style="BuildNameText" ghost="true"> 626 <action on="Load">this.caption = buildTime(0) + " (" + buildTime(2) + ")"</action>710 <action on="Load">this.caption = getBuildString()</action> 627 711 </object> 628 712 </object> 629 713 … … 635 719 size="100%-226 4 100%-198 32" 636 720 style="iconButton" 637 721 tooltip_style="sessionToolTip" 638 tooltip="Game speed"639 722 > 723 <localizableAttribute id="tooltip">Game speed</localizableAttribute> 640 724 <object size="5 5 100%-5 100%-5" type="image" sprite="stretched:session/icons/resources/time_small.png" ghost="true"/> 641 725 <action on="Press"> 642 726 toggleGameSpeed(); 643 727 </action> 644 728 </object> 645 729 646 <object size="100%-348 40 100%-198 65" name="gameSpeed" type="dropdown" buffer_zone="5" style="StoneDropDown" hidden="true" tooltip="Choose game speed" tooltip_style="sessionToolTip"/> 730 <object size="100%-348 40 100%-198 65" name="gameSpeed" type="dropdown" buffer_zone="5" style="StoneDropDown" hidden="true" tooltip_style="sessionToolTip"> 731 <localizableAttribute id="tooltip">Choose game speed</localizableAttribute> 732 </object> 733 647 734 648 735 <!-- ================================ ================================ --> 649 736 <!-- Diplomacy Button --> … … 653 740 size="100%-194 4 100%-166 32" 654 741 style="iconButton" 655 742 tooltip_style="sessionToolTip" 656 tooltip="Diplomacy"657 743 > 744 <localizableAttribute id="tooltip">Diplomacy</localizableAttribute> 658 745 <!-- TODO make the button less ugly --> 659 746 <object size="0 0 100% 100%" name="diplomacyButtonImage" type="image" sprite="stretched:session/icons/diplomacy.png" ghost="true"/> 660 747 <action on="Press"> … … 677 764 them on top of the main menu button --> 678 765 <object size="0 -4 100% 0" type="image" sprite="horizontalThinBorder" ghost="true"/> 679 766 680 <object size="50%-32 50%-16 50%+32 50%+16" type="image" sprite="menuButton" ghost="true">MENU</object> 767 <object size="50%-32 50%-16 50%+32 50%+16" type="image" sprite="menuButton" ghost="true"> 768 <localizableAttribute id="caption">MENU</localizableAttribute> 769 </object> 681 770 <action on="Press"> 682 771 toggleMenu(); 683 772 </action> … … 702 791 size="0 0 100% 28" 703 792 tooltip_style="sessionToolTip" 704 793 > 705 Settings794 <localizableAttribute id="caption">Settings</localizableAttribute> 706 795 <action on="Press">settingsMenuButton();</action> 707 796 </object> 708 797 … … 714 803 size="0 32 100% 60" 715 804 tooltip_style="sessionToolTip" 716 805 > 717 Save806 <localizableAttribute id="caption">Save</localizableAttribute> 718 807 <action on="Press"> 719 808 openSave(); 720 809 </action> … … 727 816 size="0 64 100% 92" 728 817 tooltip_style="sessionToolTip" 729 818 > 730 Chat819 <localizableAttribute id="caption">Chat</localizableAttribute> 731 820 <action on="Press">chatMenuButton();</action> 732 821 </object> 733 822 … … 738 827 size="0 96 100% 124" 739 828 tooltip_style="sessionToolTip" 740 829 > 741 Resign830 <localizableAttribute id="caption">Resign</localizableAttribute> 742 831 <action on="Press">resignMenuButton();</action> 743 832 </object> 744 833 … … 749 838 size="0 128 100% 156" 750 839 tooltip_style="sessionToolTip" 751 840 > 752 Exit841 <localizableAttribute id="caption">Exit</localizableAttribute> 753 842 <action on="Press">exitMenuButton();</action> 754 843 </object> 755 844 … … 760 849 size="0 160 100% 188" 761 850 tooltip_style="sessionToolTip" 762 851 > 763 <object name="pauseButtonText" type="text" style="CenteredButtonText" ghost="true">Pause</object> 852 <object name="pauseButtonText" type="text" style="CenteredButtonText" ghost="true"> 853 <localizableAttribute id="caption">Pause</localizableAttribute> 854 </object> 764 855 <action on="Press">togglePause();</action> 765 856 </object> 766 857 … … 771 862 size="0 192 100% 220" 772 863 tooltip_style="sessionToolTip" 773 864 > 774 Manual865 <localizableAttribute id="caption">Manual</localizableAttribute> 775 866 <action on="Press">openManual();</action> 776 867 </object> 777 868 </object> … … 795 886 size="0 36 50 86" 796 887 > 797 888 <object name="unitHeroButton" size="0 0 50 50" type="button" hidden="false" style="iconButton" 798 tooltip_style="sessionToolTip" tooltip="Attack and Armor"> 889 tooltip_style="sessionToolTip"> 890 <localizableAttribute id="tooltip">Attack and Armor</localizableAttribute> 799 891 <object name="unitHeroImage" size="5 5 100%-5 100%-5" type="image" ghost="true"/> 800 892 </object> 801 893 </object> … … 808 900 size="0% 50%-216 0%+36 50%+144" 809 901 > 810 902 <repeat count="10"> 811 <object name="unitGroupButton[n]" size="0 0 36 36" type="button" hidden="false" style="iconButton" tooltip_style="sessionToolTipBottomBold" 812 tooltip="Click to select grouped units.">903 <object name="unitGroupButton[n]" size="0 0 36 36" type="button" hidden="false" style="iconButton" tooltip_style="sessionToolTipBottomBold"> 904 <localizableAttribute id="tooltip">Click to select grouped units.</localizableAttribute> 813 905 <object name="unitGroupIcon[n]" size="3 3 33 33" type="image" sprite="groupsIcon" ghost="true"/> 814 906 <object name="unitGroupLabel[n]" type="text" style="largeCenteredOutlinedText" ghost="true"/> 815 907 </object> … … 859 951 <object type="button" 860 952 style="iconButton" 861 953 tooltip_style="sessionToolTip" 862 tooltip="Find idle worker"863 954 hotkey="selection.idleworker" 864 955 > 956 <localizableAttribute id="tooltip">Find idle worker</localizableAttribute> 865 957 <!-- TODO: should highlight the button if there's non-zero idle workers --> 866 958 <object size="0 0 100% 100%" type="image" sprite="idleWorker" ghost="true" /> 867 959 <action on="Press">findIdleUnit(["Female", "Trade", "FishingBoat", "CitizenSoldier", "Healer"]);</action> … … 904 996 size="6 36 100% 100%" 905 997 hidden="true" 906 998 > 907 <object ghost="true" style="resourceText" type="text" size="0 0 100% 20">Exchange resources:</object> 999 <object ghost="true" style="resourceText" type="text" size="0 0 100% 20"> 1000 <localizableAttribute id="tooltip">Exchange resources:</localizableAttribute> 1001 </object> 908 1002 <object size="0 32 100% 78"> 909 1003 <repeat count="4"> 910 1004 <object name="unitBarterSellButton[n]" style="iconButton" type="button" size="0 0 46 46" tooltip_style="sessionToolTipBottomBold"> … … 961 1055 <object size="0 8 100% 60" type="image" sprite="edgedPanelShader"> 962 1056 <!-- Health bar --> 963 1057 <object size="88 0 100% 24" name="healthSection"> 964 <object size="0 0 100% 16" name="healthLabel" type="text" style="StatsTextLeft" ghost="true">Health:</object> 1058 <object size="0 0 100% 16" name="healthLabel" type="text" style="StatsTextLeft" ghost="true"> 1059 <localizableAttribute id="tooltip">Health:</localizableAttribute> 1060 </object> 965 1061 <object size="0 0 100% 16" name="healthStats" type="text" style="StatsTextRight" ghost="true"/> 966 1062 <object size="1 16 100% 23" name="health" type="image"> 967 1063 <object type="image" sprite="barBorder" ghost="true" size="-1 -1 100%+1 100%+1"/> … … 973 1069 974 1070 <!-- Stamina bar --> 975 1071 <object size="88 28 100% 52" name="staminaSection"> 976 <object size="0 0 100% 16" name="staminaLabel" type="text" style="StatsTextLeft" ghost="true">Stamina:</object> 1072 <object size="0 0 100% 16" name="staminaLabel" type="text" style="StatsTextLeft" ghost="true"> 1073 <localizableAttribute id="tooltip">Stamina:</localizableAttribute> 1074 </object> 977 1075 <object size="0 0 100% 16" name="staminaStats" type="text" style="StatsTextRight" ghost="true"/> 978 1076 <object size="1 16 100% 23" name="stamina" type="image"> 979 1077 <object type="image" sprite="barBorder" ghost="true" size="-1 -1 100%+1 100%+1"/> … … 998 1096 999 1097 <object size="0 60 100% 96" type="image" sprite="edgedPanelShader"> 1000 1098 <!-- Attack and Armor --> 1001 <object size="90 -2 126 34" name="attackAndArmorStats" type="image" sprite="stretched:session/icons/stances/defensive.png" tooltip="Attack and Armor" tooltip_style="sessionToolTip"/> 1099 <object size="90 -2 126 34" name="attackAndArmorStats" type="image" sprite="stretched:session/icons/stances/defensive.png" tooltip_style="sessionToolTip"> 1100 <localizableAttribute id="tooltip">Attack and Armor</localizableAttribute> 1101 </object> 1002 1102 1003 1103 <!-- Resource carrying icon/counter --> 1004 1104 <!-- Used also for number of gatherers/builders --> … … 1011 1111 <object size="1 1 100%-1 100%-1" type="image" name="icon" ghost="true"/> 1012 1112 1013 1113 <!-- Experience bar --> 1014 <object size="2 2 6 100%-2" type="image" name="experience" tooltip="Experience" tooltip_style="sessionToolTip"> 1015 <object type="image" sprite="barBorder" ghost="true" size="-1 -1 100%+1 100%+1"/> 1016 <object type="image" sprite="experienceBackground" ghost="true"/> 1017 <object type="image" sprite="experienceForeground" ghost="true" name="experienceBar"/> 1018 <object type="image" sprite="statsBarShaderVertical" ghost="true"/> 1114 <object size="2 2 6 100%-2" type="image" name="experience" tooltip_style="sessionToolTip"> 1115 <localizableAttribute id="tooltip">Experience</localizableAttribute> 1116 <object type="image" sprite="barBorder" ghost="true" size="-1 -1 100%+1 100%+1"/> 1117 <object type="image" sprite="experienceBackground" ghost="true"/> 1118 <object type="image" sprite="experienceForeground" ghost="true" name="experienceBar"/> 1119 <object type="image" sprite="statsBarShaderVertical" ghost="true"/> 1019 1120 </object> 1020 1121 1021 <object z="20" size="4 4 20 20" name="rankIcon" type="image" tooltip="Rank" tooltip_style="sessionToolTip"/> 1122 <object z="20" size="4 4 20 20" name="rankIcon" type="image" tooltip_style="sessionToolTip"> 1123 <localizableAttribute id="tooltip">Rank</localizableAttribute> 1124 </object> 1022 1125 </object> 1023 1126 </object> 1024 1127 … … 1076 1179 <!-- Stats Bars --> 1077 1180 <object size= "100%-38 50 100%-18 100%-44" type="image" tooltip_style="sessionToolTip"> 1078 1181 <!-- Health bar --> 1079 <object size="4 0 11 100%" type="image" name="healthMultiple" tooltip="Hitpoints" tooltip_style="sessionToolTip"> 1182 <object size="4 0 11 100%" type="image" name="healthMultiple" tooltip_style="sessionToolTip"> 1183 <localizableAttribute id="tooltip">Hitpoints</localizableAttribute> 1080 1184 <object type="image" sprite="barBorder" ghost="true" size="-1 -1 100%+1 100%+1"/> 1081 1185 <object type="image" sprite="healthBackground" ghost="true"/> 1082 1186 <object type="image" sprite="healthForeground" ghost="true" name="healthBarMultiple"/> … … 1084 1188 </object> 1085 1189 1086 1190 <!-- Stamina bar --> 1087 <object size="15 0 22 100%" type="image" name="staminaMultiple" tooltip="Stamina" tooltip_style="sessionToolTipBold"> 1191 <object size="15 0 22 100%" type="image" name="staminaMultiple" tooltip_style="sessionToolTipBold"> 1192 <localizableAttribute id="tooltip">Stamina</localizableAttribute> 1088 1193 <object type="image" sprite="barBorder" ghost="true" size="-1 -1 100%+1 100%+1"/> 1089 1194 <object type="image" sprite="staminaBackground" ghost="true"/> 1090 1195 <object type="image" sprite="staminaForeground" ghost="true" name="staminaBarMultiple"/> … … 1250 1355 size="50%-84 50%+128 50%+84 50%+160" 1251 1356 tooltip_style="sessionToolTip" 1252 1357 > 1253 <object size="0 0 100% 100%" type="text" style="CenteredButtonText" name="disconnectedExitButtonText" ghost="true">Return to Main Menu</object> 1358 <object size="0 0 100% 100%" type="text" style="CenteredButtonText" name="disconnectedExitButtonText" ghost="true"> 1359 <localizableAttribute id="caption">Return to Main Menu</localizableAttribute> 1360 </object> 1254 1361 <action on="Press">leaveGame()</action> 1255 1362 </object> 1256 1363 -
binaries/data/mods/public/gui/session/unit_commands.js
diff --git a/binaries/data/mods/public/gui/session/unit_commands.js b/binaries/data/mods/public/gui/session/unit_commands.js index 0c846db..513402d 100644
a b const BARTER_RESOURCES = ["food", "wood", "stone", "metal"]; 27 27 const BARTER_ACTIONS = ["Sell", "Buy"]; 28 28 29 29 // Gate constants 30 const GATE_ACTIONS = [" Lock", "Unlock"];30 const GATE_ACTIONS = ["lock", "unlock"]; 31 31 32 32 // The number of currently visible buttons (used to optimise showing/hiding) 33 33 var g_unitPanelButtons = {"Selection": 0, "Queue": 0, "Formation": 0, "Garrison": 0, "Training": 0, "Research": 0, "Barter": 0, "Trading": 0, "Construction": 0, "Command": 0, "Stance": 0, "Gate": 0, "Pack": 0}; … … var g_unitPanels = ["Selection", "Queue", "Formation", "Garrison", "Training", " 38 38 // Indexes of resources to sell and buy on barter panel 39 39 var g_barterSell = 0; 40 40 41 // Internationalization cache â General 42 var localizedBuildingsTimesBatchSize = Engine.localize("%(buildings)s*%(batchSize)s"); 43 var localizedClassSeparator = Engine.localizeWithContext("classSeparator", " "); 44 var localizedCountAndLimit = Engine.localize("Current Count: %(count)s, Limit: %(limit)s."); 45 var localizedPopulationCapacity = Engine.localize("Insufficient population capacity:"); 46 var localizedPopulationRequirement = Engine.localize("%(population)s %(neededSlots)s"); 47 var localizedRequiresTechnology = Engine.localize("Requires %(technology)s"); 48 var localizedSetResource = Engine.localize("Set %(resource)s as trading goods"); 49 var localizedShiftClick = Engine.localize("Shift-click"); 50 51 // Internationalization cache â Training 52 var localizedTrain = Engine.localize("%(action)s to train %(number)s."); 53 var localizedTrainFull = Engine.localize("%(action)s to train %(number)s (%(fullBatch)s)."); 54 var localizedTrainFullAndRemainder = Engine.localize("%(action)s to train %(number)s (%(fullBatch)s + %(remainderBatch)s)."); 55 56 // Internationalization cache â Loading and unloading 57 var localizedUnload = Engine.localize("Unload %(name)s"); 58 var localizedUnloadHelp = Engine.localize("Single-click to unload 1. Shift-click to unload all of this type."); 59 60 // Internationalization cache â Stances 61 var localizedViolent = Engine.localize("Violent"); 62 var localizedAggressive = Engine.localize("Aggressive"); 63 var localizedPassive = Engine.localize("Passive"); 64 var localizedDefensive = Engine.localize("Defensive"); 65 var localizedStandground = Engine.localize("Standground"); 66 67 // Internationalization cache â Formations 68 var localizedFormationsArray = {} 69 var localizedDisabledFormation = Engine.localize("%(formation)s (disabled)"); 70 var localizedUnitsRequirementClasses = Engine.localize("Only units of type %(unitType)s allowed.") 71 var localizedUnitsRequirementNumber = Engine.localize("%(number)s units required"); 72 73 // Internationalization cache â Locking and unlocking 74 var localizedLockGate = Engine.localize("Lock gate"); 75 var localizedUnlockGate = Engine.localize("Unlock gate"); 76 77 // Internationalization cache â Packing and unpacking 78 var localizedPack = Engine.localize("Pack"); 79 var localizedUnpack = Engine.localize("Unpack"); 80 var localizedCancelPacking = Engine.localize("Cancel packing"); 81 var localizedCancelUnpacking = Engine.localize("Cancel unpacking"); 82 83 // Internationalization cache â Walls 84 var localizedConvertSiegeWallIntoGate = Engine.localize("Convert Siege Wall into Siege Wall Gate"); 85 var localizedConvertStoneWallIntoGate = Engine.localize("Convert Store Wall into City Gate"); 86 var localizedConvertWallIntoGate = Engine.localize("Convert %(wall)s into %(gate)s"); 87 var localizedConvertWoodenWallIntoGate = Engine.localize("Convert Wooden Wall into Wooden Gate"); 88 41 89 // Lay out a row of centered buttons (does not work inside a loop like the other function) 42 90 function layoutButtonRowCentered(rowNumber, guiName, startIndex, endIndex, width) 43 91 { … … function formatLimitString(trainEntLimit, trainEntCount) 146 194 { 147 195 if (trainEntLimit == undefined) 148 196 return ""; 149 var text = "\n\n Current Count: " + trainEntCount + ", Limit: " + trainEntLimit + ".";197 var text = "\n\n" + sprintf(localizedCountAndLimit, { count: trainEntCount, limit: trainEntLimit }); 150 198 if (trainEntCount >= trainEntLimit) 151 199 text = "[color=\"red\"]" + text + "[/color]"; 152 200 return text; … … function formatBatchTrainingString(buildingsCountToTrainFullBatch, fullBatchSize 174 222 if (buildingsCountToTrainFullBatch > 0) 175 223 { 176 224 if (buildingsCountToTrainFullBatch > 1) 177 fullBatchesString += buildingsCountToTrainFullBatch + "*"; 178 fullBatchesString += fullBatchSize; 225 { 226 fullBatchesString = sprintf(localizedBuildingsTimesBatchSize, { 227 buildings: buildingsCountToTrainFullBatch, 228 batchSize: fullBatchSize 229 }); 230 } 231 else 232 { 233 fullBatchesString = fullBatchSize; 234 } 179 235 } 180 236 var remainderBatchString = remainderBatch > 0 ? remainderBatch : ""; 181 237 var batchDetailsString = ""; 238 var action = "[font=\"serif-bold-13\"]" + localizedShiftClick + "[/font][font=\"serif-13\"]" 239 182 240 // We need to display the batch details part if there is either more than 183 241 // one building with full batch or one building with the full batch and 184 242 // another with a partial batch 185 243 if (buildingsCountToTrainFullBatch > 1 || 186 244 (buildingsCountToTrainFullBatch == 1 && remainderBatch > 0)) 187 245 { 188 batchDetailsString += " (" + fullBatchesString; 189 if (remainderBatchString != "") 190 batchDetailsString += " + " + remainderBatchString; 191 batchDetailsString += ")"; 246 if (remainderBatch > 0) 247 { 248 return "\n[font=\"serif-13\"]" + sprintf(localizedTrainFullAndRemainder, { 249 action: action, 250 number: totalBatchTrainingCount, 251 fullBatch: fullBatchesString, 252 remainderBatch: remainderBatch 253 }) + "[/font]"; 254 } 255 else 256 { 257 return "\n[font=\"serif-13\"]" + sprintf(localizedTrainFull, { 258 action: action, 259 number: totalBatchTrainingCount, 260 fullBatch: fullBatchesString 261 }) + "[/font]"; 262 } 192 263 } 264 else 265 { 266 return "\n[font=\"serif-13\"]" + sprintf(localizedTrain, { 267 action: action, 268 number: totalBatchTrainingCount 269 }) + "[/font]"; 270 } 271 } 193 272 194 return "\n[font=\"serif-bold-13\"]Shift-click[/font][font=\"serif-13\"] to train " 195 + totalBatchTrainingCount + batchDetailsString + ".[/font]"; 273 function getStanceDisplayName(name) 274 { 275 var displayName; 276 switch(name) 277 { 278 case "violent": 279 displayName = localizedViolent; 280 break; 281 case "aggressive": 282 displayName = localizedAggressive; 283 break; 284 case "passive": 285 displayName = localizedPassive; 286 break; 287 case "defensive": 288 displayName = localizedDefensive; 289 break; 290 case "standground": 291 displayName = localizedStandground; 292 break; 293 default: 294 displayName = name; 295 break; 296 } 297 return displayName; 298 } 299 300 function getFormationDisplayName(name) 301 { 302 if (localizedFormationsArray[name] === undefined) 303 { 304 localizedFormationsArray[name] = Engine.localize(name); 305 } 306 return localizedFormationsArray[name]; 196 307 } 197 308 198 309 /** … … function setupUnitPanel(guiName, usedPanels, unitEntState, playerState, items, c 374 485 break; 375 486 } 376 487 488 377 489 switch (guiName) 378 490 { 379 491 case SELECTION: … … function setupUnitPanel(guiName, usedPanels, unitEntState, playerState, items, c 386 498 case QUEUE: 387 499 var tooltip = getEntityNames(template); 388 500 if (item.neededSlots) 389 tooltip += "\n[color=\"red\"] Insufficient population capacity:\n[/color]"+getCostComponentDisplayName("population")+" "+item.neededSlots;501 tooltip += "\n[color=\"red\"]" + localizedPopulationCapacity + "\n[/color]" + sprintf(localizedPopulationRequirement, { population: getCostComponentDisplayName("population"), neededSlots: item.neededSlots }); 390 502 391 503 var progress = Math.round(item.progress*100) + "%"; 392 504 getGUIObjectByName("unit"+guiName+"Count["+i+"]").caption = (item.count > 1 ? item.count : ""); … … function setupUnitPanel(guiName, usedPanels, unitEntState, playerState, items, c 404 516 405 517 case GARRISON: 406 518 var name = getEntityNames(template); 407 var tooltip = "Unload " + name + "\nSingle-click to unload 1. Shift-click to unload all of this type.";519 var tooltip = sprintf(localizedUnload, { name: name })+ "\n" + localizedUnloadHelp; 408 520 var count = garrisonGroups.getCount(item); 409 521 getGUIObjectByName("unit"+guiName+"Count["+i+"]").caption = (count > 1 ? count : ""); 410 522 break; … … function setupUnitPanel(guiName, usedPanels, unitEntState, playerState, items, c 440 552 break; 441 553 442 554 case STANCE: 555 var tooltip = getStanceDisplayName(item); 556 break; 557 443 558 case FORMATION: 444 var tooltip = toTitleCase(item);559 var tooltip = getFormationDisplayName(item); 445 560 break; 446 561 447 562 case TRAINING: … … function setupUnitPanel(guiName, usedPanels, unitEntState, playerState, items, c 464 579 getEntityLimitAndCount(playerState, entType); 465 580 tooltip += formatLimitString(trainEntLimit, trainEntCount); 466 581 467 tooltip += "[color=\"255 251 131\"]" + formatBatchTrainingString(buildingsCountToTrainFullBatch, fullBatchSize, remainderBatch) + "[/color]";468 582 break; 469 583 470 584 case RESEARCH: … … function setupUnitPanel(guiName, usedPanels, unitEntState, playerState, items, c 517 631 break; 518 632 } 519 633 634 520 635 // Button 521 636 var button = getGUIObjectByName("unit"+guiName+"Button["+i+"]"); 522 637 var button1 = getGUIObjectByName("unit"+guiName+"Button["+(i+rowLength)+"]"); … … function setupUnitPanel(guiName, usedPanels, unitEntState, playerState, items, c 588 703 "formationName": item 589 704 }); 590 705 591 button.tooltip += " (disabled)";706 button.tooltip = sprintf(localizedDisabledFormation, { formation: button.tooltip }); 592 707 if (requirements.count > 1) 593 button.tooltip += "\n" + requirements.count + " units required";708 button.tooltip += "\n" + sprintf(localizedUnitsRequirementNumber, { number: requirements.count }); 594 709 if (requirements.classesRequired) 595 710 { 596 button.tooltip += "\nOnly units of type"; 597 for each (var classRequired in requirements.classesRequired) 598 { 599 button.tooltip += " " + classRequired; 600 } 601 button.tooltip += " allowed."; 711 button.tooltip += "\n" + sprintf(localizedUnitsRequirementClasses, { unitType: Engine.localizeArray(requirements.classesRequired).join(localizedClassSeparator) }); 602 712 } 603 713 } 604 714 … … function setupUnitPanel(guiName, usedPanels, unitEntState, playerState, items, c 631 741 // If already a gate, show locking actions 632 742 if (item.gate) 633 743 { 634 gateIcon = "icons/lock_" + GATE_ACTIONS[item.locked ? 0 : 1] .toLowerCase()+ "ed.png";744 gateIcon = "icons/lock_" + GATE_ACTIONS[item.locked ? 0 : 1] + "ed.png"; 635 745 selection.hidden = item.gate.locked === undefined ? false : item.gate.locked != item.locked; 636 746 } 637 747 // otherwise show gate upgrade icon … … function setupUnitPanel(guiName, usedPanels, unitEntState, playerState, items, c 670 780 { 671 781 button.enabled = false; 672 782 var techName = getEntityNames(GetTechnologyData(template.requiredTechnology)); 673 button.tooltip += "\n Requires " + techName;783 button.tooltip += "\n" + sprintf(localizedRequiresTechnology, { technology: techName }); 674 784 grayscale = "grayscale:"; 675 785 affordableMask.hidden = false; 676 786 affordableMask.sprite = "colour: 0 0 0 127"; … … function setupUnitTradingPanel(usedPanels, unitEntState, selection) 911 1021 var selectTradingPreferredGoodsData = { "entities": selection, "preferredGoods": resource }; 912 1022 button.onpress = (function(e){ return function() { selectTradingPreferredGoods(e); } })(selectTradingPreferredGoodsData); 913 1023 button.enabled = true; 914 button.tooltip = "Set " + resource + " as trading goods";1024 button.tooltip = sprintf(localizedSetResource, { resource: resource }); 915 1025 var icon = getGUIObjectByName("unitTradingIcon["+i+"]"); 916 1026 var preferredGoods = unitEntState.trader.preferredGoods; 917 1027 var selected = getGUIObjectByName("unitTradingSelection["+i+"]"); … … function updateUnitCommands(entState, supplementalDetailsPanel, commandsPanel, s 1098 1208 var gateTemplate = getWallGateTemplate(state.id); 1099 1209 if (gateTemplate) 1100 1210 { 1101 var wallName = GetTemplateData(state.template).name.generic; 1102 var gateName = GetTemplateData(gateTemplate).name.generic; 1211 var wallName = GetTemplateDataWithoutLocalization(state.template).name.generic; 1212 var gateName = GetTemplateDataWithoutLocalization(gateTemplate).name.generic; 1213 var tooltipString; 1214 1215 // For internationalization purposes, when possible, available combinations should be provided 1216 // as placeholder-free strings as below. 1217 // 1218 // The platceholder implementation is provided only so that undetected new combinations of wall 1219 // and gate names are not simply printed in English, but as close to a perfect translation as 1220 // possible. 1221 1222 if (wallName === "Wooden Wall" && gateName === "Wooden Gate") 1223 { 1224 tooltipString = localizedConvertWoodenWallIntoGate; 1225 } 1226 else if (wallName === "Stone Wall" && gateName === "City Gate") 1227 { 1228 tooltipString = localizedConvertStoneWallIntoGate; 1229 } 1230 else if (wallName === "Siege Wall" && gateName === "Siege Wall Gate") 1231 { 1232 tooltipString = localizedConvertSiegeWallIntoGate; 1233 } 1234 else 1235 { 1236 tooltipString = sprintf(localizedConvertWallIntoGate, { wall: Engine.localize(wallName), gate: Engine.localize(gateName) }); 1237 } 1103 1238 1104 1239 walls.push({ 1105 "tooltip": "Convert " + wallName + " to " + gateName,1240 "tooltip": tooltipString, 1106 1241 "template": gateTemplate, 1107 1242 "callback": function (item) { transformWallToGate(item.template); } 1108 1243 }); … … function updateUnitCommands(entState, supplementalDetailsPanel, commandsPanel, s 1112 1247 longWallTypes[state.template] = true; 1113 1248 } 1114 1249 else if (state.gate && !gates.length) 1115 for (var j = 0; j < GATE_ACTIONS.length; ++j) 1116 gates.push({ 1117 "gate": state.gate, 1118 "tooltip": GATE_ACTIONS[j] + " gate", 1119 "locked": j == 0, 1120 "callback": function (item) { lockGate(item.locked); } 1121 }); 1250 { 1251 gates.push({ 1252 "gate": state.gate, 1253 "tooltip": localizedLockGate, 1254 "locked": true, 1255 "callback": function (item) { lockGate(item.locked); } 1256 }); 1257 gates.push({ 1258 "gate": state.gate, 1259 "tooltip": localizedUnlockGate, 1260 "locked": false, 1261 "callback": function (item) { lockGate(item.locked); } 1262 }); 1263 } 1122 1264 // Show both 'locked' and 'unlocked' as active if the selected gates have both lock states. 1123 1265 else if (state.gate && state.gate.locked != gates[0].gate.locked) 1124 1266 for (var j = 0; j < gates.length; ++j) … … function updateUnitCommands(entState, supplementalDetailsPanel, commandsPanel, s 1163 1305 } 1164 1306 } 1165 1307 if (packButton) 1166 items.push({ "packing": false, "packed": false, "tooltip": "Pack", "callback": function() { packUnit(true); } });1308 items.push({ "packing": false, "packed": false, "tooltip": localizedPack, "callback": function() { packUnit(true); } }); 1167 1309 if (unpackButton) 1168 items.push({ "packing": false, "packed": true, "tooltip": "Unpack", "callback": function() { packUnit(false); } });1310 items.push({ "packing": false, "packed": true, "tooltip": localizedUnpack, "callback": function() { packUnit(false); } }); 1169 1311 if (packCancelButton) 1170 items.push({ "packing": true, "packed": false, "tooltip": "Cancel packing", "callback": function() { cancelPackUnit(true); } });1312 items.push({ "packing": true, "packed": false, "tooltip": localizedCancelPacking, "callback": function() { cancelPackUnit(true); } }); 1171 1313 if (unpackCancelButton) 1172 items.push({ "packing": true, "packed": true, "tooltip": "Cancel unpacking", "callback": function() { cancelPackUnit(false); } });1314 items.push({ "packing": true, "packed": true, "tooltip": localizedCancelUnpacking, "callback": function() { cancelPackUnit(false); } }); 1173 1315 1174 1316 if (items.length) 1175 1317 setupUnitPanel(PACK, usedPanels, entState, playerState, items); -
binaries/data/mods/public/gui/session/utility_functions.js
diff --git a/binaries/data/mods/public/gui/session/utility_functions.js b/binaries/data/mods/public/gui/session/utility_functions.js index 1ba9158..14529aa 100644
a b const COST_DISPLAY_NAMES = { 12 12 "time": "[icon=\"iconTime\"]" 13 13 }; 14 14 15 16 // Localizable strings. 17 18 var localizedArmor = Engine.localize("(%(armorPercentage)s)"); 19 var localizedAttack = Engine.localize("%(attackLabel)s %(damageTypes)s"); 20 var localizedAttackAndRange = Engine.localize("%(attackLabel)s %(damageTypes)s, %(rangeLabel)s %(range)s"); 21 var localizedAttackLabel = Engine.localize("Attack:"); 22 var localizedChargeAttack = Engine.localize("Charge Attack:"); 23 var localizedComponentCost = Engine.localize("%(component)s %(cost)s"); 24 var localizedComposedName = Engine.localize("%(specificName)s (%(genericName)s)"); 25 var localizedCosts = Engine.localize("Costs:"); 26 var localizedCostsListSeparator = Engine.localize(" "); 27 var localizedCrush = Engine.localize("Crush"); 28 var localizedDamage = Engine.localize("%(damage)s %(damageType)s"); 29 var localizedDamageAndArmor = Engine.localize("%(damage)s %(damageType)s %(armorPercentage)s"); 30 var localizedDelete = Engine.localize("Delete"); 31 var localizedFocusOnRallyPoint = Engine.localize("Focus on Rally Point"); 32 var localizedGain = Engine.localize("%(gain)s (%(player)s)"); 33 var localizedGarrison = Engine.localize("Garrison"); 34 var localizedHack = Engine.localize("Hack"); 35 var localizedInsufficientResources = Engine.localize("Insufficient resources:"); 36 var localizedListSeparator = Engine.localize(", "); 37 var localizedMeleeAttack = Engine.localize("Melee Attack:"); 38 var localizedMovements = Engine.localize("%(speed)s %(movementType)s"); 39 var localizedNone = Engine.localize("(None)"); 40 var localizedPierce = Engine.localize("Pierce"); 41 var localizedPlayerName = Engine.localize("player %(name)s"); 42 var localizedPlus = Engine.localize("+"); 43 var localizedPopulationBonus = Engine.localize("%(label)s %(populationBonus)s"); 44 var localizedPopulationBonusLabel = Engine.localize("Population Bonus:"); 45 var localizedRange = Engine.localize("Range:"); 46 var localizedRangedAttack = Engine.localize("Ranged Attack:"); 47 var localizedRankAndName = Engine.localize("%(rank)s %(name)s"); 48 var localizedRepair = Engine.localize("Repair"); 49 var localizedRun = Engine.localize("Run"); 50 var localizedSpeed = Engine.localize("%(label)s %(speeds)s"); 51 var localizedSpeedLabel = Engine.localize("Speed:"); 52 var localizedStop = Engine.localize("Stop"); 53 var localizedTowers = Engine.localize("Towers: %(costs)s"); 54 var localizedUnknown = Engine.localize("???"); 55 var localizedUnloadAll = Engine.localize("Unload All"); 56 var localizedWalk = Engine.localize("Walk"); 57 var localizedWalls = Engine.localize("Walls: %(costs)s"); 58 var localizedYou = Engine.localize("you"); 59 15 60 //-------------------------------- -------------------------------- -------------------------------- 16 61 // Utility functions 17 62 //-------------------------------- -------------------------------- -------------------------------- … … function damageTypeDetails(dmg) 154 199 if (dmg) 155 200 { 156 201 var dmgArray = []; 157 if (dmg.hack) dmgArray.push(dmg.hack + "[font=\"sans-10\"][color=\"orange\"] Hack[/color][/font]"); 158 if (dmg.pierce) dmgArray.push(dmg.pierce + "[font=\"sans-10\"][color=\"orange\"] Pierce[/color][/font]"); 159 if (dmg.crush) dmgArray.push(dmg.crush + "[font=\"sans-10\"][color=\"orange\"] Crush[/color][/font]"); 202 if (dmg.hack) 203 { 204 var type = "[font=\"sans-10\"][color=\"orange\"]" + localizedHack + "[/color][/font]"; 205 dmgArray.push(sprintf(localizedDamage, { damage: dmg.hack, damageType: type })); 206 } 207 if (dmg.pierce) 208 { 209 var type = "[font=\"sans-10\"][color=\"orange\"]" + localizedPierce + "[/color][/font]"; 210 dmgArray.push(sprintf(localizedDamage, { damage: dmg.pierce, damageType: type })); 211 } 212 if (dmg.crush) 213 { 214 var type = "[font=\"sans-10\"][color=\"orange\"]" + localizedCrush + "[/color][/font]"; 215 dmgArray.push(sprintf(localizedDamage, { damage: dmg.crush, damageType: type })); 216 } 160 217 161 return dmgArray.join( ", ");218 return dmgArray.join(localizedListSeparator); 162 219 } 163 220 else 164 221 { 165 return "[font=\"serif-12\"] (None)[/font]";222 return "[font=\"serif-12\"]" + localizedNone + "[/font]"; 166 223 } 167 224 } 168 225 169 226 // Converts an armor level into the actual reduction percentage 170 function armorLevelToPercentage (level)227 function armorLevelToPercentageString(level) 171 228 { 172 return 100 - Math.round(Math.pow(0.9, level) * 100);229 return (100 - Math.round(Math.pow(0.9, level) * 100)) + "%"; 173 230 } 174 231 175 232 // Also for the unit details panel … … function armorTypeDetails(dmg) 180 237 var dmgArray = []; 181 238 if (dmg.hack) 182 239 { 183 dmgArray.push(dmg.hack + "[font=\"sans-10\"][color=\"orange\"] Hack[/color][/font] " + 184 " [font=\"sans-10\"](" + armorLevelToPercentage(dmg.hack) + "%)[/font]"); 240 var damageType = "[font=\"sans-10\"][color=\"orange\"]" + localizedHack + "[/color][/font]"; 241 var armor = "[font=\"sans-10\"]" + sprintf(localizedArmor, { armorPercentage: armorLevelToPercentageString(dmg.hack) }) + "[/font]"; 242 dmgArray.push(sprintf(localizedDamageAndArmor, { damage: dmg.hack, damageType: damageType, armorPercentage: armor })); 185 243 } 186 244 if (dmg.pierce) 187 245 { 188 dmgArray.push(dmg.pierce + "[font=\"sans-10\"][color=\"orange\"] Pierce[/color][/font] " + 189 " [font=\"sans-10\"](" + armorLevelToPercentage(dmg.pierce) + "%)[/font]"); 246 var damageType = "[font=\"sans-10\"][color=\"orange\"]" + localizedPierce + "[/color][/font]"; 247 var armor = "[font=\"sans-10\"]" + sprintf(localizedArmor, { armorPercentage: armorLevelToPercentageString(dmg.pierce) }) + "[/font]"; 248 dmgArray.push(sprintf(localizedDamageAndArmor, { damage: dmg.pierce, damageType: damageType, armorPercentage: armor })); 190 249 } 191 250 if (dmg.crush) 192 251 { 193 dmgArray.push(dmg.crush + "[font=\"sans-10\"][color=\"orange\"] Crush[/color][/font] " + 194 " [font=\"sans-10\"](" + armorLevelToPercentage(dmg.crush) + "%)[/font]"); 252 var damageType = "[font=\"sans-10\"][color=\"orange\"]" + localizedCrush + "[/color][/font]"; 253 var armor = "[font=\"sans-10\"]" + sprintf(localizedArmor, { armorPercentage: armorLevelToPercentageString(dmg.crush) }) + "[/font]"; 254 dmgArray.push(sprintf(localizedDamageAndArmor, { damage: dmg.crush, damageType: damageType, armorPercentage: armor })); 195 255 } 196 256 197 return dmgArray.join( ", ");257 return dmgArray.join(localizedListSeparator); 198 258 } 199 259 else 200 260 { 201 return "[font=\"serif-12\"] (None)[/font]";261 return "[font=\"serif-12\"]" + localizedNone + "[/font]"; 202 262 } 203 263 } 204 264 205 265 // For the training tooltip 206 266 function damageTypesToText(dmg) 207 267 { 208 if (!dmg) 209 return "[font=\"serif-12\"](None)[/font]"; 210 211 var hackLabel = "[font=\"serif-12\"] Hack[/font]"; 212 var pierceLabel = "[font=\"serif-12\"] Pierce[/font]"; 213 var crushLabel = "[font=\"serif-12\"] Crush[/font]"; 214 var hackDamage = dmg.hack; 215 var pierceDamage = dmg.pierce; 216 var crushDamage = dmg.crush; 217 218 var dmgArray = []; 219 if (hackDamage) dmgArray.push(Math.round(hackDamage) + hackLabel); 220 if (pierceDamage) dmgArray.push(Math.round(pierceDamage) + pierceLabel); 221 if (crushDamage) dmgArray.push(Math.round(crushDamage) + crushLabel); 222 223 return dmgArray.join("[font=\"serif-12\"], [/font]"); 268 if (dmg) 269 { 270 var dmgArray = []; 271 if (dmg.hack) 272 { 273 var type = "[font=\"serif-12\"]" + localizedHack + "[/font]"; 274 dmgArray.push(sprintf(localizedDamage, { damage: dmg.hack, damageType: type })); 275 } 276 if (dmg.pierce) 277 { 278 var type = "[font=\"serif-12\"]" + localizedPierce + "[/font]"; 279 dmgArray.push(sprintf(localizedDamage, { damage: dmg.pierce, damageType: type })); 280 } 281 if (dmg.crush) 282 { 283 var type = "[font=\"serif-12\"]" + localizedCrush + "[/font]"; 284 dmgArray.push(sprintf(localizedDamage, { damage: dmg.crush, damageType: type })); 285 } 286 287 return dmgArray.join("[font=\"serif-12\"]" + localizedListSeparator + "[/font]"); 288 } 289 else 290 { 291 return "[font=\"serif-12\"]" + localizedNone + "[/font]"; 292 } 224 293 } 225 294 226 295 // Also for the training tooltip 227 296 function armorTypesToText(dmg) 228 297 { 229 if (!dmg) 230 return "[font=\"serif-12\"](None)[/font]"; 231 232 var hackDamage = dmg.hack; 233 var pierceDamage = dmg.pierce; 234 var crushDamage = dmg.crush; 235 var hackLabel = "[font=\"serif-12\"] Hack (" + armorLevelToPercentage(hackDamage) + "%)[/font]"; 236 var pierceLabel = "[font=\"serif-12\"] Pierce (" + armorLevelToPercentage(pierceDamage) + "%)[/font]"; 237 var crushLabel = "[font=\"serif-12\"] Crush (" + armorLevelToPercentage(crushDamage) + "%)[/font]"; 238 239 var dmgArray = []; 240 if (hackDamage) dmgArray.push(hackDamage + hackLabel); 241 if (pierceDamage) dmgArray.push(pierceDamage + pierceLabel); 242 if (crushDamage) dmgArray.push(crushDamage + crushLabel); 243 244 return dmgArray.join("[font=\"serif-12\"], [/font]"); 298 if (dmg) 299 { 300 var dmgArray = []; 301 if (dmg.hack) 302 { 303 var type = "[font=\"serif-12\"]" + localizedHack + "[/font]"; 304 var armor = "[font=\"sans-10\"]" + sprintf(localizedArmor, { armorPercentage: armorLevelToPercentageString(dmg.hack) }) + "[/font]"; 305 dmgArray.push(sprintf(localizedDamageAndArmor, { damage: dmg.hack, damageType: type, armorPercentage: armor })); 306 } 307 if (dmg.pierce) 308 { 309 var type = "[font=\"serif-12\"]" + localizedPierce + "[/font]"; 310 var armor = "[font=\"sans-10\"]" + sprintf(localizedArmor, { armorPercentage: armorLevelToPercentageString(dmg.pierce) }) + "[/font]"; 311 dmgArray.push(sprintf(localizedDamageAndArmor, { damage: dmg.pierce, damageType: type, armorPercentage: armor })); 312 } 313 if (dmg.crush) 314 { 315 var type = "[font=\"serif-12\"]" + localizedCrush + "[/font]"; 316 var armor = "[font=\"sans-10\"]" + sprintf(localizedArmor, { armorPercentage: armorLevelToPercentageString(dmg.crush) }) + "[/font]"; 317 dmgArray.push(sprintf(localizedDamageAndArmor, { damage: dmg.crush, damageType: type, armorPercentage: armor })); 318 } 319 320 return dmgArray.join("[font=\"serif-12\"]" + localizedListSeparator + "[/font]"); 321 } 322 else 323 { 324 return "[font=\"serif-12\"]" + localizedNone + "[/font]"; 325 } 245 326 } 246 327 247 328 function getEntityCommandsList(entState) … … function getEntityCommandsList(entState) 251 332 { 252 333 commands.push({ 253 334 "name": "unload-all", 254 "tooltip": "Unload All",335 "tooltip": localizedUnloadAll, 255 336 "icon": "garrison-out.png" 256 337 }); 257 338 } 258 339 259 340 commands.push({ 260 341 "name": "delete", 261 "tooltip": "Delete",342 "tooltip": localizedDelete, 262 343 "icon": "kill_small.png" 263 344 }); 264 345 … … function getEntityCommandsList(entState) 266 347 { 267 348 commands.push({ 268 349 "name": "stop", 269 "tooltip": "Stop",350 "tooltip": localizedStop, 270 351 "icon": "stop.png" 271 352 }); 272 353 commands.push({ 273 354 "name": "garrison", 274 "tooltip": "Garrison",355 "tooltip": localizedGarrison, 275 356 "icon": "garrison.png" 276 357 }); 277 358 } … … function getEntityCommandsList(entState) 280 361 { 281 362 commands.push({ 282 363 "name": "repair", 283 "tooltip": "Repair",364 "tooltip": localizedRepair, 284 365 "icon": "repair.png" 285 366 }); 286 367 } … … function getEntityCommandsList(entState) 289 370 { 290 371 commands.push({ 291 372 "name": "focus-rally", 292 "tooltip": "Focus on Rally Point",373 "tooltip": localizedFocusOnRallyPoint, 293 374 "icon": "focus-rally.png" 294 375 }); 295 376 } … … function getEntityCostComponentsTooltipString(template, trainNum, entity) 330 411 totalCosts.time = Math.ceil(template.cost.time * (entity ? Engine.GuiInterfaceCall("GetBatchTime", {"entity": entity, "batchSize": trainNum}) : 1)); 331 412 332 413 var costs = []; 333 if (totalCosts.food) costs.push( getCostComponentDisplayName("food") + " " + totalCosts.food);334 if (totalCosts.wood) costs.push( getCostComponentDisplayName("wood") + " " + totalCosts.wood);335 if (totalCosts.metal) costs.push( getCostComponentDisplayName("metal") + " " + totalCosts.metal);336 if (totalCosts.stone) costs.push( getCostComponentDisplayName("stone") + " " + totalCosts.stone);337 if (totalCosts.population) costs.push( getCostComponentDisplayName("population") + " " + totalCosts.population);338 if (totalCosts.time) costs.push( getCostComponentDisplayName("time") + " " + totalCosts.time);414 if (totalCosts.food) costs.push(sprintf(localizedComponentCost, { component: getCostComponentDisplayName("food"), cost: totalCosts.food })); 415 if (totalCosts.wood) costs.push(sprintf(localizedComponentCost, { component: getCostComponentDisplayName("wood"), cost: totalCosts.wood })); 416 if (totalCosts.metal) costs.push(sprintf(localizedComponentCost, { component: getCostComponentDisplayName("metal"), cost: totalCosts.metal })); 417 if (totalCosts.stone) costs.push(sprintf(localizedComponentCost, { component: getCostComponentDisplayName("stone"), cost: totalCosts.stone })); 418 if (totalCosts.population) costs.push(sprintf(localizedComponentCost, { component: getCostComponentDisplayName("population"), cost: totalCosts.population })); 419 if (totalCosts.time) costs.push(sprintf(localizedComponentCost, { component: getCostComponentDisplayName("time"), cost: totalCosts.time })); 339 420 return costs; 340 421 } 341 422 … … function getWallPieceTooltip(wallTypes) 391 472 } 392 473 } 393 474 else 475 { 394 476 for (var i = 0; i < wallTypes.length; ++i) 477 { 395 478 out.push(getEntityCostComponentsTooltipString(wallTypes[i]).join(", ")); 479 } 480 } 396 481 397 482 return out; 398 483 } … … function getEntityCostTooltip(template, trainNum, entity) 416 501 var wallCosts = getWallPieceTooltip([templateShort, templateMedium, templateLong]); 417 502 var towerCosts = getEntityCostComponentsTooltipString(templateTower); 418 503 419 cost += "\n"; 420 cost += " Walls: " + wallCosts.join(" ") + "\n"; 421 cost += " Towers: " + towerCosts.join(" "); 504 cost += " " + sprintf(localizedWalls, { costs: wallCosts.join(localizedCostsListSeparator) }) + "\n"; 505 cost += " " + sprintf(localizedTowers, { costs: towerCosts.join(localizedCostsListSeparator) }); 422 506 } 423 507 else if (template.cost) 424 508 { 425 509 var costs = getEntityCostComponentsTooltipString(template, trainNum, entity); 426 cost += costs.join(" ");510 cost = costs.join(localizedCostsListSeparator); 427 511 } 428 512 else 429 513 { … … function getPopulationBonusTooltip(template) 440 524 { 441 525 var popBonus = ""; 442 526 if (template.cost && template.cost.populationBonus) 443 popBonus = "\n[font=\"serif-bold-13\"]Population Bonus:[/font] " + template.cost.populationBonus; 527 { 528 var labelString = "[font=\"serif-bold-13\"]" + localizedPopulationBonusLabel + "[/font]" 529 popBonus = "\n" + sprintf(localizedPopulationBonus, { label: labelString, populationBonus: template.cost.populationBonus }); 530 } 444 531 return popBonus; 445 532 } 446 533 … … function getNeededResourcesTooltip(resources) 451 538 { 452 539 var formatted = []; 453 540 for (var resource in resources) 454 formatted.push("[font=\"serif-12\"]" + getCostComponentDisplayName(resource) + "[/font] " + resources[resource]); 541 { 542 var componentLabel = "[font=\"serif-12\"]" + getCostComponentDisplayName(resource) + "[/font]" 543 formatted.push(sprintf(localizedComponentCost, { component: componentLabel, cost: resources[resource] })); 544 } 455 545 456 return "\n\n[font=\"serif-bold-13\"][color=\"red\"] Insufficient resources:[/color][/font]\n" + formatted.join(" ");546 return "\n\n[font=\"serif-bold-13\"][color=\"red\"]" + localizedInsufficientResources + "[/color][/font]\n" + formatted.join(localizedCostsListSeparator); 457 547 } 458 548 459 549 function getEntitySpeed(template) … … function getEntitySpeed(template) 461 551 var speed = ""; 462 552 if (template.speed) 463 553 { 464 speed += "[font=\"serif-bold-13\"]Speed:[/font] ";554 var label = "[font=\"serif-bold-13\"]" + localizedSpeedLabel + "[/font]" 465 555 var speeds = []; 466 if (template.speed.walk) speeds.push( template.speed.walk + " [font=\"serif-12\"]Walk[/font]");467 if (template.speed.run) speeds.push( template.speed.run + " [font=\"serif-12\"]Run[/font]");556 if (template.speed.walk) speeds.push(sprintf(localizedMovements, { speed: template.speed.walk, movementType: "[font=\"serif-12\"]" + localizedWalk + "[/font]"})); 557 if (template.speed.run) speeds.push(sprintf(localizedMovements, { speed: template.speed.run, movementType: "[font=\"serif-12\"]" + localizedRun + "[/font]"})); 468 558 469 speed += speeds.join(", ");559 speed = sprintf(localizedSpeed, { label: label, speeds: speeds.join(localizedListSeparator) }) 470 560 } 471 561 return speed; 472 562 } … … function getEntityAttack(template) 480 570 delete template.attack['Slaughter']; 481 571 for (var type in template.attack) 482 572 { 483 var attack = " [font=\"serif-bold-13\"]" + type + " Attack:[/font] " + damageTypesToText(template.attack[type]);484 // Show max attack range if ranged attack, also convert to tiles (4m per tile)573 var attack = ""; 574 var attackLabel = "[font=\"serif-bold-13\"]" + getAttackTypeLabel(type) + "[/font]"; 485 575 if (type == "Ranged") 486 attack += ", [font=\"serif-bold-13\"]Range:[/font] "+Math.round(template.attack[type].maxRange/4); 576 { 577 // Show max attack range if ranged attack, also convert to tiles (4m per tile) 578 attack = sprintf(localizedAttackAndRange, { 579 attackLabel: attackLabel, 580 damageTypes: damageTypesToText(template.attack[type]), 581 rangeLabel: "[font=\"serif-bold-13\"]" + localizedRange + "[/font]", 582 range: Math.round(template.attack[type].maxRange/4) 583 }); 584 } 585 else 586 { 587 attack = sprintf(localizedAttack, { 588 attackLabel: attackLabel, 589 damageTypes: damageTypesToText(template.attack[type]) 590 }); 591 } 487 592 attacks.push(attack); 488 593 } 489 594 } … … function getEntityAttack(template) 492 597 493 598 function getEntityName(template) 494 599 { 495 return template.name.specific || template.name.generic || "???"; 600 if (template.name.specific) 601 { 602 return Engine.localize(template.name.specific); 603 } 604 else if (template.name.generic) 605 { 606 return Engine.localize(template.name.generic); 607 } 608 else 609 { 610 return localizedUnknown; 611 } 496 612 } 497 613 498 614 function getEntityNames(template) 499 615 { 500 var names = [];501 616 if (template.name.specific) 502 617 { 503 names.push(template.name.specific); 504 if (template.name.generic && names[0] != template.name.generic) 505 names.push("(" + template.name.generic + ")"); 618 if (template.name.generic && template.name.specific != template.name.generic) 619 { 620 return sprintf(localizedComposedName, { 621 specificName: Engine.localize(template.name.specific), 622 genericName: Engine.localize(template.name.generic) 623 }); 624 } 625 else 626 { 627 return Engine.localize(template.name.specific); 628 } 506 629 } 507 630 else if (template.name.generic) 508 names.push(template.name.generic); 509 510 return (names.length) ? names.join(" ") : "???"; 631 { 632 return Engine.localize(template.name.generic); 633 } 634 else 635 { 636 return localizedUnknown; 637 } 511 638 } 512 639 513 640 function getEntityNamesFormatted(template) … … function getEntityRankedName(entState) 537 664 var template = GetTemplateData(entState.template) 538 665 var rank = entState.identity.rank; 539 666 if (rank) 540 return rank + " " + template.name.specific;667 return sprintf(localizedRankAndName, { rank: rank, name: template.name.specific }); 541 668 else 542 669 return template.name.specific; 543 670 } … … function getRankIconSprite(entState) 559 686 */ 560 687 function getTradingTooltip(gain) 561 688 { 562 var tooltip= gain.traderGain;689 var gainString = gain.traderGain; 563 690 if (gain.market1Gain && gain.market1Owner == gain.traderOwner) 564 tooltip += "+" + gain.market1Gain; 691 { 692 gainString += localizedPlus + gain.market1Gain; 693 } 565 694 if (gain.market2Gain && gain.market2Owner == gain.traderOwner) 566 tooltip += "+" + gain.market2Gain; 567 tooltip += " (you)"; 695 { 696 gainString += localizedPlus + gain.market2Gain; 697 } 698 699 var tooltip = sprintf(localizedGain, { 700 gain: gainString, 701 player: localizedYou 702 }); 568 703 569 704 if (gain.market1Gain && gain.market1Owner != gain.traderOwner) 570 tooltip += ", " + gain.market1Gain + " (player " + gain.market1Owner + ")"; 705 { 706 tooltip += localizedListSeparator + sprintf(localizedGain, { 707 gain: gain.market1Gain, 708 player: sprintf(localizedPlayerName, { name: gain.market1Owner }) 709 }); 710 } 571 711 if (gain.market2Gain && gain.market2Owner != gain.traderOwner) 572 tooltip += ", " + gain.market2Gain + " (player " + gain.market2Owner + ")"; 712 { 713 tooltip += localizedListSeparator + sprintf(localizedGain, { 714 gain: gain.market2Gain, 715 player: sprintf(localizedPlayerName, { name: gain.market2Owner }) 716 }); 717 } 573 718 574 719 return tooltip; 575 720 } 721 722 function getAttackTypeLabel(type) 723 { 724 if (type === "Charge") return localizedChargeAttack; 725 else if (type === "Melee") return localizedMeleeAttack; 726 else if (type === "Ranged") return localizedRangedAttack; 727 else return localizedAttackLabel; 728 } -
binaries/data/mods/public/gui/splashscreen/splashscreen.js
diff --git a/binaries/data/mods/public/gui/splashscreen/splashscreen.js b/binaries/data/mods/public/gui/splashscreen/splashscreen.js index abd975e..b630ce2 100644
a b 1 1 function init(data) 2 2 { 3 getGUIObjectByName("mainText").caption = readFile("gui/splashscreen/" + data.page + ".txt");3 getGUIObjectByName("mainText").caption = Engine.localizeLines(readFile("gui/splashscreen/" + data.page + ".txt")); 4 4 } -
binaries/data/mods/public/gui/splashscreen/splashscreen.xml
diff --git a/binaries/data/mods/public/gui/splashscreen/splashscreen.xml b/binaries/data/mods/public/gui/splashscreen/splashscreen.xml index 226d621..a947d23 100644
a b 8 8 <object type="image" z="0" style="TranslucentPanel"/> 9 9 10 10 <object type="image" style="StoneDialog" size="50%-300 50%-200 50%+300 50%+200"> 11 <object type="text" style="TitleText" size="50%-128 0%-16 50%+128 16">Welcome to 0 A.D. !</object> 11 <object type="text" style="TitleText" size="50%-128 0%-16 50%+128 16"> 12 <localizableAttribute id="caption">Welcome to 0 A.D. !</localizableAttribute> 13 </object> 12 14 13 15 <object type="image" sprite="BackgroundTranslucent" size="20 20 100%-20 100%-52"> 14 16 <object name="openFundraiserPage" type="button" style="fundraiserButton" size="5 5 100% 150"> … … 21 23 </object> 22 24 </object> 23 25 <object name="btnOK" type="button" style="StoneButton" tooltip_style="snToolTip" size="24 100%-52 188 100%-24"> 24 OK26 <localizableAttribute id="caption">OK</localizableAttribute> 25 27 <action on="Press"><![CDATA[ 26 28 Engine.SetSplashScreenEnabled(!getGUIObjectByName("displaySplashScreen").checked); 27 29 Engine.PopGuiPage(); 28 30 ]]></action> 29 31 </object> 30 32 <object name="btnFundraiser" type="button" style="StoneButton" tooltip_style="snToolTip" size="196 100%-52 360 100%-24"> 31 Visit Fundraiser33 <localizableAttribute id="caption">Visit Fundraiser</localizableAttribute> 32 34 <action on="Press"><![CDATA[ 33 35 Engine.OpenURL("http://play0ad.com/fundraiser"); 34 36 ]]></action> 35 37 </object> 36 38 <object size="368 100%-52 100%-32 100%-24"> 37 39 <object size="0 0 100% 100%"> 38 <object name="displaySplashScreenText" size="0 0 100%-32 100%" type="text" style="RightLabelText">Don't show this again</object> 40 <object name="displaySplashScreenText" size="0 0 100%-32 100%" type="text" style="RightLabelText"> 41 <localizableAttribute id="caption">Don't show this again</localizableAttribute> 42 </object> 39 43 <object name="displaySplashScreen" checked="false" size="100%-16 50%-8 100% 50%+8" type="checkbox" style="StoneCrossBox"/> 40 44 </object> 41 45 </object> -
binaries/data/mods/public/gui/summary/summary.js
diff --git a/binaries/data/mods/public/gui/summary/summary.js b/binaries/data/mods/public/gui/summary/summary.js index 81129a3..4a74538 100644
a b function adjustTabDividers(tabSize) 37 37 function init(data) 38 38 { 39 39 var civData = loadCivData(); 40 var map Size = "Scenario";40 var mapDisplayType = Engine.localize("Scenario"); 41 41 42 getGUIObjectByName("timeElapsed").caption = "Time elapsed: " + timeToString(data.timeElapsed);42 getGUIObjectByName("timeElapsed").caption = sprintf(Engine.localize("Time elapsed: %(time)s"), { time: timeToString(data.timeElapsed) }); 43 43 44 44 getGUIObjectByName("summaryText").caption = data.gameResult; 45 45 … … function init(data) 54 54 { 55 55 if (mapSizes.tiles[mapSizeIndex] == data.mapSettings.Size) 56 56 { 57 map Size = mapSizes.names[mapSizeIndex];57 mapDisplayType = mapSizes.names[mapSizeIndex]; 58 58 break; 59 59 } 60 60 } 61 61 } 62 62 63 getGUIObjectByName("mapName").caption = data.mapSettings.Name + " - " + mapSize;63 getGUIObjectByName("mapName").caption = sprintf(Engine.localize("%(mapName)s - %(mapType)s"), { mapName: data.mapSettings.Name, mapType: mapDisplayType}); 64 64 65 65 // Space player boxes 66 66 var boxSpacing = 32; -
binaries/data/mods/public/gui/summary/summary.xml
diff --git a/binaries/data/mods/public/gui/summary/summary.xml b/binaries/data/mods/public/gui/summary/summary.xml index 4e50416..88988cd 100644
a b 20 20 </action> 21 21 22 22 <object style="TitleText" type="text" size="50%-128 4 50%+128 36"> 23 Summary23 <localizableAttribute id="caption">Summary</localizableAttribute> 24 24 </object> 25 25 26 26 <object type="image" sprite="ForegroundBody" size="20 20 100%-20 70"> … … 59 59 60 60 <object name="scorePanelButton" type="button" sprite="ForegroundTab" size="20 95 170 120"> 61 61 <action on="Press">selectPanel(0);</action> 62 <object type="text" style="TitleText" ghost="true">Score</object> 62 <object type="text" style="TitleText" ghost="true"> 63 <localizableAttribute id="caption">Score</localizableAttribute> 64 </object> 63 65 </object> 64 66 65 67 <object name="unitsBuildingsPanelButton" type="button" sprite="BackgroundTab" size="176 95 326 120"> 66 68 <action on="Press">selectPanel(1);</action> 67 <object type="text" style="TitleText" ghost="true">Units/buildings</object> 69 <object type="text" style="TitleText" ghost="true"> 70 <localizableAttribute id="caption">Units/buildings</localizableAttribute> 71 </object> 68 72 </object> 69 73 70 74 <object name="conquestPanelButton" type="button" sprite="BackgroundTab" size="332 95 480 120"> 71 75 <action on="Press">selectPanel(2);</action> 72 <object type="text" style="TitleText" ghost="true">Conquest</object> 76 <object type="text" style="TitleText" ghost="true"> 77 <localizableAttribute id="caption">Conquest</localizableAttribute> 78 </object> 73 79 </object> 74 80 75 81 <object name="resourcesPanelButton" type="button" sprite="BackgroundTab" size="486 95 636 120"> 76 82 <action on="Press">selectPanel(3);</action> 77 <object type="text" style="TitleText" ghost="true">Resources</object> 83 <object type="text" style="TitleText" ghost="true"> 84 <localizableAttribute id="caption">Resources</localizableAttribute> 85 </object> 78 86 </object> 79 87 80 88 <object name="marketPanelButton" type="button" sprite="BackgroundTab" size="642 95 792 120"> 81 89 <action on="Press">selectPanel(4);</action> 82 <object type="text" style="TitleText" ghost="true">Market</object> 90 <object type="text" style="TitleText" ghost="true"> 91 <localizableAttribute id="caption">Market</localizableAttribute> 92 </object> 83 93 </object> 84 94 85 95 <object name="scorePanel" type="image" sprite="ForegroundBody" size="20 120 100%-20 100%-58"> 86 96 87 97 <object size="0 0 100% 100%-50"> 88 98 <object name="playerName0Heading" type="text" style="LeftTabLabelText"> 89 Player name99 <localizableAttribute id="caption">Player name</localizableAttribute> 90 100 </object> 91 101 <object name="economyScoreHeading" type="text" style="CenteredTabLabelText"> 92 Economy score102 <localizableAttribute id="caption">Economy score</localizableAttribute> 93 103 </object> 94 104 <object name="militaryScoreHeading" type="text" style="CenteredTabLabelText"> 95 Military score105 <localizableAttribute id="caption">Military score</localizableAttribute> 96 106 </object> 97 107 <object name="explorationScoreHeading" type="text" style="CenteredTabLabelText"> 98 Exploration score108 <localizableAttribute id="caption">Exploration score</localizableAttribute> 99 109 </object> 100 110 <object name="totalScoreHeading" type="text" style="CenteredTabLabelText"> 101 Total score111 <localizableAttribute id="caption">Total score</localizableAttribute> 102 112 </object> 103 113 </object> 104 114 … … 121 131 122 132 <object size="0 0 100% 100%-50"> 123 133 <object name="playerName1Heading" type="text" style="LeftTabLabelText"> 124 Player name134 <localizableAttribute id="caption">Player name</localizableAttribute> 125 135 </object> 126 136 <object name="unitsTrainedHeading" type="text" style="CenteredTabLabelText"> 127 Units trained137 <localizableAttribute id="caption">Units trained</localizableAttribute> 128 138 </object> 129 139 <object name="unitsLostHeading" type="text" style="CenteredTabLabelText"> 130 Units lost140 <localizableAttribute id="caption">Units lost</localizableAttribute> 131 141 </object> 132 142 <object name="enemyUnitsKilledHeading" type="text" style="CenteredTabLabelText"> 133 Enemy units killed143 <localizableAttribute id="caption">Enemy units killed</localizableAttribute> 134 144 </object> 135 145 <object name="buildingsConstructedHeading" type="text" style="CenteredTabLabelText"> 136 Buildings constructed146 <localizableAttribute id="caption">Buildings constructed</localizableAttribute> 137 147 </object> 138 148 <object name="buildingsLostHeading" type="text" style="CenteredTabLabelText"> 139 Buildings lost149 <localizableAttribute id="caption">Buildings lost</localizableAttribute> 140 150 </object> 141 151 <object name="enemyBuildingsDestroyedHeading" type="text" style="CenteredTabLabelText"> 142 Enemy buildings destroyed152 <localizableAttribute id="caption">Enemy buildings destroyed</localizableAttribute> 143 153 </object> 144 154 </object> 145 155 … … 164 174 165 175 <object size="0 0 100% 100%-50"> 166 176 <object name="playerName2Heading" type="text" style="LeftTabLabelText"> 167 Player name177 <localizableAttribute id="caption">Player name</localizableAttribute> 168 178 </object> 169 179 <object name="civCentresBuiltHeading" type="text" style="CenteredTabLabelText"> 170 Civ centres built180 <localizableAttribute id="caption">Civ centres built</localizableAttribute> 171 181 </object> 172 182 <object name="enemyCivCentresDestroyedHeading" type="text" style="CenteredTabLabelText"> 173 Enemy civ centres destroyed183 <localizableAttribute id="caption">Enemy civ centres destroyed</localizableAttribute> 174 184 </object> 175 185 <object name="mapExplorationHeading" type="text" style="CenteredTabLabelText"> 176 Map exploration186 <localizableAttribute id="caption">Map exploration</localizableAttribute> 177 187 </object> 178 188 </object> 179 189 … … 195 205 196 206 <object size="0 0 100% 100%-50"> 197 207 <object name="playerName3Heading" type="text" style="LeftTabLabelText"> 198 Player name208 <localizableAttribute id="caption">Player name</localizableAttribute> 199 209 </object> 200 210 <object name="resourceHeading" type="text" style="CenteredTabLabelText"> 201 Resource Statistics (Gathered / Used)211 <localizableAttribute id="caption">Resource Statistics (Gathered / Used)</localizableAttribute> 202 212 </object> 203 213 <object name="foodGatheredHeading" type="text" style="CenteredTabLabelText"> 204 Food214 <localizableAttribute id="caption">Food</localizableAttribute> 205 215 </object> 206 216 <object name="woodGatheredHeading" type="text" style="CenteredTabLabelText"> 207 Wood217 <localizableAttribute id="caption">Wood</localizableAttribute> 208 218 </object> 209 219 <object name="stoneGatheredHeading" type="text" style="CenteredTabLabelText"> 210 Stone220 <localizableAttribute id="caption">Stone</localizableAttribute> 211 221 </object> 212 222 <object name="metalGatheredHeading" type="text" style="CenteredTabLabelText"> 213 Metal223 <localizableAttribute id="caption">Metal</localizableAttribute> 214 224 </object> 215 225 <object name="vegetarianRatioHeading" type="text" style="CenteredTabLabelText"> 216 Vegetarian ratio226 <localizableAttribute id="caption">Vegetarian ratio</localizableAttribute> 217 227 </object> 218 228 <object name="treasuresCollectedHeading" type="text" style="CenteredTabLabelText"> 219 Treasures collected229 <localizableAttribute id="caption">Treasures collected</localizableAttribute> 220 230 </object> 221 231 <object name="resourcesTributedHeading" type="text" style="CenteredTabLabelText"> 222 Tributes (Sent / Received)232 <localizableAttribute id="caption">Tributes (Sent / Received)</localizableAttribute> 223 233 </object> 224 234 </object> 225 235 … … 245 255 246 256 <object size="0 0 100% 100%-50"> 247 257 <object name="playerName4Heading" type="text" style="LeftTabLabelText"> 248 Player name258 <localizableAttribute id="caption">Player name</localizableAttribute> 249 259 </object> 250 260 <object name="exchangedFoodHeading" type="text" style="CenteredTabLabelText"> 251 Food exchanged261 <localizableAttribute id="caption">Food exchanged</localizableAttribute> 252 262 </object> 253 263 <object name="exchangedWoodHeading" type="text" style="CenteredTabLabelText"> 254 Wood exchanged264 <localizableAttribute id="caption">Wood exchanged</localizableAttribute> 255 265 </object> 256 266 <object name="exchangedStoneHeading" type="text" style="CenteredTabLabelText"> 257 Stone exchanged267 <localizableAttribute id="caption">Stone exchanged</localizableAttribute> 258 268 </object> 259 269 <object name="exchangedMetalHeading" type="text" style="CenteredTabLabelText"> 260 Metal exchanged270 <localizableAttribute id="caption">Metal exchanged</localizableAttribute> 261 271 </object> 262 272 <object name="barterEfficiencyHeading" type="text" style="CenteredTabLabelText"> 263 Barter efficiency273 <localizableAttribute id="caption">Barter efficiency</localizableAttribute> 264 274 </object> 265 275 <object name="tradeIncomeHeading" type="text" style="CenteredTabLabelText"> 266 Trade income276 <localizableAttribute id="caption">Trade income</localizableAttribute> 267 277 </object> 268 278 </object> 269 279 … … 286 296 </object> 287 297 288 298 <object type="button" style="StoneButton" size="100%-164 100%-52 100%-24 100%-24"> 289 Continue299 <localizableAttribute id="caption">Continue</localizableAttribute> 290 300 <action on="Press"> 291 301 Engine.SwitchGuiPage("page_pregame.xml"); 292 302 </action> -
new file inaries/data/mods/public/localization/.tx/config
diff --git a/binaries/data/mods/public/localization/.tx/config b/binaries/data/mods/public/localization/.tx/config new file mode 100644 index 0000000..733e2ab
- + 1 [main] 2 host = https://www.transifex.com 3 4 [0ad.public] 5 file_filter = <lang>.public.po 6 source_file = public.pot 7 source_lang = en 8 -
new file inaries/data/mods/public/localization/messages.sh
diff --git a/binaries/data/mods/public/localization/messages.sh b/binaries/data/mods/public/localization/messages.sh new file mode 100644 index 0000000..f3d9f0b
- + 1 # This file provides information about this mod that helps the internationalization system to find certain types of 2 # files that need to be localized that cannot be detected automatically. 3 # 4 # Paths are relative to the root directory of the mod. 5 6 7 # Functions to generate file lists dynamically. 8 9 loadTxtLineByLineFilesDynamically() 10 { 11 # Define required variables. 12 local basedir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 13 local root="$basedir/.." 14 15 # Enter the mod folder, so that paths are relative to it. 16 pushd $root &> /dev/null 17 18 for filepath in $(find "gui/text/tips" -name "*.txt") 19 do 20 txtLineByLineFiles+=("$filepath") 21 done 22 23 # Leave the mod folder. 24 popd &> /dev/null 25 } 26 27 loadJsonFilesDynamically() 28 { 29 # Define required variables. 30 local basedir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 31 local root="$basedir/.." 32 33 # Enter the mod folder, so that paths are relative to it. 34 pushd $root &> /dev/null 35 36 for filepath in $(find "civs" -name "*.json") 37 do 38 jsonFilesWithFilters+=("$filepath::Name,Description,History,Special,Formations,AINames") 39 done 40 41 for filepath in $(find "maps/random" -name "*.json") 42 do 43 jsonFilesWithFilters+=("$filepath::Name,Description") 44 done 45 46 for filepath in $(find "simulation/ai" -name "*.json") 47 do 48 jsonFilesWithFilters+=("$filepath::name,description") 49 done 50 51 # Determine civilization codes, as specific names are specified as "specificName: { "<civilization code>": "<name>" }. 52 pushd civs &> /dev/null 53 civilizationCodes=`for item in $(find . -type f); do echo -n "${item//.\/},"; done;` 54 popd &> /dev/null 55 civilizationCodes=${civilizationCodes//.json} 56 length=$((${#civilizationCodes} - 1)) 57 civilizationCodes=${civilizationCodes:0:$length} 58 59 for filepath in $(find "simulation/data/technologies" -name "*.json") 60 do 61 jsonFilesWithFilters+=("$filepath::specificName,genericName,description,tooltip,requirementsTooltip,$civilizationCodes") 62 done 63 64 # Leave the mod folder. 65 popd &> /dev/null 66 } 67 68 loadEntityFilesDynamically() 69 { 70 # Define required variables. 71 local basedir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 72 local root="$basedir/.." 73 74 # Enter the mod folder, so that paths are relative to it. 75 pushd $root &> /dev/null 76 77 for filepath in $(find "simulation/templates" -name "*.xml") 78 do 79 entityFiles+=("$filepath") 80 done 81 82 # Leave the mod folder. 83 popd &> /dev/null 84 } 85 86 loadXmlFilesWithJsonDynamically() 87 { 88 # Define required variables. 89 local basedir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 90 local root="$basedir/.." 91 92 # Enter the mod folder, so that paths are relative to it. 93 pushd $root &> /dev/null 94 95 while IFS= read -d $'\0' -r filepath ; do 96 xmlFilesWithJsonWithFilters+=("$filepath::ScriptSettings::Name,Description") 97 done < <(find "maps/scenarios" -name "*.xml" -print0) 98 99 while IFS= read -d $'\0' -r filepath ; do 100 xmlFilesWithJsonWithFilters+=("$filepath::ScriptSettings::Name,Description") 101 done < <(find "maps/skirmishes" -name "*.xml" -print0) 102 103 # Leave the mod folder. 104 popd &> /dev/null 105 } 106 107 108 # Variables used by the â(0 A.D. root folder)/localization/update-pot.shâ script. 109 110 declare -a txtLineByLineFiles=( 111 "gui/manual/intro.txt" 112 "gui/manual/userreport.txt" 113 "gui/text/quotes.txt" 114 "gui/splashscreen/splashscreen.txt" 115 ) 116 loadTxtLineByLineFilesDynamically 117 118 declare -a jsonFilesWithFilters=( 119 "simulation/data/game_speeds.json::Name" 120 "simulation/data/map_sizes.json::Name,LongName" 121 "simulation/data/player_defaults.json::Name" 122 ) 123 loadJsonFilesDynamically 124 125 declare -a entityFiles=() 126 loadEntityFilesDynamically 127 128 declare -a xmlFilesWithJsonWithFilters=() 129 loadXmlFilesWithJsonDynamically -
build/premake/extern_libs4.lua
diff --git a/build/premake/extern_libs4.lua b/build/premake/extern_libs4.lua index 6101b5e..a336f74 100644
a b extern_lib_defs = { 343 343 }) 344 344 end, 345 345 }, 346 icu = { 347 compile_settings = function() 348 if os.is("windows") then 349 add_default_include_paths("u") 350 end 351 end, 352 link_settings = function() 353 if os.is("windows") then 354 add_default_lib_paths("icu") 355 end 356 add_default_links({ 357 win_names = { "icu" }, 358 unix_names = { "icui18n", "icuuc" }, 359 }) 360 end, 361 }, 346 362 libcurl = { 347 363 compile_settings = function() 348 364 if os.is("windows") then … … extern_lib_defs = { 567 583 end 568 584 end, 569 585 }, 586 tinygettext = { 587 compile_settings = function() 588 includedirs { libraries_source_dir .. "tinygettext" } 589 end, 590 link_settings = function() 591 add_source_lib_paths("tinygettext") 592 add_default_links({ 593 win_names = { "tinygettext" }, 594 unix_names = { "tinygettext" }, 595 }) 596 end, 597 }, 570 598 valgrind = { 571 599 compile_settings = function() 572 600 add_source_include_paths("valgrind") -
build/premake/premake4.lua
diff --git a/build/premake/premake4.lua b/build/premake/premake4.lua index bba9714..a5b948a 100644
a b function setup_all_libs () 591 591 "zlib", 592 592 "boost", 593 593 "enet", 594 "libcurl" 594 "libcurl", 595 "tinygettext", 596 "icu", 595 597 } 596 598 597 599 if not _OPTIONS["without-audio"] then … … function setup_all_libs () 641 643 "spidermonkey", 642 644 "sdl", -- key definitions 643 645 "opengl", 644 "boost" 646 "boost", 647 "tinygettext", 645 648 } 646 649 setup_static_lib_project("gui", source_dirs, extern_libs, {}) 647 650 … … function setup_all_libs () 672 675 "libjpg", 673 676 "valgrind", 674 677 "cxxtest", 678 "tinygettext", 675 679 } 676 680 677 681 -- CPU architecture-specific … … used_extern_libs = { 762 766 "cxxtest", 763 767 "comsuppw", 764 768 "enet", 769 "tinygettext", 765 770 "libcurl", 771 "icu", 766 772 767 773 "valgrind", 768 774 } -
libraries/LICENSE.txt
diff --git a/libraries/LICENSE.txt b/libraries/LICENSE.txt index 58654d2..cd69609 100644
a b win32/ contains headers and precompiled static libs for Windows builds. 23 23 source/spidermonkey 24 24 MPL / GPL / LGPL 25 25 26 source/tinygettext 27 GNU GPL v2 (see COPYING) 28 26 29 source/valgrind 27 30 BSD 28 31 -
new file libraries/source/tinygettext/CMakeLists.txt
diff --git a/libraries/source/tinygettext/CMakeLists.txt b/libraries/source/tinygettext/CMakeLists.txt new file mode 100644 index 0000000..abe2f98
- + 1 # 2 # TinyGetText build script 3 # Copyright (C) 2006 Christoph Sommer <christoph.sommer@2006.expires.deltadevelopment.de> 4 # 5 # This program is free software; you can redistribute it and/or modify 6 # it under the terms of the GNU General Public License as published by 7 # the Free Software Foundation; either version 2 of the License, or 8 # (at your option) any later version. 9 # 10 # This program is distributed in the hope that it will be useful, 11 # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 # GNU General Public License for more details. 14 # 15 # You should have received a copy of the GNU General Public License 16 # along with this program; if not, write to the Free Software 17 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 # 19 20 21 # 22 # INSTRUCTIONS: 23 # ------------- 24 # 25 # Create a directory build/ and change to it. Run 26 # 27 # cmake .. 28 # 29 # This creates a set of Makefiles to build the project. Run 30 # 31 # make 32 # 33 34 35 CMAKE_POLICY(SET CMP0005 NEW) 36 37 ## Project name to use as command prefix 38 39 PROJECT(tinygettext) 40 SET(VERSION "0.1") 41 42 ### CMake configuration 43 44 CMAKE_MINIMUM_REQUIRED(VERSION 2.4) 45 IF(COMMAND cmake_policy) 46 CMAKE_POLICY(SET CMP0003 NEW) 47 ENDIF(COMMAND cmake_policy) 48 SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${tinygettext_SOURCE_DIR}) 49 50 # move some config clutter to the advanced section 51 MARK_AS_ADVANCED( 52 CMAKE_BACKWARDS_COMPATIBILITY 53 CMAKE_BUILD_TYPE 54 CMAKE_INSTALL_PREFIX 55 EXECUTABLE_OUTPUT_PATH 56 CMAKE_OSX_ARCHITECTURES 57 CMAKE_OSX_SYSROOT 58 ) 59 60 ## Reveal library type choice to users 61 OPTION(BUILD_SHARED_LIBS "Produce dynamic library instead of static archive" ON) 62 63 ## Add iconv to include directories 64 65 FIND_PACKAGE(ICONV REQUIRED) 66 INCLUDE_DIRECTORIES(${ICONV_INCLUDE_DIR}) 67 68 ## Check iconv_const 69 70 INCLUDE(CheckCXXSourceCompiles) 71 72 SET(CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES} ${ICONV_INCLUDE_DIR}) 73 CHECK_CXX_SOURCE_COMPILES( 74 " 75 #include <iconv.h> 76 // this declaration will fail when there already exists a non const char** version which returns size_t 77 double iconv(iconv_t cd, char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft); 78 int main() { return 0; } 79 " 80 HAVE_ICONV_CONST 81 ) 82 83 # TODO: better way of config 84 85 IF(HAVE_ICONV_CONST) 86 ADD_DEFINITIONS(-DHAVE_ICONV_CONST) 87 ELSE(HAVE_ICONV_CONST) 88 REMOVE_DEFINITIONS(-DHAVE_ICONV_CONST) 89 ENDIF(HAVE_ICONV_CONST) 90 91 ## TinyGetText library compilation 92 93 ## build list of source files 94 95 FILE(GLOB TINYGETTEXT_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} tinygettext/*.cpp) 96 FILE(GLOB TINYGETTEXT_HEADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} tinygettext/*.hpp) 97 98 ## define a target for building the library 99 100 ADD_LIBRARY(tinygettext ${TINYGETTEXT_SOURCES}) 101 102 ## Add tinygettext dir to search path 103 104 INCLUDE_DIRECTORIES(${tinygettext_SOURCE_DIR}) 105 106 ## Debug options 107 108 OPTION(WERROR "Stops on first compiler warning in debug mode" OFF) 109 IF(CMAKE_COMPILER_IS_GNUCC) 110 ADD_DEFINITIONS(-O3 -Wall -Wextra -Weffc++ -pedantic) 111 # -ansi fails in MinGW 112 OPTION(WARNINGS "Enable long list of warnings for compiler to check" ON) 113 IF(WARNINGS) 114 ADD_DEFINITIONS( 115 -Wabi -Wctor-dtor-privacy 116 -Wstrict-null-sentinel 117 -Wold-style-cast 118 -Woverloaded-virtual 119 -Wsign-promo -Wswitch-enum 120 -Wcast-align -Wcast-qual 121 -Wdisabled-optimization 122 -Wfloat-equal 123 -Wformat=2 124 -Winit-self 125 -Winvalid-pch -Wunsafe-loop-optimizations 126 -Wlogical-op 127 -Wmissing-format-attribute -Wmissing-include-dirs -Wmissing-noreturn 128 -Wpacked 129 -Wredundant-decls 130 -Wshadow 131 -Wsign-conversion -Wstack-protector 132 -Wstrict-overflow=5 133 -Wswitch-default -Wswitch-enum 134 -Wundef) 135 # Still left: 136 # -Wconversion (find alternative to using toupper(int) on char) 137 # -Wpadded (DictionaryManager has a bool that sticks out) 138 ENDIF(WARNINGS) 139 IF(WERROR) 140 ADD_DEFINITIONS(-Werror) 141 ENDIF(WERROR) 142 ENDIF(CMAKE_COMPILER_IS_GNUCC) 143 144 ## Extra definitions 145 146 ADD_DEFINITIONS(-DVERSION=\\\"${VERSION}\\\") 147 148 ## Generate test executables in the right place 149 150 SET(EXECUTABLE_OUTPUT_PATH ${tinygettext_BINARY_DIR}/test) 151 152 ## Build tinygettext tests 153 154 FOREACH(TEST tinygettext_test po_parser_test) 155 ## Add target for tinygettext test 156 ADD_EXECUTABLE(${TEST} test/${TEST}.cpp) 157 ## Link with tinygettext library 158 TARGET_LINK_LIBRARIES(${TEST} tinygettext) 159 TARGET_LINK_LIBRARIES(${TEST} ${ICONV_LIBRARY}) 160 ENDFOREACH(TEST) 161 162 ## Install tinygettext 163 164 # use standardized variable name 165 SET(LIB_SUBDIR "lib${LIB_SUFFIX}" 166 CACHE STRING "Subdirectory of prefix into which libraries are installed (e.g., lib32, lib64)") 167 168 ## prepare tinygettext.pc 169 CONFIGURE_FILE(tinygettext.pc.in tinygettext.pc @ONLY) 170 171 INSTALL(TARGETS tinygettext 172 ARCHIVE DESTINATION ${LIB_SUBDIR} 173 LIBRARY DESTINATION ${LIB_SUBDIR}) 174 INSTALL(FILES ${TINYGETTEXT_HEADERS} 175 DESTINATION include/tinygettext) 176 INSTALL(FILES ${tinygettext_BINARY_DIR}/tinygettext.pc 177 DESTINATION ${LIB_SUBDIR}/pkgconfig) -
new file libraries/source/tinygettext/COPYING
diff --git a/libraries/source/tinygettext/COPYING b/libraries/source/tinygettext/COPYING new file mode 100644 index 0000000..c45fcd8
- + 1 GNU GENERAL PUBLIC LICENSE 2 Version 2, June 1991 3 4 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 Everyone is permitted to copy and distribute verbatim copies 7 of this license document, but changing it is not allowed. 8 9 Preamble 10 11 The licenses for most software are designed to take away your 12 freedom to share and change it. By contrast, the GNU General Public 13 License is intended to guarantee your freedom to share and change free 14 software--to make sure the software is free for all its users. This 15 General Public License applies to most of the Free Software 16 Foundation's software and to any other program whose authors commit to 17 using it. (Some other Free Software Foundation software is covered by 18 the GNU Lesser General Public License instead.) You can apply it to 19 your programs, too. 20 21 When we speak of free software, we are referring to freedom, not 22 price. Our General Public Licenses are designed to make sure that you 23 have the freedom to distribute copies of free software (and charge for 24 this service if you wish), that you receive source code or can get it 25 if you want it, that you can change the software or use pieces of it 26 in new free programs; and that you know you can do these things. 27 28 To protect your rights, we need to make restrictions that forbid 29 anyone to deny you these rights or to ask you to surrender the rights. 30 These restrictions translate to certain responsibilities for you if you 31 distribute copies of the software, or if you modify it. 32 33 For example, if you distribute copies of such a program, whether 34 gratis or for a fee, you must give the recipients all the rights that 35 you have. You must make sure that they, too, receive or can get the 36 source code. And you must show them these terms so they know their 37 rights. 38 39 We protect your rights with two steps: (1) copyright the software, and 40 (2) offer you this license which gives you legal permission to copy, 41 distribute and/or modify the software. 42 43 Also, for each author's protection and ours, we want to make certain 44 that everyone understands that there is no warranty for this free 45 software. If the software is modified by someone else and passed on, we 46 want its recipients to know that what they have is not the original, so 47 that any problems introduced by others will not reflect on the original 48 authors' reputations. 49 50 Finally, any free program is threatened constantly by software 51 patents. We wish to avoid the danger that redistributors of a free 52 program will individually obtain patent licenses, in effect making the 53 program proprietary. To prevent this, we have made it clear that any 54 patent must be licensed for everyone's free use or not licensed at all. 55 56 The precise terms and conditions for copying, distribution and 57 modification follow. 58 59 GNU GENERAL PUBLIC LICENSE 60 TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 62 0. This License applies to any program or other work which contains 63 a notice placed by the copyright holder saying it may be distributed 64 under the terms of this General Public License. The "Program", below, 65 refers to any such program or work, and a "work based on the Program" 66 means either the Program or any derivative work under copyright law: 67 that is to say, a work containing the Program or a portion of it, 68 either verbatim or with modifications and/or translated into another 69 language. (Hereinafter, translation is included without limitation in 70 the term "modification".) Each licensee is addressed as "you". 71 72 Activities other than copying, distribution and modification are not 73 covered by this License; they are outside its scope. The act of 74 running the Program is not restricted, and the output from the Program 75 is covered only if its contents constitute a work based on the 76 Program (independent of having been made by running the Program). 77 Whether that is true depends on what the Program does. 78 79 1. You may copy and distribute verbatim copies of the Program's 80 source code as you receive it, in any medium, provided that you 81 conspicuously and appropriately publish on each copy an appropriate 82 copyright notice and disclaimer of warranty; keep intact all the 83 notices that refer to this License and to the absence of any warranty; 84 and give any other recipients of the Program a copy of this License 85 along with the Program. 86 87 You may charge a fee for the physical act of transferring a copy, and 88 you may at your option offer warranty protection in exchange for a fee. 89 90 2. You may modify your copy or copies of the Program or any portion 91 of it, thus forming a work based on the Program, and copy and 92 distribute such modifications or work under the terms of Section 1 93 above, provided that you also meet all of these conditions: 94 95 a) You must cause the modified files to carry prominent notices 96 stating that you changed the files and the date of any change. 97 98 b) You must cause any work that you distribute or publish, that in 99 whole or in part contains or is derived from the Program or any 100 part thereof, to be licensed as a whole at no charge to all third 101 parties under the terms of this License. 102 103 c) If the modified program normally reads commands interactively 104 when run, you must cause it, when started running for such 105 interactive use in the most ordinary way, to print or display an 106 announcement including an appropriate copyright notice and a 107 notice that there is no warranty (or else, saying that you provide 108 a warranty) and that users may redistribute the program under 109 these conditions, and telling the user how to view a copy of this 110 License. (Exception: if the Program itself is interactive but 111 does not normally print such an announcement, your work based on 112 the Program is not required to print an announcement.) 113 114 These requirements apply to the modified work as a whole. If 115 identifiable sections of that work are not derived from the Program, 116 and can be reasonably considered independent and separate works in 117 themselves, then this License, and its terms, do not apply to those 118 sections when you distribute them as separate works. But when you 119 distribute the same sections as part of a whole which is a work based 120 on the Program, the distribution of the whole must be on the terms of 121 this License, whose permissions for other licensees extend to the 122 entire whole, and thus to each and every part regardless of who wrote it. 123 124 Thus, it is not the intent of this section to claim rights or contest 125 your rights to work written entirely by you; rather, the intent is to 126 exercise the right to control the distribution of derivative or 127 collective works based on the Program. 128 129 In addition, mere aggregation of another work not based on the Program 130 with the Program (or with a work based on the Program) on a volume of 131 a storage or distribution medium does not bring the other work under 132 the scope of this License. 133 134 3. You may copy and distribute the Program (or a work based on it, 135 under Section 2) in object code or executable form under the terms of 136 Sections 1 and 2 above provided that you also do one of the following: 137 138 a) Accompany it with the complete corresponding machine-readable 139 source code, which must be distributed under the terms of Sections 140 1 and 2 above on a medium customarily used for software interchange; or, 141 142 b) Accompany it with a written offer, valid for at least three 143 years, to give any third party, for a charge no more than your 144 cost of physically performing source distribution, a complete 145 machine-readable copy of the corresponding source code, to be 146 distributed under the terms of Sections 1 and 2 above on a medium 147 customarily used for software interchange; or, 148 149 c) Accompany it with the information you received as to the offer 150 to distribute corresponding source code. (This alternative is 151 allowed only for noncommercial distribution and only if you 152 received the program in object code or executable form with such 153 an offer, in accord with Subsection b above.) 154 155 The source code for a work means the preferred form of the work for 156 making modifications to it. For an executable work, complete source 157 code means all the source code for all modules it contains, plus any 158 associated interface definition files, plus the scripts used to 159 control compilation and installation of the executable. However, as a 160 special exception, the source code distributed need not include 161 anything that is normally distributed (in either source or binary 162 form) with the major components (compiler, kernel, and so on) of the 163 operating system on which the executable runs, unless that component 164 itself accompanies the executable. 165 166 If distribution of executable or object code is made by offering 167 access to copy from a designated place, then offering equivalent 168 access to copy the source code from the same place counts as 169 distribution of the source code, even though third parties are not 170 compelled to copy the source along with the object code. 171 172 4. You may not copy, modify, sublicense, or distribute the Program 173 except as expressly provided under this License. Any attempt 174 otherwise to copy, modify, sublicense or distribute the Program is 175 void, and will automatically terminate your rights under this License. 176 However, parties who have received copies, or rights, from you under 177 this License will not have their licenses terminated so long as such 178 parties remain in full compliance. 179 180 5. You are not required to accept this License, since you have not 181 signed it. However, nothing else grants you permission to modify or 182 distribute the Program or its derivative works. These actions are 183 prohibited by law if you do not accept this License. Therefore, by 184 modifying or distributing the Program (or any work based on the 185 Program), you indicate your acceptance of this License to do so, and 186 all its terms and conditions for copying, distributing or modifying 187 the Program or works based on it. 188 189 6. Each time you redistribute the Program (or any work based on the 190 Program), the recipient automatically receives a license from the 191 original licensor to copy, distribute or modify the Program subject to 192 these terms and conditions. You may not impose any further 193 restrictions on the recipients' exercise of the rights granted herein. 194 You are not responsible for enforcing compliance by third parties to 195 this License. 196 197 7. If, as a consequence of a court judgment or allegation of patent 198 infringement or for any other reason (not limited to patent issues), 199 conditions are imposed on you (whether by court order, agreement or 200 otherwise) that contradict the conditions of this License, they do not 201 excuse you from the conditions of this License. If you cannot 202 distribute so as to satisfy simultaneously your obligations under this 203 License and any other pertinent obligations, then as a consequence you 204 may not distribute the Program at all. For example, if a patent 205 license would not permit royalty-free redistribution of the Program by 206 all those who receive copies directly or indirectly through you, then 207 the only way you could satisfy both it and this License would be to 208 refrain entirely from distribution of the Program. 209 210 If any portion of this section is held invalid or unenforceable under 211 any particular circumstance, the balance of the section is intended to 212 apply and the section as a whole is intended to apply in other 213 circumstances. 214 215 It is not the purpose of this section to induce you to infringe any 216 patents or other property right claims or to contest validity of any 217 such claims; this section has the sole purpose of protecting the 218 integrity of the free software distribution system, which is 219 implemented by public license practices. Many people have made 220 generous contributions to the wide range of software distributed 221 through that system in reliance on consistent application of that 222 system; it is up to the author/donor to decide if he or she is willing 223 to distribute software through any other system and a licensee cannot 224 impose that choice. 225 226 This section is intended to make thoroughly clear what is believed to 227 be a consequence of the rest of this License. 228 229 8. If the distribution and/or use of the Program is restricted in 230 certain countries either by patents or by copyrighted interfaces, the 231 original copyright holder who places the Program under this License 232 may add an explicit geographical distribution limitation excluding 233 those countries, so that distribution is permitted only in or among 234 countries not thus excluded. In such case, this License incorporates 235 the limitation as if written in the body of this License. 236 237 9. The Free Software Foundation may publish revised and/or new versions 238 of the General Public License from time to time. Such new versions will 239 be similar in spirit to the present version, but may differ in detail to 240 address new problems or concerns. 241 242 Each version is given a distinguishing version number. If the Program 243 specifies a version number of this License which applies to it and "any 244 later version", you have the option of following the terms and conditions 245 either of that version or of any later version published by the Free 246 Software Foundation. If the Program does not specify a version number of 247 this License, you may choose any version ever published by the Free Software 248 Foundation. 249 250 10. If you wish to incorporate parts of the Program into other free 251 programs whose distribution conditions are different, write to the author 252 to ask for permission. For software which is copyrighted by the Free 253 Software Foundation, write to the Free Software Foundation; we sometimes 254 make exceptions for this. Our decision will be guided by the two goals 255 of preserving the free status of all derivatives of our free software and 256 of promoting the sharing and reuse of software generally. 257 258 NO WARRANTY 259 260 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 REPAIR OR CORRECTION. 269 270 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 POSSIBILITY OF SUCH DAMAGES. 279 280 END OF TERMS AND CONDITIONS 281 282 How to Apply These Terms to Your New Programs 283 284 If you develop a new program, and you want it to be of the greatest 285 possible use to the public, the best way to achieve this is to make it 286 free software which everyone can redistribute and change under these terms. 287 288 To do so, attach the following notices to the program. It is safest 289 to attach them to the start of each source file to most effectively 290 convey the exclusion of warranty; and each file should have at least 291 the "copyright" line and a pointer to where the full notice is found. 292 293 tinygettext - A gettext replacement that works directly on .po files 294 Copyright (C) 2006 Ingo Ruhnke <grumbel@gmx.de> 295 296 This program is free software; you can redistribute it and/or modify 297 it under the terms of the GNU General Public License as published by 298 the Free Software Foundation; either version 2 of the License, or 299 (at your option) any later version. 300 301 This program is distributed in the hope that it will be useful, 302 but WITHOUT ANY WARRANTY; without even the implied warranty of 303 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 GNU General Public License for more details. 305 306 You should have received a copy of the GNU General Public License along 307 with this program; if not, write to the Free Software Foundation, Inc., 308 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 310 Also add information on how to contact you by electronic and paper mail. 311 312 If the program is interactive, make it output a short notice like this 313 when it starts in an interactive mode: 314 315 Gnomovision version 69, Copyright (C) year name of author 316 Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 This is free software, and you are welcome to redistribute it 318 under certain conditions; type `show c' for details. 319 320 The hypothetical commands `show w' and `show c' should show the appropriate 321 parts of the General Public License. Of course, the commands you use may 322 be called something other than `show w' and `show c'; they could even be 323 mouse-clicks or menu items--whatever suits your program. 324 325 You should also get your employer (if you work as a programmer) or your 326 school, if any, to sign a "copyright disclaimer" for the program, if 327 necessary. Here is a sample; alter the names: 328 329 Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 332 <signature of Ty Coon>, 1 April 1989 333 Ty Coon, President of Vice 334 335 This General Public License does not permit incorporating your program into 336 proprietary programs. If your program is a subroutine library, you may 337 consider it more useful to permit linking proprietary applications with the 338 library. If this is what you want to do, use the GNU Lesser General 339 Public License instead of this License. -
new file libraries/source/tinygettext/FindICONV.cmake
diff --git a/libraries/source/tinygettext/FindICONV.cmake b/libraries/source/tinygettext/FindICONV.cmake new file mode 100644 index 0000000..65e3609
- + 1 # 2 # Copyright (c) 2006, Peter Kümmel, <syntheticpp@gmx.net> 3 # 4 # Redistribution and use in source and binary forms, with or without 5 # modification, are permitted provided that the following conditions 6 # are met: 7 # 8 # 1. Redistributions of source code must retain the copyright 9 # notice, this list of conditions and the following disclaimer. 10 # 2. Redistributions in binary form must reproduce the copyright 11 # notice, this list of conditions and the following disclaimer in the 12 # documentation and/or other materials provided with the distribution. 13 # 3. The name of the author may not be used to endorse or promote products 14 # derived from this software without specific prior written permission. 15 # 16 # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 # IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 # NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 # 27 28 set(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS true) 29 30 if (ICONV_INCLUDE_DIR) 31 # Already in cache, be silent 32 set(ICONV_FIND_QUIETLY TRUE) 33 endif() 34 35 find_path(ICONV_INCLUDE_DIR iconv.h 36 /usr/include 37 /usr/local/include) 38 39 set(POTENTIAL_ICONV_LIBS iconv libiconv libiconv2) 40 41 find_library(ICONV_LIBRARY NAMES ${POTENTIAL_ICONV_LIBS} 42 PATHS /usr/lib /usr/local/lib) 43 44 if(WIN32) 45 set(ICONV_DLL_NAMES iconv.dll libiconv.dll libiconv2.dll) 46 find_file(ICONV_DLL 47 NAMES ${ICONV_DLL_NAMES} 48 PATHS ENV PATH 49 NO_DEFAULT_PATH) 50 find_file(ICONV_DLL_HELP 51 NAMES ${ICONV_DLL_NAMES} 52 PATHS ENV PATH 53 ${ICONV_INCLUDE_DIR}/../bin) 54 if(ICONV_FIND_REQUIRED) 55 if(NOT ICONV_DLL AND NOT ICONV_DLL_HELP) 56 message(FATAL_ERROR "Could not find iconv.dll, please add correct your PATH environment variable") 57 endif() 58 if(NOT ICONV_DLL AND ICONV_DLL_HELP) 59 get_filename_component(ICONV_DLL_HELP ${ICONV_DLL_HELP} PATH) 60 message(STATUS) 61 message(STATUS "Could not find iconv.dll in standard search path, please add ") 62 message(STATUS "${ICONV_DLL_HELP}") 63 message(STATUS "to your PATH environment variable.") 64 message(STATUS) 65 message(FATAL_ERROR "exit cmake") 66 endif() 67 endif() 68 if(ICONV_INCLUDE_DIR AND ICONV_LIBRARY AND ICONV_DLL) 69 set(ICONV_FOUND TRUE) 70 endif() 71 else() 72 include(CheckFunctionExists) 73 check_function_exists(iconv HAVE_ICONV_IN_LIBC) 74 if(ICONV_INCLUDE_DIR AND HAVE_ICONV_IN_LIBC) 75 set(ICONV_FOUND TRUE) 76 set(ICONV_LIBRARY CACHE TYPE STRING FORCE) 77 endif() 78 if(ICONV_INCLUDE_DIR AND ICONV_LIBRARY) 79 set(ICONV_FOUND TRUE) 80 endif() 81 endif() 82 83 84 85 if(ICONV_FOUND) 86 if(NOT ICONV_FIND_QUIETLY) 87 message(STATUS "Found iconv library: ${ICONV_LIBRARY}") 88 #message(STATUS "Found iconv dll : ${ICONV_DLL}") 89 endif() 90 else() 91 if(ICONV_FIND_REQUIRED) 92 message(STATUS "Looked for iconv library named ${POTENTIAL_ICONV_LIBS}.") 93 message(STATUS "Found no acceptable iconv library. This is fatal.") 94 message(STATUS "iconv header: ${ICONV_INCLUDE_DIR}") 95 message(STATUS "iconv lib : ${ICONV_LIBRARY}") 96 message(FATAL_ERROR "Could NOT find iconv library") 97 endif() 98 endif() 99 100 mark_as_advanced(ICONV_LIBRARY ICONV_INCLUDE_DIR) -
new file libraries/source/tinygettext/NEWS
diff --git a/libraries/source/tinygettext/NEWS b/libraries/source/tinygettext/NEWS new file mode 100644 index 0000000..fcf6ef6
- + 1 tinygettext 0.0.1 - (??. Feb 2009) 2 ================================== 3 4 * initial release 5 6 # EOF # -
new file libraries/source/tinygettext/README
diff --git a/libraries/source/tinygettext/README b/libraries/source/tinygettext/README new file mode 100644 index 0000000..0eeabe9
- + 1 tinygettext 2 =========== 3 4 tinygettext is a minimal gettext() replacement written in C++. It can 5 read .po files directly and doesn't need .mo files generated from .po. 6 It also can read the .po files from arbitary locations, so its much 7 better suited for non-Unix systems and situations in which one wants 8 to store or distrubite .po files seperatly from the software itself. 9 10 11 12 Detecting the locale setting 13 ============================ 14 15 Different operating systems store the default locale in different 16 places; a portable way to find it is provided by FindLocale: 17 18 * http://icculus.org/~aspirin/findlocale/ 19 20 21 # EOF # -
new file libraries/source/tinygettext/SConstruct
diff --git a/libraries/source/tinygettext/SConstruct b/libraries/source/tinygettext/SConstruct new file mode 100644 index 0000000..cc5f9ec
- + 1 # -*- python -*- 2 3 env = Environment(CXXFLAGS=['-O0', 4 '-g3', 5 '-Wall', 6 '-Wcast-qual', 7 '-Wconversion', 8 '-Weffc++', 9 '-Werror', 10 '-Wextra', 11 '-Winit-self', 12 '-Wno-unused-parameter', 13 '-Wnon-virtual-dtor', 14 '-Wshadow', 15 '-ansi', 16 '-pedantic', 17 ], 18 CPPPATH=['tinygettext', '.']) 19 20 # env.ParseConfig("sdl-config --cflags --libs") 21 # env['CPPDEFINES'] += HAVE_SDL 22 23 libtinygettext = env.SharedLibrary('tinygettext/tinygettext', 24 ['tinygettext/tinygettext.cpp', 25 'tinygettext/language.cpp', 26 'tinygettext/plural_forms.cpp', 27 'tinygettext/dictionary.cpp', 28 'tinygettext/dictionary_manager.cpp', 29 'tinygettext/unix_file_system.cpp', 30 'tinygettext/po_parser.cpp', 31 'tinygettext/iconv.cpp', 32 'tinygettext/log.cpp']) 33 34 env.Program('test/tinygettext_test', ['test/tinygettext_test.cpp', libtinygettext]) 35 env.Program('test/po_parser_test', ['test/po_parser_test.cpp', libtinygettext]) 36 37 # EOF # -
new file libraries/source/tinygettext/TODO
diff --git a/libraries/source/tinygettext/TODO b/libraries/source/tinygettext/TODO new file mode 100644 index 0000000..899dc2c
- + 1 tinygettext API related stuff: 2 ============================== 3 4 * translate, translate_ctxt, translate_ctxt_plural, ... could be 5 unified via overloading, not sure if that is a good idea. For the 6 same reason add_translation() could be de-overloaded, to 7 add_translation_ctxt, ... 8 9 * iconv handling needs cleanup and more flexibility, since some 10 systems don't provide iconv or only through SDL 11 12 * Customizability could use grouping and documentation or other means 13 to make it more obvious: 14 15 - POParser::pedantic 16 - iconv (???) 17 - logging (log_callback(std::string)) 18 19 * handle errors better, not with log_* stream, cases of errors: 20 21 - couldn't translate 22 - collision while adding translation 23 - failure to open file or directory 24 - unknown language 25 - iconv failure to convert charset 26 27 * ABI management/freezing. If tinygettext is to benefit other projects, 28 it should be able to provide a stable API (and, better, ABI). 29 30 31 tinygettext implementation details: 32 =================================== 33 34 * with PluralForms moved into Dictionary a lot of the Langugae stuff 35 is pointless 36 37 * get rid of goto 38 39 * POParser can handle Big5, but needs testing. 40 Big5 is one byte for ASCII letters and two bytes for chinese ones, 41 this means some two byte characters collide with '\', some .po files 42 seem to escape the \ properly so that the string can be read as 43 usual, while others don't. 44 45 * _() -> getext() (gettext default) 46 N_(id) -> gettext_noop(id) (gettext default) 47 C_(ctxt, id) -> pgettext(ctxt, id) (Gnome does this: http://library.gnome.org/devel/glib/2.16/glib-I18N.html#Q-:CAPS) 48 NC_(ctxt, id) -> pgettext(ctxt, id) (Gnome does this: http://library.gnome.org/devel/glib/2.16/glib-I18N.html#Q-:CAPS) 49 50 * figure out how up-to-date other tinygettext implementations in the 51 wild are (LinCity): 52 53 Pingus: 54 ------- 55 dictionary.hpp (synced with Pingus) 56 dictionary_manager.hpp (PhysFS vs opendir()) 57 language_def.hpp (synced with Pingus) 58 po_file_reader.hpp (UTF-8 0xef-'header', lots of stuff from mathner) 59 tinygettext.hpp (iconv vs convert) 60 61 0 62 63 Random Unimportant Stuff 64 ======================== 65 66 * a hashmap instead of std::map might be a good idea 67 68 * support for .gmo files would be cool 69 1 70 71 tinygettext Documentation: 72 ========================== 73 74 * recommend a way to handle translation of speech and other data files 75 76 * document how to use tinygettext and make it work like gettext -
new file libraries/source/tinygettext/build.sh
+ +# EOF # diff --git a/libraries/source/tinygettext/build.sh b/libraries/source/tinygettext/build.sh new file mode 100755 index 0000000..1f9f99b
- + 1 #!/bin/sh 2 3 set -e 4 5 JOBS=${JOBS:="-j2"} 6 7 echo "Building TinyGettextâ¦" 8 echo 9 10 scons ${JOBS} 11 12 mkdir -p lib/ 13 14 if [ "`uname -s`" = "Darwin" ] 15 then 16 extension=dylib 17 else 18 extension=so 19 fi 20 21 filepath=tinygettext/libtinygettext.${extension} 22 cp $filepath lib/ 23 cp $filepath ../../../binaries/system/ -
new file libraries/source/tinygettext/test/broken.po
diff --git a/libraries/source/tinygettext/test/broken.po b/libraries/source/tinygettext/test/broken.po new file mode 100644 index 0000000..c841a73
- + 1 # SOME DESCRIPTIVE TITLE. 2 # Copyright (C) YEAR Free Software Foundation, Inc. 3 # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. 4 # 5 #, fuzzy 6 msgid "" 7 msgstr "" 8 "Project-Id-Version: PACKAGE VERSION\n" 9 "Report-Msgid-Bugs-To: \n" 10 "POT-Creation-Date: 2009-01-30 08:01+0100\n" 11 "PO-Revision-Date: 2009-01-30 08:39+0100\n" 12 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" 13 "Language-Team: LANGUAGE <LL@li.org>\n" 14 "MIME-Version: 1.0\n" 15 "Content-Type: text/plain; charset=UTF-8\n" 16 "Content-Transfer-Encoding: 8bit\n" 17 18 #: helloworld.cpp:7 19 msgid "Short Hello World" 20 msgstr "kurzes Hallo Welt 21 22 #: helloworld.cpp:8 helloworld.cpp:14 23 #, fuzzy 24 msgid "Hello World" 25 msgid_plural "Hello Worlds" 26 msgstr[0] "Hallo Welt (singular)" 27 msgstr[1] "Hallo Welt (plural)" 28 msgstr[10] "Hallo Welt (plural)" 29 30 #: helloworld.cpp:10 helloworld.cpp:16 31 #, fuzzy 32 msgctxt "" 33 msgid "Hello World" 34 msgid_plural "Hello Worlds" 35 msgstr[0] Hallo Welt (singular) mit leerem Kontext" 36 msgstr[1] "Hallo Welt (plural) mit leerem Kontext" 37 38 #: helloworld.cpp:11 helloworld.cpp:17 39 msgctxt "console" 40 msgid "Hello World" 41 msgid_plural "Hello Worlds" 42 msgstr[0]"Hallo Welt (singular) in der Console" 43 msgstr[1] "Hallo Welt (plural) in der Console" 44 45 #: helloworld.cpp:13 46 msgid "gui" 47 msgid_plural "Hello World" 48 msgstr[0] "Hallo Welt (singular)" 49 msgstr[1] "Hallo Welt (plural)" 50 51 #: helloworld.cpp:18 52 #, fuzzy 53 msgctxt "gui" 54 msgid "Hello World" 55 msgid_plural "Hello Worlds" 56 msgstr[0] "Hallo Welt im GUI" 57 msgstr[1] "Hallo Welt (plural) im GUI" -
new file libraries/source/tinygettext/test/game/de.po
diff --git a/libraries/source/tinygettext/test/game/de.po b/libraries/source/tinygettext/test/game/de.po new file mode 100644 index 0000000..a92db3b
- + 1 # SOME DESCRIPTIVE TITLE. 2 # Copyright (C) YEAR Free Software Foundation, Inc. 3 # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. 4 # 5 msgid "" 6 msgstr "" 7 "Project-Id-Version: Pingus 0.6.0\n" 8 "Report-Msgid-Bugs-To: \n" 9 "POT-Creation-Date: 2004-04-09 18:37+0000\n" 10 "PO-Revision-Date: 2003-04-15 17:31+0200\n" 11 "Last-Translator: David Philippi <david@torangan.de>\n" 12 "Language-Team: David Philippi <david@torangan.de>, Ingo Ruhnke <grumbel@gmx." 13 "de>, Giray Devlet <giray@devlet.cc>\n" 14 "MIME-Version: 1.0\n" 15 "Content-Type: text/plain; charset=ISO-8859-1\n" 16 "Content-Transfer-Encoding: 8bit\n" 17 18 #: src/actions/bridger.cxx:48 src/actions/bridger.cxx:232 19 #: src/pingu_enums.cxx:40 20 msgid "Bridger" 21 msgstr "Bridger" 22 23 #: src/config.cxx:73 24 msgid "Couldn't open: " 25 msgstr "Datei oder Verzeichnis konnte nicht geöffnet werden: " 26 27 #: src/config.cxx:172 28 msgid "Unexpected char: '" 29 msgstr "Unerwartetes Zeichen: '" 30 31 #: src/config.cxx:206 32 msgid "Unexpected char '" 33 msgstr "Unerwartetes Zeichen: '" 34 35 #: src/credits.cxx:48 36 msgid "-Idea" 37 msgstr "-Idee" 38 39 #: src/credits.cxx:52 40 msgid "-Maintaining" 41 msgstr "-Verwaltung" 42 43 #: src/credits.cxx:56 44 msgid "-Programming" 45 msgstr "-Programmierung" 46 47 #: src/credits.cxx:62 48 msgid "-Porting (Win32)" 49 msgstr "-Portierung (Win32)" 50 51 #: src/credits.cxx:70 52 msgid "-Gfx" 53 msgstr "-Grafiken" 54 55 #: src/credits.cxx:82 56 msgid "-Music" 57 msgstr "-Musik" 58 59 #: src/credits.cxx:88 60 msgid "-Level Design" 61 msgstr "-Level Design" 62 63 #: src/credits.cxx:93 64 msgid "-Story" 65 msgstr "-Geschichte" 66 67 #: src/credits.cxx:97 68 msgid "-Translation" 69 msgstr "-Übersetzung" 70 71 #: src/credits.cxx:112 72 msgid "-Special" 73 msgstr "-Besonderen" 74 75 #: src/credits.cxx:113 76 msgid "-Thanks to" 77 msgstr "-Dank an" 78 79 #: src/credits.cxx:154 80 msgid "_And a very Special Thanks" 81 msgstr "_Und einen besonderen Dank" 82 83 #: src/credits.cxx:155 84 msgid "_to all the people who" 85 msgstr "_an alle Leute die" 86 87 #: src/credits.cxx:156 88 msgid "_contribute to" 89 msgstr "_an Freier Software" 90 91 #: src/credits.cxx:157 92 msgid "_Free Software!" 93 msgstr "_mitarbeiten!" 94 95 #: src/credits.cxx:163 96 msgid "_Thank you for" 97 msgstr "_Dankeschön fürs" 98 99 #: src/credits.cxx:164 100 msgid "_playing!" 101 msgstr "_spielen!" 102 103 #: src/editor/editor_event.cxx:588 104 msgid "Enter filename to save as:" 105 msgstr "Datei speichern als: " 106 107 #: src/editor/editor_help_screen.cxx:43 108 msgid "Editor Helpscreen (hide with F1)" 109 msgstr "Editor Hilfe (ausblenden mit F1)" 110 111 #: src/editor/editor_help_screen.cxx:51 112 msgid "F1 - show/hide this help screen" 113 msgstr "F1 - Hilfe anzeigen/verstecken" 114 115 #: src/editor/editor_help_screen.cxx:52 116 msgid "F2 - launch level building tutorial" 117 msgstr "F2 - Starte Levelbau Tutorial" 118 119 #: src/editor/editor_help_screen.cxx:53 120 msgid "F3 - toggle background color" 121 msgstr "F3 - Hintergrundfarbe aendern" 122 123 #: src/editor/editor_help_screen.cxx:54 124 msgid "F4 - play/test the level" 125 msgstr "F4 - Level starten/testen" 126 127 #: src/editor/editor_help_screen.cxx:55 128 msgid "F5 - load a level" 129 msgstr "Level Laden (F5)" 130 131 #: src/editor/editor_help_screen.cxx:56 132 msgid "F6 - save this level" 133 msgstr "Level Speichern (F6)" 134 135 #: src/editor/editor_help_screen.cxx:57 136 msgid "F7 - [unset]" 137 msgstr "F7 - [nicht belegt]" 138 139 #: src/editor/editor_help_screen.cxx:58 140 msgid "F8 - quick save/backup save?!" 141 msgstr "F8 - Schnellspeichern/Backup" 142 143 #: src/editor/editor_help_screen.cxx:59 144 msgid "F9 - change level width and height" 145 msgstr "F9 - Level Höhe und Breite ändern" 146 147 #: src/editor/editor_help_screen.cxx:60 148 msgid "F10 - [unset]" 149 msgstr "F10 - [nicht belegt]" 150 151 #: src/editor/editor_help_screen.cxx:61 152 msgid "F11 - toggle fps counter" 153 msgstr "F11 - fps Zähler an/aus" 154 155 #: src/editor/editor_help_screen.cxx:62 156 msgid "F12 - make screenshot" 157 msgstr "F12 - Screenshot erstellen" 158 159 #: src/editor/editor_help_screen.cxx:66 160 msgid "Home - increase object size" 161 msgstr "Einfg - Objekt vergrößern" 162 163 #: src/editor/editor_help_screen.cxx:67 164 msgid "End - decrease object size" 165 msgstr "Ende - Objekt verkleinern" 166 167 #: src/editor/editor_help_screen.cxx:68 168 msgid "Cursor Keys - Move object" 169 msgstr "Cursor Tasten - Objekt bewegen" 170 171 #: src/editor/editor_help_screen.cxx:69 172 msgid "Shift 'Cursor Keys' - Move objects fast " 173 msgstr "Shift Cursor Tasten - Objekt schneller bewegen" 174 175 #: src/editor/editor_help_screen.cxx:70 176 msgid "PageUp - level object up" 177 msgstr "Bild rauf - Objekt nach oben" 178 179 #: src/editor/editor_help_screen.cxx:71 180 msgid "PageDown - level object down" 181 msgstr "Bild runter - Objekt nach unten" 182 183 #: src/editor/editor_help_screen.cxx:72 184 msgid "Shift PageUp - increase objects z-pos by 50" 185 msgstr "Shift Bild rauf - Objekt nach oben" 186 187 #: src/editor/editor_help_screen.cxx:73 188 msgid "Shift PageDown - decrease objects z-pos by 50" 189 msgstr "Shift Bild runter - Objekt nach unten" 190 191 #: src/editor/editor_help_screen.cxx:74 192 msgid "Enter - Set default zoom (1:1)" 193 msgstr "Eingabe - Setze Standard Zoom (1:1)" 194 195 #: src/editor/editor_help_screen.cxx:75 196 msgid "d - duplicate object" 197 msgstr "d - Objekt kopieren" 198 199 #: src/editor/editor_help_screen.cxx:76 200 msgid "a - mark all objects" 201 msgstr "a - Alle Objekte markieren" 202 203 #: src/editor/editor_help_screen.cxx:77 204 msgid "shift leftmouseclick - add object to selection" 205 msgstr "Shift + linke Maustaste - Objekt zur Auswahl tun" 206 207 #: src/editor/editor_help_screen.cxx:78 208 msgid "leftmouseclick - select object" 209 msgstr "linke Maustaste - Objekt auswählen" 210 211 #: src/editor/editor_help_screen.cxx:79 212 msgid "Insert - insert new object" 213 msgstr "Einfügen - neues Objekt einfügen" 214 215 #: src/editor/editor_help_screen.cxx:80 216 msgid "Remove - remove selected object" 217 msgstr "Entfernen - entferne ausgewähltes Objekt" 218 219 #: src/editor/editor_help_screen.cxx:81 220 msgid "g - ungroup/group current selection" 221 msgstr "g - Auswahl gruppieren / Gruppierung aufheben" 222 223 #: src/editor/editor_help_screen.cxx:82 224 msgid "Ctrl PageUp - increase objects z-pos by 1" 225 msgstr "Strg Bild rauf - z-pos des Objekts um 1 erhöhen" 226 227 #: src/editor/editor_help_screen.cxx:83 228 msgid "Ctrl PageDown - decrease objects z-pos by 1" 229 msgstr "Strg Bild runter - z-pos des Objekts um 1 senken" 230 231 #: src/editor/editor_help_screen.cxx:89 232 msgid "Naming Convention: <LEVELNAME><NUMBER>-<CREATOR>.plf" 233 msgstr "Dateinamensvorgabe: <LEVELNAME><NUMMER>-<AUTOR>.pfl" 234 235 #: src/editor/editor_help_screen.cxx:91 236 msgid "" 237 "When you have created a level and want to have it in the next Pingus " 238 "release,\n" 239 "please mail it to pingus-devel@nongnu.org." 240 msgstr "" 241 "Falls Du einen Level erstellt hast und ihn gerne im nächsten Pingus\n" 242 "Release hättest, schicke ihn an pingus-devel@nongnu.org." 243 244 #: src/editor/object_selector.cxx:106 245 msgid "1 - guillotine" 246 msgstr "1 - Guillotine" 247 248 #: src/editor/object_selector.cxx:107 249 msgid "2 - hammer" 250 msgstr "2 - Hammer" 251 252 #: src/editor/object_selector.cxx:108 253 msgid "3 - spike" 254 msgstr "3 - Stacheln" 255 256 #: src/editor/object_selector.cxx:109 257 msgid "4 - laser_exit" 258 msgstr "4 - Laser Ausgang" 259 260 #: src/editor/object_selector.cxx:110 261 msgid "5 - fake_exit" 262 msgstr "5 - Täusch Ausgang" 263 264 #: src/editor/object_selector.cxx:111 265 msgid "6 - smasher" 266 msgstr "6 - Stampfer" 267 268 #: src/editor/object_selector.cxx:112 269 msgid "7 - bumper" 270 msgstr "7 - Stosser" 271 272 #: src/editor/object_selector.cxx:186 273 msgid "Select a WorldObj" 274 msgstr "Wähle ein WeltObjekt" 275 276 #: src/editor/object_selector.cxx:187 277 msgid "1 - teleporter" 278 msgstr "1 - Teleporter" 279 280 #: src/editor/object_selector.cxx:188 281 msgid "2 - switch and door" 282 msgstr "2 - Schalter und Tür" 283 284 #: src/editor/object_selector.cxx:189 285 msgid "3 - ConveyorBelt" 286 msgstr "3 - Förderband" 287 288 #: src/editor/object_selector.cxx:190 289 msgid "4 - IceBlock" 290 msgstr "4 - Eisblock" 291 292 #: src/editor/object_selector.cxx:191 293 msgid "5 - InfoBox" 294 msgstr "5 - InfoBox" 295 296 #: src/editor/object_selector.cxx:232 297 msgid "Select a weather" 298 msgstr "Wähle ein Wetter" 299 300 #: src/editor/object_selector.cxx:233 301 msgid "1 - snow" 302 msgstr "1 - Schnee" 303 304 #: src/editor/object_selector.cxx:234 305 msgid "2 - rain" 306 msgstr "2 - Regen" 307 308 #: src/editor/object_selector.cxx:265 309 msgid "Select an entrance" 310 msgstr "Wähle einen Eingang" 311 312 #: src/editor/object_selector.cxx:266 313 msgid "1 - generic" 314 msgstr "1 - allgemein" 315 316 #: src/editor/object_selector.cxx:267 317 msgid "2 - woodthing" 318 msgstr "2 - hölzern" 319 320 #: src/editor/object_selector.cxx:268 321 msgid "3 - cloud" 322 msgstr "3 - Wolke" 323 324 #: src/editor/object_selector.cxx:269 325 msgid "h - entrance surface (hotspot)" 326 msgstr "h - Eingangs Grafik (hotspot)" 327 328 #: src/editor/object_selector.cxx:343 329 msgid "What object type do you want?" 330 msgstr "Was für ein Objekt willst du?" 331 332 #: src/editor/object_selector.cxx:344 src/editor/object_selector.cxx:400 333 msgid "h - Hotspot" 334 msgstr "h - Grafikelement (hotspot)" 335 336 #: src/editor/object_selector.cxx:345 337 msgid "g - Groundpiece (ground) [not implemented]" 338 msgstr "g - Bodenstück (ground) [nicht implementiert]" 339 340 #: src/editor/object_selector.cxx:394 src/editor/object_selector.cxx:562 341 msgid "Which object do you want?" 342 msgstr "Welches Objekt willst du?" 343 344 #: src/editor/object_selector.cxx:395 345 msgid "g - Groundpiece (ground)" 346 msgstr "g - Bodenstück (ground)" 347 348 #: src/editor/object_selector.cxx:396 349 msgid "s - Groundpiece (solid)" 350 msgstr "s - Bodenelement (Stahl)" 351 352 #: src/editor/object_selector.cxx:397 353 msgid "b - Groundpiece (bridge)" 354 msgstr "b - Bodenelement (Bruecke)" 355 356 #: src/editor/object_selector.cxx:398 357 msgid "n - Groundpiece (transparent)" 358 msgstr "n - Bodenelement (transparent)" 359 360 #: src/editor/object_selector.cxx:399 361 msgid "r - Groundpiece (remove)" 362 msgstr "r - Bodenelement (entfernen)" 363 364 #: src/editor/object_selector.cxx:401 365 msgid "e - Entrance" 366 msgstr "e - Eingang" 367 368 #: src/editor/object_selector.cxx:402 369 msgid "x - Exit" 370 msgstr "x - Ausgang" 371 372 #: src/editor/object_selector.cxx:403 373 msgid "l - Liquid" 374 msgstr "l - Flüssigkeit" 375 376 #: src/editor/object_selector.cxx:404 377 msgid "w - Weather" 378 msgstr "w - Wetter" 379 380 #: src/editor/object_selector.cxx:405 381 msgid "t - Traps" 382 msgstr "t - Falle" 383 384 #: src/editor/object_selector.cxx:406 385 msgid "o - WorldObject" 386 msgstr "o - WeltObjekt" 387 388 #: src/editor/object_selector.cxx:407 389 msgid "z - Background" 390 msgstr "z - Hintergrund" 391 392 #: src/editor/object_selector.cxx:408 393 msgid "p - Prefab (ObjectGroup)" 394 msgstr "p - Prefab (Objekt Gruppe)" 395 396 #: src/editor/object_selector.cxx:409 397 msgid "f - something from file (~/.pingus/images/)" 398 msgstr "f - etwas aus einer Datei (~/.pingus/images/)" 399 400 #: src/editor/object_selector.cxx:498 401 msgid "Which prefab do you want?" 402 msgstr "Welche Prefab willst du?" 403 404 #: src/editor/object_selector.cxx:563 405 msgid "1 - Surface Background" 406 msgstr "1 - Bild Hintergrund" 407 408 #: src/editor/object_selector.cxx:564 409 msgid "2 - Solid Color Background" 410 msgstr "2 - Farb Hintergrund" 411 412 #: src/editor/object_selector.cxx:565 413 msgid "3 - Starfield Background" 414 msgstr "3 - Sternen Hintergrund" 415 416 #: src/editor/object_selector.cxx:566 417 msgid "4 - Thunderstorm Background" 418 msgstr "4 - Gewitter Hintergrund" 419 420 #: src/editor/panel_icons.cxx:33 421 msgid "Load a level (F5)" 422 msgstr "Level laden (F5)" 423 424 #: src/editor/panel_icons.cxx:46 425 msgid "Exit the editor (Escape)" 426 msgstr "Editor Beenden (Esc)" 427 428 #: src/editor/panel_icons.cxx:58 429 msgid "Save this level (F6)" 430 msgstr "Level Speichern (F6)" 431 432 #: src/editor/panel_icons.cxx:70 433 msgid "Delete marked objects (delete)" 434 msgstr "Markierte Objekte Löschen (Entfernen)" 435 436 #: src/editor/panel_icons.cxx:82 437 msgid "Duplicate current object (d)" 438 msgstr "Aktuelles Object kopieren (d)" 439 440 #: src/editor/panel_icons.cxx:94 441 msgid "Edit Level Properties" 442 msgstr "Leveleigenschaften ändern" 443 444 #: src/editor/panel_icons.cxx:106 445 msgid "Edit Object Properties" 446 msgstr "Objekteigenschaften ändern" 447 448 #: src/editor/panel_icons.cxx:118 449 msgid "Start the level and test it (F4)" 450 msgstr "Level starten und testen (F4)" 451 452 #: src/editor/panel_icons.cxx:130 453 msgid "Create a new level from scratch" 454 msgstr "Neuen Level erstellen" 455 456 #: src/editor/panel_icons.cxx:142 457 msgid "Insert an object (Insert)" 458 msgstr "Objekt einfuegen (Einfg)" 459 460 #: src/editor/panel_icons.cxx:154 461 msgid "Zoom into a region" 462 msgstr "Einen Bereich vergrössern" 463 464 #: src/editor/panel_icons.cxx:166 465 msgid "Zoom in" 466 msgstr "Vergroessern" 467 468 #: src/editor/panel_icons.cxx:179 469 msgid "Zoom out" 470 msgstr "Verkleinern" 471 472 #: src/editor/panel_icons.cxx:192 473 msgid "Setup Number of Actions" 474 msgstr "Stelle die Anzahl der Fähigkeiten ein" 475 476 #: src/editor/panel_icons.cxx:204 477 msgid "Display Help Screen (F1)" 478 msgstr "Hilfe Anzeigen (F1)" 479 480 #: src/exit_menu.cxx:48 481 msgid "Yes" 482 msgstr "Ja" 483 484 #: src/exit_menu.cxx:81 485 msgid "No" 486 msgstr "Nein" 487 488 #: src/exit_menu.cxx:114 489 msgid "Exit Pingus?" 490 msgstr "Pingus beenden?" 491 492 #: src/fps_counter.cxx:48 493 msgid "unknown" 494 msgstr "unbekannt" 495 496 #: src/game_time.cxx:70 497 msgid "unlimited" 498 msgstr "unbegrenzt" 499 500 #: src/level_desc.cxx:74 501 msgid "Designed by " 502 msgstr "Erstellt von " 503 504 #: src/level_desc.cxx:79 505 #, c-format 506 msgid "Pingus to Save: %d" 507 msgstr "Zu rettende Pingus: %d" 508 509 #: src/level_desc.cxx:81 510 #, c-format 511 msgid "Number of Pingus: %d" 512 msgstr "Anzahl an Pingus: %d" 513 514 #: src/level_desc.cxx:86 515 msgid "Loading..." 516 msgstr "Ladevorgang läuft..." 517 518 #: src/level_desc.cxx:89 519 msgid "Loading finished. Press a mouse button to start the level" 520 msgstr "" 521 "Ladevorgang abgeschlossen. Drücke eine Maus Taste um den Level zu starten" 522 523 #: src/level_result.cxx:61 524 msgid "Results:" 525 msgstr "Ergebnisse:" 526 527 #: src/level_result.cxx:67 528 #, c-format 529 msgid "Pingus saved: %3d/%3d" 530 msgstr "Gerettete Pingus: %3d/%3d" 531 532 #: src/level_result.cxx:72 533 #, c-format 534 msgid "Pingus died: %3d/%3d" 535 msgstr "Tote Pingus: %3d/%3d" 536 537 #: src/level_result.cxx:88 538 msgid "Press button to continue..." 539 msgstr "Knopf drücken um fortzufahren" 540 541 #: src/level_result.cxx:102 542 msgid "" 543 "As many Pingus escaped as entered the level. That's going to be hard to " 544 "beat.... unless this game becomes pornographic." 545 msgstr "" 546 "Es wurden alle Pingu dieses Levels gerettet. Das wird hart zu schlagen " 547 "sein... es sei denn dieses Spiel wird pornographisch." 548 549 #: src/level_result.cxx:104 550 msgid "Very impressive indeed." 551 msgstr "In der Tat sehr eindrucksvoll." 552 553 #: src/level_result.cxx:106 554 msgid "Good work. Still room for improvement though." 555 msgstr "Gute Arbeit. Aber Übung macht den Meiser!" 556 557 #: src/level_result.cxx:108 558 msgid "Not too shabby, not too shabby at all." 559 msgstr "Nicht schlecht, nicht schlecht!" 560 561 #: src/level_result.cxx:110 562 msgid "" 563 "That was OK, but Pingu life insurance premiums have just gotten more " 564 "expensive." 565 msgstr "" 566 "Das war ok, aber die Lebensversicherungsprämien für Pingus sind gerade " 567 "gestiegen." 568 569 #: src/level_result.cxx:112 570 msgid "Maybe this level calls for a different strategy." 571 msgstr "Möglicherweise verlangt dieser Level eine andere Strategie." 572 573 #: src/level_result.cxx:114 574 msgid "Exactly half. Are you saving only the female ones?" 575 msgstr "Genau die Hälfte! Rettest du nur die Weibchen?" 576 577 #: src/level_result.cxx:116 578 msgid "If I were a Pingu, I never would have left that entrance." 579 msgstr "Wenn ich ein Pingu wäre, hätte ich den Eingang nie verlassen." 580 581 #: src/level_result.cxx:118 582 msgid "Maybe you would feel more at home playing Quake." 583 msgstr "Möglicherweise wäre es besser Quake zu spielen?" 584 585 #: src/level_result.cxx:120 586 msgid "" 587 "Maybe this level calls for a different strategy. Like attempting to save " 588 "them, for example." 589 msgstr "" 590 "Es kann sein, dass wir etwas anderes versuchen sollten. Vielleicht könnten " 591 "wir ja die Pingus retten?" 592 593 #: src/level_result.cxx:122 594 msgid "Ever considered a career as a Pingu exterminator?" 595 msgstr "Hast du mal über eine Karriere als Pingu Zerstörer nachgedacht?" 596 597 #: src/level_result.cxx:124 598 msgid "You missed one! What's your excuse!?" 599 msgstr "Du hast einen vergessen! Was ist deine Entschuldigung?" 600 601 #: src/level_result.cxx:126 602 msgid "Please reassure me that you hit the Armageddon button." 603 msgstr "Bestätige mir bitte, dass das die Armageddon Taste war." 604 605 #: src/level_result.cxx:128 606 msgid "You've got a negative save/total value, something is buggy." 607 msgstr "Ein negativer Wert? Hier liegt ein Fehler vor." 608 609 #: src/menu_button.cxx:181 610 msgid "..:: The people who brought this game to you ::.." 611 msgstr "..:: Die Leute, die fuer dieses Spiel verantwortlich sind... ::.." 612 613 #: src/menu_button.cxx:184 614 msgid "Credits" 615 msgstr "Mitwirkende" 616 617 #: src/menu_button.cxx:216 618 msgid "..:: Takes you to the options menu ::.." 619 msgstr "..:: Einstellungen, Cheats und Debugging stuff ::.." 620 621 #: src/menu_button.cxx:219 622 msgid "Options" 623 msgstr "Einstellungen" 624 625 #: src/menu_button.cxx:252 626 msgid "..:: Bye, bye ::.." 627 msgstr "..:: Auf Wiedersehen ::.." 628 629 #: src/menu_button.cxx:255 630 msgid "Exit" 631 msgstr "Beenden" 632 633 #: src/menu_button.cxx:306 634 msgid "..:: Launch the level editor ::.." 635 msgstr "..:: Erstelle deinen eigenen Level ::.." 636 637 #: src/menu_button.cxx:309 638 msgid "Create a" 639 msgstr "Bau einen" 640 641 #: src/menu_button.cxx:310 642 msgid "Level" 643 msgstr "Level" 644 645 #: src/menu_button.cxx:344 646 msgid "..:: Start the game ::.." 647 msgstr "..:: das Spiel starten ::.." 648 649 #: src/menu_button.cxx:345 650 msgid "Start" 651 msgstr "Start" 652 653 #: src/menu_button.cxx:375 654 msgid "..:: Start a contrib level ::.." 655 msgstr "..:: Contrib level Spielen ::.." 656 657 #: src/menu_button.cxx:377 658 msgid "Contrib" 659 msgstr "Levels" 660 661 #: src/menu_button.cxx:399 662 msgid "..:: Multiplayer Modes... experimental stuff ::.." 663 msgstr "..:: Mehrspieler Modus ::.. Experimentelles Zeug ::.." 664 665 #: src/menu_button.cxx:401 666 msgid "Multi" 667 msgstr "Multi" 668 669 #: src/pingu_enums.cxx:35 670 msgid "Angel" 671 msgstr "Angel" 672 673 #: src/pingu_enums.cxx:36 674 msgid "Basher" 675 msgstr "Basher" 676 677 #: src/pingu_enums.cxx:37 678 msgid "Blocker" 679 msgstr "Blocker" 680 681 #: src/pingu_enums.cxx:38 682 msgid "Boarder" 683 msgstr "Boarder" 684 685 #: src/pingu_enums.cxx:39 686 msgid "Bomber" 687 msgstr "Bomber" 688 689 #: src/pingu_enums.cxx:41 690 msgid "Climber" 691 msgstr "Climber" 692 693 #: src/pingu_enums.cxx:42 694 msgid "Digger" 695 msgstr "Digger" 696 697 #: src/pingu_enums.cxx:43 698 msgid "Drown" 699 msgstr "Drown" 700 701 #: src/pingu_enums.cxx:44 702 msgid "Exiter" 703 msgstr "Exiter" 704 705 #: src/pingu_enums.cxx:45 706 msgid "Faller" 707 msgstr "Faller" 708 709 #: src/pingu_enums.cxx:46 710 msgid "Floater" 711 msgstr "Floater" 712 713 #: src/pingu_enums.cxx:47 714 msgid "Jumper" 715 msgstr "Jumper" 716 717 #: src/pingu_enums.cxx:48 718 msgid "Laserkill" 719 msgstr "Laserkill" 720 721 #: src/pingu_enums.cxx:49 722 msgid "Miner" 723 msgstr "Miner" 724 725 #: src/pingu_enums.cxx:50 726 msgid "Rocketlauncher" 727 msgstr "Rocketlauncher" 728 729 #: src/pingu_enums.cxx:51 730 msgid "Slider" 731 msgstr "Slider" 732 733 #: src/pingu_enums.cxx:52 734 msgid "Smashed" 735 msgstr "Smashed" 736 737 #: src/pingu_enums.cxx:53 738 msgid "Splashed" 739 msgstr "Splashed" 740 741 #: src/pingu_enums.cxx:54 742 msgid "Superman" 743 msgstr "Superman" 744 745 #: src/pingu_enums.cxx:55 746 msgid "Teleported" 747 msgstr "Teleported" 748 749 #: src/pingu_enums.cxx:56 750 msgid "Waiter" 751 msgstr "Waiter" 752 753 #: src/pingu_enums.cxx:57 754 msgid "Walker" 755 msgstr "Walker" 756 757 #: src/pingus_counter.cxx:52 758 #, c-format 759 msgid "Released:%3d/%-3d Out:%3d Saved:%3d/%-3d" 760 msgstr "Rein: %3d/%-3d Raus: %3d Gerettet: %3d/%-3d" 761 762 #: src/pingus_main.cxx:90 763 msgid "| segfault_handler: catched a SIGSEGV." 764 msgstr "| segfault_handler: SIGSEGV abgefangen." 765 766 #: src/pingus_main.cxx:92 767 msgid "| Woops, Pingus just crashed, congratulations you've found a bug." 768 msgstr "" 769 "| Woops, Pingus ist abgestürzt. Gratuliere, du hast einen Bug gefunden." 770 771 #: src/pingus_main.cxx:93 772 msgid "" 773 "| Please write a little bug report to <grumbel@gmx.de>, include informations" 774 msgstr "" 775 "| Bitte schreibe einen kleinen Report an <pingus-devel@nongnu.org, mit " 776 "Informationen," 777 778 #: src/pingus_main.cxx:94 779 msgid "| where exacly the SIGSEGV occured and how to reproduce it." 780 msgstr "| wo genau der SIGSEGV auftrat und wie man ihn reproduziert." 781 782 #: src/pingus_main.cxx:95 783 msgid "| Also try include a backtrace, you can get it like this:" 784 msgstr "| Versuche auch einen backtrace zu erstellen, du bekommst ihn so:" 785 786 #: src/pingus_main.cxx:101 787 msgid "| If that doesn't work, try this:" 788 msgstr "| Wenn das nicht geht, versuche dies:" 789 790 #: src/pingus_main.cxx:105 791 msgid "| [play until it crashes again]" 792 msgstr "| [spiele bis es wieder crasht]" 793 794 #: src/pingus_main.cxx:113 795 msgid "| Warning: Pingus recieved a SIGINT, exiting now." 796 msgstr "| Warnung: Pingus erhielt einen SIGINT, beende jetzt." 797 798 #: src/pingus_main.cxx:301 799 msgid "Warning: Larger resolution than 800x600 will result in visual problems" 800 msgstr "" 801 "Warnung: Auflösungen grösser als 800x600 können zu visuellen Problemen führen" 802 803 #: src/pingus_main.cxx:488 804 msgid "Unknow char: " 805 msgstr "Unbekannter Buchstabe: " 806 807 #: src/pingus_main.cxx:489 808 msgid "Usage: " 809 msgstr "Benutzung: " 810 811 #: src/pingus_main.cxx:489 812 msgid " [OPTIONS]... [LEVELFILE]" 813 msgstr "[OPTIONEN]... [LEVELDATEI]" 814 815 #: src/pingus_main.cxx:492 816 msgid "Options:" 817 msgstr "Einstellungen" 818 819 #: src/pingus_main.cxx:494 820 msgid "Set the resolution for pingus (default: 800x600)" 821 msgstr "Setze die Auflösung für Pingus (Standard: 800x600)" 822 823 #: src/pingus_main.cxx:495 824 msgid "Displays this help" 825 msgstr "Hilfe Anzeigen" 826 827 #: src/pingus_main.cxx:496 828 msgid "Disable intro" 829 msgstr "Intro abschalten" 830 831 #: src/pingus_main.cxx:497 832 msgid "Use OpenGL" 833 msgstr "OpenGL benutzen" 834 835 #: src/pingus_main.cxx:499 836 msgid "Start in Window Mode" 837 msgstr "Pingus im Fenster starten" 838 839 #: src/pingus_main.cxx:500 840 msgid "Start in Fullscreen" 841 msgstr "Pingus im Vollbild starten" 842 843 #: src/pingus_main.cxx:504 844 msgid "FILE " 845 msgstr "Datei " 846 847 #: src/pingus_main.cxx:504 848 msgid "Load a custom level from FILE" 849 msgstr "Einen Level aus DATEI laden" 850 851 #: src/pingus_main.cxx:505 852 msgid "FILE " 853 msgstr "Datei " 854 855 #: src/pingus_main.cxx:505 856 msgid "Load a custom worldmap from FILE" 857 msgstr "Eine Weltkarte aus DATEI laden" 858 859 #: src/pingus_main.cxx:506 860 msgid "Print some more messages to stdout, can be set" 861 msgstr "Gibt mehr Nachrichten auf stdout aus, kann" 862 863 #: src/pingus_main.cxx:507 864 msgid "multiple times to increase verbosity" 865 msgstr "mehrmals gesetzt werden, um die Genauigkeit zu erhöhen" 866 867 #: src/pingus_main.cxx:508 868 msgid "Prints version number and exit" 869 msgstr "Version ausgeben und beenden" 870 871 #: src/pingus_main.cxx:509 872 msgid "Launch the Level editor (experimental)" 873 msgstr "Level Editor starten (Experimentell)" 874 875 #: src/pingus_main.cxx:510 876 msgid "Disable automatic scrolling" 877 msgstr "Automatisches Scrollen abschalten" 878 879 #: src/pingus_main.cxx:512 880 msgid "Enable software cursor" 881 msgstr "Aktiviere Software Cursor" 882 883 #: src/pingus_main.cxx:515 884 msgid "Don't read ~/.pingus/config" 885 msgstr "~/.pingus/config nicht einlesen" 886 887 #: src/pingus_main.cxx:516 888 msgid "FILE " 889 msgstr "Datei " 890 891 #: src/pingus_main.cxx:516 892 msgid "Read config from FILE (default: ~/.pingus/config)" 893 msgstr "Konfiguration aus DATEI lesen" 894 895 #: src/pingus_main.cxx:517 896 msgid "reduce CPU usage, might speed up the game on slower machines" 897 msgstr "" 898 "reduziere CPU Belastung, könnte das Spiel auf langsamen Rechnern " 899 "beschleunigen" 900 901 #: src/pingus_main.cxx:518 902 msgid "Uses the controller given in FILE" 903 msgstr "Controller aus FILE benutzen" 904 905 #: src/pingus_main.cxx:520 906 msgid "Debugging and experimental stuff:" 907 msgstr "Debug und Experimentelles Zeug" 908 909 #: src/pingus_main.cxx:521 910 msgid "Enables some features, only interesting programmers" 911 msgstr "Aktiviere einige Funktionen, nur für Programmierer" 912 913 #: src/pingus_main.cxx:522 914 msgid "Enable the output of debugging infos, possible" 915 msgstr "Aktiviere die Ausgabe von Debug Informationen, mögliche" 916 917 #: src/pingus_main.cxx:523 918 msgid "OPTION's are tiles, gametime, actions, sound, resources, gui," 919 msgstr "Optionen sind tiles, gametime, actions, sound, resources, gui," 920 921 #: src/pingus_main.cxx:525 922 msgid "Skip at least N frames, larger values speed the game up" 923 msgstr "" 924 "Überspringe mindestens N Bilder, größere Werte erhöhen die Geschwindigkeit" 925 926 #: src/pingus_main.cxx:526 927 msgid "Skip at most N frames" 928 msgstr "Überspringe maximal N Bilder" 929 930 #: src/pingus_main.cxx:527 931 msgid "Set both min and max frameskip to N" 932 msgstr "Setze sowohl minimalen als auch maximalen Bildsprung auf N" 933 934 #: src/pingus_main.cxx:528 935 msgid "Set the game speed (0=fastest, >0=slower)" 936 msgstr "Setze die Geschwindigkeit (0=schnellste, >0=langsamer)" 937 938 #: src/pingus_main.cxx:529 939 msgid "Prints the fps to stdout" 940 msgstr "Schreibe die fps auf stdout" 941 942 #: src/pingus_main.cxx:530 943 msgid "Set the size of the map tiles (default: 32)" 944 msgstr "Setze die Größe der Kartenteile (Standard: 32)" 945 946 #: src/pingus_main.cxx:531 947 msgid "Disable some cpu intensive features" 948 msgstr "Deaktivere einige CPU intensive Funktionen" 949 950 #: src/pingus_main.cxx:532 951 msgid "Reduces the CPU usage by issuing sleep()" 952 msgstr "Reduziert die CPU Belastung durch Verwendung von sleep()" 953 954 #: src/pingus_main.cxx:534 955 msgid "Demo playing and recording:" 956 msgstr "Demo aufzeichnung und wiedergabe:" 957 958 #: src/pingus_main.cxx:535 959 msgid "FILE " 960 msgstr "Datei " 961 962 #: src/pingus_main.cxx:535 963 msgid "Plays a demo session from FILE" 964 msgstr "Spielt eine Demo Sitzung aus FILE" 965 966 #: src/pingus_main.cxx:537 967 msgid "Record demos for each played level" 968 msgstr "Nehme Demos für jeden gespielten Level auf" 969 970 #: src/pingus_main.cxx:539 971 msgid "Sound:" 972 msgstr "Sound" 973 974 #: src/pingus_main.cxx:540 975 msgid "Disable sound" 976 msgstr "Sound deaktivieren" 977 978 #: src/pingus_main.cxx:541 979 msgid "Disable music" 980 msgstr "Musik deaktivieren" 981 982 #: src/pingus_main.cxx:720 983 msgid "clanVorbis support: ok" 984 msgstr "clanVorbis Unterstützung: ok" 985 986 #: src/pingus_main.cxx:722 987 msgid "clanVoribs support: missing (.ogg music files will not be playable)" 988 msgstr "" 989 "clanVorbis Unterstützung: fehlt (.ogg Musik Datein können nicht abgespielt " 990 "werden)" 991 992 #: src/pingus_main.cxx:726 993 msgid "clanMikMod support: ok" 994 msgstr "clanMikMod Unterstützung: ok" 995 996 #: src/pingus_main.cxx:728 997 msgid "clanMikMod support: missing (music files will not be playable)" 998 msgstr "" 999 "clanMikMod Untersützung: fehlt (Musikdateien können nicht abgespielt werden)" 1000 1001 #: src/pingus_main.cxx:732 1002 msgid "getext support: ok" 1003 msgstr "gettext Unterstützung: ok" 1004 1005 #: src/pingus_main.cxx:733 1006 msgid "gettext language: english" 1007 msgstr "gettext Sprache: deutsch" 1008 1009 #: src/pingus_main.cxx:739 1010 msgid "sound support: enabled" 1011 msgstr "Sound Unterstützung: an" 1012 1013 #: src/pingus_main.cxx:741 1014 msgid "sound support: disabled" 1015 msgstr "Sound Unterstützung: aus" 1016 1017 #: src/pingus_main.cxx:744 1018 msgid "music support: enabled" 1019 msgstr "Musik Unterstützung: an" 1020 1021 #: src/pingus_main.cxx:746 1022 msgid "music support: disabled" 1023 msgstr "Musik Unterstützung: aus" 1024 1025 #: src/pingus_main.cxx:748 1026 msgid "resolution set to: " 1027 msgstr "Auflösung: " 1028 1029 #: src/pingus_main.cxx:749 1030 msgid "fullscreen: " 1031 msgstr "Vollbild: " 1032 1033 #: src/pingus_main.cxx:750 1034 msgid " enabled" 1035 msgstr "aktiviert" 1036 1037 #: src/pingus_main.cxx:750 1038 msgid "disabled" 1039 msgstr "deaktiviert" 1040 -
new file libraries/source/tinygettext/test/helloworld.cpp
diff --git a/libraries/source/tinygettext/test/helloworld.cpp b/libraries/source/tinygettext/test/helloworld.cpp new file mode 100644 index 0000000..071ab96
- + 1 #include <iostream> 2 3 #define _(x) gettext(x) 4 5 int main() 6 { 7 std::cout << _("Short Hello World") << std::endl; 8 std::cout << gettext("Hello World") << std::endl; 9 std::cout << gettext("Hello Worlds") << std::endl; 10 11 std::cout << pgettext("", "Hello World") << std::endl; 12 std::cout << pgettext("console", "Hello World") << std::endl; 13 14 std::cout << ngettext("gui", "Hello World") << std::endl; 15 std::cout << ngettext("Hello World", "Hello Worlds", 5) << std::endl; 16 17 std::cout << npgettext("", "Hello World", "Hello Worlds", 5) << std::endl; 18 std::cout << npgettext("console", "Hello World", "Hello Worlds", 5) << std::endl; 19 std::cout << npgettext("gui", "Hello World", "Hello Worlds", 5) << std::endl; 20 21 return 0; 22 } 23 24 /* EOF */ -
new file libraries/source/tinygettext/test/helloworld/de.po
diff --git a/libraries/source/tinygettext/test/helloworld/de.po b/libraries/source/tinygettext/test/helloworld/de.po new file mode 100644 index 0000000..048acc6
- + 1 # SOME DESCRIPTIVE TITLE. 2 # Copyright (C) YEAR Free Software Foundation, Inc. 3 # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. 4 # 5 #, fuzzy 6 msgid "" 7 msgstr "" 8 "Project-Id-Version: PACKAGE VERSION\n" 9 "Report-Msgid-Bugs-To: \n" 10 "POT-Creation-Date: 2009-01-30 08:01+0100\n" 11 "PO-Revision-Date: 2009-01-30 08:39+0100\n" 12 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" 13 "Language-Team: LANGUAGE <LL@li.org>\n" 14 "MIME-Version: 1.0\n" 15 "Content-Type: text/plain; charset=UTF-8\n" 16 "Content-Transfer-Encoding: 8bit\n" 17 18 #: helloworld.cpp:7 19 msgid "Short Hello World" 20 msgstr "kurzes Hallo Welt" 21 22 #: helloworld.cpp:8 helloworld.cpp:14 23 #, fuzzy 24 msgid "Hello World" 25 msgid_plural "Hello Worlds" 26 msgstr[0] "Hallo Welt (singular)" 27 msgstr[1] "Hallo Welt (plural)" 28 29 #: helloworld.cpp:10 helloworld.cpp:16 30 #, fuzzy 31 msgctxt "" 32 msgid "Hello World" 33 msgid_plural "Hello Worlds" 34 msgstr[0] "Hallo Welt (singular) mit leerem Kontext" 35 msgstr[1] "Hallo Welt (plural) mit leerem Kontext" 36 37 #: helloworld.cpp:11 helloworld.cpp:17 38 msgctxt "console" 39 msgid "Hello World" 40 msgid_plural "Hello Worlds" 41 msgstr[0] "Hallo Welt (singular) in der Console" 42 msgstr[1] "Hallo Welt (plural) in der Console" 43 44 #: helloworld.cpp:13 45 msgid "gui" 46 msgid_plural "Hello World" 47 msgstr[0] "Hallo Welt (singular)" 48 msgstr[1] "Hallo Welt (plural)" 49 50 #: helloworld.cpp:18 51 #, fuzzy 52 msgctxt "gui" 53 msgid "Hello World" 54 msgid_plural "Hello Worlds" 55 msgstr[0] "Hallo Welt im GUI" 56 msgstr[1] "Hallo Welt (plural) im GUI" -
new file libraries/source/tinygettext/test/helloworld/helloworld.pot
diff --git a/libraries/source/tinygettext/test/helloworld/helloworld.pot b/libraries/source/tinygettext/test/helloworld/helloworld.pot new file mode 100644 index 0000000..a9174f8
- + 1 # SOME DESCRIPTIVE TITLE. 2 # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER 3 # This file is distributed under the same license as the PACKAGE package. 4 # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. 5 # 6 #, fuzzy 7 msgid "" 8 msgstr "" 9 "Project-Id-Version: PACKAGE VERSION\n" 10 "Report-Msgid-Bugs-To: \n" 11 "POT-Creation-Date: 2009-01-30 08:10+0100\n" 12 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 13 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" 14 "Language-Team: LANGUAGE <LL@li.org>\n" 15 "MIME-Version: 1.0\n" 16 "Content-Type: text/plain; charset=CHARSET\n" 17 "Content-Transfer-Encoding: 8bit\n" 18 "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" 19 20 #: helloworld.cpp:7 21 msgid "Short Hello World" 22 msgstr "" 23 24 #: helloworld.cpp:8 helloworld.cpp:14 25 msgid "Hello World" 26 msgid_plural "Hello Worlds" 27 msgstr[0] "" 28 msgstr[1] "" 29 30 #: helloworld.cpp:10 helloworld.cpp:16 31 msgctxt "" 32 msgid "Hello World" 33 msgid_plural "Hello Worlds" 34 msgstr[0] "" 35 msgstr[1] "" 36 37 #: helloworld.cpp:11 helloworld.cpp:17 38 msgctxt "console" 39 msgid "Hello World" 40 msgid_plural "Hello Worlds" 41 msgstr[0] "" 42 msgstr[1] "" 43 44 #: helloworld.cpp:13 45 msgid "gui" 46 msgid_plural "Hello World" 47 msgstr[0] "" 48 msgstr[1] "" 49 50 #: helloworld.cpp:18 51 msgctxt "gui" 52 msgid "Hello World" 53 msgid_plural "Hello Worlds" 54 msgstr[0] "" 55 msgstr[1] "" -
new file libraries/source/tinygettext/test/level/de.po
diff --git a/libraries/source/tinygettext/test/level/de.po b/libraries/source/tinygettext/test/level/de.po new file mode 100644 index 0000000..69e0206
- + 1 # SOME DESCRIPTIVE TITLE. 2 # Copyright (C) YEAR Free Software Foundation, Inc. 3 # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. 4 # 5 #, fuzzy 6 msgid "" 7 msgstr "" 8 "Project-Id-Version: PACKAGE VERSION\n" 9 "PO-Revision-Date: YEAR-MO-DA HO:MI +ZONE\n" 10 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" 11 "Language-Team: LANGUAGE <LL@li.org>\n" 12 "MIME-Version: 1.0\n" 13 "Content-Type: text/plain; charset=CHARSET\n" 14 "Content-Transfer-Encoding: 8bit\n" 15 16 #: src/pingus_main.cxx:760 17 msgid "PingusMain: Starting Main: " 18 msgstr "PingusMain: Hauptteil wird gestartet: " 19 20 #: src/pingus_main.cxx:805 21 msgid "PingusMain: Levelfile not found, ignoring: " 22 msgstr "PingusMain: Leveldatei nicht gefunden, Fehler wird ignoriert: " 23 24 #: src/pingus_main.cxx:909 25 msgid "Error caught from ClanLib: " 26 msgstr "ClanLib Fehler abgefangen: " 27 28 #: src/pingus_main.cxx:913 29 msgid "Error caught from Pingus: " 30 msgstr "Pingus Fehler wurde abgefangen: " 31 32 #: src/pingus_main.cxx:917 33 msgid "Pingus: Out of memory!" 34 msgstr "Pingus: Speicher ist ausgegangen" 35 36 #: src/pingus_main.cxx:921 37 msgid "Pingus: Standard exception caught!:\n" 38 msgstr "Pingus: Standard Ausnahme abgefangen!:\n" 39 40 #: src/pingus_main.cxx:925 41 msgid "Pingus: Unknown throw caught!" 42 msgstr "Pingus: Unbekannte Ausnahme abgefangen!" 43 44 #: src/result_screen.cxx:99 src/start_screen.cxx:111 45 msgid "Abort" 46 msgstr "Abbruch" 47 48 #: src/result_screen.cxx:167 49 msgid "Retry" 50 msgstr "Versuche erneut" 51 52 #: src/result_screen.cxx:175 53 msgid "Success!" 54 msgstr "Erfolg!" 55 56 #: src/result_screen.cxx:182 57 msgid "Failure!" 58 msgstr "Fehler!" 59 60 #: src/result_screen.cxx:191 61 msgid "Perfect! You saved everyone possible - great!" 62 msgstr "Perfekt! Du hast alle gerettet!" 63 64 #: src/result_screen.cxx:193 65 msgid "No-one got killed, pretty good work." 66 msgstr "Keiner wurde getötet, sehr gute Arbeit." 67 68 #: src/result_screen.cxx:195 69 msgid "" 70 "You saved exactly what you needed - you made it, but\n" 71 "maybe you can do better?" 72 msgstr "" 73 "Du hast so viele gerettet wie nötig. Du hast es\n" 74 "geschafft, aber vielleicht kannst Du es noch besser?" 75 76 #: src/result_screen.cxx:198 77 msgid "Not everybody was saved, but still good work!" 78 msgstr "Nicht alle wurden gerettet, aber trotzdem noch gute Arbeit!" 79 80 #: src/result_screen.cxx:200 81 msgid "What can I say, you made it - congratulations!" 82 msgstr "Was soll ich sagen, Du hast es geschafft. Gratuliere!" 83 84 #: src/result_screen.cxx:205 85 msgid "You killed everybody, not good." 86 msgstr "Du hast alle getötet, nicht gut." 87 88 #: src/result_screen.cxx:207 89 msgid "No-one got saved - I know you can do better." 90 msgstr "Keiner wurde gerettet, ich weiß, dass du es besser kannst." 91 92 #: src/result_screen.cxx:209 93 msgid "" 94 "You didn't save enough, but you saved a few. Next\n" 95 "time you might do better." 96 msgstr "" 97 "Du hast nicht genug gerettet, aber immerhin ein paar.\n" 98 "Nächstes Mal machst du es bestimmt besser." 99 100 #: src/result_screen.cxx:212 101 msgid "Only one more and you would have made it - try again!" 102 msgstr "Einer mehr und du hast es, versuch es nochmal!" 103 104 #: src/result_screen.cxx:214 105 msgid "Only a handful more and you would have made it - try again!" 106 msgstr "Nur ein paar mehr und du hättest es, versuch es nochmal!" 107 108 #: src/result_screen.cxx:216 109 msgid "Better luck next time!" 110 msgstr "Mehr Glück fürs nächste Mal!" 111 112 #: src/result_screen.cxx:232 113 msgid "Saved: " 114 msgstr "Gerettet: " 115 116 #: src/result_screen.cxx:236 117 msgid "Died: " 118 msgstr "Getötet: " 119 120 #: src/result_screen.cxx:240 121 msgid "Time left: " 122 msgstr "Verbliebene Zeit: " 123 124 #: src/screenshot.cxx:45 125 msgid "Screenshot: Saving screenshot to: " 126 msgstr "Screenshot: Speichere Screenshot als: " 127 128 #: src/screenshot.cxx:47 129 msgid "Screenshot: Screenshot is done." 130 msgstr "Screenshot: Screenshot wurde erstellt." 131 132 #: src/screenshot.cxx:53 133 msgid "Screenshot: Couldn't save screenshot" 134 msgstr "Screenshot: Screenshot konnte nicht gespeichert werden" 135 136 #: src/screenshot.cxx:138 137 msgid "Screenshot: Couldn't write file: " 138 msgstr "Screenshot: Datei konnte nicht geschrieben werden: " 139 140 #: src/spot_map.cxx:286 141 #, c-format 142 msgid "Image has wrong color depth: %d" 143 msgstr "Bild hat falsche Farbtiefe: %d" 144 145 #: src/start_screen.cxx:75 146 msgid "Ok" 147 msgstr "Ok" 148 149 #: src/start_screen.cxx:158 150 msgid "Number of Pingus: " 151 msgstr "Anzahl an Pingus: " 152 153 #: src/start_screen.cxx:161 154 msgid "Number to Save: " 155 msgstr "Zu rettende Pingus: " 156 157 #: src/start_screen.cxx:164 158 msgid "Time: " 159 msgstr "Zeit: " 160 161 #: src/start_screen.cxx:167 162 msgid "Difficulty:" 163 msgstr "Schwierigkeitsgrad:" 164 165 #: src/start_screen.cxx:175 166 msgid "Author: " 167 msgstr "Autor: " 168 169 #: src/start_screen.cxx:178 170 msgid "Filename: " 171 msgstr "Dateiname: " 172 173 #: src/story.cxx:41 174 msgid "The Journey Continues" 175 msgstr "Die Reise geht weiter" 176 177 #: src/story.cxx:46 178 msgid "" 179 "Now after you and the Pingus have learned the basics and\n" 180 "practiced a bit it is time to move on and begin the journey into\n" 181 "the world. Since the ice floe with which the Pingus traveled to the\n" 182 "Tutorial Island isn't going to hold on the whole way into the warmer\n" 183 "climates the Pingus have to find something else to guide\n" 184 "them on their journey.\n" 185 msgstr "" 186 "Nachdem Du und die Pingus nun die Grundlagen gelernt und\n" 187 "ein wenig Übung haben, ist es an der Zeit, weiter zu gehen und die\n" 188 "Reise in die Welt zu beginnen. Da die Scholle, mit der die Pingus zum\n" 189 "Tutorial Island reisten, nicht den ganzen Weg in die wärmeren Regionen\n" 190 "halten wird, müssen die Pingus etwas anderes finden, um sie auf der\n" 191 "Reise zu begleiten.\n" 192 193 #: src/story.cxx:58 194 msgid "" 195 "But as the eldest have said, the Tutorial Island provides not\n" 196 "only a good way to practice, but it is also the starting point into\n" 197 "the world. After some searching the Pingus discovered the meaning\n" 198 "of this, and they found the large tree at the end of the island\n" 199 "which gave them wood to construct a float.\n" 200 msgstr "" 201 "Aber wie die Weisen sagten, ist Tutorial Island nicht nur\n" 202 "eine Möglichkeit zum üben, es ist auch der erste Schritt in\n" 203 "die Welt, denn das Holz der Bäume am Ende der Insel liefert\n" 204 "gutes Material, um ein Floß zu bauen.\n" 205 206 #: src/story.cxx:69 207 msgid "" 208 "So the Pingus set out and constructed some large rafts, enough\n" 209 "to carry them all. After also packing a bunch of provisions\n" 210 "they were prepared to start their journey and leave\n" 211 "their familiar ground and enter the unknown parts of the world.\n" 212 msgstr "" 213 "So gingen die Pingus hin und bauten ein paar große\n" 214 "Flöße, genug, um alle zu tragen. Nachdem sie auch noch einigen\n" 215 "Proviant eingepackt hatten, waren sie endlich bereit, ihre Reise zu\n" 216 "beginnen, den bekannten Bereich zu verlassen und die unbekannten\n" 217 "Bereiche der Welt zu betreten.\n" 218 219 #: src/story.cxx:79 220 msgid "" 221 "So the Pingus sit on their raft, worrying about what's to come and\n" 222 "where to go, while floating into the sunset.\n" 223 "\n" 224 "To be continued..." 225 msgstr "" 226 "So saßen die Pingus nur auf ihrem Floß und sorgten sich, was denn nun\n" 227 "kommen möge, während sie in den Sonnenuntergang trieben.\n" 228 "\n" 229 "Fortsetzung folgt..." 230 231 #: src/story.cxx:91 232 msgid "The Journey Begins" 233 msgstr "Die Reise beginnt" 234 235 #: src/story.cxx:96 236 msgid "" 237 "For a long time, the Pingus have lived happily in peace on the\n" 238 "South Pole along with all the other animals. Everything was in\n" 239 "balance and it seemed like nothing could disrupt their peace. The\n" 240 "Pingus were happy and it seemed like this could never end.\n" 241 msgstr "" 242 "Die Pingus lebten schon lange glücklich und in Frieden am Südpol,\n" 243 "zusammen mit all den anderen Tieren. Alles war im Gleichgewicht und\n" 244 "es schien, als könnte nichts ihren Frieden stören. Die Pingus waren\n" 245 "glücklich und es schien, als würde dies niemals enden.\n" 246 247 #: src/story.cxx:106 248 msgid "" 249 "But then one day, things began to change slowly: the sky got darker\n" 250 "and the earth got warmer. Firstly, they thought this was just a\n" 251 "normal fluctuation in the world's climate, but things seemed to get\n" 252 "worse and worse with every year." 253 msgstr "" 254 "Aber dann, eines Tages, veränderten sich die Dinge langsam. Der\n" 255 "Himmel wurde dunkler und die Erde wärmer. Zuerst dachten sie, dies\n" 256 "wäre nur eine normale Schwankung im Klima, aber es wurde von Jahr \n" 257 "zu Jahr immer schlimmer." 258 259 #: src/story.cxx:117 260 msgid "" 261 "The snow began to melt away in a few areas and food became an\n" 262 "issue. Other animals tried to leave the region to search\n" 263 "for colder areas, but the Pingus knew that this wouldn't help:\n" 264 "they knew that they had to do something about it." 265 msgstr "" 266 "Der Schnee begann in einigen Bereichen zu schmelzen und Nahrung\n" 267 "wurde ein Problem. Andere Tiere begannen bereits, die Region zu\n" 268 "verlassen, um kältere Gebiete zu suchen. Aber die Pingus wussten,\n" 269 "dass dies nicht helfen würde, sie wussten, es musste etwas gegen\n" 270 "dieses Problem getan werden." 271 272 #: src/story.cxx:127 273 msgid "" 274 "So the circle of the eldest came together to decide what to do\n" 275 "about it. They decided to send out an expedition around the world\n" 276 "to find the cause of this warming. The expedition consisted of\n" 277 "hundreds of the bravest Pingus on the South Pole." 278 msgstr "" 279 "Darum traf sich der Rat der Ältesten, um zu entscheiden, was dagegen\n" 280 "getan werden sollte. Sie entschieden, eine Expedition um die Welt\n" 281 "zu senden, um den Grund für die Erwärmung zu finden. Die Expedition\n" 282 "bestand aus hunderten der mutigsten Pingus des ganzen Südpols." 283 284 #: src/story.cxx:137 285 msgid "" 286 "And they picked you to lead them on their journey around the\n" 287 "world. Since the journey will be dangerous and difficult, your\n" 288 "first goal is the Island of Mogorok, also known as the Tutorial\n" 289 "Island. According to the eldest, this island has always been the\n" 290 "first stop of Pingus that were sent out into the world." 291 msgstr "" 292 "Und sie wählten dich, um sie auf der Reise um die Welt zu führen.\n" 293 "Denn die Reise wird gefährlich und schwierig werden. Dein erstes Ziel ist\n" 294 "die Insel Mogorok, auch bekannt als Tutorial Island. Den Weisen\n" 295 "zufolge war diese Insel immer der erste Anlaufpunkt für Pingus,\n" 296 "die in die Welt gesandt wurden." 297 298 #: src/story.cxx:148 299 msgid "" 300 "The island consists of many areas that are ideal to teach the\n" 301 "Pingus their abilities. The Pingus can learn to build\n" 302 "bridges, climb, bash and use many other talents which they\n" 303 "will need on their long and dangerous journey." 304 msgstr "" 305 "Die Insel besteht aus verschiedenen Regionen, die ideal sind, um die\n" 306 "Fähigkeiten der Pingus zu trainieren. Sie können dort ihre Fähig-\n" 307 "keiten im Brückenbau, klettern, graben und all die anderen Talente\n" 308 "trainieren, die sie sicher auf der langen und gefährlichen Reise\n" 309 "benötigen werden." 310 311 #: src/story.cxx:158 312 msgid "" 313 "While there, you can practice your abilities in commanding\n" 314 "and guiding the Pingus. You can also get familiar with\n" 315 "all the abilities the Pingus provide and learn to master them,\n" 316 "since you will need all of them on your journey around the\n" 317 "world." 318 msgstr "" 319 "Währenddessen kannst Du auf der anderen Seite deine Fähigkeit, die\n" 320 "Pingus zu leiten und zu führen, trainieren. Du kannst dich dort auch mit\n" 321 "allen Fähigkeiten vertraut machen, die die Pingus besitzen und\n" 322 "erlernen, sie zu meistern, denn du wirst sie sicher alle auf der\n" 323 "Reise um die Welt benötigen." 324 325 #: src/story.cxx:169 326 msgid "" 327 "Now that you and the Pingus have arrived at Tutorial Island it\n" 328 "is time to take command and begin your mission.\n" 329 "\n" 330 "Good Luck!" 331 msgstr "" 332 "Nun da du und die Pingus im Tutorial Island angekommen sind,\n" 333 "musst du das Kommando übernehmen und deine Mission beginnen.\n" 334 "\n" 335 "Viel Glück!" 336 337 #: src/system.cxx:273 338 msgid "Environment variable $HOME not set, fix that and start again." 339 msgstr "" 340 "Umgebungs Variable $HOME ist nicht gesetzt. Setze sie und starte erneut." 341 342 #: src/worldmap/level_dot.cxx:174 src/worldmap/level_dot.cxx:184 343 msgid "locked" 344 msgstr "gesperrt" 345 346 #: src/worldmap/manager.cxx:103 347 msgid "Show Ending?" 348 msgstr "Ende anzeigen?" 349 350 #: src/worldmap/manager.cxx:133 351 msgid "Show Story?" 352 msgstr "Story zeigen?" 353 354 #: src/worldmap/manager.cxx:161 355 msgid "Leave?" 356 msgstr "Verlassen?" 357 358 #: src/worldmap/manager.cxx:201 359 msgid "Enter?" 360 msgstr "Betreten?" 361 362 #: src/worldmap/worldmap.cxx:77 363 msgid "WorldMap: File not found: " 364 msgstr "Worldmap: Datei nicht gefunden: " 365 366 #: src/worldmap/worldmap.cxx:261 367 msgid "...walking..." 368 msgstr "...laufe..." 369 370 msgid "You got %d error.\n" 371 msgid_plural "You got %d error.\n" 372 msgstr[0] "Du hast %d fehler\n" 373 msgstr[1] "Du hast %d fehlers\n" 374 375 msgid "found %d fatal error" 376 msgid_plural "found %d fatal errors" 377 msgstr[0] "s'ha trobat %d error fatal" 378 msgstr[1] "s'han trobat %d errors fatals" 379 -
new file libraries/source/tinygettext/test/po/de.po
diff --git a/libraries/source/tinygettext/test/po/de.po b/libraries/source/tinygettext/test/po/de.po new file mode 100644 index 0000000..e863f81
- + 1 # SOME DESCRIPTIVE TITLE. 2 # Copyright (C) YEAR Free Software Foundation, Inc. 3 # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. 4 # 5 msgid "" 6 msgstr "" 7 "Project-Id-Version: Pingus 0.6.0\n" 8 "Report-Msgid-Bugs-To: \n" 9 "POT-Creation-Date: 2004-04-09 18:37+0000\n" 10 "PO-Revision-Date: 2009-02-01 17:44+0100\n" 11 "Last-Translator: David Philippi <david@torangan.de>\n" 12 "Language-Team: David Philippi <david@torangan.de>, Ingo Ruhnke <grumbel@gmx.de>, Giray Devlet <giray@devlet.cc>\n" 13 "MIME-Version: 1.0\n" 14 "Plural-Forms: nplurals=2; plural=(n != 1);\n" 15 "Content-Type: text/plain; charset=UTF-8\n" 16 "Content-Transfer-Encoding: 8bit\n" 17 18 msgid "umlaut" 19 msgstr "ÃÃÃäöüÃ" 20 21 #: src/actions/bridger.cxx:48 src/actions/bridger.cxx:232 22 #: src/pingu_enums.cxx:40 23 msgid "Bridger" 24 msgstr "Bridger" 25 26 #: src/config.cxx:73 27 msgid "Couldn't open: " 28 msgstr "Datei oder Verzeichnis konnte nicht geöffnet werden: " 29 30 #: src/config.cxx:172 31 msgid "Unexpected char: '" 32 msgstr "Unerwartetes Zeichen: '" 33 34 #: src/config.cxx:206 35 msgid "Unexpected char '" 36 msgstr "Unerwartetes Zeichen: '" 37 38 #: src/credits.cxx:48 39 msgid "-Idea" 40 msgstr "-Idee" 41 42 #: src/credits.cxx:52 43 msgid "-Maintaining" 44 msgstr "-Verwaltung" 45 46 #: src/credits.cxx:56 47 msgid "-Programming" 48 msgstr "-Programmierung" 49 50 #: src/credits.cxx:62 51 msgid "-Porting (Win32)" 52 msgstr "-Portierung (Win32)" 53 54 #: src/credits.cxx:70 55 msgid "-Gfx" 56 msgstr "-Grafiken" 57 58 #: src/credits.cxx:82 59 msgid "-Music" 60 msgstr "-Musik" 61 62 #: src/credits.cxx:88 63 msgid "-Level Design" 64 msgstr "-Level Design" 65 66 #: src/credits.cxx:93 67 msgid "-Story" 68 msgstr "-Geschichte" 69 70 #: src/credits.cxx:97 71 msgid "-Translation" 72 msgstr "-Übersetzung" 73 74 #: src/credits.cxx:112 75 msgid "-Special" 76 msgstr "-Besonderen" 77 78 #: src/credits.cxx:113 79 msgid "-Thanks to" 80 msgstr "-Dank an" 81 82 #: src/credits.cxx:154 83 msgid "_And a very Special Thanks" 84 msgstr "_Und einen besonderen Dank" 85 86 #: src/credits.cxx:155 87 msgid "_to all the people who" 88 msgstr "_an alle Leute die" 89 90 #: src/credits.cxx:156 91 msgid "_contribute to" 92 msgstr "_an Freier Software" 93 94 #: src/credits.cxx:157 95 msgid "_Free Software!" 96 msgstr "_mitarbeiten!" 97 98 #: src/credits.cxx:163 99 msgid "_Thank you for" 100 msgstr "_Dankeschön fürs" 101 102 #: src/credits.cxx:164 103 msgid "_playing!" 104 msgstr "_spielen!" 105 106 #: src/editor/editor_event.cxx:588 107 msgid "Enter filename to save as:" 108 msgstr "Datei speichern als: " 109 110 #: src/editor/editor_help_screen.cxx:43 111 msgid "Editor Helpscreen (hide with F1)" 112 msgstr "Editor Hilfe (ausblenden mit F1)" 113 114 #: src/editor/editor_help_screen.cxx:51 115 msgid "F1 - show/hide this help screen" 116 msgstr "F1 - Hilfe anzeigen/verstecken" 117 118 #: src/editor/editor_help_screen.cxx:52 119 msgid "F2 - launch level building tutorial" 120 msgstr "F2 - Starte Levelbau Tutorial" 121 122 #: src/editor/editor_help_screen.cxx:53 123 msgid "F3 - toggle background color" 124 msgstr "F3 - Hintergrundfarbe aendern" 125 126 #: src/editor/editor_help_screen.cxx:54 127 msgid "F4 - play/test the level" 128 msgstr "F4 - Level starten/testen" 129 130 #: src/editor/editor_help_screen.cxx:55 131 msgid "F5 - load a level" 132 msgstr "Level Laden (F5)" 133 134 #: src/editor/editor_help_screen.cxx:56 135 msgid "F6 - save this level" 136 msgstr "Level Speichern (F6)" 137 138 #: src/editor/editor_help_screen.cxx:57 139 msgid "F7 - [unset]" 140 msgstr "F7 - [nicht belegt]" 141 142 #: src/editor/editor_help_screen.cxx:58 143 msgid "F8 - quick save/backup save?!" 144 msgstr "F8 - Schnellspeichern/Backup" 145 146 #: src/editor/editor_help_screen.cxx:59 147 msgid "F9 - change level width and height" 148 msgstr "F9 - Level Höhe und Breite ändern" 149 150 #: src/editor/editor_help_screen.cxx:60 151 msgid "F10 - [unset]" 152 msgstr "F10 - [nicht belegt]" 153 154 #: src/editor/editor_help_screen.cxx:61 155 msgid "F11 - toggle fps counter" 156 msgstr "F11 - fps Zähler an/aus" 157 158 #: src/editor/editor_help_screen.cxx:62 159 msgid "F12 - make screenshot" 160 msgstr "F12 - Screenshot erstellen" 161 162 #: src/editor/editor_help_screen.cxx:66 163 msgid "Home - increase object size" 164 msgstr "Einfg - Objekt vergrößern" 165 166 #: src/editor/editor_help_screen.cxx:67 167 msgid "End - decrease object size" 168 msgstr "Ende - Objekt verkleinern" 169 170 #: src/editor/editor_help_screen.cxx:68 171 msgid "Cursor Keys - Move object" 172 msgstr "Cursor Tasten - Objekt bewegen" 173 174 #: src/editor/editor_help_screen.cxx:69 175 msgid "Shift 'Cursor Keys' - Move objects fast " 176 msgstr "Shift Cursor Tasten - Objekt schneller bewegen" 177 178 #: src/editor/editor_help_screen.cxx:70 179 msgid "PageUp - level object up" 180 msgstr "Bild rauf - Objekt nach oben" 181 182 #: src/editor/editor_help_screen.cxx:71 183 msgid "PageDown - level object down" 184 msgstr "Bild runter - Objekt nach unten" 185 186 #: src/editor/editor_help_screen.cxx:72 187 msgid "Shift PageUp - increase objects z-pos by 50" 188 msgstr "Shift Bild rauf - Objekt nach oben" 189 190 #: src/editor/editor_help_screen.cxx:73 191 msgid "Shift PageDown - decrease objects z-pos by 50" 192 msgstr "Shift Bild runter - Objekt nach unten" 193 194 #: src/editor/editor_help_screen.cxx:74 195 msgid "Enter - Set default zoom (1:1)" 196 msgstr "Eingabe - Setze Standard Zoom (1:1)" 197 198 #: src/editor/editor_help_screen.cxx:75 199 msgid "d - duplicate object" 200 msgstr "d - Objekt kopieren" 201 202 #: src/editor/editor_help_screen.cxx:76 203 msgid "a - mark all objects" 204 msgstr "a - Alle Objekte markieren" 205 206 #: src/editor/editor_help_screen.cxx:77 207 msgid "shift leftmouseclick - add object to selection" 208 msgstr "Shift + linke Maustaste - Objekt zur Auswahl tun" 209 210 #: src/editor/editor_help_screen.cxx:78 211 msgid "leftmouseclick - select object" 212 msgstr "linke Maustaste - Objekt auswählen" 213 214 #: src/editor/editor_help_screen.cxx:79 215 msgid "Insert - insert new object" 216 msgstr "Einfügen - neues Objekt einfügen" 217 218 #: src/editor/editor_help_screen.cxx:80 219 msgid "Remove - remove selected object" 220 msgstr "Entfernen - entferne ausgewähltes Objekt" 221 222 #: src/editor/editor_help_screen.cxx:81 223 msgid "g - ungroup/group current selection" 224 msgstr "g - Auswahl gruppieren / Gruppierung aufheben" 225 226 #: src/editor/editor_help_screen.cxx:82 227 msgid "Ctrl PageUp - increase objects z-pos by 1" 228 msgstr "Strg Bild rauf - z-pos des Objekts um 1 erhöhen" 229 230 #: src/editor/editor_help_screen.cxx:83 231 msgid "Ctrl PageDown - decrease objects z-pos by 1" 232 msgstr "Strg Bild runter - z-pos des Objekts um 1 senken" 233 234 #: src/editor/editor_help_screen.cxx:89 235 msgid "Naming Convention: <LEVELNAME><NUMBER>-<CREATOR>.plf" 236 msgstr "Dateinamensvorgabe: <LEVELNAME><NUMMER>-<AUTOR>.pfl" 237 238 #: src/editor/editor_help_screen.cxx:91 239 msgid "" 240 "When you have created a level and want to have it in the next Pingus " 241 "release,\n" 242 "please mail it to pingus-devel@nongnu.org." 243 msgstr "" 244 "Falls Du einen Level erstellt hast und ihn gerne im nächsten Pingus\n" 245 "Release hättest, schicke ihn an pingus-devel@nongnu.org." 246 247 #: src/editor/object_selector.cxx:106 248 msgid "1 - guillotine" 249 msgstr "1 - Guillotine" 250 251 #: src/editor/object_selector.cxx:107 252 msgid "2 - hammer" 253 msgstr "2 - Hammer" 254 255 #: src/editor/object_selector.cxx:108 256 msgid "3 - spike" 257 msgstr "3 - Stacheln" 258 259 #: src/editor/object_selector.cxx:109 260 msgid "4 - laser_exit" 261 msgstr "4 - Laser Ausgang" 262 263 #: src/editor/object_selector.cxx:110 264 msgid "5 - fake_exit" 265 msgstr "5 - Täusch Ausgang" 266 267 #: src/editor/object_selector.cxx:111 268 msgid "6 - smasher" 269 msgstr "6 - Stampfer" 270 271 #: src/editor/object_selector.cxx:112 272 msgid "7 - bumper" 273 msgstr "7 - Stosser" 274 275 #: src/editor/object_selector.cxx:186 276 msgid "Select a WorldObj" 277 msgstr "Wähle ein WeltObjekt" 278 279 #: src/editor/object_selector.cxx:187 280 msgid "1 - teleporter" 281 msgstr "1 - Teleporter" 282 283 #: src/editor/object_selector.cxx:188 284 msgid "2 - switch and door" 285 msgstr "2 - Schalter und Tür" 286 287 #: src/editor/object_selector.cxx:189 288 msgid "3 - ConveyorBelt" 289 msgstr "3 - Förderband" 290 291 #: src/editor/object_selector.cxx:190 292 msgid "4 - IceBlock" 293 msgstr "4 - Eisblock" 294 295 #: src/editor/object_selector.cxx:191 296 msgid "5 - InfoBox" 297 msgstr "5 - InfoBox" 298 299 #: src/editor/object_selector.cxx:232 300 msgid "Select a weather" 301 msgstr "Wähle ein Wetter" 302 303 #: src/editor/object_selector.cxx:233 304 msgid "1 - snow" 305 msgstr "1 - Schnee" 306 307 #: src/editor/object_selector.cxx:234 308 msgid "2 - rain" 309 msgstr "2 - Regen" 310 311 #: src/editor/object_selector.cxx:265 312 msgid "Select an entrance" 313 msgstr "Wähle einen Eingang" 314 315 #: src/editor/object_selector.cxx:266 316 msgid "1 - generic" 317 msgstr "1 - allgemein" 318 319 #: src/editor/object_selector.cxx:267 320 msgid "2 - woodthing" 321 msgstr "2 - hölzern" 322 323 #: src/editor/object_selector.cxx:268 324 msgid "3 - cloud" 325 msgstr "3 - Wolke" 326 327 #: src/editor/object_selector.cxx:269 328 msgid "h - entrance surface (hotspot)" 329 msgstr "h - Eingangs Grafik (hotspot)" 330 331 #: src/editor/object_selector.cxx:343 332 msgid "What object type do you want?" 333 msgstr "Was für ein Objekt willst du?" 334 335 #: src/editor/object_selector.cxx:344 src/editor/object_selector.cxx:400 336 msgid "h - Hotspot" 337 msgstr "h - Grafikelement (hotspot)" 338 339 #: src/editor/object_selector.cxx:345 340 msgid "g - Groundpiece (ground) [not implemented]" 341 msgstr "g - Bodenstück (ground) [nicht implementiert]" 342 343 #: src/editor/object_selector.cxx:394 src/editor/object_selector.cxx:562 344 msgid "Which object do you want?" 345 msgstr "Welches Objekt willst du?" 346 347 #: src/editor/object_selector.cxx:395 348 msgid "g - Groundpiece (ground)" 349 msgstr "g - Bodenstück (ground)" 350 351 #: src/editor/object_selector.cxx:396 352 msgid "s - Groundpiece (solid)" 353 msgstr "s - Bodenelement (Stahl)" 354 355 #: src/editor/object_selector.cxx:397 356 msgid "b - Groundpiece (bridge)" 357 msgstr "b - Bodenelement (Bruecke)" 358 359 #: src/editor/object_selector.cxx:398 360 msgid "n - Groundpiece (transparent)" 361 msgstr "n - Bodenelement (transparent)" 362 363 #: src/editor/object_selector.cxx:399 364 msgid "r - Groundpiece (remove)" 365 msgstr "r - Bodenelement (entfernen)" 366 367 #: src/editor/object_selector.cxx:401 368 msgid "e - Entrance" 369 msgstr "e - Eingang" 370 371 #: src/editor/object_selector.cxx:402 372 msgid "x - Exit" 373 msgstr "x - Ausgang" 374 375 #: src/editor/object_selector.cxx:403 376 msgid "l - Liquid" 377 msgstr "l - Flüssigkeit" 378 379 #: src/editor/object_selector.cxx:404 380 msgid "w - Weather" 381 msgstr "w - Wetter" 382 383 #: src/editor/object_selector.cxx:405 384 msgid "t - Traps" 385 msgstr "t - Falle" 386 387 #: src/editor/object_selector.cxx:406 388 msgid "o - WorldObject" 389 msgstr "o - WeltObjekt" 390 391 #: src/editor/object_selector.cxx:407 392 msgid "z - Background" 393 msgstr "z - Hintergrund" 394 395 #: src/editor/object_selector.cxx:408 396 msgid "p - Prefab (ObjectGroup)" 397 msgstr "p - Prefab (Objekt Gruppe)" 398 399 #: src/editor/object_selector.cxx:409 400 msgid "f - something from file (~/.pingus/images/)" 401 msgstr "f - etwas aus einer Datei (~/.pingus/images/)" 402 403 #: src/editor/object_selector.cxx:498 404 msgid "Which prefab do you want?" 405 msgstr "Welche Prefab willst du?" 406 407 #: src/editor/object_selector.cxx:563 408 msgid "1 - Surface Background" 409 msgstr "1 - Bild Hintergrund" 410 411 #: src/editor/object_selector.cxx:564 412 msgid "2 - Solid Color Background" 413 msgstr "2 - Farb Hintergrund" 414 415 #: src/editor/object_selector.cxx:565 416 msgid "3 - Starfield Background" 417 msgstr "3 - Sternen Hintergrund" 418 419 #: src/editor/object_selector.cxx:566 420 msgid "4 - Thunderstorm Background" 421 msgstr "4 - Gewitter Hintergrund" 422 423 #: src/editor/panel_icons.cxx:33 424 msgid "Load a level (F5)" 425 msgstr "Level laden (F5)" 426 427 #: src/editor/panel_icons.cxx:46 428 msgid "Exit the editor (Escape)" 429 msgstr "Editor Beenden (Esc)" 430 431 #: src/editor/panel_icons.cxx:58 432 msgid "Save this level (F6)" 433 msgstr "Level Speichern (F6)" 434 435 #: src/editor/panel_icons.cxx:70 436 msgid "Delete marked objects (delete)" 437 msgstr "Markierte Objekte Löschen (Entfernen)" 438 439 #: src/editor/panel_icons.cxx:82 440 msgid "Duplicate current object (d)" 441 msgstr "Aktuelles Object kopieren (d)" 442 443 #: src/editor/panel_icons.cxx:94 444 msgid "Edit Level Properties" 445 msgstr "Leveleigenschaften ändern" 446 447 #: src/editor/panel_icons.cxx:106 448 msgid "Edit Object Properties" 449 msgstr "Objekteigenschaften ändern" 450 451 #: src/editor/panel_icons.cxx:118 452 msgid "Start the level and test it (F4)" 453 msgstr "Level starten und testen (F4)" 454 455 #: src/editor/panel_icons.cxx:130 456 msgid "Create a new level from scratch" 457 msgstr "Neuen Level erstellen" 458 459 #: src/editor/panel_icons.cxx:142 460 msgid "Insert an object (Insert)" 461 msgstr "Objekt einfuegen (Einfg)" 462 463 #: src/editor/panel_icons.cxx:154 464 msgid "Zoom into a region" 465 msgstr "Einen Bereich vergrössern" 466 467 #: src/editor/panel_icons.cxx:166 468 msgid "Zoom in" 469 msgstr "Vergroessern" 470 471 #: src/editor/panel_icons.cxx:179 472 msgid "Zoom out" 473 msgstr "Verkleinern" 474 475 #: src/editor/panel_icons.cxx:192 476 msgid "Setup Number of Actions" 477 msgstr "Stelle die Anzahl der Fähigkeiten ein" 478 479 #: src/editor/panel_icons.cxx:204 480 msgid "Display Help Screen (F1)" 481 msgstr "Hilfe Anzeigen (F1)" 482 483 #: src/exit_menu.cxx:48 484 msgid "Yes" 485 msgstr "Ja" 486 487 #: src/exit_menu.cxx:81 488 msgid "No" 489 msgstr "Nein" 490 491 #: src/exit_menu.cxx:114 492 msgid "Exit Pingus?" 493 msgstr "Pingus beenden?" 494 495 #: src/fps_counter.cxx:48 496 msgid "unknown" 497 msgstr "unbekannt" 498 499 #: src/game_time.cxx:70 500 msgid "unlimited" 501 msgstr "unbegrenzt" 502 503 #: src/level_desc.cxx:74 504 msgid "Designed by " 505 msgstr "Erstellt von " 506 507 #: src/level_desc.cxx:79 508 #, c-format 509 msgid "Pingus to Save: %d" 510 msgstr "Zu rettende Pingus: %d" 511 512 #: src/level_desc.cxx:81 513 #, c-format 514 msgid "Number of Pingus: %d" 515 msgstr "Anzahl an Pingus: %d" 516 517 #: src/level_desc.cxx:86 518 msgid "Loading..." 519 msgstr "Ladevorgang läuft..." 520 521 #: src/level_desc.cxx:89 522 msgid "Loading finished. Press a mouse button to start the level" 523 msgstr "" 524 "Ladevorgang abgeschlossen. Drücke eine Maus Taste um den Level zu starten" 525 526 #: src/level_result.cxx:61 527 msgid "Results:" 528 msgstr "Ergebnisse:" 529 530 #: src/level_result.cxx:67 531 #, c-format 532 msgid "Pingus saved: %3d/%3d" 533 msgstr "Gerettete Pingus: %3d/%3d" 534 535 #: src/level_result.cxx:72 536 #, c-format 537 msgid "Pingus died: %3d/%3d" 538 msgstr "Tote Pingus: %3d/%3d" 539 540 #: src/level_result.cxx:88 541 msgid "Press button to continue..." 542 msgstr "Knopf drücken um fortzufahren" 543 544 #: src/level_result.cxx:102 545 msgid "" 546 "As many Pingus escaped as entered the level. That's going to be hard to " 547 "beat.... unless this game becomes pornographic." 548 msgstr "" 549 "Es wurden alle Pingu dieses Levels gerettet. Das wird hart zu schlagen " 550 "sein... es sei denn dieses Spiel wird pornographisch." 551 552 #: src/level_result.cxx:104 553 msgid "Very impressive indeed." 554 msgstr "In der Tat sehr eindrucksvoll." 555 556 #: src/level_result.cxx:106 557 msgid "Good work. Still room for improvement though." 558 msgstr "Gute Arbeit. Aber Übung macht den Meiser!" 559 560 #: src/level_result.cxx:108 561 msgid "Not too shabby, not too shabby at all." 562 msgstr "Nicht schlecht, nicht schlecht!" 563 564 #: src/level_result.cxx:110 565 msgid "" 566 "That was OK, but Pingu life insurance premiums have just gotten more " 567 "expensive." 568 msgstr "" 569 "Das war ok, aber die Lebensversicherungsprämien für Pingus sind gerade " 570 "gestiegen." 571 572 #: src/level_result.cxx:112 573 msgid "Maybe this level calls for a different strategy." 574 msgstr "Möglicherweise verlangt dieser Level eine andere Strategie." 575 576 #: src/level_result.cxx:114 577 msgid "Exactly half. Are you saving only the female ones?" 578 msgstr "Genau die Hälfte! Rettest du nur die Weibchen?" 579 580 #: src/level_result.cxx:116 581 msgid "If I were a Pingu, I never would have left that entrance." 582 msgstr "Wenn ich ein Pingu wäre, hätte ich den Eingang nie verlassen." 583 584 #: src/level_result.cxx:118 585 msgid "Maybe you would feel more at home playing Quake." 586 msgstr "Möglicherweise wäre es besser Quake zu spielen?" 587 588 #: src/level_result.cxx:120 589 msgid "" 590 "Maybe this level calls for a different strategy. Like attempting to save " 591 "them, for example." 592 msgstr "" 593 "Es kann sein, dass wir etwas anderes versuchen sollten. Vielleicht könnten " 594 "wir ja die Pingus retten?" 595 596 #: src/level_result.cxx:122 597 msgid "Ever considered a career as a Pingu exterminator?" 598 msgstr "Hast du mal über eine Karriere als Pingu Zerstörer nachgedacht?" 599 600 #: src/level_result.cxx:124 601 msgid "You missed one! What's your excuse!?" 602 msgstr "Du hast einen vergessen! Was ist deine Entschuldigung?" 603 604 #: src/level_result.cxx:126 605 msgid "Please reassure me that you hit the Armageddon button." 606 msgstr "Bestätige mir bitte, dass das die Armageddon Taste war." 607 608 #: src/level_result.cxx:128 609 msgid "You've got a negative save/total value, something is buggy." 610 msgstr "Ein negativer Wert? Hier liegt ein Fehler vor." 611 612 #: src/menu_button.cxx:181 613 msgid "..:: The people who brought this game to you ::.." 614 msgstr "..:: Die Leute, die fuer dieses Spiel verantwortlich sind... ::.." 615 616 #: src/menu_button.cxx:184 617 msgid "Credits" 618 msgstr "Mitwirkende" 619 620 #: src/menu_button.cxx:216 621 msgid "..:: Takes you to the options menu ::.." 622 msgstr "..:: Einstellungen, Cheats und Debugging stuff ::.." 623 624 #: src/menu_button.cxx:219 625 msgid "Options" 626 msgstr "Einstellungen" 627 628 #: src/menu_button.cxx:252 629 msgid "..:: Bye, bye ::.." 630 msgstr "..:: Auf Wiedersehen ::.." 631 632 #: src/menu_button.cxx:255 633 msgid "Exit" 634 msgstr "Beenden" 635 636 #: src/menu_button.cxx:306 637 msgid "..:: Launch the level editor ::.." 638 msgstr "..:: Erstelle deinen eigenen Level ::.." 639 640 #: src/menu_button.cxx:309 641 msgid "Create a" 642 msgstr "Bau einen" 643 644 #: src/menu_button.cxx:310 645 msgid "Level" 646 msgstr "Level" 647 648 #: src/menu_button.cxx:344 649 msgid "..:: Start the game ::.." 650 msgstr "..:: das Spiel starten ::.." 651 652 #: src/menu_button.cxx:345 653 msgid "Start" 654 msgstr "Start" 655 656 #: src/menu_button.cxx:375 657 msgid "..:: Start a contrib level ::.." 658 msgstr "..:: Contrib level Spielen ::.." 659 660 #: src/menu_button.cxx:377 661 msgid "Contrib" 662 msgstr "Levels" 663 664 #: src/menu_button.cxx:399 665 msgid "..:: Multiplayer Modes... experimental stuff ::.." 666 msgstr "..:: Mehrspieler Modus ::.. Experimentelles Zeug ::.." 667 668 #: src/menu_button.cxx:401 669 msgid "Multi" 670 msgstr "Multi" 671 672 #: src/pingu_enums.cxx:35 673 msgid "Angel" 674 msgstr "Angel" 675 676 #: src/pingu_enums.cxx:36 677 msgid "Basher" 678 msgstr "Basher" 679 680 #: src/pingu_enums.cxx:37 681 msgid "Blocker" 682 msgstr "Blocker" 683 684 #: src/pingu_enums.cxx:38 685 msgid "Boarder" 686 msgstr "Boarder" 687 688 #: src/pingu_enums.cxx:39 689 msgid "Bomber" 690 msgstr "Bomber" 691 692 #: src/pingu_enums.cxx:41 693 msgid "Climber" 694 msgstr "Climber" 695 696 #: src/pingu_enums.cxx:42 697 msgid "Digger" 698 msgstr "Digger" 699 700 #: src/pingu_enums.cxx:43 701 msgid "Drown" 702 msgstr "Drown" 703 704 #: src/pingu_enums.cxx:44 705 msgid "Exiter" 706 msgstr "Exiter" 707 708 #: src/pingu_enums.cxx:45 709 msgid "Faller" 710 msgstr "Faller" 711 712 #: src/pingu_enums.cxx:46 713 msgid "Floater" 714 msgstr "Floater" 715 716 #: src/pingu_enums.cxx:47 717 msgid "Jumper" 718 msgstr "Jumper" 719 720 #: src/pingu_enums.cxx:48 721 msgid "Laserkill" 722 msgstr "Laserkill" 723 724 #: src/pingu_enums.cxx:49 725 msgid "Miner" 726 msgstr "Miner" 727 728 #: src/pingu_enums.cxx:50 729 msgid "Rocketlauncher" 730 msgstr "Rocketlauncher" 731 732 #: src/pingu_enums.cxx:51 733 msgid "Slider" 734 msgstr "Slider" 735 736 #: src/pingu_enums.cxx:52 737 msgid "Smashed" 738 msgstr "Smashed" 739 740 #: src/pingu_enums.cxx:53 741 msgid "Splashed" 742 msgstr "Splashed" 743 744 #: src/pingu_enums.cxx:54 745 msgid "Superman" 746 msgstr "Superman" 747 748 #: src/pingu_enums.cxx:55 749 msgid "Teleported" 750 msgstr "Teleported" 751 752 #: src/pingu_enums.cxx:56 753 msgid "Waiter" 754 msgstr "Waiter" 755 756 #: src/pingu_enums.cxx:57 757 msgid "Walker" 758 msgstr "Walker" 759 760 #: src/pingus_counter.cxx:52 761 #, c-format 762 msgid "Released:%3d/%-3d Out:%3d Saved:%3d/%-3d" 763 msgstr "Rein: %3d/%-3d Raus: %3d Gerettet: %3d/%-3d" 764 765 #: src/pingus_main.cxx:90 766 msgid "| segfault_handler: catched a SIGSEGV." 767 msgstr "| segfault_handler: SIGSEGV abgefangen." 768 769 #: src/pingus_main.cxx:92 770 msgid "| Woops, Pingus just crashed, congratulations you've found a bug." 771 msgstr "" 772 "| Woops, Pingus ist abgestürzt. Gratuliere, du hast einen Bug gefunden." 773 774 #: src/pingus_main.cxx:93 775 msgid "" 776 "| Please write a little bug report to <grumbel@gmx.de>, include informations" 777 msgstr "" 778 "| Bitte schreibe einen kleinen Report an <pingus-devel@nongnu.org, mit " 779 "Informationen," 780 781 #: src/pingus_main.cxx:94 782 msgid "| where exacly the SIGSEGV occured and how to reproduce it." 783 msgstr "| wo genau der SIGSEGV auftrat und wie man ihn reproduziert." 784 785 #: src/pingus_main.cxx:95 786 msgid "| Also try include a backtrace, you can get it like this:" 787 msgstr "| Versuche auch einen backtrace zu erstellen, du bekommst ihn so:" 788 789 #: src/pingus_main.cxx:101 790 msgid "| If that doesn't work, try this:" 791 msgstr "| Wenn das nicht geht, versuche dies:" 792 793 #: src/pingus_main.cxx:105 794 msgid "| [play until it crashes again]" 795 msgstr "| [spiele bis es wieder crasht]" 796 797 #: src/pingus_main.cxx:113 798 msgid "| Warning: Pingus recieved a SIGINT, exiting now." 799 msgstr "| Warnung: Pingus erhielt einen SIGINT, beende jetzt." 800 801 #: src/pingus_main.cxx:301 802 msgid "Warning: Larger resolution than 800x600 will result in visual problems" 803 msgstr "" 804 "Warnung: Auflösungen grösser als 800x600 können zu visuellen Problemen führen" 805 806 #: src/pingus_main.cxx:488 807 msgid "Unknow char: " 808 msgstr "Unbekannter Buchstabe: " 809 810 #: src/pingus_main.cxx:489 811 msgid "Usage: " 812 msgstr "Benutzung: " 813 814 #: src/pingus_main.cxx:489 815 msgid " [OPTIONS]... [LEVELFILE]" 816 msgstr "[OPTIONEN]... [LEVELDATEI]" 817 818 #: src/pingus_main.cxx:492 819 msgid "Options:" 820 msgstr "Einstellungen" 821 822 #: src/pingus_main.cxx:494 823 msgid "Set the resolution for pingus (default: 800x600)" 824 msgstr "Setze die Auflösung für Pingus (Standard: 800x600)" 825 826 #: src/pingus_main.cxx:495 827 msgid "Displays this help" 828 msgstr "Hilfe Anzeigen" 829 830 #: src/pingus_main.cxx:496 831 msgid "Disable intro" 832 msgstr "Intro abschalten" 833 834 #: src/pingus_main.cxx:497 835 msgid "Use OpenGL" 836 msgstr "OpenGL benutzen" 837 838 #: src/pingus_main.cxx:499 839 msgid "Start in Window Mode" 840 msgstr "Pingus im Fenster starten" 841 842 #: src/pingus_main.cxx:500 843 msgid "Start in Fullscreen" 844 msgstr "Pingus im Vollbild starten" 845 846 #: src/pingus_main.cxx:504 847 msgid "FILE " 848 msgstr "Datei " 849 850 #: src/pingus_main.cxx:504 851 msgid "Load a custom level from FILE" 852 msgstr "Einen Level aus DATEI laden" 853 854 #: src/pingus_main.cxx:505 855 msgid "FILE " 856 msgstr "Datei " 857 858 #: src/pingus_main.cxx:505 859 msgid "Load a custom worldmap from FILE" 860 msgstr "Eine Weltkarte aus DATEI laden" 861 862 #: src/pingus_main.cxx:506 863 msgid "Print some more messages to stdout, can be set" 864 msgstr "Gibt mehr Nachrichten auf stdout aus, kann" 865 866 #: src/pingus_main.cxx:507 867 msgid "multiple times to increase verbosity" 868 msgstr "mehrmals gesetzt werden, um die Genauigkeit zu erhöhen" 869 870 #: src/pingus_main.cxx:508 871 msgid "Prints version number and exit" 872 msgstr "Version ausgeben und beenden" 873 874 #: src/pingus_main.cxx:509 875 msgid "Launch the Level editor (experimental)" 876 msgstr "Level Editor starten (Experimentell)" 877 878 #: src/pingus_main.cxx:510 879 msgid "Disable automatic scrolling" 880 msgstr "Automatisches Scrollen abschalten" 881 882 #: src/pingus_main.cxx:512 883 msgid "Enable software cursor" 884 msgstr "Aktiviere Software Cursor" 885 886 #: src/pingus_main.cxx:515 887 msgid "Don't read ~/.pingus/config" 888 msgstr "~/.pingus/config nicht einlesen" 889 890 #: src/pingus_main.cxx:516 891 msgid "FILE " 892 msgstr "Datei " 893 894 #: src/pingus_main.cxx:516 895 msgid "Read config from FILE (default: ~/.pingus/config)" 896 msgstr "Konfiguration aus DATEI lesen" 897 898 #: src/pingus_main.cxx:517 899 msgid "reduce CPU usage, might speed up the game on slower machines" 900 msgstr "" 901 "reduziere CPU Belastung, könnte das Spiel auf langsamen Rechnern " 902 "beschleunigen" 903 904 #: src/pingus_main.cxx:518 905 msgid "Uses the controller given in FILE" 906 msgstr "Controller aus FILE benutzen" 907 908 #: src/pingus_main.cxx:520 909 msgid "Debugging and experimental stuff:" 910 msgstr "Debug und Experimentelles Zeug" 911 912 #: src/pingus_main.cxx:521 913 msgid "Enables some features, only interesting programmers" 914 msgstr "Aktiviere einige Funktionen, nur für Programmierer" 915 916 #: src/pingus_main.cxx:522 917 msgid "Enable the output of debugging infos, possible" 918 msgstr "Aktiviere die Ausgabe von Debug Informationen, mögliche" 919 920 #: src/pingus_main.cxx:523 921 msgid "OPTION's are tiles, gametime, actions, sound, resources, gui," 922 msgstr "Optionen sind tiles, gametime, actions, sound, resources, gui," 923 924 #: src/pingus_main.cxx:525 925 msgid "Skip at least N frames, larger values speed the game up" 926 msgstr "" 927 "Überspringe mindestens N Bilder, größere Werte erhöhen die Geschwindigkeit" 928 929 #: src/pingus_main.cxx:526 930 msgid "Skip at most N frames" 931 msgstr "Überspringe maximal N Bilder" 932 933 #: src/pingus_main.cxx:527 934 msgid "Set both min and max frameskip to N" 935 msgstr "Setze sowohl minimalen als auch maximalen Bildsprung auf N" 936 937 #: src/pingus_main.cxx:528 938 msgid "Set the game speed (0=fastest, >0=slower)" 939 msgstr "Setze die Geschwindigkeit (0=schnellste, >0=langsamer)" 940 941 #: src/pingus_main.cxx:529 942 msgid "Prints the fps to stdout" 943 msgstr "Schreibe die fps auf stdout" 944 945 #: src/pingus_main.cxx:530 946 msgid "Set the size of the map tiles (default: 32)" 947 msgstr "Setze die Größe der Kartenteile (Standard: 32)" 948 949 #: src/pingus_main.cxx:531 950 msgid "Disable some cpu intensive features" 951 msgstr "Deaktivere einige CPU intensive Funktionen" 952 953 #: src/pingus_main.cxx:532 954 msgid "Reduces the CPU usage by issuing sleep()" 955 msgstr "Reduziert die CPU Belastung durch Verwendung von sleep()" 956 957 #: src/pingus_main.cxx:534 958 msgid "Demo playing and recording:" 959 msgstr "Demo aufzeichnung und wiedergabe:" 960 961 #: src/pingus_main.cxx:535 962 msgid "FILE " 963 msgstr "Datei " 964 965 #: src/pingus_main.cxx:535 966 msgid "Plays a demo session from FILE" 967 msgstr "Spielt eine Demo Sitzung aus FILE" 968 969 #: src/pingus_main.cxx:537 970 msgid "Record demos for each played level" 971 msgstr "Nehme Demos für jeden gespielten Level auf" 972 973 #: src/pingus_main.cxx:539 974 msgid "Sound:" 975 msgstr "Sound" 976 977 #: src/pingus_main.cxx:540 978 msgid "Disable sound" 979 msgstr "Sound deaktivieren" 980 981 #: src/pingus_main.cxx:541 982 msgid "Disable music" 983 msgstr "Musik deaktivieren" 984 985 #: src/pingus_main.cxx:720 986 msgid "clanVorbis support: ok" 987 msgstr "clanVorbis Unterstützung: ok" 988 989 #: src/pingus_main.cxx:722 990 msgid "clanVoribs support: missing (.ogg music files will not be playable)" 991 msgstr "" 992 "clanVorbis Unterstützung: fehlt (.ogg Musik Datein können nicht abgespielt " 993 "werden)" 994 995 #: src/pingus_main.cxx:726 996 msgid "clanMikMod support: ok" 997 msgstr "clanMikMod Unterstützung: ok" 998 999 #: src/pingus_main.cxx:728 1000 msgid "clanMikMod support: missing (music files will not be playable)" 1001 msgstr "" 1002 "clanMikMod Untersützung: fehlt (Musikdateien können nicht abgespielt werden)" 1003 1004 #: src/pingus_main.cxx:732 1005 msgid "getext support: ok" 1006 msgstr "gettext Unterstützung: ok" 1007 1008 #: src/pingus_main.cxx:733 1009 msgid "gettext language: english" 1010 msgstr "gettext Sprache: deutsch" 1011 1012 #: src/pingus_main.cxx:739 1013 msgid "sound support: enabled" 1014 msgstr "Sound Unterstützung: an" 1015 1016 #: src/pingus_main.cxx:741 1017 msgid "sound support: disabled" 1018 msgstr "Sound Unterstützung: aus" 1019 1020 #: src/pingus_main.cxx:744 1021 msgid "music support: enabled" 1022 msgstr "Musik Unterstützung: an" 1023 1024 #: src/pingus_main.cxx:746 1025 msgid "music support: disabled" 1026 msgstr "Musik Unterstützung: aus" 1027 1028 #: src/pingus_main.cxx:748 1029 msgid "resolution set to: " 1030 msgstr "Auflösung: " 1031 1032 #: src/pingus_main.cxx:749 1033 msgid "fullscreen: " 1034 msgstr "Vollbild: " 1035 1036 #: src/pingus_main.cxx:750 1037 msgid " enabled" 1038 msgstr "aktiviert" 1039 1040 #: src/pingus_main.cxx:750 1041 msgid "disabled" 1042 msgstr "däktiviert" 1043 1044 1045 #: src/pingus_main.cxx:751 1046 msgid "reenabled" 1047 msgstr "" -
new file libraries/source/tinygettext/test/po/de_AT.po
diff --git a/libraries/source/tinygettext/test/po/de_AT.po b/libraries/source/tinygettext/test/po/de_AT.po new file mode 100644 index 0000000..f4c3d81
- + 1 # SOME DESCRIPTIVE TITLE. 2 # Copyright (C) YEAR Free Software Foundation, Inc. 3 # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. 4 # 5 #, fuzzy 6 msgid "" 7 msgstr "" 8 "Project-Id-Version: PACKAGE VERSION\n" 9 "PO-Revision-Date: 2009-02-02 12:07+0100\n" 10 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" 11 "Language-Team: LANGUAGE <LL@li.org>\n" 12 "MIME-Version: 1.0\n" 13 "Content-Type: text/plain; charset=UTF-8\n" 14 "Content-Transfer-Encoding: 8bit\n" 15 "Plural-Forms: nplurals=2; plural=( n != 1);\n" 16 17 msgid "umlaut" 18 msgstr "ÃÃÃäöüÃâ¬Â¢" 19 20 msgid "You got %d error." 21 msgid_plural "You got %d error." 22 msgstr[0] "Du hast %d fehler" 23 msgstr[1] "Du hast %d fehlers" 24 25 msgid "found %d fatal error" 26 msgid_plural "found %d fatal errors" 27 msgstr[0] "s'ha trobat %d error fätal" 28 msgstr[1] "s'han trobat %d errors fätals" 29 30 31 msgid "I ate %d pizza." 32 msgid_plural "I ate %d pizzas." 33 msgstr[0] "" -
new file libraries/source/tinygettext/test/po/fr.po
diff --git a/libraries/source/tinygettext/test/po/fr.po b/libraries/source/tinygettext/test/po/fr.po new file mode 100644 index 0000000..0670f48
- + 1 # SOME DESCRIPTIVE TITLE. 2 # Copyright (C) YEAR Free Software Foundation, Inc. 3 # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. 4 # 5 #, fuzzy 6 msgid "" 7 msgstr "" 8 "Project-Id-Version: PACKAGE VERSION\n" 9 "PO-Revision-Date: 2009-01-28 08:45+0100\n" 10 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" 11 "Language-Team: LANGUAGE <LL@li.org>\n" 12 "MIME-Version: 1.0\n" 13 "Content-Type: text/plain; charset=utf-8\n" 14 "Content-Transfer-Encoding: 8bit\n" 15 16 #: src/actions/bridger.cxx:48 src/actions/bridger.cxx:232 17 #: src/pingu_enums.cxx:40 18 msgid "invalid" 19 msgstr "ungütig" 20 -
new file libraries/source/tinygettext/test/po_parser_test.cpp
diff --git a/libraries/source/tinygettext/test/po_parser_test.cpp b/libraries/source/tinygettext/test/po_parser_test.cpp new file mode 100644 index 0000000..4e288a9
- + 1 // tinygettext - A gettext replacement that works directly on .po files 2 // Copyright (C) 2009 Ingo Ruhnke <grumbel@gmx.de> 3 // 4 // This program is free software; you can redistribute it and/or 5 // modify it under the terms of the GNU General Public License 6 // as published by the Free Software Foundation; either version 2 7 // of the License, or (at your option) any later version. 8 // 9 // This program is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with this program; if not, write to the Free Software 16 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 17 18 #include <errno.h> 19 #include <string.h> 20 #include <iostream> 21 #include <fstream> 22 #include <stdexcept> 23 24 #include "tinygettext/po_parser.hpp" 25 #include "tinygettext/tinygettext.hpp" 26 #include "tinygettext/log.hpp" 27 28 void my_log_callback(const std::string& err) 29 { 30 std::cerr << err; 31 } 32 33 int main(int argc, char** argv) 34 { 35 if (argc < 2) 36 { 37 std::cout << argv[0] << " FILENAME..." << std::endl; 38 } 39 else 40 { 41 tinygettext::Log::set_log_info_callback(my_log_callback); 42 tinygettext::Log::set_log_warning_callback(my_log_callback); 43 tinygettext::Log::set_log_error_callback(my_log_callback); 44 45 for(int i = 1; i < argc; ++i) 46 { 47 std::ifstream in(argv[i]); 48 if (!in) 49 { 50 std::cerr << argv[0] << ": cannot access " << argv[i] << ": " << strerror(errno) << std::endl; 51 } 52 else 53 { 54 try 55 { 56 tinygettext::Dictionary dict1; 57 tinygettext::POParser::parse(argv[i], in, dict1); 58 59 //tinygettext::Dictionary dict2; 60 //tinygettext::POFileReader::read(in, dict2); 61 } 62 catch(std::runtime_error& err) 63 { 64 std::cout << argv[i] << ": exception: " << err.what() << std::endl; 65 } 66 } 67 } 68 } 69 } 70 71 /* EOF */ -
new file libraries/source/tinygettext/test/test.sh
diff --git a/libraries/source/tinygettext/test/test.sh b/libraries/source/tinygettext/test/test.sh new file mode 100644 index 0000000..a7b7789
- + 1 #!/bin/sh 2 3 ./tinygettext_test translate po/fr.po "invalid" 4 ./tinygettext_test directory po/ umlaut Deutsch 5 ./tinygettext_test directory po/ umlaut deutsch 6 ./tinygettext_test directory po/ umlaut de 7 8 # EOF # -
new file libraries/source/tinygettext/test/tinygettext_test.cpp
diff --git a/libraries/source/tinygettext/test/tinygettext_test.cpp b/libraries/source/tinygettext/test/tinygettext_test.cpp new file mode 100644 index 0000000..cea845e
- + 1 // TinyGetText 2 // Copyright (C) 2009 Ingo Ruhnke <grumbel@gmx.de> 3 // 4 // This program is free software; you can redistribute it and/or 5 // modify it under the terms of the GNU General Public License 6 // as published by the Free Software Foundation; either version 2 7 // of the License, or (at your option) any later version. 8 // 9 // This program is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with this program; if not, write to the Free Software 16 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 17 18 #include <iostream> 19 #include <string.h> 20 #include <fstream> 21 #include <stdlib.h> 22 #include <iostream> 23 #include <stdexcept> 24 #include "tinygettext/po_parser.hpp" 25 #include "tinygettext/tinygettext.hpp" 26 27 using namespace tinygettext; 28 29 void print_msg(const std::string& msgid, const std::vector<std::string>& msgstrs) 30 { 31 std::cout << "Msgid: " << msgid << std::endl; 32 for(std::vector<std::string>::const_iterator i = msgstrs.begin(); i != msgstrs.end(); ++i) 33 { 34 std::cout << *i << std::endl; 35 } 36 } 37 38 void print_msg_ctxt(const std::string& ctxt, const std::string& msgid, const std::vector<std::string>& msgstrs) 39 { 40 std::cout << "Msgctxt: " << ctxt << std::endl; 41 std::cout << "Msgid: " << msgid << std::endl; 42 for(std::vector<std::string>::const_iterator i = msgstrs.begin(); i != msgstrs.end(); ++i) 43 { 44 std::cout << *i << std::endl; 45 } 46 } 47 48 void print_usage(int /*argc*/, char** argv) 49 { 50 std::cout << "Usage: " << argv[0] << " translate FILE MESSAGE" << std::endl; 51 std::cout << " " << argv[0] << " translate FILE MESSAGE_S MESSAGE_P NUM" << std::endl; 52 std::cout << " " << argv[0] << " directory DIRECTORY MESSAGE [LANG]" << std::endl; 53 std::cout << " " << argv[0] << " language LANGUAGE" << std::endl; 54 std::cout << " " << argv[0] << " language-dir DIR" << std::endl; 55 std::cout << " " << argv[0] << " list-msgstrs FILE" << std::endl; 56 } 57 58 void read_dictionary(const std::string& filename, Dictionary& dict) 59 { 60 std::ifstream in(filename.c_str()); 61 62 if (!in) 63 { 64 throw std::runtime_error("Couldn't open " + filename); 65 } 66 else 67 { 68 POParser::parse(filename, in, dict); 69 in.close(); 70 } 71 } 72 73 int main(int argc, char** argv) 74 { 75 try 76 { 77 if (argc == 3 && strcmp(argv[1], "language-dir") == 0) 78 { 79 DictionaryManager dictionary_manager; 80 dictionary_manager.add_directory(argv[2]); 81 const std::set<Language>& languages = dictionary_manager.get_languages(); 82 std::cout << "Number of languages: " << languages.size() << std::endl; 83 for (std::set<Language>::const_iterator i = languages.begin(); i != languages.end(); ++i) 84 { 85 const Language& language = *i; 86 std::cout << "Env: " << language.str() << std::endl 87 << "Name: " << language.get_name() << std::endl 88 << "Language: " << language.get_language() << std::endl 89 << "Country: " << language.get_country() << std::endl 90 << "Modifier: " << language.get_modifier() << std::endl 91 << std::endl; 92 } 93 } 94 else if (argc == 3 && strcmp(argv[1], "language") == 0) 95 { 96 Language language = Language::from_name(argv[2]); 97 98 if (language) 99 std::cout << "Env: " << language.str() << std::endl 100 << "Name: " << language.get_name() << std::endl 101 << "Language: " << language.get_language() << std::endl 102 << "Country: " << language.get_country() << std::endl 103 << "Modifier: " << language.get_modifier() << std::endl; 104 else 105 std::cout << "not found" << std::endl; 106 } 107 else if (argc == 4 && strcmp(argv[1], "translate") == 0) 108 { 109 const char* filename = argv[2]; 110 const char* message = argv[3]; 111 112 Dictionary dict; 113 read_dictionary(filename, dict); 114 std::cout << "TRANSLATION: \"\"\"" << dict.translate(message) << "\"\"\""<< std::endl; 115 } 116 else if (argc == 5 && strcmp(argv[1], "translate") == 0) 117 { 118 const char* filename = argv[2]; 119 const char* context = argv[3]; 120 const char* message = argv[4]; 121 122 Dictionary dict; 123 read_dictionary(filename, dict); 124 std::cout << dict.translate_ctxt(context, message) << std::endl; 125 } 126 else if (argc == 6 && strcmp(argv[1], "translate") == 0) 127 { 128 const char* filename = argv[2]; 129 const char* message_singular = argv[3]; 130 const char* message_plural = argv[4]; 131 int num = atoi(argv[5]); 132 133 Dictionary dict; 134 read_dictionary(filename, dict); 135 std::cout << dict.translate_plural(message_singular, message_plural, num) << std::endl; 136 } 137 else if (argc == 7 && strcmp(argv[1], "translate") == 0) 138 { 139 const char* filename = argv[2]; 140 const char* context = argv[3]; 141 const char* message_singular = argv[4]; 142 const char* message_plural = argv[5]; 143 int num = atoi(argv[6]); 144 145 Dictionary dict; 146 read_dictionary(filename, dict); 147 std::cout << dict.translate_ctxt_plural(context, message_singular, message_plural, num) << std::endl; 148 } 149 else if ((argc == 4 || argc == 5) && strcmp(argv[1], "directory") == 0) 150 { 151 const char* directory = argv[2]; 152 const char* message = argv[3]; 153 const char* language = (argc == 5) ? argv[4] : NULL; 154 155 DictionaryManager manager; 156 manager.add_directory(directory); 157 158 if (language) 159 { 160 Language lang = Language::from_name(language); 161 if (lang) 162 { 163 manager.set_language(lang); 164 } 165 else 166 { 167 std::cout << "Unknown language: " << language << std::endl; 168 exit(EXIT_FAILURE); 169 } 170 } 171 172 std::cout << "Directory: '" << directory << "'" << std::endl; 173 std::cout << "Message: '" << message << "'" << std::endl; 174 std::cout << "Language: '" << manager.get_language().str() << "' (name: '" 175 << manager.get_language().get_name() << "', language: '" 176 << manager.get_language().get_language() << "', country: '" 177 << manager.get_language().get_country() << "', modifier: '" 178 << manager.get_language().get_modifier() << "')" 179 << std::endl; 180 std::cout << "Translation: '" << manager.get_dictionary().translate(message) << "'" << std::endl; 181 } 182 else if ((argc == 3) && strcmp(argv[1], "list-msgstrs") == 0) 183 { 184 const char* filename = argv[2]; 185 186 Dictionary dict; 187 read_dictionary(filename, dict); 188 dict.foreach(print_msg); 189 dict.foreach_ctxt(print_msg_ctxt); 190 } 191 else 192 { 193 print_usage(argc, argv); 194 } 195 } 196 catch(std::exception& err) 197 { 198 std::cout << "Exception: " << err.what() << std::endl; 199 } 200 201 return 0; 202 } 203 204 /* EOF */ -
new file libraries/source/tinygettext/tinygettext.pc.in
diff --git a/libraries/source/tinygettext/tinygettext.pc.in b/libraries/source/tinygettext/tinygettext.pc.in new file mode 100644 index 0000000..ef82a93
- + 1 # Unfortunately, since this project is built with cmake, 2 # these variables can't properly be set. 3 4 prefix=@CMAKE_INSTALL_PREFIX@ 5 exec_prefix=${prefix} 6 libdir=${exec_prefix}/@LIB_SUBDIR@ 7 includedir=${prefix}/include 8 9 Name: @PROJECT_NAME@ 10 Description: tiny, minimal gettext replacement 11 Version: @VERSION@ 12 URL: http://tinygettext.googlecode.com/ 13 Requires: 14 Libs: -L${libdir} -ltinygettext 15 Libs.private: 16 Cflags: -I${includedir} -
new file libraries/source/tinygettext/tinygettext/dictionary.cpp
diff --git a/libraries/source/tinygettext/tinygettext/dictionary.cpp b/libraries/source/tinygettext/tinygettext/dictionary.cpp new file mode 100644 index 0000000..9765d75
- + 1 // tinygettext - A gettext replacement that works directly on .po files 2 // Copyright (C) 2006 Ingo Ruhnke <grumbel@gmx.de> 3 // 4 // This program is free software; you can redistribute it and/or 5 // modify it under the terms of the GNU General Public License 6 // as published by the Free Software Foundation; either version 2 7 // of the License, or (at your option) any later version. 8 // 9 // This program is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with this program; if not, write to the Free Software 16 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 17 18 #include <assert.h> 19 #include "log_stream.hpp" 20 #include "dictionary.hpp" 21 22 namespace tinygettext { 23 0 24 25 Dictionary::Dictionary(const std::string& charset_) : 26 entries(), 27 ctxt_entries(), 28 charset(charset_), 29 plural_forms() 30 { 31 } 32 33 Dictionary::~Dictionary() 34 { 35 } 36 37 std::string 38 Dictionary::get_charset() const 39 { 40 return charset; 41 } 42 43 void 44 Dictionary::set_plural_forms(const PluralForms& plural_forms_) 45 { 46 plural_forms = plural_forms_; 47 } 48 49 PluralForms 50 Dictionary::get_plural_forms() const 51 { 52 return plural_forms; 53 } 54 55 std::string 56 Dictionary::translate_plural(const std::string& msgid, const std::string& msgid_plural, int num) 57 { 58 return translate_plural(entries, msgid, msgid_plural, num); 59 } 60 61 std::string 62 Dictionary::translate_plural(const Entries& dict, const std::string& msgid, const std::string& msgid_plural, int count) 63 { 64 Entries::const_iterator i = dict.find(msgid); 65 const std::vector<std::string>& msgstrs = i->second; 66 67 if (i != dict.end()) 68 { 69 unsigned int n = 0; 70 n = plural_forms.get_plural(count); 71 assert(/*n >= 0 &&*/ n < msgstrs.size()); 72 73 if (!msgstrs[n].empty()) 74 return msgstrs[n]; 75 else 76 if (count == 1) // default to english rules 77 return msgid; 78 else 79 return msgid_plural; 80 } 81 else 82 { 83 log_info << "Couldn't translate: " << msgid << std::endl; 84 log_info << "Candidates: " << std::endl; 85 for (i = dict.begin(); i != dict.end(); ++i) 86 log_info << "'" << i->first << "'" << std::endl; 87 88 if (count == 1) // default to english rules 89 return msgid; 90 else 91 return msgid_plural; 92 } 93 } 94 95 std::string 96 Dictionary::translate(const std::string& msgid) 97 { 98 return translate(entries, msgid); 99 } 100 101 std::string 102 Dictionary::translate(const Entries& dict, const std::string& msgid) 103 { 104 Entries::const_iterator i = dict.find(msgid); 105 if (i != dict.end() && !i->second.empty()) 106 { 107 return i->second[0]; 108 } 109 else 110 { 111 log_info << "Couldn't translate: " << msgid << std::endl; 112 return msgid; 113 } 114 } 115 116 std::string 117 Dictionary::translate_ctxt(const std::string& msgctxt, const std::string& msgid) 118 { 119 CtxtEntries::iterator i = ctxt_entries.find(msgctxt); 120 if (i != ctxt_entries.end()) 121 { 122 return translate(i->second, msgid); 123 } 124 else 125 { 126 log_info << "Couldn't translate: " << msgid << std::endl; 127 return msgid; 128 } 129 } 130 131 std::string 132 Dictionary::translate_ctxt_plural(const std::string& msgctxt, 133 const std::string& msgid, const std::string& msgidplural, int num) 134 { 135 CtxtEntries::iterator i = ctxt_entries.find(msgctxt); 136 if (i != ctxt_entries.end()) 137 { 138 return translate_plural(i->second, msgid, msgidplural, num); 139 } 140 else 141 { 142 log_info << "Couldn't translate: " << msgid << std::endl; 143 if (num != 1) // default to english 144 return msgidplural; 145 else 146 return msgid; 147 } 148 } 149 1 150 151 void 152 Dictionary::add_translation(const std::string& msgid, const std::string& , 153 const std::vector<std::string>& msgstrs) 154 { 155 // Do we need msgid2 for anything? its after all supplied to the 156 // translate call, so we just throw it away here 157 entries[msgid] = msgstrs; 158 } 159 160 void 161 Dictionary::add_translation(const std::string& msgid, const std::string& msgstr) 162 { 163 std::vector<std::string>& vec = entries[msgid]; 164 if (vec.empty()) 165 { 166 vec.push_back(msgstr); 167 } 168 else 169 { 170 log_warning << "collision in add_translation: '" 171 << msgid << "' -> '" << msgstr << "' vs '" << vec[0] << "'" << std::endl; 172 vec[0] = msgstr; 173 } 174 } 175 176 void 177 Dictionary::add_translation(const std::string& msgctxt, 178 const std::string& msgid, const std::string& msgid_plural, 179 const std::vector<std::string>& msgstrs) 180 { 181 std::vector<std::string>& vec = ctxt_entries[msgctxt][msgid]; 182 if (vec.empty()) 183 { 184 vec = msgstrs; 185 } 186 else 187 { 188 log_warning << "collision in add_translation(\"" << msgctxt << "\", \"" << msgid << "\", \"" << msgid_plural << "\")" << std::endl; 189 vec = msgstrs; 190 } 191 } 192 193 void 194 Dictionary::add_translation(const std::string& msgctxt, const std::string& msgid, const std::string& msgstr) 195 { 196 std::vector<std::string>& vec = ctxt_entries[msgctxt][msgid]; 197 if (vec.empty()) 198 { 199 vec.push_back(msgstr); 200 } 201 else 202 { 203 log_warning << "collision in add_translation(\"" << msgctxt << "\", \"" << msgid << "\")" << std::endl; 204 vec[0] = msgstr; 205 } 206 } 207 2 208 -
new file libraries/source/tinygettext/tinygettext/dictionary.hpp
+} // namespace tinygettext + +/* EOF */ diff --git a/libraries/source/tinygettext/tinygettext/dictionary.hpp b/libraries/source/tinygettext/tinygettext/dictionary.hpp new file mode 100644 index 0000000..743e075
- + 1 // tinygettext - A gettext replacement that works directly on .po files 2 // Copyright (C) 2006 Ingo Ruhnke <grumbel@gmx.de> 3 // 4 // This program is free software; you can redistribute it and/or 5 // modify it under the terms of the GNU General Public License 6 // as published by the Free Software Foundation; either version 2 7 // of the License, or (at your option) any later version. 8 // 9 // This program is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with this program; if not, write to the Free Software 16 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 17 18 #ifndef HEADER_TINYGETTEXT_DICTIONARY_HPP 19 #define HEADER_TINYGETTEXT_DICTIONARY_HPP 20 21 #include <map> 22 #include <vector> 23 #include <string> 24 #include "plural_forms.hpp" 25 26 namespace tinygettext { 27 28 /** A simple dictionary class that mimics gettext() behaviour. Each 29 Dictionary only works for a single language, for managing multiple 30 languages and .po files at once use the DictionaryManager. */ 31 class Dictionary 32 { 33 private: 34 typedef std::map<std::string, std::vector<std::string> > Entries; 35 Entries entries; 36 37 typedef std::map<std::string, Entries> CtxtEntries; 38 CtxtEntries ctxt_entries; 39 40 std::string charset; 41 PluralForms plural_forms; 42 43 std::string translate(const Entries& dict, const std::string& msgid); 44 std::string translate_plural(const Entries& dict, const std::string& msgid, const std::string& msgidplural, int num); 45 46 public: 47 /** Constructs a dictionary converting to the specified \a charset (default UTF-8) */ 48 Dictionary(const std::string& charset = "UTF-8"); 49 ~Dictionary(); 50 51 /** Return the charset used for this dictionary */ 52 std::string get_charset() const; 53 54 void set_plural_forms(const PluralForms&); 55 PluralForms get_plural_forms() const; 56 57 58 /** Translate the string \a msgid. */ 59 std::string translate(const std::string& msgid); 60 61 /** Translate the string \a msgid to its correct plural form, based 62 on the number of items given by \a num. \a msgid_plural is \a msgid in 63 plural form. */ 64 std::string translate_plural(const std::string& msgid, const std::string& msgidplural, int num); 65 66 /** Translate the string \a msgid that is in context \a msgctx. A 67 context is a way to disambiguate msgids that contain the same 68 letters, but different meaning. For example "exit" might mean to 69 quit doing something or it might refer to a door that leads 70 outside (i.e. 'Ausgang' vs 'Beenden' in german) */ 71 std::string translate_ctxt(const std::string& msgctxt, const std::string& msgid); 72 73 std::string translate_ctxt_plural(const std::string& msgctxt, const std::string& msgid, const std::string& msgidplural, int num); 74 75 /** Add a translation from \a msgid to \a msgstr to the dictionary, 76 where \a msgid is the singular form of the message, msgid_plural the 77 plural form and msgstrs a table of translations. The right 78 translation will be calculated based on the \a num argument to 79 translate(). */ 80 void add_translation(const std::string& msgid, const std::string& msgid_plural, 81 const std::vector<std::string>& msgstrs); 82 void add_translation(const std::string& msgctxt, 83 const std::string& msgid, const std::string& msgid_plural, 84 const std::vector<std::string>& msgstrs); 85 86 /** Add a translation from \a msgid to \a msgstr to the 87 dictionary */ 88 void add_translation(const std::string& msgid, const std::string& msgstr); 89 void add_translation(const std::string& msgctxt, const std::string& msgid, const std::string& msgstr); 90 91 /** Iterate over all messages, Func is of type: 92 void func(const std::string& msgid, const std::vector<std::string>& msgstrs) */ 93 template<class Func> 94 Func foreach(Func func) 95 { 96 for(Entries::iterator i = entries.begin(); i != entries.end(); ++i) 97 { 98 func(i->first, i->second); 99 } 100 return func; 101 } 102 103 /** Iterate over all messages with a context, Func is of type: 104 void func(const std::string& ctxt, const std::string& msgid, const std::vector<std::string>& msgstrs) */ 105 template<class Func> 106 Func foreach_ctxt(Func func) 107 { 108 for(CtxtEntries::iterator i = ctxt_entries.begin(); i != ctxt_entries.end(); ++i) 109 { 110 for(Entries::iterator j = i->second.begin(); j != i->second.end(); ++j) 111 { 112 func(i->first, j->first, j->second); 113 } 114 } 115 return func; 116 } 117 }; 118 119 } // namespace tinygettext 120 121 #endif 122 123 /* EOF */ -
new file libraries/source/tinygettext/tinygettext/dictionary_manager.cpp
diff --git a/libraries/source/tinygettext/tinygettext/dictionary_manager.cpp b/libraries/source/tinygettext/tinygettext/dictionary_manager.cpp new file mode 100644 index 0000000..f923470
- + 1 // tinygettext - A gettext replacement that works directly on .po files 2 // Copyright (C) 2006 Ingo Ruhnke <grumbel@gmx.de> 3 // 4 // This program is free software; you can redistribute it and/or 5 // modify it under the terms of the GNU General Public License 6 // as published by the Free Software Foundation; either version 2 7 // of the License, or (at your option) any later version. 8 // 9 // This program is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with this program; if not, write to the Free Software 16 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 17 18 #include "dictionary_manager.hpp" 19 20 #include <memory> 21 #include <assert.h> 22 #include <stdlib.h> 23 #include <string.h> 24 #include <fstream> 25 #include <algorithm> 26 27 #include "log_stream.hpp" 28 #include "po_parser.hpp" 29 #include "unix_file_system.hpp" 30 31 namespace tinygettext { 32 33 static bool has_suffix(const std::string& lhs, const std::string rhs) 34 { 35 if (lhs.length() < rhs.length()) 36 return false; 37 else 38 return lhs.compare(lhs.length() - rhs.length(), rhs.length(), rhs) == 0; 39 } 40 41 DictionaryManager::DictionaryManager(const std::string& charset_) : 42 dictionaries(), 43 search_path(), 44 charset(charset_), 45 use_fuzzy(true), 46 current_language(), 47 current_dict(0), 48 empty_dict(), 49 filesystem(new UnixFileSystem) 50 { 51 } 52 53 DictionaryManager::~DictionaryManager() 54 { 55 for(Dictionaries::iterator i = dictionaries.begin(); i != dictionaries.end(); ++i) 56 { 57 delete i->second; 58 } 59 } 60 61 void 62 DictionaryManager::clear_cache() 63 { 64 for(Dictionaries::iterator i = dictionaries.begin(); i != dictionaries.end(); ++i) 65 { 66 delete i->second; 67 } 68 dictionaries.clear(); 69 70 current_dict = 0; 71 } 72 73 Dictionary& 74 DictionaryManager::get_dictionary() 75 { 76 if (current_dict) 77 { 78 return *current_dict; 79 } 80 else 81 { 82 if (current_language) 83 { 84 current_dict = &get_dictionary(current_language); 85 return *current_dict; 86 } 87 else 88 { 89 return empty_dict; 90 } 91 } 92 } 93 94 Dictionary& 95 DictionaryManager::get_dictionary(const Language& language) 96 { 97 //log_debug << "Dictionary for language \"" << spec << "\" requested" << std::endl; 98 //log_debug << "...normalized as \"" << lang << "\"" << std::endl; 99 assert(language); 100 101 Dictionaries::iterator i = dictionaries.find(language); 102 if (i != dictionaries.end()) 103 { 104 return *i->second; 105 } 106 else // Dictionary for languages lang isn't loaded, so we load it 107 { 108 //log_debug << "get_dictionary: " << lang << std::endl; 109 Dictionary* dict = new Dictionary(charset); 110 111 dictionaries[language] = dict; 112 113 for (SearchPath::reverse_iterator p = search_path.rbegin(); p != search_path.rend(); ++p) 114 { 115 std::vector<std::string> files = filesystem->open_directory(*p); 116 117 std::string best_filename; 118 int best_score = 0; 119 120 for(std::vector<std::string>::iterator filename = files.begin(); filename != files.end(); filename++) 121 { 122 // check if filename matches requested language 123 if (has_suffix(*filename, ".po")) 124 { // ignore anything that isn't a .po file 125 Language po_language = Language::from_env(filename->substr(0, filename->size()-3)); 126 127 if (!po_language) 128 { 129 log_warning << *filename << ": warning: ignoring, unknown language" << std::endl; 130 } 131 else 132 { 133 int score = Language::match(language, po_language); 134 135 if (score > best_score) 136 { 137 best_score = score; 138 best_filename = *filename; 139 } 140 } 141 } 142 } 143 144 if (!best_filename.empty()) 145 { 146 std::string pofile = *p + "/" + best_filename; 147 try 148 { 149 std::auto_ptr<std::istream> in = filesystem->open_file(pofile); 150 if (!in.get()) 151 { 152 log_error << "error: failure opening: " << pofile << std::endl; 153 } 154 else 155 { 156 POParser::parse(pofile, *in, *dict); 157 } 158 } 159 catch(std::exception& e) 160 { 161 log_error << "error: failure parsing: " << pofile << std::endl; 162 log_error << e.what() << "" << std::endl; 163 } 164 } 165 } 166 167 return *dict; 168 } 169 } 170 171 std::set<Language> 172 DictionaryManager::get_languages() 173 { 174 std::set<Language> languages; 175 176 for (SearchPath::iterator p = search_path.begin(); p != search_path.end(); ++p) 177 { 178 std::vector<std::string> files = filesystem->open_directory(*p); 179 180 for(std::vector<std::string>::iterator file = files.begin(); file != files.end(); ++file) 181 { 182 if (has_suffix(*file, ".po")) 183 { 184 languages.insert(Language::from_env(file->substr(0, file->size()-3))); 185 } 186 } 187 } 188 return languages; 189 } 190 191 void 192 DictionaryManager::set_language(const Language& language) 193 { 194 if (current_language != language) 195 { 196 current_language = language; 197 current_dict = 0; 198 } 199 } 200 201 Language 202 DictionaryManager::get_language() const 203 { 204 return current_language; 205 } 206 207 void 208 DictionaryManager::set_charset(const std::string& charset_) 209 { 210 clear_cache(); // changing charset invalidates cache 211 charset = charset_; 212 } 213 214 void 215 DictionaryManager::set_use_fuzzy(bool t) 216 { 217 clear_cache(); 218 use_fuzzy = t; 219 } 220 221 bool 222 DictionaryManager::get_use_fuzzy() const 223 { 224 return use_fuzzy; 225 } 226 227 void 228 DictionaryManager::add_directory(const std::string& pathname) 229 { 230 clear_cache(); // adding directories invalidates cache 231 search_path.push_back(pathname); 232 } 233 234 void 235 DictionaryManager::set_filesystem(std::auto_ptr<FileSystem> filesystem_) 236 { 237 filesystem = filesystem_; 238 } 239 240 } // namespace tinygettext 241 242 /* EOF */ -
new file libraries/source/tinygettext/tinygettext/dictionary_manager.hpp
diff --git a/libraries/source/tinygettext/tinygettext/dictionary_manager.hpp b/libraries/source/tinygettext/tinygettext/dictionary_manager.hpp new file mode 100644 index 0000000..7c3d7f3
- + 1 // tinygettext - A gettext replacement that works directly on .po files 2 // Copyright (C) 2006 Ingo Ruhnke <grumbel@gmx.de> 3 // 4 // This program is free software; you can redistribute it and/or 5 // modify it under the terms of the GNU General Public License 6 // as published by the Free Software Foundation; either version 2 7 // of the License, or (at your option) any later version. 8 // 9 // This program is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with this program; if not, write to the Free Software 16 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 17 18 #ifndef HEADER_TINYGETTEXT_DICTIONARY_MANAGER_HPP 19 #define HEADER_TINYGETTEXT_DICTIONARY_MANAGER_HPP 20 21 #include <map> 22 #include <set> 23 #include <string> 24 #include <vector> 25 #include <memory> 26 27 #include "dictionary.hpp" 28 #include "language.hpp" 29 30 namespace tinygettext { 31 32 class FileSystem; 33 34 /** Manager class for dictionaries, you give it a bunch of directories 35 with .po files and it will then automatically load the right file 36 on demand depending on which language was set. */ 37 class DictionaryManager 38 { 39 private: 40 typedef std::map<Language, Dictionary*> Dictionaries; 41 Dictionaries dictionaries; 42 43 typedef std::vector<std::string> SearchPath; 44 SearchPath search_path; 45 46 std::string charset; 47 bool use_fuzzy; 48 49 Language current_language; 50 Dictionary* current_dict; 51 52 Dictionary empty_dict; 53 54 std::auto_ptr<FileSystem> filesystem; 55 56 void clear_cache(); 57 58 public: 59 DictionaryManager(const std::string& charset_ = "UTF-8"); 60 ~DictionaryManager(); 61 62 /** Return the currently active dictionary, if none is set, an empty 63 dictionary is returned. */ 64 Dictionary& get_dictionary(); 65 66 /** Get dictionary for language */ 67 Dictionary& get_dictionary(const Language& language); 68 69 /** Set a language based on a four? letter country code */ 70 void set_language(const Language& language); 71 72 /** returns the (normalized) country code of the currently used language */ 73 Language get_language() const; 74 75 void set_use_fuzzy(bool t); 76 bool get_use_fuzzy() const; 77 78 /** Set a charset that will be set on the returned dictionaries */ 79 void set_charset(const std::string& charset); 80 81 /** Add a directory to the search path for dictionaries, earlier 82 added directories have higher priority then later added ones */ 83 void add_directory(const std::string& pathname); 84 85 /** Return a set of the available languages in their country code */ 86 std::set<Language> get_languages(); 87 88 void set_filesystem(std::auto_ptr<FileSystem> filesystem); 89 90 private: 91 DictionaryManager (const DictionaryManager&); 92 DictionaryManager& operator= (const DictionaryManager&); 93 }; 94 95 } // namespace tinygettext 96 97 #endif 98 99 /* EOF */ -
new file libraries/source/tinygettext/tinygettext/file_system.hpp
diff --git a/libraries/source/tinygettext/tinygettext/file_system.hpp b/libraries/source/tinygettext/tinygettext/file_system.hpp new file mode 100644 index 0000000..af47aaf
- + 1 // tinygettext - A gettext replacement that works directly on .po files 2 // Copyright (C) 2009 Ingo Ruhnke <grumbel@gmx.de> 3 // 4 // This program is free software; you can redistribute it and/or 5 // modify it under the terms of the GNU General Public License 6 // as published by the Free Software Foundation; either version 2 7 // of the License, or (at your option) any later version. 8 // 9 // This program is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with this program; if not, write to the Free Software 16 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 17 18 #ifndef HEADER_TINYGETTEXT_FILE_SYSTEM_HPP 19 #define HEADER_TINYGETTEXT_FILE_SYSTEM_HPP 20 21 #include <vector> 22 #include <memory> 23 #include <iosfwd> 24 #include <string> 25 26 namespace tinygettext { 27 28 class FileSystem 29 { 30 public: 31 virtual ~FileSystem() {} 32 33 virtual std::vector<std::string> open_directory(const std::string& pathname) =0; 34 virtual std::auto_ptr<std::istream> open_file(const std::string& filename) =0; 35 }; 36 37 } // namespace tinygettext 38 39 #endif 40 41 /* EOF */ 42 -
new file libraries/source/tinygettext/tinygettext/iconv.cpp
diff --git a/libraries/source/tinygettext/tinygettext/iconv.cpp b/libraries/source/tinygettext/tinygettext/iconv.cpp new file mode 100644 index 0000000..c0b8b60
- + 1 // tinygettext - A gettext replacement that works directly on .po files 2 // Copyright (C) 2009 Ingo Ruhnke <grumbel@gmx.de> 3 // 4 // This program is free software; you can redistribute it and/or 5 // modify it under the terms of the GNU General Public License 6 // as published by the Free Software Foundation; either version 2 7 // of the License, or (at your option) any later version. 8 // 9 // This program is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with this program; if not, write to the Free Software 16 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 17 18 #include <ctype.h> 19 #include <assert.h> 20 #include <sstream> 21 #include <errno.h> 22 #include <stdexcept> 23 #include <string.h> 24 #include <stdlib.h> 25 26 #include "iconv.hpp" 27 #include "log_stream.hpp" 28 29 namespace tinygettext { 30 31 #ifndef tinygettext_ICONV_CONST 32 # define tinygettext_ICONV_CONST 33 #endif 34 35 IConv::IConv() 36 : to_charset(), 37 from_charset(), 38 cd(0) 39 {} 40 41 IConv::IConv(const std::string& from_charset_, const std::string& to_charset_) 42 : to_charset(), 43 from_charset(), 44 cd(0) 45 { 46 set_charsets(from_charset_, to_charset_); 47 } 48 49 IConv::~IConv() 50 { 51 if (cd) 52 tinygettext_iconv_close(cd); 53 } 54 55 void 56 IConv::set_charsets(const std::string& from_charset_, const std::string& to_charset_) 57 { 58 if (cd) 59 tinygettext_iconv_close(cd); 60 61 from_charset = from_charset_; 62 to_charset = to_charset_; 63 64 for(std::string::iterator i = to_charset.begin(); i != to_charset.end(); ++i) 65 *i = static_cast<char>(toupper(*i)); 66 67 for(std::string::iterator i = from_charset.begin(); i != from_charset.end(); ++i) 68 *i = static_cast<char>(toupper(*i)); 69 70 if (to_charset == from_charset) 71 { 72 cd = 0; 73 } 74 else 75 { 76 cd = tinygettext_iconv_open(to_charset.c_str(), from_charset.c_str()); 77 if (cd == reinterpret_cast<tinygettext_iconv_t>(-1)) 78 { 79 if(errno == EINVAL) 80 { 81 std::ostringstream str; 82 str << "IConv construction failed: conversion from '" << from_charset 83 << "' to '" << to_charset << "' not available"; 84 throw std::runtime_error(str.str()); 85 } 86 else 87 { 88 std::ostringstream str; 89 str << "IConv: construction failed: " << strerror(errno); 90 throw std::runtime_error(str.str()); 91 } 92 } 93 } 94 } 95 96 /// Convert a string from encoding to another. 97 std::string 98 IConv::convert(const std::string& text) 99 { 100 if (!cd) 101 { 102 return text; 103 } 104 else 105 { 106 size_t inbytesleft = text.size(); 107 size_t outbytesleft = 4*inbytesleft; // Worst case scenario: ASCII -> UTF-32? 108 109 // We try to avoid to much copying around, so we write directly into 110 // a std::string 111 tinygettext_ICONV_CONST char* inbuf = const_cast<char*>(&text[0]); 112 std::string result(outbytesleft, 'X'); 113 char* outbuf = &result[0]; 114 115 // Try to convert the text. 116 size_t ret = tinygettext_iconv(cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft); 117 if (ret == static_cast<size_t>(-1)) 118 { 119 if (errno == EILSEQ || errno == EINVAL) 120 { // invalid multibyte sequence 121 tinygettext_iconv(cd, NULL, NULL, NULL, NULL); // reset state 122 123 // FIXME: Could try to skip the invalid byte and continue 124 log_error << "error: tinygettext:iconv: invalid multibyte sequence in: \"" << text << "\"" << std::endl; 125 } 126 else if (errno == E2BIG) 127 { // output buffer to small 128 assert(!"tinygettext/iconv.cpp: E2BIG: This should never be reached"); 129 } 130 else if (errno == EBADF) 131 { 132 assert(!"tinygettext/iconv.cpp: EBADF: This should never be reached"); 133 } 134 else 135 { 136 assert(!"tinygettext/iconv.cpp: <unknown>: This should never be reached"); 137 } 138 } 139 140 result.resize(4*text.size() - outbytesleft); 141 142 return result; 143 } 144 } 145 146 } // namespace tinygettext 147 148 /* EOF */ -
new file libraries/source/tinygettext/tinygettext/iconv.hpp
diff --git a/libraries/source/tinygettext/tinygettext/iconv.hpp b/libraries/source/tinygettext/tinygettext/iconv.hpp new file mode 100644 index 0000000..1ae1750
- + 1 // tinygettext - A gettext replacement that works directly on .po files 2 // Copyright (C) 2006 Ingo Ruhnke <grumbel@gmx.de> 3 // 4 // This program is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // This program is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with this program. If not, see <http://www.gnu.org/licenses/>. 16 17 #ifndef HEADER_TINYGETTEXT_ICONV_HPP 18 #define HEADER_TINYGETTEXT_ICONV_HPP 19 20 #include <string> 21 22 #ifdef HAVE_SDL 23 # include "SDL.h" 24 25 # define tinygettext_ICONV_CONST const 26 # define tinygettext_iconv_t SDL_iconv_t 27 # define tinygettext_iconv SDL_iconv 28 # define tinygettext_iconv_open SDL_iconv_open 29 # define tinygettext_iconv_close SDL_iconv_close 30 #else 31 # include <iconv.h> 32 33 # ifdef HAVE_ICONV_CONST 34 # define tinygettext_ICONV_CONST ICONV_CONST 35 # else 36 # define tinygettext_ICONV_CONST 37 # endif 38 39 # define tinygettext_iconv_t iconv_t 40 # define tinygettext_iconv iconv 41 # define tinygettext_iconv_open iconv_open 42 # define tinygettext_iconv_close iconv_close 43 #endif 44 45 namespace tinygettext { 46 47 class IConv 48 { 49 private: 50 std::string to_charset; 51 std::string from_charset; 52 tinygettext_iconv_t cd; 53 54 public: 55 IConv(); 56 IConv(const std::string& fromcode, const std::string& tocode); 57 ~IConv(); 58 59 void set_charsets(const std::string& fromcode, const std::string& tocode); 60 std::string convert(const std::string& text); 61 62 private: 63 IConv (const IConv&); 64 IConv& operator= (const IConv&); 65 }; 66 67 } // namespace tinygettext 68 69 #endif 70 71 /* EOF */ -
new file libraries/source/tinygettext/tinygettext/language.cpp
diff --git a/libraries/source/tinygettext/tinygettext/language.cpp b/libraries/source/tinygettext/tinygettext/language.cpp new file mode 100644 index 0000000..1b6aac0
- + 1 // tinygettext - A gettext replacement that works directly on .po files 2 // Copyright (C) 2006 Ingo Ruhnke <grumbel@gmx.de> 3 // 4 // This program is free software; you can redistribute it and/or 5 // modify it under the terms of the GNU General Public License 6 // as published by the Free Software Foundation; either version 2 7 // of the License, or (at your option) any later version. 8 // 9 // This program is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with this program; if not, write to the Free Software 16 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 17 18 #include "language.hpp" 19 20 #include <map> 21 #include <assert.h> 22 #include <vector> 23 24 namespace tinygettext { 25 0 26 27 struct LanguageSpec { 28 /** Language code: "de", "en", ... */ 29 const char* language; 30 31 /** Country code: "BR", "DE", ..., can be 0 */ 32 const char* country; 33 34 /** Modifier/Varint: "Latn", "ije", "latin"..., can be 0 */ 35 const char* modifier; 36 37 /** Language name: "German", "English", "French", ... */ 38 const char* name; 39 }; 40 1 41 42 /** Language Definitions */ 43 //*{ 44 LanguageSpec languages[] = { 45 { "aa", 0, 0, "Afar" }, 46 { "af", 0, 0, "Afrikaans" }, 47 { "af", "ZA", 0, "Afrikaans (South Africa)" }, 48 { "am", 0, 0, "Amharic" }, 49 { "ar", 0, 0, "Arabic" }, 50 { "ar", "AR", 0, "Arabic (Argentina)" }, 51 { "ar", "OM", 0, "Arabic (Oman)" }, 52 { "ar", "SA", 0, "Arabic (Saudi Arabia)" }, 53 { "ar", "SY", 0, "Arabic (Syrian Arab Republic)" }, 54 { "ar", "TN", 0, "Arabic (Tunisia)" }, 55 { "as", 0, 0, "Assamese" }, 56 { "ast",0, 0, "Asturian" }, 57 { "ay", 0, 0, "Aymara" }, 58 { "az", 0, 0, "Azerbaijani" }, 59 { "az", "IR", 0, "Azerbaijani (Iran)" }, 60 { "be", 0, 0, "Belarusian" }, 61 { "be", 0, "latin", "Belarusian" }, 62 { "bg", 0, 0, "Bulgarian" }, 63 { "bg", "BG", 0, "Bulgarian (Bulgaria)" }, 64 { "bn", 0, 0, "Bengali" }, 65 { "bn", "BD", 0, "Bengali (Bangladesh)" }, 66 { "bn", "IN", 0, "Bengali (India)" }, 67 { "bo", 0, 0, "Tibetan" }, 68 { "br", 0, 0, "Breton" }, 69 { "bs", 0, 0, "Bosnian" }, 70 { "bs", "BA", 0, "Bosnian (Bosnia/Herzegovina)"}, 71 { "bs", "BS", 0, "Bosnian (Bahamas)" }, 72 { "ca", "ES", "valencia", "Catalan (valencia)" }, 73 { "ca", "ES", 0, "Catalan (Spain)" }, 74 { "ca", 0, "valencia", "Catalan (valencia)" }, 75 { "ca", 0, 0, "Catalan" }, 76 { "co", 0, 0, "Corsican" }, 77 { "cs", 0, 0, "Czech" }, 78 { "cs", "CZ", 0, "Czech (Czech Republic)" }, 79 { "cy", 0, 0, "Welsh" }, 80 { "cy", "GB", 0, "Welsh (Great Britain)" }, 81 { "cz", 0, 0, "Unknown language" }, 82 { "da", 0, 0, "Danish" }, 83 { "da", "DK", 0, "Danish (Denmark)" }, 84 { "de", 0, 0, "German" }, 85 { "de", "AT", 0, "German (Austria)" }, 86 { "de", "CH", 0, "German (Switzerland)" }, 87 { "de", "DE", 0, "German (Germany)" }, 88 { "dk", 0, 0, "Unknown language" }, 89 { "dz", 0, 0, "Dzongkha" }, 90 { "el", 0, 0, "Greek" }, 91 { "el", "GR", 0, "Greek (Greece)" }, 92 { "en", 0, 0, "English" }, 93 { "en", "AU", 0, "English (Australia)" }, 94 { "en", "CA", 0, "English (Canada)" }, 95 { "en", "GB", 0, "English (Great Britain)" }, 96 { "en", "US", 0, "English (United States)" }, 97 { "en", "ZA", 0, "English (South Africa)" }, 98 { "en", 0, "boldquot", "English" }, 99 { "en", 0, "quot", "English" }, 100 { "en", "US", "piglatin", "English" }, 101 { "eo", 0, 0, "Esperanto" }, 102 { "es", 0, 0, "Spanish" }, 103 { "es", "AR", 0, "Spanish (Argentina)" }, 104 { "es", "CL", 0, "Spanish (Chile)" }, 105 { "es", "CO", 0, "Spanish (Colombia)" }, 106 { "es", "CR", 0, "Spanish (Costa Rica)" }, 107 { "es", "DO", 0, "Spanish (Dominican Republic)"}, 108 { "es", "EC", 0, "Spanish (Ecuador)" }, 109 { "es", "ES", 0, "Spanish (Spain)" }, 110 { "es", "GT", 0, "Spanish (Guatemala)" }, 111 { "es", "HN", 0, "Spanish (Honduras)" }, 112 { "es", "LA", 0, "Spanish (Laos)" }, 113 { "es", "MX", 0, "Spanish (Mexico)" }, 114 { "es", "NI", 0, "Spanish (Nicaragua)" }, 115 { "es", "PA", 0, "Spanish (Panama)" }, 116 { "es", "PE", 0, "Spanish (Peru)" }, 117 { "es", "PR", 0, "Spanish (Puerto Rico)" }, 118 { "es", "SV", 0, "Spanish (El Salvador)" }, 119 { "es", "UY", 0, "Spanish (Uruguay)" }, 120 { "es", "VE", 0, "Spanish (Venezuela)" }, 121 { "et", 0, 0, "Estonian" }, 122 { "et", "EE", 0, "Estonian (Estonia)" }, 123 { "et", "ET", 0, "Estonian (Ethiopia)" }, 124 { "eu", 0, 0, "Basque" }, 125 { "eu", "ES", 0, "Basque (Spain)" }, 126 { "fa", 0, 0, "Persian" }, 127 { "fa", "AF", 0, "Persian (Afghanistan)" }, 128 { "fa", "IR", 0, "Persian (Iran)" }, 129 { "fi", 0, 0, "Finnish" }, 130 { "fi", "FI", 0, "Finnish (Finland)" }, 131 { "fo", 0, 0, "Faroese" }, 132 { "fo", "FO", 0, "Faeroese (Faroe Islands)" }, 133 { "fr", 0, 0, "French" }, 134 { "fr", "CA", 0, "French (Canada)" }, 135 { "fr", "CH", 0, "French (Switzerland)" }, 136 { "fr", "FR", 0, "French (France)" }, 137 { "fr", "LU", 0, "French (Luxembourg)" }, 138 { "fy", 0, 0, "Frisian" }, 139 { "ga", 0, 0, "Irish" }, 140 { "gd", 0, 0, "Gaelic Scots" }, 141 { "gl", 0, 0, "Galician" }, 142 { "gl", "ES", 0, "Galician (Spain)" }, 143 { "gn", 0, 0, "Guarani" }, 144 { "gu", 0, 0, "Gujarati" }, 145 { "gv", 0, 0, "Manx" }, 146 { "ha", 0, 0, "Hausa" }, 147 { "he", 0, 0, "Hebrew" }, 148 { "he", "IL", 0, "Hebrew (Israel)" }, 149 { "hi", 0, 0, "Hindi" }, 150 { "hr", 0, 0, "Croatian" }, 151 { "hr", "HR", 0, "Croatian (Croatia)" }, 152 { "hu", 0, 0, "Hungarian" }, 153 { "hu", "HU", 0, "Hungarian (Hungary)" }, 154 { "hy", 0, 0, "Armenian" }, 155 { "ia", 0, 0, "Interlingua" }, 156 { "id", 0, 0, "Indonesian" }, 157 { "id", "ID", 0, "Indonesian (Indonesia)" }, 158 { "is", 0, 0, "Icelandic" }, 159 { "is", "IS", 0, "Icelandic (Iceland)" }, 160 { "it", 0, 0, "Italian" }, 161 { "it", "CH", 0, "Italian (Switzerland)" }, 162 { "it", "IT", 0, "Italian (Italy)" }, 163 { "iu", 0, 0, "Inuktitut" }, 164 { "ja", 0, 0, "Japanese" }, 165 { "ja", "JP", 0, "Japanese (Japan)" }, 166 { "ka", 0, 0, "Georgian" }, 167 { "kk", 0, 0, "Kazakh" }, 168 { "kl", 0, 0, "Kalaallisut" }, 169 { "km", 0, 0, "Khmer" }, 170 { "km", "KH", 0, "Khmer (Cambodia)" }, 171 { "kn", 0, 0, "Kannada" }, 172 { "ko", 0, 0, "Korean" }, 173 { "ko", "KR", 0, "Korean (Korea)" }, 174 { "ku", 0, 0, "Kurdish" }, 175 { "kw", 0, 0, "Cornish" }, 176 { "ky", 0, 0, "Kirghiz" }, 177 { "la", 0, 0, "Latin" }, 178 { "lo", 0, 0, "Lao" }, 179 { "lt", 0, 0, "Lithuanian" }, 180 { "lt", "LT", 0, "Lithuanian (Lithuania)" }, 181 { "lv", 0, 0, "Latvian" }, 182 { "lv", "LV", 0, "Latvian (Latvia)" }, 183 { "mg", 0, 0, "Malagasy" }, 184 { "mi", 0, 0, "Maori" }, 185 { "mk", 0, 0, "Macedonian" }, 186 { "mk", "MK", 0, "Macedonian (Macedonia)" }, 187 { "ml", 0, 0, "Malayalam" }, 188 { "mn", 0, 0, "Mongolian" }, 189 { "mr", 0, 0, "Marathi" }, 190 { "ms", 0, 0, "Malay" }, 191 { "ms", "MY", 0, "Malay (Malaysia)" }, 192 { "mt", 0, 0, "Maltese" }, 193 { "my", 0, 0, "Burmese" }, 194 { "my", "MM", 0, "Burmese (Myanmar)" }, 195 { "nb", 0, 0, "Norwegian Bokmal" }, 196 { "nb", "NO", 0, "Norwegian Bokmål (Norway)" }, 197 { "ne", 0, 0, "Nepali" }, 198 { "nl", 0, 0, "Dutch" }, 199 { "nl", "BE", 0, "Dutch (Belgium)" }, 200 { "nl", "NL", 0, "Dutch (Netherlands)" }, 201 { "nn", 0, 0, "Norwegian Nynorsk" }, 202 { "nn", "NO", 0, "Norwegian Nynorsk (Norway)" }, 203 { "no", 0, 0, "Norwegian" }, 204 { "no", "NO", 0, "Norwegian (Norway)" }, 205 { "no", "NY", 0, "Norwegian (NY)" }, 206 { "nr", 0, 0, "Ndebele, South" }, 207 { "oc", 0, 0, "Occitan post 1500" }, 208 { "om", 0, 0, "Oromo" }, 209 { "or", 0, 0, "Oriya" }, 210 { "pa", 0, 0, "Punjabi" }, 211 { "pl", 0, 0, "Polish" }, 212 { "pl", "PL", 0, "Polish (Poland)" }, 213 { "ps", 0, 0, "Pashto" }, 214 { "pt", 0, 0, "Portuguese" }, 215 { "pt", "BR", 0, "Brazilian" }, 216 { "pt", "PT", 0, "Portuguese (Portugal)" }, 217 { "qu", 0, 0, "Quechua" }, 218 { "rm", 0, 0, "Rhaeto-Romance" }, 219 { "ro", 0, 0, "Romanian" }, 220 { "ro", "RO", 0, "Romanian (Romania)" }, 221 { "ru", 0, 0, "Russian" }, 222 { "ru", "RU", 0, "Russian (Russia" }, 223 { "rw", 0, 0, "Kinyarwanda" }, 224 { "sa", 0, 0, "Sanskrit" }, 225 { "sd", 0, 0, "Sindhi" }, 226 { "se", 0, 0, "Sami" }, 227 { "se", "NO", 0, "Sami (Norway)" }, 228 { "si", 0, 0, "Sinhalese" }, 229 { "sk", 0, 0, "Slovak" }, 230 { "sk", "SK", 0, "Slovak (Slovakia)" }, 231 { "sl", 0, 0, "Slovenian" }, 232 { "sl", "SI", 0, "Slovenian (Slovenia)" }, 233 { "sl", "SL", 0, "Slovenian (Sierra Leone)" }, 234 { "sm", 0, 0, "Samoan" }, 235 { "so", 0, 0, "Somali" }, 236 { "sp", 0, 0, "Unknown language" }, 237 { "sq", 0, 0, "Albanian" }, 238 { "sq", "AL", 0, "Albanian (Albania)" }, 239 { "sr", 0, 0, "Serbian" }, 240 { "sr", "YU", 0, "Serbian (Yugoslavia)" }, 241 { "sr", 0,"ije", "Serbian" }, 242 { "sr", 0, "latin", "Serbian" }, 243 { "sr", 0, "Latn", "Serbian" }, 244 { "ss", 0, 0, "Swati" }, 245 { "st", 0, 0, "Sotho" }, 246 { "sv", 0, 0, "Swedish" }, 247 { "sv", "SE", 0, "Swedish (Sweden)" }, 248 { "sv", "SV", 0, "Swedish (El Salvador)" }, 249 { "sw", 0, 0, "Swahili" }, 250 { "ta", 0, 0, "Tamil" }, 251 { "te", 0, 0, "Telugu" }, 252 { "tg", 0, 0, "Tajik" }, 253 { "th", 0, 0, "Thai" }, 254 { "th", "TH", 0, "Thai (Thailand)" }, 255 { "ti", 0, 0, "Tigrinya" }, 256 { "tk", 0, 0, "Turkmen" }, 257 { "tl", 0, 0, "Tagalog" }, 258 { "to", 0, 0, "Tonga" }, 259 { "tr", 0, 0, "Turkish" }, 260 { "tr", "TR", 0, "Turkish (Turkey)" }, 261 { "ts", 0, 0, "Tsonga" }, 262 { "tt", 0, 0, "Tatar" }, 263 { "ug", 0, 0, "Uighur" }, 264 { "uk", 0, 0, "Ukrainian" }, 265 { "uk", "UA", 0, "Ukrainian (Ukraine)" }, 266 { "ur", 0, 0, "Urdu" }, 267 { "ur", "PK", 0, "Urdu (Pakistan)" }, 268 { "uz", 0, 0, "Uzbek" }, 269 { "uz", 0, "cyrillic", "Uzbek" }, 270 { "vi", 0, 0, "Vietnamese" }, 271 { "vi", "VN", 0, "Vietnamese (Vietnam)" }, 272 { "wa", 0, 0, "Walloon" }, 273 { "wo", 0, 0, "Wolof" }, 274 { "xh", 0, 0, "Xhosa" }, 275 { "yi", 0, 0, "Yiddish" }, 276 { "yo", 0, 0, "Yoruba" }, 277 { "zh", 0, 0, "Chinese" }, 278 { "zh", "CN", 0, "Chinese (simplified)" }, 279 { "zh", "HK", 0, "Chinese (Hong Kong)" }, 280 { "zh", "TW", 0, "Chinese (traditional)" }, 281 { "zu", 0, 0, "Zulu" }, 282 { NULL, 0, 0, NULL } 283 }; 284 //*} 285 2 286 287 std::string 288 resolve_language_alias(const std::string& name) 289 { 290 typedef std::map<std::string, std::string> Aliases; 291 static Aliases language_aliases; 292 if (language_aliases.empty()) 293 { 294 // FIXME: Many of those are not useful for us, since we leave 295 // encoding to the app, not to the language, we could/should 296 // also match against all language names, not just aliases from 297 // locale.alias 298 299 // Aliases taken from /etc/locale.alias 300 language_aliases["bokmal"] = "nb_NO.ISO-8859-1"; 301 language_aliases["bokmål"] = "nb_NO.ISO-8859-1"; 302 language_aliases["catalan"] = "ca_ES.ISO-8859-1"; 303 language_aliases["croatian"] = "hr_HR.ISO-8859-2"; 304 language_aliases["czech"] = "cs_CZ.ISO-8859-2"; 305 language_aliases["danish"] = "da_DK.ISO-8859-1"; 306 language_aliases["dansk"] = "da_DK.ISO-8859-1"; 307 language_aliases["deutsch"] = "de_DE.ISO-8859-1"; 308 language_aliases["dutch"] = "nl_NL.ISO-8859-1"; 309 language_aliases["eesti"] = "et_EE.ISO-8859-1"; 310 language_aliases["estonian"] = "et_EE.ISO-8859-1"; 311 language_aliases["finnish"] = "fi_FI.ISO-8859-1"; 312 language_aliases["français"] = "fr_FR.ISO-8859-1"; 313 language_aliases["french"] = "fr_FR.ISO-8859-1"; 314 language_aliases["galego"] = "gl_ES.ISO-8859-1"; 315 language_aliases["galician"] = "gl_ES.ISO-8859-1"; 316 language_aliases["german"] = "de_DE.ISO-8859-1"; 317 language_aliases["greek"] = "el_GR.ISO-8859-7"; 318 language_aliases["hebrew"] = "he_IL.ISO-8859-8"; 319 language_aliases["hrvatski"] = "hr_HR.ISO-8859-2"; 320 language_aliases["hungarian"] = "hu_HU.ISO-8859-2"; 321 language_aliases["icelandic"] = "is_IS.ISO-8859-1"; 322 language_aliases["italian"] = "it_IT.ISO-8859-1"; 323 language_aliases["japanese"] = "ja_JP.eucJP"; 324 language_aliases["japanese.euc"] = "ja_JP.eucJP"; 325 language_aliases["ja_JP"] = "ja_JP.eucJP"; 326 language_aliases["ja_JP.ujis"] = "ja_JP.eucJP"; 327 language_aliases["japanese.sjis"] = "ja_JP.SJIS"; 328 language_aliases["korean"] = "ko_KR.eucKR"; 329 language_aliases["korean.euc"] = "ko_KR.eucKR"; 330 language_aliases["ko_KR"] = "ko_KR.eucKR"; 331 language_aliases["lithuanian"] = "lt_LT.ISO-8859-13"; 332 language_aliases["no_NO"] = "nb_NO.ISO-8859-1"; 333 language_aliases["no_NO.ISO-8859-1"] = "nb_NO.ISO-8859-1"; 334 language_aliases["norwegian"] = "nb_NO.ISO-8859-1"; 335 language_aliases["nynorsk"] = "nn_NO.ISO-8859-1"; 336 language_aliases["polish"] = "pl_PL.ISO-8859-2"; 337 language_aliases["portuguese"] = "pt_PT.ISO-8859-1"; 338 language_aliases["romanian"] = "ro_RO.ISO-8859-2"; 339 language_aliases["russian"] = "ru_RU.ISO-8859-5"; 340 language_aliases["slovak"] = "sk_SK.ISO-8859-2"; 341 language_aliases["slovene"] = "sl_SI.ISO-8859-2"; 342 language_aliases["slovenian"] = "sl_SI.ISO-8859-2"; 343 language_aliases["spanish"] = "es_ES.ISO-8859-1"; 344 language_aliases["swedish"] = "sv_SE.ISO-8859-1"; 345 language_aliases["thai"] = "th_TH.TIS-620"; 346 language_aliases["turkish"] = "tr_TR.ISO-8859-9"; 347 } 348 349 std::string name_lowercase; 350 name_lowercase.resize(name.size()); 351 for(std::string::size_type i = 0; i < name.size(); ++i) 352 name_lowercase[i] = static_cast<char>(tolower(name[i])); 353 354 Aliases::iterator i = language_aliases.find(name_lowercase); 355 if (i != language_aliases.end()) 356 { 357 return i->second; 358 } 359 else 360 { 361 return name; 362 } 363 } 364 3 365 366 Language 367 Language::from_spec(const std::string& language, const std::string& country, const std::string& modifier) 368 { 369 static std::map<std::string, std::vector<LanguageSpec*> > language_map; 370 371 if (language_map.empty()) 372 { // Init language_map 373 for(int i = 0; languages[i].language != NULL; ++i) 374 language_map[languages[i].language].push_back(&languages[i]); 375 } 376 377 std::map<std::string, std::vector<LanguageSpec*> >::iterator i = language_map.find(language); 378 if (i != language_map.end()) 379 { 380 std::vector<LanguageSpec*>& lst = i->second; 381 382 LanguageSpec tmpspec; 383 tmpspec.language = language.c_str(); 384 tmpspec.country = country.c_str(); 385 tmpspec.modifier = modifier.c_str(); 386 Language tmplang(&tmpspec); 387 388 LanguageSpec* best_match = 0; 389 int best_match_score = 0; 390 for(std::vector<LanguageSpec*>::iterator j = lst.begin(); j != lst.end(); ++j) 391 { // Search for the language that best matches the given spec, value country more then modifier 392 int score = Language::match(Language(*j), tmplang); 393 394 if (score > best_match_score) 395 { 396 best_match = *j; 397 best_match_score = score; 398 } 399 } 400 assert(best_match); 401 return Language(best_match); 402 } 403 else 404 { 405 return Language(); 406 } 407 } 408 409 Language 410 Language::from_name(const std::string& spec_str) 411 { 412 return from_env(resolve_language_alias(spec_str)); 413 } 414 415 Language 416 Language::from_env(const std::string& env) 417 { 418 // Split LANGUAGE_COUNTRY.CODESET@MODIFIER into parts 419 std::string::size_type ln = env.find('_'); 420 std::string::size_type dt = env.find('.'); 421 std::string::size_type at = env.find('@'); 422 423 std::string language; 424 std::string country; 425 std::string codeset; 426 std::string modifier; 427 428 //std::cout << ln << " " << dt << " " << at << std::endl; 429 430 language = env.substr(0, std::min(std::min(ln, dt), at)); 431 432 if (ln != std::string::npos && ln+1 < env.size()) // _ 433 { 434 country = env.substr(ln+1, (std::min(dt, at) == std::string::npos) ? std::string::npos : std::min(dt, at) - (ln+1)); 435 } 436 437 if (dt != std::string::npos && dt+1 < env.size()) // . 438 { 439 codeset = env.substr(dt+1, (at == std::string::npos) ? std::string::npos : (at - (dt+1))); 440 } 441 442 if (at != std::string::npos && at+1 < env.size()) // @ 443 { 444 modifier = env.substr(at+1); 445 } 446 447 return from_spec(language, country, modifier); 448 } 449 4 450 451 Language::Language(LanguageSpec* language_spec_) 452 : language_spec(language_spec_) 453 { 454 } 455 456 Language::Language() 457 : language_spec(0) 458 { 459 } 460 461 int 462 Language::match(const Language& lhs, const Language& rhs) 463 { 464 if (lhs.get_language() != rhs.get_language()) 465 { 466 return 0; 467 } 468 else 469 { 470 static int match_tbl[3][3] = { 471 // modifier match, wildchard, miss 472 { 9, 8, 5 }, // country match 473 { 7, 6, 3 }, // country wildcard 474 { 4, 2, 1 }, // country miss 475 }; 476 477 int c; 478 if (lhs.get_country() == rhs.get_country()) 479 c = 0; 480 else if (lhs.get_country().empty() || rhs.get_country().empty()) 481 c = 1; 482 else 483 c = 2; 484 485 int m; 486 if (lhs.get_modifier() == rhs.get_modifier()) 487 m = 0; 488 else if (lhs.get_modifier().empty() || rhs.get_modifier().empty()) 489 m = 1; 490 else 491 m = 2; 492 493 return match_tbl[c][m]; 494 } 495 } 496 497 std::string 498 Language::get_language() const 499 { 500 if (language_spec) 501 return language_spec->language; 502 else 503 return ""; 504 } 505 506 std::string 507 Language::get_country() const 508 { 509 if (language_spec && language_spec->country) 510 return language_spec->country; 511 else 512 return ""; 513 } 514 515 std::string 516 Language::get_modifier() const 517 { 518 if (language_spec && language_spec->modifier) 519 return language_spec->modifier; 520 else 521 return ""; 522 } 523 524 std::string 525 Language::get_name() const 526 { 527 if (language_spec) 528 return language_spec->name; 529 else 530 return ""; 531 } 532 533 std::string 534 Language::str() const 535 { 536 if (language_spec) 537 { 538 std::string var; 539 var += language_spec->language; 540 if (language_spec->country) 541 { 542 var += "_"; 543 var += language_spec->country; 544 } 545 546 if (language_spec->modifier) 547 { 548 var += "@"; 549 var += language_spec->modifier; 550 } 551 return var; 552 } 553 else 554 { 555 return ""; 556 } 557 } 558 559 bool 560 Language::operator==(const Language& rhs) const 561 { 562 return language_spec == rhs.language_spec; 563 } 564 565 bool 566 Language::operator!=(const Language& rhs) const 567 { 568 return language_spec != rhs.language_spec; -
new file libraries/source/tinygettext/tinygettext/language.hpp
+} + +} // namespace tinygettext + +/* EOF */ diff --git a/libraries/source/tinygettext/tinygettext/language.hpp b/libraries/source/tinygettext/tinygettext/language.hpp new file mode 100644 index 0000000..b997a13
- + 1 // tinygettext - A gettext replacement that works directly on .po files 2 // Copyright (C) 2006 Ingo Ruhnke <grumbel@gmx.de> 3 // 4 // This program is free software; you can redistribute it and/or 5 // modify it under the terms of the GNU General Public License 6 // as published by the Free Software Foundation; either version 2 7 // of the License, or (at your option) any later version. 8 // 9 // This program is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with this program; if not, write to the Free Software 16 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 17 18 #ifndef HEADER_TINYGETTEXT_LANGUAGE_HPP 19 #define HEADER_TINYGETTEXT_LANGUAGE_HPP 20 21 #include <string> 22 23 namespace tinygettext { 24 25 struct LanguageSpec; 26 27 /** Lightweight wrapper around LanguageSpec */ 28 class Language 29 { 30 private: 31 LanguageSpec* language_spec; 32 33 Language(LanguageSpec* language_spec); 34 35 public: 36 /** Create a language from language and country code: 37 Example: Languge("de", "DE"); */ 38 static Language from_spec(const std::string& language, 39 const std::string& country = std::string(), 40 const std::string& modifier = std::string()); 41 42 /** Create a language from language and country code: 43 Example: Languge("deutsch"); 44 Example: Languge("de_DE"); */ 45 static Language from_name(const std::string& str); 46 47 /** Create a language from an environment variable style string (e.g de_DE.UTF-8@modifier) */ 48 static Language from_env(const std::string& env); 49 50 /** Compares two Languages, returns 0 on missmatch and a score 51 between 1 and 9 on match, the higher the score the better the 52 match */ 53 static int match(const Language& lhs, const Language& rhs); 54 55 /** Create an undefined Language object */ 56 Language(); 57 58 operator bool() const { return language_spec; } 59 60 /** Returns the language code (i.e. de, en, fr) */ 61 std::string get_language() const; 62 63 /** Returns the country code (i.e. DE, AT, US) */ 64 std::string get_country() const; 65 66 /** Returns the modifier of the language (i.e. latn or Latn for 67 Serbian with non-cyrilic characters) */ 68 std::string get_modifier() const; 69 70 /** Returns the human readable name of the Language */ 71 std::string get_name() const; 72 73 /** Returns the Language as string in the form of an environment 74 variable: {language}_{country}@{modifier} */ 75 std::string str() const; 76 77 bool operator==(const Language& rhs) const; 78 bool operator!=(const Language& rhs) const; 79 80 friend bool operator<(const Language& lhs, const Language& rhs); 81 }; 82 83 inline bool operator<(const Language& lhs, const Language& rhs) { 84 return lhs.language_spec < rhs.language_spec; 85 } 86 87 } // namespace tinygettext 88 89 #endif 90 91 /* EOF */ -
new file libraries/source/tinygettext/tinygettext/log.cpp
diff --git a/libraries/source/tinygettext/tinygettext/log.cpp b/libraries/source/tinygettext/tinygettext/log.cpp new file mode 100644 index 0000000..55c89df
- + 1 // tinygettext - A gettext replacement that works directly on .po files 2 // Copyright (C) 2009 Ingo Ruhnke <grumbel@gmx.de> 3 // 4 // This program is free software; you can redistribute it and/or 5 // modify it under the terms of the GNU General Public License 6 // as published by the Free Software Foundation; either version 2 7 // of the License, or (at your option) any later version. 8 // 9 // This program is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with this program; if not, write to the Free Software 16 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 17 18 #include <iostream> 19 #include "log.hpp" 20 21 namespace tinygettext { 22 0 23 24 Log::log_callback_t Log::log_info_callback = &Log::default_log_callback; 25 Log::log_callback_t Log::log_warning_callback = &Log::default_log_callback; 26 Log::log_callback_t Log::log_error_callback = &Log::default_log_callback; 27 1 28 29 void 30 Log::default_log_callback(const std::string& str) 31 { 32 // std::cerr << "tinygettext: " << str; 33 } 34 35 void 36 Log::set_log_info_callback(log_callback_t callback) 37 { 38 log_info_callback = callback; 39 } 40 41 void 42 Log::set_log_warning_callback(log_callback_t callback) 43 { 44 log_warning_callback = callback; 45 } 46 47 void 48 Log::set_log_error_callback(log_callback_t callback) 49 { 50 log_error_callback = callback; 51 } 52 2 53 54 Log::Log(log_callback_t callback_) : 55 callback(callback_), 56 out() 57 { 58 } 59 60 Log::~Log() 61 { 62 callback(out.str()); 63 } 64 65 std::ostream& 66 Log::get() 67 { 68 return out; 69 } 70 -
new file libraries/source/tinygettext/tinygettext/log.hpp
+} // namespace tinygettext + +/* EOF */ diff --git a/libraries/source/tinygettext/tinygettext/log.hpp b/libraries/source/tinygettext/tinygettext/log.hpp new file mode 100644 index 0000000..a8eadb4
- + 1 // tinygettext - A gettext replacement that works directly on .po files 2 // Copyright (C) 2009 Ingo Ruhnke <grumbel@gmx.de> 3 // 4 // This program is free software; you can redistribute it and/or 5 // modify it under the terms of the GNU General Public License 6 // as published by the Free Software Foundation; either version 2 7 // of the License, or (at your option) any later version. 8 // 9 // This program is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with this program; if not, write to the Free Software 16 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 17 18 #ifndef HEADER_TINYGETTEXT_LOG_HPP 19 #define HEADER_TINYGETTEXT_LOG_HPP 20 21 #include <sstream> 22 23 namespace tinygettext { 24 25 class Log 26 { 27 public: 28 typedef void (*log_callback_t)(const std::string&); 29 30 static log_callback_t log_info_callback; 31 static log_callback_t log_warning_callback; 32 static log_callback_t log_error_callback; 33 34 35 static void default_log_callback(const std::string& str); 36 37 static void set_log_info_callback(log_callback_t callback); 38 static void set_log_warning_callback(log_callback_t callback); 39 static void set_log_error_callback(log_callback_t callback); 40 41 private: 42 log_callback_t callback; 43 std::ostringstream out; 44 45 public: 46 Log(log_callback_t callback); 47 ~Log(); 48 49 std::ostream& get(); 50 }; 51 52 } // namespace tinygettext 53 54 #endif 55 56 /* EOF */ -
new file libraries/source/tinygettext/tinygettext/log_stream.hpp
diff --git a/libraries/source/tinygettext/tinygettext/log_stream.hpp b/libraries/source/tinygettext/tinygettext/log_stream.hpp new file mode 100644 index 0000000..8ad4c02
- + 1 // tinygettext - A gettext replacement that works directly on .po files 2 // Copyright (C) 2009 Ingo Ruhnke <grumbel@gmx.de> 3 // 4 // This program is free software; you can redistribute it and/or 5 // modify it under the terms of the GNU General Public License 6 // as published by the Free Software Foundation; either version 2 7 // of the License, or (at your option) any later version. 8 // 9 // This program is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with this program; if not, write to the Free Software 16 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 17 18 #ifndef HEADER_TINYGETTEXT_LOG_STREAM_HPP 19 #define HEADER_TINYGETTEXT_LOG_STREAM_HPP 20 21 #include "log.hpp" 22 23 namespace tinygettext { 24 25 // FIXME: very bad to have such things in the API 26 #define log_error if (!Log::log_error_callback); else (Log(Log::log_error_callback)).get() 27 #define log_warning if (!Log::log_warning_callback); else (Log(Log::log_warning_callback)).get() 28 #define log_info if (!Log::log_info_callback); else (Log(Log::log_warning_callback)).get() 29 30 } // namespace tinygettext 31 32 #endif 33 34 /* EOF */ -
new file libraries/source/tinygettext/tinygettext/plural_forms.cpp
diff --git a/libraries/source/tinygettext/tinygettext/plural_forms.cpp b/libraries/source/tinygettext/tinygettext/plural_forms.cpp new file mode 100644 index 0000000..8271437
- + 1 // tinygettext - A gettext replacement that works directly on .po files 2 // Copyright (C) 2006 Ingo Ruhnke <grumbel@gmx.de> 3 // 4 // This program is free software; you can redistribute it and/or 5 // modify it under the terms of the GNU General Public License 6 // as published by the Free Software Foundation; either version 2 7 // of the License, or (at your option) any later version. 8 // 9 // This program is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with this program; if not, write to the Free Software 16 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 17 18 #include "plural_forms.hpp" 19 20 #include <map> 21 22 namespace tinygettext { 23 0 24 25 /** 26 * Plural functions are used to select a string that matches a given 27 * count. \a n is the count and the return value is the string index 28 * used in the .po file, for example: 29 * 30 * msgstr[0] = "You got %d error"; 31 * msgstr[1] = "You got %d errors"; 32 * ^-- return value of plural function 33 */ 34 unsigned int plural1(int ) { return 0; } 35 unsigned int plural2_1(int n) { return (n != 1); } 36 unsigned int plural2_2(int n) { return (n > 1); } 37 unsigned int plural2_mk(int n) { return n==1 || n%10==1 ? 0 : 1; } 38 unsigned int plural3_lv(int n) { return static_cast<unsigned int>(n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2); } 39 unsigned int plural3_ga(int n) { return static_cast<unsigned int>(n==1 ? 0 : n==2 ? 1 : 2); } 40 unsigned int plural3_lt(int n) { return static_cast<unsigned int>(n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2); } 41 unsigned int plural3_1(int n) { return static_cast<unsigned int>(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2); } 42 unsigned int plural3_sk(int n) { return static_cast<unsigned int>( (n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2 ); } 43 unsigned int plural3_pl(int n) { return static_cast<unsigned int>(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2); } 44 unsigned int plural3_sl(int n) { return static_cast<unsigned int>(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3); } 45 unsigned int plural4_ar(int n) { return static_cast<unsigned int>( n==1 ? 0 : n==2 ? 1 : n>=3 && n<=10 ? 2 : 3 ); } 46 1 47 48 PluralForms 49 PluralForms::from_string(const std::string& str) 50 { 51 static std::map<std::string, struct PluralForms> plural_forms; 52 53 if (plural_forms.empty()) 54 { 55 // Note that the plural forms here shouldn't contain any spaces 56 plural_forms["Plural-Forms:nplurals=1;plural=0;"] = PluralForms(1, plural1); 57 plural_forms["Plural-Forms:nplurals=2;plural=(n!=1);"] = PluralForms(2, plural2_1); 58 plural_forms["Plural-Forms:nplurals=2;plural=n!=1;"] = PluralForms(2, plural2_1); 59 plural_forms["Plural-Forms:nplurals=2;plural=(n>1);"] = PluralForms(2, plural2_2); 60 plural_forms["Plural-Forms:nplurals=2;plural=n==1||n%10==1?0:1;"] = PluralForms(2, plural2_mk); 61 plural_forms["Plural-Forms:nplurals=3;plural=n%10==1&&n%100!=11?0:n!=0?1:2);"] = PluralForms(2, plural3_lv); 62 plural_forms["Plural-Forms:nplurals=3;plural=n==1?0:n==2?1:2;"] = PluralForms(3, plural3_ga); 63 plural_forms["Plural-Forms:nplurals=3;plural=(n%10==1&&n%100!=11?0:n%10>=2&&(n%100<10||n%100>=20)?1:2);"] = PluralForms(3, plural3_lt); 64 plural_forms["Plural-Forms:nplurals=3;plural=(n%10==1&&n%100!=11?0:n%10>=2&&n%10<=4&&(n%100<10||n%100>=20)?1:2);"] = PluralForms(3, plural3_1); 65 plural_forms["Plural-Forms:nplurals=3;plural=(n==1)?0:(n>=2&&n<=4)?1:2;"] = PluralForms(3, plural3_sk); 66 plural_forms["Plural-Forms:nplurals=3;plural=(n==1?0:n%10>=2&&n%10<=4&&(n%100<10||n%100>=20)?1:2);"] = PluralForms(3, plural3_pl); 67 plural_forms["Plural-Forms:nplurals=3;plural=(n%100==1?0:n%100==2?1:n%100==3||n%100==4?2:3);"] = PluralForms(3, plural3_sl); 68 69 plural_forms["Plural-Forms:nplurals=4;plural=n==1?0:n==2?1:n>=3&&n<=10?2:3;"]=PluralForms(4, plural4_ar); 70 } 71 72 // Remove spaces from string before lookup 73 std::string space_less_str; 74 for(std::string::size_type i = 0; i < str.size(); ++i) 75 if (!isspace(str[i])) 76 space_less_str += str[i]; 77 78 std::map<std::string, struct PluralForms>::const_iterator it= plural_forms.find(space_less_str); 79 if (it != plural_forms.end()) 80 { 81 return it->second; 82 } 83 else 84 { 85 return PluralForms(); 86 } 87 } 88 89 } // namespace tinygettext -
new file libraries/source/tinygettext/tinygettext/plural_forms.hpp
+ +/* EOF */ diff --git a/libraries/source/tinygettext/tinygettext/plural_forms.hpp b/libraries/source/tinygettext/tinygettext/plural_forms.hpp new file mode 100644 index 0000000..0b06449
- + 1 // tinygettext - A gettext replacement that works directly on .po files 2 // Copyright (C) 2006 Ingo Ruhnke <grumbel@gmx.de> 3 // 4 // This program is free software; you can redistribute it and/or 5 // modify it under the terms of the GNU General Public License 6 // as published by the Free Software Foundation; either version 2 7 // of the License, or (at your option) any later version. 8 // 9 // This program is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with this program; if not, write to the Free Software 16 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 17 18 #ifndef HEADER_TINYGETTEXT_PLURAL_FORMS_HPP 19 #define HEADER_TINYGETTEXT_PLURAL_FORMS_HPP 20 21 #include <string> 22 23 namespace tinygettext { 24 25 typedef unsigned int (*PluralFunc)(int n); 26 27 class PluralForms 28 { 29 private: 30 unsigned int nplural; 31 PluralFunc plural; 32 33 public: 34 static PluralForms from_string(const std::string& str); 35 36 PluralForms() 37 : nplural(0), 38 plural(0) 39 {} 40 41 PluralForms(unsigned int nplural_, PluralFunc plural_) 42 : nplural(nplural_), 43 plural(plural_) 44 {} 45 46 unsigned int get_nplural() const { return nplural; } 47 unsigned int get_plural(int n) const { if (plural) return plural(n); else return 0; } 48 49 bool operator==(const PluralForms& other) { return nplural == other.nplural && plural == other.plural; } 50 bool operator!=(const PluralForms& other) { return !(*this == other); } 51 52 operator bool() const { 53 return plural; 54 } 55 }; 56 57 } // namespace tinygettext 58 59 #endif 60 61 /* EOF */ -
new file libraries/source/tinygettext/tinygettext/po_parser.cpp
diff --git a/libraries/source/tinygettext/tinygettext/po_parser.cpp b/libraries/source/tinygettext/tinygettext/po_parser.cpp new file mode 100644 index 0000000..ec73eed
- + 1 // tinygettext - A gettext replacement that works directly on .po files 2 // Copyright (C) 2009 Ingo Ruhnke <grumbel@gmx.de> 3 // 4 // This program is free software; you can redistribute it and/or 5 // modify it under the terms of the GNU General Public License 6 // as published by the Free Software Foundation; either version 2 7 // of the License, or (at your option) any later version. 8 // 9 // This program is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with this program; if not, write to the Free Software 16 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 17 18 #include "po_parser.hpp" 19 20 #include <iostream> 21 #include <ctype.h> 22 #include <string> 23 #include <istream> 24 #include <string.h> 25 #include <map> 26 #include <stdlib.h> 27 28 #include "language.hpp" 29 #include "log_stream.hpp" 30 #include "iconv.hpp" 31 #include "dictionary.hpp" 32 #include "plural_forms.hpp" 33 34 namespace tinygettext { 35 36 bool POParser::pedantic = true; 37 38 void 39 POParser::parse(const std::string& filename, std::istream& in, Dictionary& dict, bool use_fuzzy_) 40 { 41 POParser parser(filename, in, dict, use_fuzzy_); 42 parser.parse(); 43 } 44 0 45 46 class POParserError {}; 47 48 POParser::POParser(const std::string& filename_, std::istream& in_, Dictionary& dict_, bool use_fuzzy_) : 49 filename(filename_), 50 in(in_), 51 dict(dict_), 52 use_fuzzy(use_fuzzy_), 53 running(false), 54 eof(false), 55 big5(false), 56 line_number(0), 57 current_line(), 58 conv() 59 { 60 } 61 62 POParser::~POParser() 63 { 64 } 65 66 void 67 POParser::warning(const std::string& msg) 68 { 69 log_warning << filename << ":" << line_number << ": warning: " << msg << ": " << current_line << std::endl; 70 //log_warning << "Line: " << current_line << std::endl; 71 } 72 73 void 74 POParser::error(const std::string& msg) 75 { 76 log_error << filename << ":" << line_number << ": error: " << msg << ": " << current_line << std::endl; 77 78 // Try to recover from an error by searching for start of another entry 79 do 80 next_line(); 81 while(!eof && !is_empty_line()); 82 83 throw POParserError(); 84 } 85 86 void 87 POParser::next_line() 88 { 89 line_number += 1; 90 if (!std::getline(in, current_line)) 91 eof = true; 92 } 93 94 void 95 POParser::get_string_line(std::ostringstream& out,std::string::size_type skip) 96 { 97 if (skip+1 >= static_cast<std::string::size_type>(current_line.size())) 98 error("unexpected end of line"); 99 100 if (current_line[skip] != '"') 101 error("expected start of string '\"'"); 102 103 std::string::size_type i; 104 for(i = skip+1; current_line[i] != '\"'; ++i) 105 { 106 if (big5 && static_cast<unsigned char>(current_line[i]) >= 0x81 && static_cast<unsigned char>(current_line[i]) <= 0xfe) 107 { 108 out << current_line[i]; 109 110 i += 1; 111 112 if (i >= current_line.size()) 113 error("invalid big5 encoding"); 114 115 out << current_line[i]; 116 } 117 else if (i >= current_line.size()) 118 { 119 error("unexpected end of string"); 120 } 121 else if (current_line[i] == '\\') 122 { 123 i += 1; 124 125 if (i >= current_line.size()) 126 error("unexpected end of string in handling '\\'"); 127 128 switch (current_line[i]) 129 { 130 case 'a': out << '\a'; break; 131 case 'b': out << '\b'; break; 132 case 'v': out << '\v'; break; 133 case 'n': out << '\n'; break; 134 case 't': out << '\t'; break; 135 case 'r': out << '\r'; break; 136 case '"': out << '"'; break; 137 case '\\': out << '\\'; break; 138 default: 139 std::ostringstream err; 140 err << "unhandled escape '\\" << current_line[i] << "'"; 141 warning(err.str()); 142 143 out << current_line[i-1] << current_line[i]; 144 break; 145 } 146 } 147 else 148 { 149 out << current_line[i]; 150 } 151 } 152 153 // process trailing garbage in line and warn if there is any 154 for(i = i+1; i < current_line.size(); ++i) 155 if (!isspace(current_line[i])) 156 { 157 warning("unexpected garbage after string ignoren"); 158 break; 159 } 160 } 161 162 std::string 163 POParser::get_string(std::string::size_type skip) 164 { 165 std::ostringstream out; 166 167 if (skip+1 >= static_cast<std::string::size_type>(current_line.size())) 168 error("unexpected end of line"); 169 170 if (current_line[skip] == ' ' && current_line[skip+1] == '"') 171 { 172 get_string_line(out, skip+1); 173 } 174 else 175 { 176 if (pedantic) 177 warning("keyword and string must be seperated by a single space"); 178 179 for(;;) 180 { 181 if (skip >= static_cast<std::string::size_type>(current_line.size())) 182 error("unexpected end of line"); 183 else if (current_line[skip] == '\"') 184 { 185 get_string_line(out, skip); 186 break; 187 } 188 else if (!isspace(current_line[skip])) 189 { 190 error("string must start with '\"'"); 191 } 192 else 193 { 194 // skip space 195 } 196 197 skip += 1; 198 } 199 } 200 201 next: 202 next_line(); 203 for(std::string::size_type i = 0; i < current_line.size(); ++i) 204 { 205 if (current_line[i] == '"') 206 { 207 if (i == 1) 208 if (pedantic) 209 warning("leading whitespace before string"); 210 211 get_string_line(out, i); 212 goto next; 213 } 214 else if (isspace(current_line[i])) 215 { 216 // skip 217 } 218 else 219 { 220 break; 221 } 222 } 223 224 return out.str(); 225 } 226 227 static bool has_prefix(const std::string& lhs, const std::string rhs) 228 { 229 if (lhs.length() < rhs.length()) 230 return false; 231 else 232 return lhs.compare(0, rhs.length(), rhs) == 0; 233 } 234 235 void 236 POParser::parse_header(const std::string& header) 237 { 238 std::string from_charset; 239 std::string::size_type start = 0; 240 for(std::string::size_type i = 0; i < header.length(); ++i) 241 { 242 if (header[i] == '\n') 243 { 244 std::string line = header.substr(start, i - start); 245 246 if (has_prefix(line, "Content-Type:")) 247 { 248 // from_charset = line.substr(len); 249 std::string::size_type len = strlen("Content-Type: text/plain; charset="); 250 if (line.compare(0, len, "Content-Type: text/plain; charset=") == 0) 251 { 252 from_charset = line.substr(len); 253 254 for(std::string::iterator ch = from_charset.begin(); ch != from_charset.end(); ++ch) 255 *ch = static_cast<char>(toupper(*ch)); 256 } 257 else 258 { 259 warning("malformed Content-Type header"); 260 } 261 } 262 else if (has_prefix(line, "Plural-Forms:")) 263 { 264 PluralForms plural_forms = PluralForms::from_string(line); 265 if (!plural_forms) 266 { 267 warning("unknown Plural-Forms given"); 268 } 269 else 270 { 271 if (!dict.get_plural_forms()) 272 { 273 dict.set_plural_forms(plural_forms); 274 } 275 else 276 { 277 if (dict.get_plural_forms() != plural_forms) 278 { 279 warning("Plural-Forms missmatch between .po file and dictionary"); 280 } 281 } 282 } 283 } 284 start = i+1; 285 } 286 } 287 288 if (from_charset.empty() || from_charset == "CHARSET") 289 { 290 warning("charset not specified for .po, fallback to utf-8"); 291 from_charset = "UTF-8"; 292 } 293 else if (from_charset == "BIG5") 294 { 295 big5 = true; 296 } 297 298 conv.set_charsets(from_charset, dict.get_charset()); 299 } 300 301 bool 302 POParser::is_empty_line() 303 { 304 if (current_line.empty()) 305 { 306 return true; 307 } 308 else if (current_line[0] == '#') 309 { // handle comments as empty lines 310 if (current_line.size() == 1 || (current_line.size() >= 2 && isspace(current_line[1]))) 311 return true; 312 else 313 return false; 314 } 315 else 316 { 317 for(std::string::iterator i = current_line.begin(); i != current_line.end(); ++i) 318 { 319 if (!isspace(*i)) 320 return false; 321 } 322 } 323 return true; 324 } 325 326 bool 327 POParser::prefix(const char* prefix_str) 328 { 329 return current_line.compare(0, strlen(prefix_str), prefix_str) == 0; 330 } 331 332 void 333 POParser::parse() 334 { 335 next_line(); 336 337 // skip UTF-8 intro that some text editors produce 338 // see http://en.wikipedia.org/wiki/Byte-order_mark 339 if (current_line.size() >= 3 && 340 current_line[0] == static_cast<char>(0xef) && 341 current_line[1] == static_cast<char>(0xbb) && 342 current_line[2] == static_cast<char>(0xbf)) 343 { 344 current_line = current_line.substr(3); 345 } 346 347 // Parser structure 348 while(!eof) 349 { 350 try 351 { 352 bool fuzzy = false; 353 bool has_msgctxt = false; 354 std::string msgctxt; 355 std::string msgid; 356 357 while(prefix("#")) 358 { 359 if (current_line.size() >= 2 && current_line[1] == ',') 360 { 361 // FIXME: Rather simplistic hunt for fuzzy flag 362 if (current_line.find("fuzzy", 2) != std::string::npos) 363 fuzzy = true; 364 } 365 366 next_line(); 367 } 368 369 if (!is_empty_line()) 370 { 371 if (prefix("msgctxt")) 372 { 373 has_msgctxt = true; 374 msgctxt = get_string(7); 375 } 376 377 if (prefix("msgid")) 378 msgid = get_string(5); 379 else 380 error("expected 'msgid'"); 381 382 if (prefix("msgid_plural")) 383 { 384 std::string msgid_plural = get_string(12); 385 std::vector<std::string> msgstr_num; 386 bool saw_nonempty_msgstr = false; 387 388 next: 389 if (is_empty_line()) 390 { 391 if (msgstr_num.empty()) 392 error("expected 'msgstr[N] (0 <= N <= 9)'"); 393 } 394 else if (prefix("msgstr[") && 395 current_line.size() > 8 && 396 isdigit(current_line[7]) && current_line[8] == ']') 397 { 398 std::string::size_type number = static_cast<std::string::size_type>(current_line[7] - '0'); 399 std::string msgstr = get_string(9); 400 401 if(!msgstr.empty()) 402 saw_nonempty_msgstr = true; 403 404 if (number >= msgstr_num.size()) 405 msgstr_num.resize(number+1); 406 407 msgstr_num[number] = conv.convert(msgstr); 408 goto next; 409 } 410 else 411 { 412 error("expected 'msgstr[N]'"); 413 } 414 415 if (!is_empty_line()) 416 error("expected 'msgstr[N]' or empty line"); 417 418 if (saw_nonempty_msgstr) 419 { 420 if (use_fuzzy || !fuzzy) 421 { 422 if (!dict.get_plural_forms()) 423 { 424 warning("msgstr[N] seen, but no Plural-Forms given"); 425 } 426 else 427 { 428 if (msgstr_num.size() != dict.get_plural_forms().get_nplural()) 429 { 430 warning("msgstr[N] count doesn't match Plural-Forms.nplural"); 431 } 432 } 433 434 if (has_msgctxt) 435 dict.add_translation(msgctxt, msgid, msgid_plural, msgstr_num); 436 else 437 dict.add_translation(msgid, msgid_plural, msgstr_num); 438 } 439 440 if (0) 441 { 442 std::cout << (fuzzy?"fuzzy":"not-fuzzy") << std::endl; 443 std::cout << "msgid \"" << msgid << "\"" << std::endl; 444 std::cout << "msgid_plural \"" << msgid_plural << "\"" << std::endl; 445 for(std::vector<std::string>::size_type i = 0; i < msgstr_num.size(); ++i) 446 std::cout << "msgstr[" << i << "] \"" << conv.convert(msgstr_num[i]) << "\"" << std::endl; 447 std::cout << std::endl; 448 } 449 } 450 } 451 else if (prefix("msgstr")) 452 { 453 std::string msgstr = get_string(6); 454 455 if (msgid.empty()) 456 { 457 parse_header(msgstr); 458 } 459 else if(!msgstr.empty()) 460 { 461 if (use_fuzzy || !fuzzy) 462 { 463 if (has_msgctxt) 464 dict.add_translation(msgctxt, msgid, conv.convert(msgstr)); 465 else 466 dict.add_translation(msgid, conv.convert(msgstr)); 467 } 468 469 if (0) 470 { 471 std::cout << (fuzzy?"fuzzy":"not-fuzzy") << std::endl; 472 std::cout << "msgid \"" << msgid << "\"" << std::endl; 473 std::cout << "msgstr \"" << conv.convert(msgstr) << "\"" << std::endl; 474 std::cout << std::endl; 475 } 476 } 477 } 478 else 479 { 480 error("expected 'msgstr' or 'msgid_plural'"); 481 } 482 } 483 484 if (!is_empty_line()) 485 error("expected empty line"); 486 487 next_line(); 488 } 489 catch(POParserError&) 490 { 491 } 492 } 493 } 494 495 } // namespace tinygettext 496 -
new file libraries/source/tinygettext/tinygettext/po_parser.hpp
+/* EOF */ diff --git a/libraries/source/tinygettext/tinygettext/po_parser.hpp b/libraries/source/tinygettext/tinygettext/po_parser.hpp new file mode 100644 index 0000000..841382c
- + 1 // tinygettext - A gettext replacement that works directly on .po files 2 // Copyright (C) 2009 Ingo Ruhnke <grumbel@gmx.de> 3 // 4 // This program is free software; you can redistribute it and/or 5 // modify it under the terms of the GNU General Public License 6 // as published by the Free Software Foundation; either version 2 7 // of the License, or (at your option) any later version. 8 // 9 // This program is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with this program; if not, write to the Free Software 16 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 17 18 #ifndef HEADER_TINYGETTEXT_PO_PARSER_HPP 19 #define HEADER_TINYGETTEXT_PO_PARSER_HPP 20 21 #include <iosfwd> 22 23 #include "iconv.hpp" 24 25 namespace tinygettext { 26 27 class Dictionary; 28 29 class POParser 30 { 31 private: 32 std::string filename; 33 std::istream& in; 34 Dictionary& dict; 35 bool use_fuzzy; 36 37 bool running; 38 bool eof; 39 bool big5; 40 41 int line_number; 42 std::string current_line; 43 44 IConv conv; 45 46 POParser(const std::string& filename, std::istream& in_, Dictionary& dict_, bool use_fuzzy = true); 47 ~POParser(); 48 49 void parse_header(const std::string& header); 50 void parse(); 51 void next_line(); 52 std::string get_string(std::string::size_type skip); 53 void get_string_line(std::ostringstream& str,std::string::size_type skip); 54 bool is_empty_line(); 55 bool prefix(const char* ); 56 void error(const std::string& msg) __attribute__((__noreturn__)); 57 void warning(const std::string& msg); 58 59 public: 60 /** @param filename name of the istream, only used in error messages 61 @param in stream from which the PO file is read. 62 @param dict dictionary to which the strings are written */ 63 static void parse(const std::string& filename, std::istream& in, Dictionary& dict, bool use_fuzzy = true); 64 static bool pedantic; 65 66 private: 67 POParser (const POParser&); 68 POParser& operator= (const POParser&); 69 }; 70 71 } // namespace tinygettext 72 73 #endif 74 75 /* EOF */ -
new file libraries/source/tinygettext/tinygettext/tinygettext.cpp
diff --git a/libraries/source/tinygettext/tinygettext/tinygettext.cpp b/libraries/source/tinygettext/tinygettext/tinygettext.cpp new file mode 100644 index 0000000..7f5adc8
- + 1 // tinygettext - A gettext replacement that works directly on .po files 2 // Copyright (C) 2006 Ingo Ruhnke <grumbel@gmx.de> 3 // 4 // This program is free software; you can redistribute it and/or 5 // modify it under the terms of the GNU General Public License 6 // as published by the Free Software Foundation; either version 2 7 // of the License, or (at your option) any later version. 8 // 9 // This program is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with this program; if not, write to the Free Software 16 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 17 18 namespace tinygettext { 19 20 } // namespace tinygettext 21 22 /* EOF */ -
new file libraries/source/tinygettext/tinygettext/tinygettext.hpp
diff --git a/libraries/source/tinygettext/tinygettext/tinygettext.hpp b/libraries/source/tinygettext/tinygettext/tinygettext.hpp new file mode 100644 index 0000000..19fd4c6
- + 1 // tinygettext - A gettext replacement that works directly on .po files 2 // Copyright (C) 2006 Ingo Ruhnke <grumbel@gmx.de> 3 // 4 // This program is free software; you can redistribute it and/or 5 // modify it under the terms of the GNU General Public License 6 // as published by the Free Software Foundation; either version 2 7 // of the License, or (at your option) any later version. 8 // 9 // This program is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with this program; if not, write to the Free Software 16 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 17 18 #ifndef HEADER_TINYGETTEXT_TINYGETTEXT_HPP 19 #define HEADER_TINYGETTEXT_TINYGETTEXT_HPP 20 21 #include "dictionary.hpp" 22 #include "dictionary_manager.hpp" 23 #include "language.hpp" 24 25 #endif 26 27 /* EOF */ -
new file libraries/source/tinygettext/tinygettext/unix_file_system.cpp
diff --git a/libraries/source/tinygettext/tinygettext/unix_file_system.cpp b/libraries/source/tinygettext/tinygettext/unix_file_system.cpp new file mode 100644 index 0000000..5e14d17
- + 1 // tinygettext - A gettext replacement that works directly on .po files 2 // Copyright (C) 2009 Ingo Ruhnke <grumbel@gmx.de> 3 // 4 // This program is free software; you can redistribute it and/or 5 // modify it under the terms of the GNU General Public License 6 // as published by the Free Software Foundation; either version 2 7 // of the License, or (at your option) any later version. 8 // 9 // This program is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with this program; if not, write to the Free Software 16 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 17 18 #include "unix_file_system.hpp" 19 20 #include <sys/types.h> 21 #include <fstream> 22 #include <dirent.h> 23 #include <stdlib.h> 24 #include <dirent.h> 25 #include <string.h> 26 27 namespace tinygettext { 28 29 UnixFileSystem::UnixFileSystem() 30 { 31 } 32 33 std::vector<std::string> 34 UnixFileSystem::open_directory(const std::string& pathname) 35 { 36 DIR* dir = opendir(pathname.c_str()); 37 if (!dir) 38 { 39 // FIXME: error handling 40 return std::vector<std::string>(); 41 } 42 else 43 { 44 std::vector<std::string> files; 45 46 struct dirent* dp; 47 while((dp = readdir(dir)) != 0) 48 { 49 files.push_back(dp->d_name); 50 } 51 closedir(dir); 52 53 return files; 54 } 55 } 56 57 std::auto_ptr<std::istream> 58 UnixFileSystem::open_file(const std::string& filename) 59 { 60 return std::auto_ptr<std::istream>(new std::ifstream(filename.c_str())); 61 } 62 63 } // namespace tinygettext 64 65 /* EOF */ -
new file libraries/source/tinygettext/tinygettext/unix_file_system.hpp
diff --git a/libraries/source/tinygettext/tinygettext/unix_file_system.hpp b/libraries/source/tinygettext/tinygettext/unix_file_system.hpp new file mode 100644 index 0000000..80f3e6d
- + 1 // tinygettext - A gettext replacement that works directly on .po files 2 // Copyright (C) 2009 Ingo Ruhnke <grumbel@gmx.de> 3 // 4 // This program is free software; you can redistribute it and/or 5 // modify it under the terms of the GNU General Public License 6 // as published by the Free Software Foundation; either version 2 7 // of the License, or (at your option) any later version. 8 // 9 // This program is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with this program; if not, write to the Free Software 16 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 17 18 #ifndef HEADER_TINYGETTEXT_UNIX_FILE_SYSTEM_HPP 19 #define HEADER_TINYGETTEXT_UNIX_FILE_SYSTEM_HPP 20 21 #include "file_system.hpp" 22 23 namespace tinygettext { 24 25 class UnixFileSystem : public FileSystem 26 { 27 public: 28 UnixFileSystem(); 29 30 std::vector<std::string> open_directory(const std::string& pathname); 31 std::auto_ptr<std::istream> open_file(const std::string& filename); 32 }; 33 34 } // namespace tinygettext 35 36 #endif 37 38 /* EOF */ -
source/gui/CGUI.cpp
diff --git a/source/gui/CGUI.cpp b/source/gui/CGUI.cpp index e6bfdec..c6e7ccc 100644
a b CGUI 45 45 #include "graphics/TextRenderer.h" 46 46 #include "lib/input.h" 47 47 #include "lib/bits.h" 48 #include "lib/localization.h" 48 49 #include "lib/timer.h" 49 50 #include "lib/sysdep/sysdep.h" 51 #include "lib/utf8.h" 50 52 #include "ps/CLogger.h" 51 53 #include "ps/Filesystem.h" 52 54 #include "ps/Font.h" … … void CGUI::Xeromyces_ReadObject(XMBElement Element, CXeromyces* pFile, IGUIObjec 1180 1182 ELMT(object); 1181 1183 ELMT(action); 1182 1184 ELMT(repeat); 1185 ELMT(localizableAttribute); 1186 ELMT(localize); 1187 ELMT(attribute); 1188 ELMT(keep); 1183 1189 ATTR(style); 1184 1190 ATTR(type); 1185 1191 ATTR(name); … … void CGUI::Xeromyces_ReadObject(XMBElement Element, CXeromyces* pFile, IGUIObjec 1187 1193 ATTR(z); 1188 1194 ATTR(on); 1189 1195 ATTR(file); 1196 ATTR(id); 1190 1197 1191 1198 // 1192 1199 // Read Style and set defaults … … void CGUI::Xeromyces_ReadObject(XMBElement Element, CXeromyces* pFile, IGUIObjec 1327 1334 code = scriptfile.DecodeUTF8(); // assume it's UTF-8 1328 1335 } 1329 1336 1330 // Read the inline code (concatenating to the file code, if both are specified) 1331 code += CStr(child.GetText()); 1337 XMBElementList grandchildren = child.GetChildNodes(); 1338 if (grandchildren.Count > 0) // The <action> element contains <keep> and <localize> tags. 1339 { 1340 for (int i = 0; i < grandchildren.Count; ++i) 1341 { 1342 XMBElement grandchild = grandchildren.Item(i); 1343 if (grandchild.GetNodeName() == elmt_localize) 1344 { 1345 code += Localization::getInstance().localize(grandchild.GetText()); 1346 } 1347 else if (grandchild.GetNodeName() == elmt_keep) 1348 { 1349 code += grandchild.GetText(); 1350 } 1351 } 1352 } 1353 else // Itâs pure JavaScript code. 1354 { 1355 // Read the inline code (concatenating to the file code, if both are specified) 1356 code += CStr(child.GetText()); 1357 } 1332 1358 1333 1359 CStr action = CStr(child.GetAttributes().GetNamedItem(attr_on)); 1334 1360 object->RegisterScriptHandler(action.LowerCase(), code, this); … … void CGUI::Xeromyces_ReadObject(XMBElement Element, CXeromyces* pFile, IGUIObjec 1337 1363 { 1338 1364 Xeromyces_ReadRepeat(child, pFile, object, Paths); 1339 1365 } 1366 else if (element_name == elmt_localizableAttribute) 1367 { 1368 // This is an element in the form â<localizableAttribute id="attributeName">attributeValue</localizableAttribute>â. 1369 CStr attributeName(child.GetAttributes().GetNamedItem(attr_id)); // Read the attribute name. 1370 if (!attributeName.empty()) 1371 { 1372 CStr value(child.GetText()); 1373 if (!value.empty()) 1374 { 1375 CStr localizedValue(Localization::getInstance().localize(value)); 1376 object->SetSetting(attributeName, localizedValue.UnescapeBackslashes().FromUTF8(), true); 1377 } 1378 } 1379 else // Ignore. 1380 { 1381 LOGERROR(L"GUI: âattributeâ XML element with empty âidâ XML attribute found. (object: %hs)", object->GetPresentableName().c_str()); 1382 } 1383 } 1384 else if (element_name == elmt_attribute) 1385 { 1386 // This is an element in the form â<attribute id="attributeName"><keep>Donât translate this part 1387 // </keep><localize>but translate this one.</localize></attribute>â. 1388 CStr attributeName(child.GetAttributes().GetNamedItem(attr_id)); // Read the attribute name. 1389 if (!attributeName.empty()) 1390 { 1391 CStr localizedValue; 1392 1393 XMBElementList grandchildren = child.GetChildNodes(); 1394 for (int i = 0; i < grandchildren.Count; ++i) 1395 { 1396 XMBElement grandchild = grandchildren.Item(i); 1397 if (grandchild.GetNodeName() == elmt_localize) 1398 { 1399 localizedValue += Localization::getInstance().localize(grandchild.GetText()); 1400 } 1401 else if (grandchild.GetNodeName() == elmt_keep) 1402 { 1403 localizedValue += grandchild.GetText(); 1404 } 1405 } 1406 object->SetSetting(attributeName, localizedValue.UnescapeBackslashes().FromUTF8(), true); 1407 } 1408 else // Ignore. 1409 { 1410 LOGERROR(L"GUI: âattributeâ XML element with empty âidâ XML attribute found. (object: %hs)", object->GetPresentableName().c_str()); 1411 } 1412 } 1340 1413 else 1341 1414 { 1342 1415 // Try making the object read the tag. -
source/gui/GUIRenderer.cpp
diff --git a/source/gui/GUIRenderer.cpp b/source/gui/GUIRenderer.cpp index 9531158..e5f2b09 100644
a b 22 22 #include "graphics/ShaderManager.h" 23 23 #include "graphics/TextureManager.h" 24 24 #include "gui/GUIutil.h" 25 #include "lib/localization.h" 25 26 #include "lib/ogl.h" 26 27 #include "lib/utf8.h" 27 28 #include "lib/res/h_mgr.h" … … void GUIRenderer::UpdateDrawCallCache(DrawCalls &Calls, const CStr& SpriteName, 200 201 201 202 if (! cit->m_TextureName.empty()) 202 203 { 203 CTextureProperties textureProps( cit->m_TextureName);204 CTextureProperties textureProps(Localization::getInstance().localizePath(cit->m_TextureName)); 204 205 textureProps.SetWrap(cit->m_WrapMode); 205 206 CTexturePtr texture = g_Renderer.GetTextureManager().CreateTexture(textureProps); 206 207 texture->Prefetch(); -
source/gui/scripting/ScriptFunctions.cpp
diff --git a/source/gui/scripting/ScriptFunctions.cpp b/source/gui/scripting/ScriptFunctions.cpp index 6913c2b..5058436 100644
a b 24 24 #include "graphics/MapReader.h" 25 25 #include "gui/GUIManager.h" 26 26 #include "graphics/scripting/JSInterface_GameView.h" 27 #include "lib/localization.h" 28 #include "lib/svn_revision.h" 27 29 #include "lib/timer.h" 28 30 #include "lib/utf8.h" 29 31 #include "lib/sysdep/sysdep.h" … … void SetBoundingBoxDebugOverlay(void* UNUSED(cbdata), bool enabled) 650 652 ICmpSelectable::ms_EnableDebugOverlays = enabled; 651 653 } 652 654 655 // Return the date/time at which the current executable was compiled. 656 // params: none (-> "date time (svn revision)") OR an integer specifying 657 // what to display: 0 for date, 1 for time, 2 for svn revision 658 // returns: string with the requested timestamp info 659 // notes: 660 // - Displayed on main menu screen; tells non-programmers which auto-build 661 // they are running. Could also be determined via .EXE file properties, 662 // but that's a bit more trouble. 663 // - To be exact, the date/time returned is when scriptglue.cpp was 664 // last compiled, but the auto-build does full rebuilds. 665 // - svn revision is generated by calling svnversion and cached in 666 // lib/svn_revision.cpp. it is useful to know when attempting to 667 // reproduce bugs (the main EXE and PDB should be temporarily reverted to 668 // that revision so that they match user-submitted crashdumps). 669 std::wstring GetBuildTimestamp(void* UNUSED(cbdata), int mode) 670 { 671 char buf[200]; 672 if (mode == -1) // Date, time and revision. 673 { 674 UDate dateTime = Localization::getInstance().parseDateTime(__DATE__ " " __TIME__, "MMM d yyyy HH:mm:ss", Locale::getUS()); 675 std::string dateTimeString = Localization::getInstance().localizeDateTime(dateTime, Localization::DateTime, SimpleDateFormat::DATE_TIME); 676 char svnRevision[32]; 677 sprintf_s(svnRevision, ARRAY_SIZE(svnRevision), "%ls", svn_revision); 678 if (strcmp(svnRevision, "custom build") == 0) 679 { 680 // Localization: First item is a date and time, item between parenthesis is the Subversion revision number of the current build. 681 sprintf_s(buf, ARRAY_SIZE(buf), Localization::getInstance().localize("%s (custom build)").c_str(), dateTimeString.c_str()); 682 } 683 else 684 { 685 // Localization: First item is a date and time, item between parenthesis is the Subversion revision number of the current build. 686 sprintf_s(buf, ARRAY_SIZE(buf), Localization::getInstance().localize("%s (%ls)").c_str(), dateTimeString.c_str(), svn_revision); 687 } 688 } 689 else if (mode == 0) // Date. 690 { 691 UDate dateTime = Localization::getInstance().parseDateTime(__DATE__, "MMM d yyyy", Locale::getUS()); 692 std::string dateTimeString = Localization::getInstance().localizeDateTime(dateTime, Localization::Date, SimpleDateFormat::MEDIUM); 693 sprintf_s(buf, ARRAY_SIZE(buf), "%s", dateTimeString.c_str()); 694 } 695 else if (mode == 1) // Time. 696 { 697 UDate dateTime = Localization::getInstance().parseDateTime(__TIME__, "HH:mm:ss", Locale::getUS()); 698 std::string dateTimeString = Localization::getInstance().localizeDateTime(dateTime, Localization::Time, SimpleDateFormat::MEDIUM); 699 sprintf_s(buf, ARRAY_SIZE(buf), "%s", dateTimeString.c_str()); 700 } 701 else if (mode == 2) // Revision. 702 { 703 char svnRevision[32]; 704 sprintf_s(svnRevision, ARRAY_SIZE(svnRevision), "%ls", svn_revision); 705 if (strcmp(svnRevision, "custom build") == 0) 706 { 707 sprintf_s(buf, ARRAY_SIZE(buf), Localization::getInstance().localize("custom build").c_str()); 708 } 709 else 710 { 711 sprintf_s(buf, ARRAY_SIZE(buf), "%ls", svn_revision); 712 } 713 } 714 715 return wstring_from_utf8(buf); 716 } 717 718 // Return the current locale code. 719 std::string getCurrentLocale(void* UNUSED(cbdata)) 720 { 721 return Localization::getInstance().getCurrentLocale().getLanguage(); 722 } 723 724 // Return a localized version of the given string. 725 std::wstring localize(void* UNUSED(cbdata), std::wstring sourceString) 726 { 727 return wstring_from_utf8(Localization::getInstance().localize(utf8_from_wstring(sourceString))); 728 } 729 730 // Return a localized version of the given string, for the specified context. 731 std::wstring localizeWithContext(void* UNUSED(cbdata), std::string context, std::wstring sourceString) 732 { 733 return wstring_from_utf8(Localization::getInstance().localizeWithContext(context, utf8_from_wstring(sourceString))); 734 } 735 736 // Return a localized version of the given strings (singular and plural) depending on an integer value. 737 std::wstring localizePlural(void* UNUSED(cbdata), std::wstring singularSourceString, std::wstring pluralSourceString, int number) 738 { 739 return wstring_from_utf8(Localization::getInstance().localizePlural(utf8_from_wstring(singularSourceString), utf8_from_wstring(pluralSourceString), number)); 740 } 741 742 // Return a localized version of the given strings (singular and plural) depending on an integer value, for the specified context. 743 std::wstring localizePluralWithContext(void* UNUSED(cbdata), std::string context, std::wstring singularSourceString, std::wstring pluralSourceString, int number) 744 { 745 return wstring_from_utf8(Localization::getInstance().localizePluralWithContext(context, utf8_from_wstring(singularSourceString), utf8_from_wstring(pluralSourceString), number)); 746 } 747 748 // Return a localized version of the given string, localizing it line by line. 749 std::wstring localizeLines(void* UNUSED(cbdata), std::wstring sourceString) 750 { 751 return wstring_from_utf8(Localization::getInstance().localizeLines(utf8_from_wstring(sourceString))); 752 } 753 754 // Return a localized version of the items in the specified array. 755 std::vector<std::wstring> localizeArray(void* UNUSED(cbdata), std::vector<std::wstring> sourceArray) 756 { 757 std::vector<std::wstring> localizedArray; 758 for (std::vector<std::wstring>::iterator iterator = sourceArray.begin(); iterator != sourceArray.end(); ++iterator) 759 { 760 localizedArray.push_back(wstring_from_utf8(Localization::getInstance().localize(utf8_from_wstring(*iterator)))); 761 } 762 return localizedArray; 763 } 764 765 // Return a localized version of a time given in milliseconds. 766 std::wstring formatMillisecondsIntoDateString(void* UNUSED(cbdata), int milliseconds, std::wstring formatString) 767 { 768 return wstring_from_utf8(Localization::getInstance().formatMillisecondsIntoDateString(milliseconds, utf8_from_wstring(formatString))); 769 } 770 771 // Return a localized version of the given decimal number. 772 std::wstring formatDecimalNumberIntoString(void* UNUSED(cbdata), double number) 773 { 774 return wstring_from_utf8(Localization::getInstance().formatDecimalNumberIntoString(number)); 775 } 776 777 // Return a localized version of the given decimal number. 778 std::wstring markToLocalize(void* UNUSED(cbdata), std::wstring sourceString) 779 { 780 return sourceString; 781 } 782 783 std::vector<std::string> GetSupportedLocaleCodes(void* UNUSED(cbdata)) 784 { 785 return Localization::getInstance().getSupportedLocaleCodes(); 786 } 787 788 std::vector<std::wstring> GetSupportedLocaleDisplayNames(void* UNUSED(cbdata)) 789 { 790 return Localization::getInstance().getSupportedLocaleDisplayNames(); 791 } 792 793 int GetCurrentLocaleIndex(void* UNUSED(cbdata)) 794 { 795 return Localization::getInstance().getCurrentLocaleIndex(); 796 } 797 798 void SetLocale(void* UNUSED(cbdata), std::string locale) 799 { 800 g_ConfigDB.CreateValue(CFG_USER, "locale")->m_String = locale; 801 g_ConfigDB.WriteFile(CFG_USER); 802 } 803 653 804 } // namespace 654 805 655 806 void GuiScriptingInit(ScriptInterface& scriptInterface) … … void GuiScriptingInit(ScriptInterface& scriptInterface) 743 894 scriptInterface.RegisterFunction<void, unsigned int, &EnableTimeWarpRecording>("EnableTimeWarpRecording"); 744 895 scriptInterface.RegisterFunction<void, &RewindTimeWarp>("RewindTimeWarp"); 745 896 scriptInterface.RegisterFunction<void, bool, &SetBoundingBoxDebugOverlay>("SetBoundingBoxDebugOverlay"); 897 898 // Internationalization and localization functions 899 scriptInterface.RegisterFunction<std::wstring, int, &GetBuildTimestamp>("GetBuildTimestamp"); 900 scriptInterface.RegisterFunction<std::string, &getCurrentLocale>("getCurrentLocale"); 901 scriptInterface.RegisterFunction<std::wstring, std::wstring, &localize>("localize"); 902 scriptInterface.RegisterFunction<std::wstring, std::string, std::wstring, &localizeWithContext>("localizeWithContext"); 903 scriptInterface.RegisterFunction<std::wstring, std::wstring, std::wstring, int, &localizePlural>("localizePlural"); 904 scriptInterface.RegisterFunction<std::wstring, std::string, std::wstring, std::wstring, int, &localizePluralWithContext>("localizePluralWithContext"); 905 scriptInterface.RegisterFunction<std::wstring, std::wstring, &localizeLines>("localizeLines"); 906 scriptInterface.RegisterFunction<std::vector<std::wstring>, std::vector<std::wstring>, &localizeArray>("localizeArray"); 907 scriptInterface.RegisterFunction<std::wstring, int, std::wstring, &formatMillisecondsIntoDateString>("formatMillisecondsIntoDateString"); 908 scriptInterface.RegisterFunction<std::wstring, double, &formatDecimalNumberIntoString>("formatDecimalNumberIntoString"); 909 scriptInterface.RegisterFunction<std::wstring, std::wstring, &markToLocalize>("markToLocalize"); 910 scriptInterface.RegisterFunction<std::vector<std::string>, &GetSupportedLocaleCodes>("GetSupportedLocaleCodes"); 911 scriptInterface.RegisterFunction<std::vector<std::wstring>, &GetSupportedLocaleDisplayNames>("GetSupportedLocaleDisplayNames"); 912 scriptInterface.RegisterFunction<int, &GetCurrentLocaleIndex>("GetCurrentLocaleIndex"); 913 scriptInterface.RegisterFunction<void, std::string, &SetLocale>("SetLocale"); 746 914 } -
new file source/lib/external_libraries/icu.h
diff --git a/source/lib/external_libraries/icu.h b/source/lib/external_libraries/icu.h new file mode 100644 index 0000000..07b8ba2
- + 1 /* Copyright (c) 2013 Wildfire Games 2 * 3 * Permission is hereby granted, free of charge, to any person obtaining 4 * a copy of this software and associated documentation files (the 5 * "Software"), to deal in the Software without restriction, including 6 * without limitation the rights to use, copy, modify, merge, publish, 7 * distribute, sublicense, and/or sell copies of the Software, and to 8 * permit persons to whom the Software is furnished to do so, subject to 9 * the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included 12 * in all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 18 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 19 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 20 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 */ 22 23 #ifndef INCLUDED_ICU 24 #define INCLUDED_ICU 25 26 #include <unicode/smpdtfmt.h> 27 28 #endif // #ifndef INCLUDED_ICU -
new file source/lib/external_libraries/tinygettext.h
diff --git a/source/lib/external_libraries/tinygettext.h b/source/lib/external_libraries/tinygettext.h new file mode 100644 index 0000000..f347395
- + 1 /* Copyright (c) 2011 Wildfire Games 2 * 3 * Permission is hereby granted, free of charge, to any person obtaining 4 * a copy of this software and associated documentation files (the 5 * "Software"), to deal in the Software without restriction, including 6 * without limitation the rights to use, copy, modify, merge, publish, 7 * distribute, sublicense, and/or sell copies of the Software, and to 8 * permit persons to whom the Software is furnished to do so, subject to 9 * the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included 12 * in all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 18 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 19 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 20 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 */ 22 23 /* 24 * Bring in the TinyGettext header file. 25 */ 26 27 #ifndef INCLUDED_TINYGETTEXT 28 #define INCLUDED_TINYGETTEXT 29 30 #include <tinygettext/tinygettext.hpp> 31 #include <tinygettext/po_parser.hpp> 32 33 #endif // INCLUDED_TINYGETTEXT -
new file source/lib/localization.cpp
diff --git a/source/lib/localization.cpp b/source/lib/localization.cpp new file mode 100644 index 0000000..11eaf74
- + 1 /* Copyright (c) 2013 Wildfire Games 2 * 3 * Permission is hereby granted, free of charge, to any person obtaining 4 * a copy of this software and associated documentation files (the 5 * "Software"), to deal in the Software without restriction, including 6 * without limitation the rights to use, copy, modify, merge, publish, 7 * distribute, sublicense, and/or sell copies of the Software, and to 8 * permit persons to whom the Software is furnished to do so, subject to 9 * the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included 12 * in all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 18 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 19 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 20 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 */ 22 23 #include "lib/localization.h" 24 25 #include <iostream> 26 #include <string> 27 #include <boost/concept_check.hpp> 28 29 #include "lib/file/file_system.h" 30 #include "lib/utf8.h" 31 32 #include "ps/CLogger.h" 33 #include "ps/ConfigDB.h" 34 #include "ps/Filesystem.h" 35 36 37 Localization& Localization::getInstance() 38 { 39 static Localization instance; 40 return instance; 41 } 42 43 Localization::Localization() 44 : currentLocaleIsOriginalGameLocale(false) // determineCurrentLocale() takes care of setting this value to true. 45 { 46 loadListOfAvailableLocales(); 47 determineCurrentLocale(); 48 loadDictionaryFromCurrentLocale(); 49 } 50 51 Localization::~Localization() 52 { 53 delete dictionary; 54 } 55 56 Locale Localization::getCurrentLocale() 57 { 58 return currentLocale; 59 } 60 61 std::vector< std::string > Localization::getSupportedLocaleCodes() 62 { 63 std::vector<std::string> supportedLocaleCodes; 64 for (std::vector<Locale*>::iterator iterator = availableLocales.begin(); iterator != availableLocales.end(); ++iterator) 65 { 66 supportedLocaleCodes.push_back((*iterator)->getBaseName()); 67 } 68 return supportedLocaleCodes; 69 } 70 71 std::vector< std::wstring > Localization::getSupportedLocaleDisplayNames() 72 { 73 std::vector<std::wstring> supportedLocaleDisplayNames; 74 for (std::vector<Locale*>::iterator iterator = availableLocales.begin(); iterator != availableLocales.end(); ++iterator) 75 { 76 UnicodeString utf16LocaleDisplayName; 77 (**iterator).getDisplayName(**iterator, utf16LocaleDisplayName); 78 std::string localeDisplayName; 79 utf16LocaleDisplayName.toUTF8String(localeDisplayName); 80 supportedLocaleDisplayNames.push_back(wstring_from_utf8(localeDisplayName)); 81 } 82 return supportedLocaleDisplayNames; 83 } 84 85 int Localization::getCurrentLocaleIndex() 86 { 87 std::vector<std::string> supportedLocaleCodes; 88 89 // Try to match a whole code first. 90 for (std::vector<Locale*>::iterator iterator = availableLocales.begin(); iterator != availableLocales.end(); ++iterator) 91 { 92 if (strcmp((**iterator).getBaseName(), getCurrentLocale().getBaseName()) == 0) 93 { 94 return iterator - availableLocales.begin(); 95 } 96 } 97 98 // Match language code only if no whole code matched. 99 for (std::vector<Locale*>::iterator iterator = availableLocales.begin(); iterator != availableLocales.end(); ++iterator) 100 { 101 if (strcmp((**iterator).getLanguage(), getCurrentLocale().getLanguage()) == 0) 102 { 103 return iterator - availableLocales.begin(); 104 } 105 } 106 107 // Use en_US, the default locale. 108 for (std::vector<Locale*>::iterator iterator = availableLocales.begin(); iterator != availableLocales.end(); ++iterator) 109 { 110 if (strcmp((**iterator).getLanguage(), Locale::getUS().getLanguage()) == 0) 111 { 112 return iterator - availableLocales.begin(); 113 } 114 } 115 116 return 0; // It should never get this far. 117 } 118 119 std::string Localization::localize(const std::string& sourceString) 120 { 121 if (!currentLocaleIsOriginalGameLocale) 122 { 123 return dictionary->translate(sourceString); 124 } 125 else 126 { 127 return sourceString; 128 } 129 } 130 131 std::string Localization::localizeWithContext(const std::string& context, const std::string& sourceString) 132 { 133 if (!currentLocaleIsOriginalGameLocale) 134 { 135 return dictionary->translate_ctxt(context, sourceString); 136 } 137 else 138 { 139 return sourceString; 140 } 141 } 142 143 std::string Localization::localizePlural(const std::string& singularSourceString, const std::string& pluralSourceString, int number) 144 { 145 if (!currentLocaleIsOriginalGameLocale) 146 { 147 return dictionary->translate_plural(singularSourceString, pluralSourceString, number); 148 } 149 else 150 { 151 if (number == 1) 152 { 153 return singularSourceString; 154 } 155 else 156 { 157 return pluralSourceString; 158 } 159 } 160 } 161 162 std::string Localization::localizePluralWithContext(const std::string& context, const std::string& singularSourceString, const std::string& pluralSourceString, int number) 163 { 164 if (!currentLocaleIsOriginalGameLocale) 165 { 166 return dictionary->translate_ctxt_plural(context, singularSourceString, pluralSourceString, number); 167 } 168 else 169 { 170 if (number == 1) 171 { 172 return singularSourceString; 173 } 174 else 175 { 176 return pluralSourceString; 177 } 178 } 179 } 180 181 std::string Localization::localizeLines(const std::string& sourceString) 182 { 183 std::string targetString; 184 std::stringstream stringOfLines(sourceString); 185 std::string line; 186 187 while (std::getline(stringOfLines, line)) { 188 targetString.append(localize(line)); 189 targetString.append("\n"); 190 } 191 192 return targetString; 193 } 194 195 UDate Localization::parseDateTime(const std::string& dateTimeString, const std::string& dateTimeFormat, const Locale& locale) 196 { 197 UErrorCode success = U_ZERO_ERROR; 198 UnicodeString utf16DateTimeString = UnicodeString::fromUTF8(dateTimeString); 199 UnicodeString utf16DateTimeFormat = UnicodeString::fromUTF8(dateTimeFormat); 200 201 DateFormat* dateFormatter = new SimpleDateFormat(utf16DateTimeFormat, locale, success); 202 UDate date = dateFormatter->parse(utf16DateTimeString, success); 203 delete dateFormatter; 204 205 return date; 206 } 207 208 std::string Localization::localizeDateTime(const UDate& dateTime, DateTimeType type, DateFormat::EStyle style) 209 { 210 UnicodeString utf16Date; 211 std::string utf8Date; 212 213 DateFormat* dateFormatter = createDateTimeInstance(type, style, currentLocale); 214 dateFormatter->format(dateTime, utf16Date); 215 utf16Date.toUTF8String(utf8Date); 216 delete dateFormatter; 217 218 return utf8Date; 219 } 220 221 std::string Localization::formatMillisecondsIntoDateString(int milliseconds, const std::string& formatString) 222 { 223 UErrorCode success = U_ZERO_ERROR; 224 std::string utf8Date; 225 UnicodeString utf16Date; 226 UnicodeString utf16SourceDateTimeFormat = UnicodeString::fromUTF8("A"); 227 UnicodeString utf16LocalizedDateTimeFormat = UnicodeString::fromUTF8(formatString); 228 char buffer[32]; 229 std::string utf8MillisecondsString(std::string(buffer, sprintf(buffer, "%d", milliseconds))); 230 UnicodeString utf16MillisecondsString = UnicodeString::fromUTF8(utf8MillisecondsString); 231 232 SimpleDateFormat* dateFormatter = new SimpleDateFormat(utf16SourceDateTimeFormat, currentLocale, success); 233 UDate dateTime = dateFormatter->parse(utf16MillisecondsString, success); 234 dateFormatter->applyLocalizedPattern(utf16LocalizedDateTimeFormat, success); 235 dateFormatter->format(dateTime, utf16Date); 236 utf16Date.toUTF8String(utf8Date); 237 delete dateFormatter; 238 239 return utf8Date; 240 } 241 242 std::string Localization::formatDecimalNumberIntoString(double number) 243 { 244 UErrorCode success = U_ZERO_ERROR; 245 UnicodeString utf16Number; 246 std::string utf8Number; 247 NumberFormat* numberFormatter = NumberFormat::createInstance(currentLocale, UNUM_DECIMAL, success); 248 numberFormatter->format(number, utf16Number); 249 utf16Number.toUTF8String(utf8Number); 250 return utf8Number; 251 } 252 253 VfsPath Localization::localizePath(VfsPath sourcePath) 254 { 255 VfsPath path = sourcePath; 256 257 VfsPath localizedPath = sourcePath.Parent() / L"localization" / wstring_from_utf8(currentLocale.getLanguage()) / sourcePath.Filename(); 258 if (VfsFileExists(localizedPath)) 259 { 260 path = localizedPath; 261 } 262 263 return path; 264 } 265 266 void Localization::determineCurrentLocale() 267 { 268 CConfigValue *value = g_ConfigDB.GetValue(CFG_COMMAND, "locale"); 269 if (value) 270 { 271 currentLocale = Locale(Locale::createCanonical(value->m_String.c_str())); 272 } 273 else 274 { 275 currentLocale = Locale::getDefault(); 276 } 277 278 if (currentLocale == Locale::getUS()) 279 { 280 currentLocaleIsOriginalGameLocale = true; 281 } 282 else 283 { 284 currentLocaleIsOriginalGameLocale = false; 285 } 286 } 287 288 void Localization::loadDictionaryFromCurrentLocale() 289 { 290 if (!currentLocaleIsOriginalGameLocale) 291 { 292 delete dictionary; 293 dictionary = new tinygettext::Dictionary(); 294 295 VfsPaths filenames; 296 if (vfs::GetPathnames(g_VFS, L"localization/", (wstring_from_utf8(currentLocale.getLanguage()) + L".*.po").c_str(), filenames) < 0) 297 return; 298 299 for (VfsPaths::iterator it = filenames.begin(); it != filenames.end(); ++it) 300 { 301 VfsPath filename = *it; 302 CVFSFile file; 303 file.Load(g_VFS, filename); 304 std::string content = file.DecodeUTF8(); 305 readPoIntoDictionary(content, dictionary); 306 } 307 } 308 } 309 310 void Localization::loadListOfAvailableLocales() 311 { 312 for (std::vector<Locale*>::iterator iterator = availableLocales.begin(); iterator != availableLocales.end(); ++iterator) 313 { 314 delete *iterator; 315 } 316 availableLocales.clear(); 317 318 Locale* defaultLocale = new Locale(Locale::getUS()); 319 availableLocales.push_back(defaultLocale); // Always available. 320 321 VfsPaths filenames; 322 if (vfs::GetPathnames(g_VFS, L"localization/", L"*.po", filenames) < 0) 323 return; 324 325 for (VfsPaths::iterator it = filenames.begin(); it != filenames.end(); ++it) 326 { 327 // Note: PO files follow this naming convention: âlocalization/<locale code>.<mod name>.poâ. For example: âlocalization/gl.public.poâ. 328 VfsPath filepath = *it; 329 std::string filename = utf8_from_wstring(filepath.string()).substr(strlen("localization/")); 330 std::size_t lengthToFirstDot = filename.find('.'); 331 std::string localeCode = filename.substr(0, lengthToFirstDot); 332 Locale* locale = new Locale(Locale::createCanonical(localeCode.c_str())); 333 334 bool localeIsAlreadyAvailable = false; 335 for (std::vector<Locale*>::iterator iterator = availableLocales.begin(); iterator != availableLocales.end(); ++iterator) 336 { 337 if (*locale == **iterator) 338 { 339 localeIsAlreadyAvailable = true; 340 break; 341 } 342 } 343 344 if (!localeIsAlreadyAvailable) 345 { 346 availableLocales.push_back(locale); 347 } 348 } 349 } 350 351 void Localization::readPoIntoDictionary(const std::string& poContent, tinygettext::Dictionary* dictionary) 352 { 353 try 354 { 355 std::istringstream inputStream(poContent); 356 tinygettext::POParser::parse("virtual PO file", inputStream, *dictionary, false); 357 } 358 catch(std::exception& e) 359 { 360 LOGERROR(L"[Localization] Exception while reading virtual PO file"); 361 } 362 } 363 364 DateFormat* Localization::createDateTimeInstance(Localization::DateTimeType type, DateFormat::EStyle style, const Locale& locale) 365 { 366 if (type == Date) 367 { 368 return SimpleDateFormat::createDateInstance(style, locale); 369 } 370 else if (type == Time) 371 { 372 return SimpleDateFormat::createTimeInstance(style, locale); 373 } 374 else // Provide DateTime by default. 375 { 376 return SimpleDateFormat::createDateTimeInstance(style, style, locale); 377 } 378 } -
new file source/lib/localization.h
diff --git a/source/lib/localization.h b/source/lib/localization.h new file mode 100644 index 0000000..5b34605
- + 1 /* Copyright (c) 2013 Wildfire Games 2 * 3 * Permission is hereby granted, free of charge, to any person obtaining 4 * a copy of this software and associated documentation files (the 5 * "Software"), to deal in the Software without restriction, including 6 * without limitation the rights to use, copy, modify, merge, publish, 7 * distribute, sublicense, and/or sell copies of the Software, and to 8 * permit persons to whom the Software is furnished to do so, subject to 9 * the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included 12 * in all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 18 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 19 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 20 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 */ 22 23 #ifndef LOCALIZATION_H 24 #define LOCALIZATION_H 25 26 #include <string> 27 #include <vector> 28 29 #include "lib/external_libraries/icu.h" 30 #include "lib/external_libraries/tinygettext.h" 31 32 #include "lib/file/vfs/vfs_path.h" 33 34 class Localization 35 { 36 public: 37 38 enum DateTimeType { DateTime, Date, Time }; 39 40 static Localization& getInstance(); 41 42 Localization(); 43 Localization(Localization const&); // Donât implement. 44 void operator=(Localization const&); // Donât implement. 45 ~Localization(); 46 47 Locale getCurrentLocale(); 48 std::vector<std::string> getSupportedLocaleCodes(); 49 std::vector<std::wstring> getSupportedLocaleDisplayNames(); 50 int getCurrentLocaleIndex(); 51 52 std::string localize(const std::string& sourceString); 53 std::string localizeWithContext(const std::string& context, const std::string& sourceString); 54 std::string localizePlural(const std::string& singularSourceString, const std::string& pluralSourceString, int number); 55 std::string localizePluralWithContext(const std::string& context, const std::string& singularSourceString, const std::string& pluralSourceString, int number); 56 std::string localizeLines(const std::string& sourceString); 57 58 UDate parseDateTime(const std::string& dateTimeString, const std::string& dateTimeFormat, const Locale& locale); 59 std::string localizeDateTime(const UDate& dateTime, DateTimeType type, DateFormat::EStyle style); 60 std::string formatMillisecondsIntoDateString(int milliseconds, const std::string& formatString); 61 std::string formatDecimalNumberIntoString(double number); 62 63 VfsPath localizePath(VfsPath sourcePath); 64 65 // bool isRTLLanguage() const; 66 67 // std::string getCurrentLanguageName(); 68 69 private: 70 tinygettext::Dictionary* dictionary; 71 bool isRtlLanguage; 72 Locale currentLocale; 73 std::vector<Locale*> availableLocales; 74 bool currentLocaleIsOriginalGameLocale; 75 76 77 void determineCurrentLocale(); 78 void loadDictionaryFromCurrentLocale(); 79 void loadListOfAvailableLocales(); 80 81 void readPoIntoDictionary(const std::string& poContent, tinygettext::Dictionary* dictionary); 82 83 DateFormat* createDateTimeInstance(DateTimeType type, DateFormat::EStyle style, const Locale& locale); 84 }; 85 86 87 extern Localization* localization; 88 89 #endif // LOCALIZATION_H -
source/ps/CLogger.cpp
diff --git a/source/ps/CLogger.cpp b/source/ps/CLogger.cpp index f791924..0d06bbd 100644
a b 21 21 #include "CConsole.h" 22 22 #include "graphics/ShaderManager.h" 23 23 #include "graphics/TextRenderer.h" 24 #include "lib/localization.h" 24 25 #include "lib/ogl.h" 25 26 #include "lib/timer.h" 26 27 #include "lib/utf8.h" … … void CLogger::Render() 300 301 301 302 for (std::deque<RenderedMessage>::iterator it = m_RenderMessages.begin(); it != m_RenderMessages.end(); ++it) 302 303 { 303 const wchar_t* type;304 304 if (it->method == Normal) 305 305 { 306 type = L"info";307 306 textRenderer.Color(0.0f, 0.8f, 0.0f); 307 textRenderer.PrintfAdvance(wstring_from_utf8(Localization::getInstance().localize("[%8.3f] info: ")).c_str(), it->time); 308 308 } 309 309 else if (it->method == Warning) 310 310 { 311 type = L"warning";312 311 textRenderer.Color(1.0f, 1.0f, 0.0f); 312 textRenderer.PrintfAdvance(wstring_from_utf8(Localization::getInstance().localize("[%8.3f] warning: ")).c_str(), it->time); 313 313 } 314 314 else 315 315 { 316 type = L"error";317 316 textRenderer.Color(1.0f, 0.0f, 0.0f); 317 textRenderer.PrintfAdvance(wstring_from_utf8(Localization::getInstance().localize("[%8.3f] error: ")).c_str(), it->time); 318 318 } 319 319 320 320 CMatrix3D savedTransform = textRenderer.GetTransform(); 321 321 322 textRenderer.PrintfAdvance(L"[%8.3f] %ls: ", it->time, type);323 322 // Display the actual message in white so it's more readable 324 323 textRenderer.Color(1.0f, 1.0f, 1.0f); 325 324 textRenderer.Put(0.0f, 0.0f, it->message.c_str()); -
source/ps/GameSetup/GameSetup.cpp
diff --git a/source/ps/GameSetup/GameSetup.cpp b/source/ps/GameSetup/GameSetup.cpp index b675343..3a8c3a1 100644
a b static void InitVfs(const CmdLineArgs& args, int flags) 455 455 g_VFS->Mount(L"config/", readonlyConfig); 456 456 bool dev = (g_VFS->GetFileInfo(L"config/dev.cfg", NULL) == INFO::OK); 457 457 458 // Engine localization files. 459 g_VFS->Mount(L"localization/", paths.RData()/"localization"/""); 460 458 461 const std::vector<CStr> mods = GetMods(args, dev); 459 462 460 463 OsPath modPath = paths.RData()/"mods"; -
source/ps/SavedGame.cpp
diff --git a/source/ps/SavedGame.cpp b/source/ps/SavedGame.cpp index 274d22f..2b93ad8 100644
a b 22 22 #include "gui/GUIManager.h" 23 23 #include "lib/allocators/shared_ptr.h" 24 24 #include "lib/file/archive/archive_zip.h" 25 #include "lib/localization.h" 26 #include "lib/utf8.h" 25 27 #include "ps/CLogger.h" 26 28 #include "ps/Filesystem.h" 27 29 #include "scriptinterface/ScriptInterface.h" … … Status SavedGames::Save(const std::wstring& name, const std::wstring& descriptio 106 108 107 109 OsPath realPath; 108 110 WARN_RETURN_STATUS_IF_ERR(g_VFS->GetRealPath(filename, realPath)); 109 LOGMESSAGERENDER( L"Saved game to %ls\n", realPath.string().c_str());111 LOGMESSAGERENDER(wstring_from_utf8(Localization::getInstance().localize("Saved game to %ls") + "\n").c_str(), realPath.string().c_str()); 110 112 111 113 return INFO::OK; 112 114 } … … std::vector<CScriptValRooted> SavedGames::GetSavedGames(ScriptInterface& scriptI 198 200 if (!archiveReader) 199 201 { 200 202 // Triggered by e.g. the file being open in another program 201 LOGWARNING( L"Failed to read saved game '%ls'", realPath.string().c_str());203 LOGWARNING(wstring_from_utf8(Localization::getInstance().localize("Failed to read saved game '%ls'") + "\n").c_str(), realPath.string().c_str()); 202 204 continue; // skip this file 203 205 } 204 206 -
source/scripting/ScriptGlue.cpp
diff --git a/source/scripting/ScriptGlue.cpp b/source/scripting/ScriptGlue.cpp index b2c7353..ecb1686 100644
a b 34 34 #include "gui/GUIManager.h" 35 35 #include "gui/IGUIObject.h" 36 36 #include "lib/frequency_filter.h" 37 #include "lib/svn_revision.h"38 37 #include "lib/timer.h" 39 38 #include "lib/sysdep/sysdep.h" // sys_OpenFile 40 39 #include "maths/scripting/JSInterface_Vector3D.h" … … JSBool GetGUIObjectByName(JSContext* cx, uintN argc, jsval* vp) 229 228 } 230 229 } 231 230 232 //-----------------------------------------------------------------------------233 // Miscellany234 //-----------------------------------------------------------------------------235 236 // Return the date/time at which the current executable was compiled.237 // params: none (-> "date time (svn revision)") OR an integer specifying238 // what to display: 0 for date, 1 for time, 2 for svn revision239 // returns: string with the requested timestamp info240 // notes:241 // - Displayed on main menu screen; tells non-programmers which auto-build242 // they are running. Could also be determined via .EXE file properties,243 // but that's a bit more trouble.244 // - To be exact, the date/time returned is when scriptglue.cpp was245 // last compiled, but the auto-build does full rebuilds.246 // - svn revision is generated by calling svnversion and cached in247 // lib/svn_revision.cpp. it is useful to know when attempting to248 // reproduce bugs (the main EXE and PDB should be temporarily reverted to249 // that revision so that they match user-submitted crashdumps).250 JSBool GetBuildTimestamp(JSContext* cx, uintN argc, jsval* vp)251 {252 JSU_REQUIRE_MAX_PARAMS(1);253 254 char buf[200];255 256 // see function documentation257 const int mode = argc? JSVAL_TO_INT(JS_ARGV(cx, vp)[0]) : -1;258 switch(mode)259 {260 case -1:261 sprintf_s(buf, ARRAY_SIZE(buf), "%s %s (%ls)", __DATE__, __TIME__, svn_revision);262 break;263 case 0:264 sprintf_s(buf, ARRAY_SIZE(buf), "%s", __DATE__);265 break;266 case 1:267 sprintf_s(buf, ARRAY_SIZE(buf), "%s", __TIME__);268 break;269 case 2:270 sprintf_s(buf, ARRAY_SIZE(buf), "%ls", svn_revision);271 break;272 }273 274 JS_SET_RVAL(cx, vp, STRING_TO_JSVAL(JS_NewStringCopyZ(cx, buf)));275 return JS_TRUE;276 }277 278 231 #if MOZJS_DEBUG_ABI 279 232 void DumpHeap(const char* basename, int idx, JSContext* cx) 280 233 { … … JSFunctionSpec ScriptFunctionTable[] = 395 348 JS_FUNC("getGUIObjectByName", GetGUIObjectByName, 1) 396 349 397 350 // Miscellany 398 JS_FUNC("buildTime", GetBuildTimestamp, 0)399 351 JS_FUNC("dumpHeaps", DumpHeaps, 0) 400 352 401 353 // end of table marker -
new file source/tools/localization/entities.its
diff --git a/source/tools/localization/entities.its b/source/tools/localization/entities.its new file mode 100644 index 0000000..644e358
- + 1 <its:rules 2 xmlns:its="http://www.w3.org/2005/11/its" 3 xmlns:itst="http://itstool.org/extensions/" 4 version="1.0"> 5 6 <its:translateRule selector="//Entity" translate="no" /> 7 8 <!-- Translate the value of these elements only. --> 9 <its:translateRule selector="//GenericName" translate="yes" /> 10 <its:translateRule selector="//SpecificName" translate="yes" /> 11 <!-- 12 To be added in the future: (available in the XML files, not visible in-game) 13 <its:translateRule selector="//History" translate="yes" /> 14 --> 15 <itst:preserveSpaceRule preserveSpace="yes" selector="//Tooltip" /> 16 <its:translateRule selector="//Tooltip" translate="yes" /> 17 18 </its:rules> -
new file source/tools/localization/gui.its
diff --git a/source/tools/localization/gui.its b/source/tools/localization/gui.its new file mode 100644 index 0000000..331b3cd
- + 1 <its:rules 2 xmlns:its="http://www.w3.org/2005/11/its" 3 version="1.0"> 4 5 <its:translateRule selector="//objects" translate="no" /> 6 <its:translateRule selector="//page" translate="no" /> 7 <its:translateRule selector="//setup" translate="no" /> 8 <its:translateRule selector="//sprites" translate="no" /> 9 <its:translateRule selector="//styles" translate="no" /> 10 11 <!-- Translate the value of these elements only. --> 12 <its:translateRule selector="//localizableAttribute" translate="yes" /> 13 <its:translateRule selector="//localize" translate="yes" /> 14 15 </its:rules> -
new file source/tools/localization/sync-transifex.sh
diff --git a/source/tools/localization/sync-transifex.sh b/source/tools/localization/sync-transifex.sh new file mode 100644 index 0000000..9202dfc
- + 1 #!/bin/bash 2 3 basedir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 4 rootdir="$basedir/../../.." 5 6 # Go to the 0ad root, so that the paths in the POT file go from there. 7 pushd $rootdir &> /dev/null 8 9 10 # ENGINE 11 12 pushd "binaries/data/localization" &> /dev/null 13 tx pull -af 14 popd &> /dev/null 15 16 17 # MODS 18 19 # Get a list of modules with a âpoâ directory. 20 declare -a modPaths 21 for modFolderPath in binaries/data/mods/* 22 do 23 poPath="${modFolderPath}/localization" 24 if [ -d "${poPath}" ]; then 25 26 pushd ${poPath} &> /dev/null 27 28 # Initialize the â.txâ folder if it is not initialized yet. 29 txDir=".tx" 30 if [ ! -d "${txDir}" ]; then 31 mkdir "${txDir}" 32 echo "[main]" > "${txDir}/config" 33 echo "host = https://www.transifex.net" >> "${txDir}/config" 34 modName=$(basename ${modFolderPath}) 35 tx set \ 36 --auto-local \ 37 -r 0-ad-unofficial.${modName} \ 38 --source-language=en \ 39 --source-file "${modName}.pot" \ 40 --execute \ 41 "<lang>.${modName}.po" \ 42 &> /dev/null 43 fi 44 45 tx pull -af 46 47 popd &> /dev/null 48 fi 49 done 50 51 popd &> /dev/null 52 -
new file source/tools/localization/update-pot.sh
diff --git a/source/tools/localization/update-pot.sh b/source/tools/localization/update-pot.sh new file mode 100644 index 0000000..aff6ae7
- + 1 #!/bin/bash 2 # 3 # This is true spaghetti code, but it works. 4 # You should ask Gallaecio to rewrite this in an actual scripting language such as Python instead of Bash. 5 6 basedir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 7 rootdir="$basedir/../../.." 8 xgettextKeywords="-klocalize -klocalizePlural:1,2 -klocalizeWithContext:1c,2 -klocalizePluralWithContext:1c,2,3 -kmarkToLocalize" 9 10 # Go to the 0ad root, so that the paths in the POT file go from there. 11 pushd $rootdir &> /dev/null 12 13 14 # ENGINE 15 16 # Extract C++ code strings. 17 declare -a sourceFiles 18 for sourceFile in $(find "source" -name "*.cpp") 19 do 20 sourceFiles=("${sourceFiles[@]}" "$sourceFile") 21 done 22 outputPot="binaries/data/localization/engine.pot" 23 xgettext --from-code=utf-8 $xgettextKeywords -cLocalization -o ${outputPot} ${sourceFiles[@]} &> /dev/null 24 unset sourceFiles 25 26 27 # MODS 28 29 for modFolderPath in binaries/data/mods/* 30 do 31 # Work only on mods that contain a âlocalizationâ folder. Other mods are considered as âdisabledâ for internationalization. 32 if [ -d "$modFolderPath/localization" ]; then 33 34 source "$modFolderPath/localization/messages.sh" 35 36 modName=$(basename $modFolderPath) 37 38 # Extract JavaScript code strings. 39 declare -a sourceFiles 40 for sourceFile in $(find $modFolderPath -name "*.js") 41 do 42 sourceFiles=("${sourceFiles[@]}" "$sourceFile") 43 done 44 outputPot=$modFolderPath/localization/${modName}-javascript.pot 45 xgettext --language=Python --from-code=utf-8 $xgettextKeywords -o ${outputPot} ${sourceFiles[@]} &> /dev/null 46 unset sourceFiles 47 48 49 # Extract GUI XML strings. 50 if [ -d "$modFolderPath/gui" ]; then 51 52 declare -a sourceFiles 53 for sourceFile in $(find $modFolderPath/gui -name "*.xml") 54 do 55 sourceFiles=("${sourceFiles[@]}" "$sourceFile") 56 done 57 58 outputPot=$modFolderPath/localization/${modName}-gui-xml.pot 59 60 itstool -o ${outputPot} -i $basedir/gui.its ${sourceFiles[@]} 61 unset sourceFiles 62 63 sed -e "s/\&/\&/g" -i ${outputPot} 64 fi 65 66 67 # Extract GUI TXT strings. 68 if [ -d "$modFolderPath/gui" ]; then 69 70 outputPot=$modFolderPath/localization/${modName}-gui-txt.pot 71 72 # Print POT header. 73 echo "msgid \"\"" > $outputPot 74 echo "msgstr \"\"" >> $outputPot 75 echo "\"Project-Id-Version: PACKAGE VERSION\n\"" >> $outputPot 76 echo "\"POT-Creation-Date: $(date +"%Y-%m-%d %H:%M:%S%z")\n\"" >> $outputPot 77 echo "\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n\"" >> $outputPot 78 echo "\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n\"" >> $outputPot 79 echo "\"Language-Team: LANGUAGE <LL@li.org>\n\"" >> $outputPot 80 echo "\"MIME-Version: 1.0\n\"" >> $outputPot 81 echo "\"Content-Type: text/plain; charset=UTF-8\n\"" >> $outputPot 82 echo "\"Content-Transfer-Encoding: 8bit\n\"" >> $outputPot 83 echo "" >> $outputPot 84 85 # Parse TXT files line by line. 86 for filepath in "${txtLineByLineFiles[@]}" 87 do 88 lineNumber=0 89 while read -r line 90 do 91 lineNumber=$((lineNumber + 1)) 92 if [ -n "${line}" ]; then 93 echo "#: ${filepath}:${lineNumber}" >> $outputPot 94 echo "msgid \"$(echo "${line}" | sed -e 's#\\#\\\\#g' -e 's#"#\\\"#g')\"" >> $outputPot 95 echo "msgstr \"\"" >> $outputPot 96 echo "" >> $outputPot 97 fi 98 done < "$modFolderPath/${filepath}" 99 done 100 101 msguniq $outputPot -o $outputPot 102 103 fi 104 105 106 # Extract JSON strings. 107 outputPot="$modFolderPath/localization/${modName}-json.pot" 108 temporaryOutputPot="$modFolderPath/localization/${modName}-json-tmp.pot" 109 temporaryOutputPot2="$modFolderPath/localization/${modName}-json-tmp2.pot" 110 rm -rf $outputPot; touch $outputPot 111 for filepathAndFilter in "${jsonFilesWithFilters[@]}" 112 do 113 filepathAndFilterArray=(${filepathAndFilter//::/ }) 114 json2po --duplicates=merge --filter=${filepathAndFilterArray[1]} "$modFolderPath/${filepathAndFilterArray[0]}" $temporaryOutputPot &> /dev/null 115 sed "/msgctxt/d" -i $temporaryOutputPot 116 perl -pe 'BEGIN{undef $/;} s/(#[^\n]*\n)+msgid ""\nmsgstr ""\n\n//smg' -i $temporaryOutputPot # Removes troublesome empty msgid entries. 117 msgcat --use-first $outputPot $temporaryOutputPot > $temporaryOutputPot2 118 perl -pe 'BEGIN{undef $/;} s/(#[^\n]*\n)+msgid "_: (\.[A-Za-z]+(\[[0-9]\])?)+\\n"\nmsgstr ""\n\n//smg' -i $temporaryOutputPot2 # Removes some weird entries generated from empty JSON entries. 119 rm $temporaryOutputPot 120 mv $temporaryOutputPot2 $outputPot 121 done 122 123 124 # Extract Entity (XML) strings. 125 outputPot="$rootdir/$modFolderPath/localization/${modName}-entities-xml.pot" 126 pushd $modFolderPath &> /dev/null 127 itstool -o ${outputPot} -i "$basedir/entities.its" ${entityFiles[@]} 128 sed -e "s/\&/\&/g" -i ${outputPot} 129 popd &> /dev/null 130 131 132 # Extract JSON strings within XML files. 133 outputPot="$modFolderPath/localization/${modName}-xml-json.pot" 134 temporaryOutputJson="$modFolderPath/localization/${modName}-xml-json-tmp.json" 135 temporaryOutputPot="$modFolderPath/localization/${modName}-xml-json-tmp.pot" 136 temporaryOutputPot2="$modFolderPath/localization/${modName}-xml-json-tmp2.pot" 137 rm -rf $outputPot; touch $outputPot 138 for filepathAndFilter in "${xmlFilesWithJsonWithFilters[@]}" 139 do 140 declare -a filepathAndElementAndFilterArray=() 141 while IFS= read -d $'\t' -r item ; do 142 filepathAndElementAndFilterArray+=("$item") 143 done < <(printf "$(echo "$filepathAndFilter" | sed "s/::/\t/g")\t") 144 xmlstarlet sel -t -v "//${filepathAndElementAndFilterArray[1]}" "$modFolderPath/${filepathAndElementAndFilterArray[0]}" > $temporaryOutputJson 145 json2po --duplicates=merge --filter=${filepathAndElementAndFilterArray[2]} "$temporaryOutputJson" $temporaryOutputPot &> /dev/null 146 sed "/msgctxt/d" -i $temporaryOutputPot 147 perl -pe 'BEGIN{undef $/;} s/(#[^\n]*\n)+msgid ""\nmsgstr ""\n\n//smg' -i $temporaryOutputPot # Removes troublesome empty msgid entries. 148 msgcat --use-first $outputPot $temporaryOutputPot > $temporaryOutputPot2 149 perl -pe 'BEGIN{undef $/;} s/(#[^\n]*\n)+msgid "_: (\.[A-Za-z]+(\[[0-9]\])?)+\\n"\nmsgstr ""\n\n//smg' -i $temporaryOutputPot2 # Removes some weird entries generated from empty JSON entries. 150 rm $temporaryOutputJson 151 rm $temporaryOutputPot 152 mv $temporaryOutputPot2 $outputPot 153 unset filepathAndElementAndFilterArray 154 done 155 156 157 # Unset data from messages.sh, so that it doesnât affect the parsing of other mods. 158 unset txtLineByLineFiles 159 unset jsonFilesWithFilters 160 unset entityFiles 161 unset xmlFilesWithJsonWithFilters 162 163 164 # Merge POT files into a single one. 165 # NOTE: Depending on how much they grow, we might want to consider leaving them split in the future. 166 167 temporalPot="$modFolderPath/localization/${modName}.pot.tmp" 168 finalPot="$modFolderPath/localization/${modName}.pot" 169 rm ${finalPot} # Remove old POT. 170 msgcat $modFolderPath/localization/*.pot > ${temporalPot} # Mix new POT files into a single POT file. 171 msguniq ${temporalPot} -o ${temporalPot} 172 rm $modFolderPath/localization/*.pot # Remove all POT files but the one that cointains the rest. 173 mv ${temporalPot} ${finalPot} # Give the right name to the main POT file. 174 175 fi # [ -d "$modFolderPath/localization" ] 176 177 done 178 179 popd &> /dev/null 180 181 182