Changeset 107:20f7d813bb0f
- Timestamp:
- 11/30/08 12:17:56 (1 month ago)
- Files:
-
- data/L10n/FontOptions.mtt (deleted)
- data/L10n/MiscOptions.mtt (deleted)
- data/L10n/VideoOptions.mtt (deleted)
- data/L10n/en-GB.mtt (added)
- data/conf/gui.mtt (modified) (2 diffs)
- mde/content/Items.d (modified) (4 diffs)
- mde/input/Input.d (modified) (1 diff)
- mde/lookup/Translation.d (modified) (5 diffs)
- mde/mde.d (modified) (1 diff)
- mde/setup/paths.d (modified) (7 diffs)
- unittest/Translation.mtt (deleted)
- unittest/conf/InputConfig.mtt (moved) (moved from unittest/InputConfig.mtt)
- unittest/data/L10n/locale-1.mtt (added)
- unittest/data/L10n/locale-2.mtt (added)
- unittest/data/L10n/locale-3.mtt (added)
- unittest/data/L10n/locale-4.mtt (added)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
data/conf/gui.mtt
r105 r107 6 6 <WidgetData|square={0:[0x1,6,6]}> 7 7 <WidgetData|blank={0:[0x2]}> 8 <WidgetData|opts={0:[0x2031,0x6030,0],1:["Options","optCls"]}> 9 <WidgetData|optCls={0:[0xC100,0,2,1],1:["optName","optVars"]}> 8 <WidgetData|opts={0:[0x2031,0xC100,0,2,1],1:["Options","optName","optSecs"]}> 9 <WidgetData|optSecs={0:[0x6030,0],1:["optSec"]}> 10 <WidgetData|optSec={0:[0xC100,0,2,1],1:["optName","optVars"]}> 10 11 <WidgetData|optVars={0:[0x6030,0],1:["optDBox"]}> 11 12 <WidgetData|optDBox={0:[0xC100,1,2,1],1:["optBox","optDesc"]}> … … 15 16 <WidgetData|optVal={0:[0x6030]}> 16 17 <WidgetData|optSep={0:[0x21, 0xff],1:["="]}> 17 <WidgetData|floating={0:[0x8200,6,14,6],1:["L10n","blank","opts"]}> 18 <WidgetData|L10n={0:[0x2031,0xC100,0,2,1],1:["Options.MiscOptions.L10n","optBox2","apply"]}> 19 <WidgetData|optBox2={0:[0xC100,0,1,3],1:["optName","optSep","optVal"]}>!{cloned to avoid bug #4} 20 <WidgetData|apply={0:[0x2031,0x4043],1:["quit"]}> 18 <WidgetData|floating={0:[0x8200,6,14,6],1:["quit","blank","opts"]}> 19 <WidgetData|quit={0:[0x2031,0x4043],1:["imde.quit"]}> 21 20 {Basic} 22 21 <WidgetData|root={0:[0x21,0x90D970],1:["A string!"]}> mde/content/Items.d
r105 r107 52 52 } 53 53 Options.allContentList = new ContentList (h, list); 54 Options.allContentList.name ("Options"); //FIXME 54 Translation trl = Translation.get (h); 55 Translation.Entry trle = trl.getStruct (h); 56 Options.allContentList.name (trle.name, trle.desc); 55 57 } 56 58 return Options.allContentList; … … 69 71 return *q; 70 72 } 71 } else if (h == "quit" && item is null) { 72 quit.name ("Quit"); //FIXME 73 return quit; 73 } else if (h == "imde") { 74 if (!imdeTransl) { 75 Translation trl = Translation.get (h); 76 Translation.Entry trle = trl.getStruct ("quit"); 77 quit.name (trle.name, trle.desc); 78 imdeTransl = true; 79 } 80 h = head (item); 81 if (h == "quit" && item is null) { 82 quit.name ("Quit"); //FIXME 83 return quit; 84 } 74 85 } 75 86 throw new ContentItemException (h); … … 93 104 void loadTransl (Options p, char[] n) { 94 105 debug logger.trace ("Loading translation strings for Options."~n); 95 Translation trans = Translation. load ("L10n/"~n);106 Translation trans = Translation.get (n); 96 107 Translation.Entry transled = trans.getStruct (n); 97 108 p.contentList = new ContentList (n, p.content); … … 102 113 } 103 114 } 115 116 bool imdeTransl = false; // Has section imde been translated? mde/input/Input.d
r99 r107 587 587 debug (mdeUnitTest) unittest { 588 588 Input ut = new Input(); 589 ut.loadConfig (" unittest/InputConfig");590 589 ut.loadConfig ("InputConfig"); 590 591 591 int[6] counters; // counters for callbacks 592 592 // Should become: [2,2,0,2,1,1] 593 593 594 594 //BEGIN Set up some callbacks 595 595 ut.addButtonCallback (0x03F0, delegate void(inputID id, bool status) { mde/lookup/Translation.d
r103 r107 57 57 class Translation : IDataSection 58 58 { 59 final char[] name; /// The module/package/... which the instance is for 60 final char[] L10n; /// The localization loaded (e.g. en-GB) 59 /** Load the translation for the requested module/package/... 60 * 61 * Options (mde.options) must have been loaded before this is run. 62 * 63 * Params: 64 * name The module/package/... to load strings for. 65 * 66 * Throws: 67 * If no localization exists for this name and the current locale (or any locale to be chain- 68 * loaded), or an error occurs while loading the database, a L10nLoadException will be thrown. 69 */ 70 static { 71 /** Get Translation instance for _section section. 72 * 73 * On the first call, loads all Translation sections. 74 * 75 * These are loaded from data/L10n/locale.mtt where locale is the current locale, as well 76 * as any files named for locales specified in the header tag <char[][]|depends=[...]>. 77 * 78 * On errors, a message is logged and the function continues, likely resulting in some 79 * symbol names being untranslated. */ 80 Translation get (char[] section) { 81 if (sections is null) { 82 char[][] files = [miscOpts.L10n()]; // initial locale plus dependencies 83 size_t read = 0; // index in files of next file to read 84 while (read < files.length) { 85 try { 86 IReader reader = dataDir.makeMTReader ("L10n/"~files[read++], PRIORITY.HIGH_LOW, null, true); 87 assert (reader.dataset.header); 88 auto dp = "depends" in reader.dataset.header._charAA; 89 if (dp) { // append, making sure no duplicates are inserted 90 f1: foreach (dep; *dp) { 91 foreach (f; files) 92 if (f == dep) 93 continue f1; 94 files ~= dep; 95 } 96 } 97 reader.dataSecCreator = delegate IDataSection(ID sec) { 98 auto p = sec in sections; 99 if (p) return *p; 100 return new Translation (sec); 101 }; 102 reader.read; 103 } catch (MTException e) { 104 logger.error ("Mergetag exception occurred:"); 105 logger.error (e.msg); 106 } 107 } 108 } 109 auto p = section in sections; 110 if (p is null) { 111 logger.warn ("Section "~section ~ " not found in files; strings will not be translated."); 112 return new Translation (section); 113 } 114 return *p; 115 } 116 Translation[char[]] sections; 117 } 118 119 final char[] section; // ONLY used to log an error message 61 120 62 121 alias entry opCall; /// Convenience alias … … 95 154 return ret; 96 155 } 97 }98 99 /** Load the translation for the requested module/package/...100 *101 * Options (mde.options) must have been loaded before this is run.102 *103 * Params:104 * name The module/package/... to load strings for.105 *106 * Throws:107 * If no localization exists for this name and the current locale (or any locale to be chain-108 * loaded), or an error occurs while loading the database, a L10nLoadException will be thrown.109 */110 static Translation load (char[] name)111 {112 bool[ID] loadedSecs; // set of all locales/sections loaded; used to prevent circular loading113 ID[] secsToLoad // locales/sections to load (dependancies may be added)114 = [cast(ID) miscOpts.L10n]; // start by loading the current locale115 116 Translation transl = new Translation (name, miscOpts.L10n());117 118 IReader reader;119 try {120 reader = dataDir.makeMTReader (name, PRIORITY.HIGH_LOW);121 /* Note: we don't want to load every translation section depended on to its own class122 * instance, since we want to merge them. So make every mergetag section use the same123 * instance. */124 reader.dataSecCreator = delegate IDataSection(ID) {125 return transl;126 };127 128 while (secsToLoad.length) { // while we have sections left to load129 ID sec = secsToLoad[0]; // take current section130 secsToLoad = secsToLoad[1..$]; // and remove from list131 132 if (sec in loadedSecs) continue; // skip if it's already been loaded133 loadedSecs[sec] = true;134 135 reader.read ([sec]); // Do the actual loading136 137 // Add dependancies to front of list:138 secsToLoad = transl.depends ~ secsToLoad;139 }140 // When loop finishes, we're done loading.141 } catch (MTException e) {142 // If an error occurs, log a message but continue (strings will just be untranslated)143 logger.error ("Mergetag exception occurred:");144 logger.error (e.msg);145 }146 147 delete transl.depends; // Free memory148 transl.depends = [];149 150 return transl;151 156 } 152 157 … … 173 178 Entry entry = deserialize!(Entry) (dt); 174 179 if (entry.name is null) { // This tag is invalid; ignore it 175 logger.error (" For name "~name~", L10n "~L10n~": tag with ID "~cast(char[])id~" has no data");180 logger.error ("In L10n/*.mtt section "~section~": tag with ID "~cast(char[])id~" has no data"); 176 181 return; 177 182 } … … 195 200 196 201 private: 197 /* Sets name and L10n. 198 * 199 * Also ensures only load() can create instances. */ 200 this (char[] n, char[] l) { 201 name = n; 202 L10n = l; 202 /* Sets name and ensures only Translation's static functions can create instances. */ 203 this (char[] n) { 204 section = n; 205 sections[n] = this; 203 206 } 204 207 … … 212 215 213 216 debug (mdeUnitTest) unittest { 214 /* Relies on file: conf/L10n/i18nUnitTest.mtt 215 * Contents: 216 ********* 217 {MT01} 218 {test-1} 219 <entry|Str1=["Test 1"]> 220 <char[][]|depends=["test-2"]> 221 {test-2} 222 <entry|Str1=["Test 2"]> 223 <entry|Str2=["Test 3","Description",bogus,"entries",56]> 224 *********/ 217 // Relies on files in unittest/data/L10n: locale-x.mtt for x in 1..4 225 218 226 // Hack a specific locale... 227 // Also to allow unittest to run without init. 228 TextContent realL10n = miscOpts.L10n; 229 miscOpts.L10n = new TextContent ("L10n", "test-1"); 219 // Hack a specific locale. Also to allow unittest to run without init. 220 StringContent realL10n = miscOpts.L10n; 221 miscOpts.L10n = new StringContent ("L10n", "locale-1"); 230 222 231 Translation transl = load ("unittest/Translation"); 232 233 // Simple get-string, check dependancy's entry doesn't override 234 assert (transl.entry ("Str1") == "Test 1"); 235 236 // Entry included from dependancy with description 237 char[] desc; 238 assert (transl.entry ("Str2", desc) == "Test 3"); 239 assert (desc == "Description"); 240 241 // No entry: fallback to identifier string 242 assert (transl.entry ("Str3") == "Str3"); 243 244 // No checks for version info since it's not functionality of this module. 245 // Only check extra entries are allowed but ignored. 246 223 // Struct tests 224 Translation t = get ("section-2"); 225 Entry e = t.getStruct ("entry-1"); 226 assert (e.name == "Test 1"); 227 assert (e.desc == "Description"); 228 e = t.getStruct ("entry-2"); 229 assert (e.name == "Test 2"); 230 assert (e.desc is null); 231 232 // Dependency tests. Priority should be 1,2,3,4 (entries should come from first file in list that they appear in). 233 t = get ("section-1"); 234 char[] d = "1"; 235 assert (t.entry ("file-1", d) == "locale-1"); 236 assert (d is null); 237 assert (t.entry ("file-2", d) == "locale-2"); 238 assert (d == "desc2"); 239 assert (t.entry ("file-3") == "locale-3"); 240 assert (t.entry ("file-4") == "locale-4"); 241 247 242 // Restore 248 243 delete miscOpts.L10n; 249 244 miscOpts.L10n = realL10n; 245 sections = null; 250 246 251 247 logger.info ("Unittest complete."); mde/mde.d
r103 r107 34 34 import mde.file.ssi; 35 35 import mde.file.mergetag.mdeUT; 36 import mde.lookup.Translation; 36 37 } 37 38 mde/setup/paths.d
r106 r107 140 140 FilePath[] ret; 141 141 142 debug (mdeUnitTest) {143 /* Alternate approach - just try from current directory.144 * Really just for unittests, but with the if condition it shouldn't break anything else. */145 if (pathsLen == 0) {146 FilePath file = findFile (filename);147 if (file !is null)148 ret ~= file;149 return ret;150 }151 }152 153 142 if (readOrder == PRIORITY.LOW_HIGH) { 154 143 for (size_t i = 0; i < pathsLen; ++i) { … … 173 162 // Unconditionally add a path 174 163 void addPath (char[] path) { 164 assert (pathsLen < MAX_PATHS); 175 165 paths[pathsLen++] = path~'/'; 176 166 } … … 178 168 // Test a path and add if is a folder. 179 169 bool tryPath (char[] path, bool create = false) { 180 FilePath fp = FilePath (path); 170 assert (pathsLen < MAX_PATHS); 171 FilePath fp = FilePath (path); 181 172 if (fp.exists && fp.isFolder) { 182 173 paths[pathsLen++] = path~'/'; … … 214 205 215 206 //BEGIN Path resolution 216 // These are used several times: 217 const DATA = "/data"; 218 const CONF = "/conf"; 219 220 /** Find at least one path for each required directory. 221 * 222 * Note: the logger cannot be used yet, so only output is exception messages. */ 207 /** Find at least one path for each required directory. */ 208 debug (mdeUnitTest) { 209 /** In unittest mode, add paths unittest/data and unittest/conf before init runs. */ 210 static this () { 211 dataDir.tryPath ("unittest/data"); 212 confDir.tryPath ("unittest/conf"); 213 if (!(dataDir.pathsLen && confDir.pathsLen)) 214 throw new mdeException ("Fatal: unittest/data and unittest/conf don't both exist"); 215 // Don't bother with real paths or logDir or font dir(s) for unittest. 216 } 217 } 223 218 version (linux) { 224 219 SortedMap!(char[],char[]) fontFiles; // key is file name, value is CString path … … 247 242 // Static data paths: 248 243 dataDir.addPath (staticPath.toString); // we know this is valid anyway 249 dataDir.tryPath (userPath.toString ~ DATA);244 dataDir.tryPath (userPath.toString ~ "/data"); 250 245 if (extraDataPath) dataDir.tryPath (extraDataPath); 251 246 if (!dataDir.pathsLen) throw new mdeException ("Fatal: no data path found!"); 252 247 253 248 // Configuration paths: 254 confDir.tryPath (staticPath.toString ~ CONF);249 confDir.tryPath (staticPath.toString ~ "/conf"); 255 250 confDir.tryPath ("/etc/mde"); 256 confDir.tryPath (userPath.toString ~ CONF, true);251 confDir.tryPath (userPath.toString ~ "/conf", true); 257 252 if (extraConfPath) confDir.tryPath (extraConfPath); 258 253 if (!confDir.pathsLen) throw new mdeException ("Fatal: no conf path found!"); … … 294 289 // Static data paths: 295 290 dataDir.addPath (staticPath.toString); // we know this is valid anyway 296 dataDir.tryPath (userPath.toString ~ DATA);291 dataDir.tryPath (userPath.toString ~ "/data"); 297 292 if (extraDataPath) dataDir.tryPath (extraDataPath); 298 293 if (!dataDir.pathsLen) throw new mdeException ("Fatal: no data path found!"); 299 294 300 295 // Configuration paths: 301 confDir.tryPath (staticPath.toString ~ CONF);296 confDir.tryPath (staticPath.toString ~ "/conf"); 302 297 confDir.tryPath (installPath.append("user").toString); 303 confDir.tryPath (userPath.toString ~ CONF, true);298 confDir.tryPath (userPath.toString ~ "/conf", true); 304 299 if (extraConfPath) confDir.tryPath (extraConfPath); 305 300 if (!confDir.pathsLen) throw new mdeException ("Fatal: no conf path found!"); … … 325 320 } 326 321 327 // The maximum number of paths for any one "directory". 328 // There are NO CHECKS that this is not exceeded. 322 // The maximum number of paths for any one "directory". 329 323 const MAX_PATHS = 4; 330 324
