# HG changeset patch # User Diggory Hardy # Date 1228065476 0 # Node ID 20f7d813bb0f659d3de98fbdd5148e61c4cf3575 # Parent 7f7b40fed72b7b9406b7e9b2effa28024af643da Translation: now has a file for each locale, instead of a file for each section. Items updated; all strings translated. New unittest for Translation; I realised the old one wasn't run anymore. Changed unittest data and conf dirs. diff -r 7f7b40fed72b -r 20f7d813bb0f data/L10n/FontOptions.mtt --- a/data/L10n/FontOptions.mtt Sat Nov 29 16:43:44 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,5 +0,0 @@ -{MT01} -{en-GB} - - - diff -r 7f7b40fed72b -r 20f7d813bb0f data/L10n/MiscOptions.mtt --- a/data/L10n/MiscOptions.mtt Sat Nov 29 16:43:44 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,9 +0,0 @@ -{MT01} -{en-GB} - - - - - - - diff -r 7f7b40fed72b -r 20f7d813bb0f data/L10n/VideoOptions.mtt --- a/data/L10n/VideoOptions.mtt Sat Nov 29 16:43:44 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,11 +0,0 @@ -{MT01} -{en-GB} - - - - - - - - - diff -r 7f7b40fed72b -r 20f7d813bb0f data/L10n/en-GB.mtt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/data/L10n/en-GB.mtt Sun Nov 30 17:17:56 2008 +0000 @@ -0,0 +1,27 @@ +{MT01} +{imde} + +{Options} + +{FontOptions} + + + +{MiscOptions} + + + + + + + +{VideoOptions} + + + + + + + + + diff -r 7f7b40fed72b -r 20f7d813bb0f data/conf/gui.mtt --- a/data/conf/gui.mtt Sat Nov 29 16:43:44 2008 +0000 +++ b/data/conf/gui.mtt Sun Nov 30 17:17:56 2008 +0000 @@ -5,8 +5,9 @@ - - + + + @@ -14,9 +15,7 @@ - -!{cloned to avoid bug #4} - + + {Basic} diff -r 7f7b40fed72b -r 20f7d813bb0f mde/content/Items.d --- a/mde/content/Items.d Sat Nov 29 16:43:44 2008 +0000 +++ b/mde/content/Items.d Sun Nov 30 17:17:56 2008 +0000 @@ -51,7 +51,9 @@ list[i++] = opts.contentList; } Options.allContentList = new ContentList (h, list); - Options.allContentList.name ("Options"); //FIXME + Translation trl = Translation.get (h); + Translation.Entry trle = trl.getStruct (h); + Options.allContentList.name (trle.name, trle.desc); } return Options.allContentList; } @@ -68,9 +70,18 @@ if (q && item is null) // enforce item is an exact match return *q; } - } else if (h == "quit" && item is null) { - quit.name ("Quit"); //FIXME - return quit; + } else if (h == "imde") { + if (!imdeTransl) { + Translation trl = Translation.get (h); + Translation.Entry trle = trl.getStruct ("quit"); + quit.name (trle.name, trle.desc); + imdeTransl = true; + } + h = head (item); + if (h == "quit" && item is null) { + quit.name ("Quit"); //FIXME + return quit; + } } throw new ContentItemException (h); } @@ -92,7 +103,7 @@ void loadTransl (Options p, char[] n) { debug logger.trace ("Loading translation strings for Options."~n); - Translation trans = Translation.load ("L10n/"~n); + Translation trans = Translation.get (n); Translation.Entry transled = trans.getStruct (n); p.contentList = new ContentList (n, p.content); p.contentList.name (transled.name, transled.desc); @@ -101,3 +112,5 @@ v.name (transled.name, transled.desc); } } + + bool imdeTransl = false; // Has section imde been translated? diff -r 7f7b40fed72b -r 20f7d813bb0f mde/input/Input.d --- a/mde/input/Input.d Sat Nov 29 16:43:44 2008 +0000 +++ b/mde/input/Input.d Sun Nov 30 17:17:56 2008 +0000 @@ -586,11 +586,11 @@ * currently conf/input.mtt). */ debug (mdeUnitTest) unittest { Input ut = new Input(); - ut.loadConfig ("unittest/InputConfig"); - + ut.loadConfig ("InputConfig"); + int[6] counters; // counters for callbacks // Should become: [2,2,0,2,1,1] - + //BEGIN Set up some callbacks ut.addButtonCallback (0x03F0, delegate void(inputID id, bool status) { assert (status == !counters[0]); // true first call, false next diff -r 7f7b40fed72b -r 20f7d813bb0f mde/lookup/Translation.d --- a/mde/lookup/Translation.d Sat Nov 29 16:43:44 2008 +0000 +++ b/mde/lookup/Translation.d Sun Nov 30 17:17:56 2008 +0000 @@ -56,8 +56,67 @@ */ class Translation : IDataSection { - final char[] name; /// The module/package/... which the instance is for - final char[] L10n; /// The localization loaded (e.g. en-GB) + /** Load the translation for the requested module/package/... + * + * Options (mde.options) must have been loaded before this is run. + * + * Params: + * name The module/package/... to load strings for. + * + * Throws: + * If no localization exists for this name and the current locale (or any locale to be chain- + * loaded), or an error occurs while loading the database, a L10nLoadException will be thrown. + */ + static { + /** Get Translation instance for _section section. + * + * On the first call, loads all Translation sections. + * + * These are loaded from data/L10n/locale.mtt where locale is the current locale, as well + * as any files named for locales specified in the header tag . + * + * On errors, a message is logged and the function continues, likely resulting in some + * symbol names being untranslated. */ + Translation get (char[] section) { + if (sections is null) { + char[][] files = [miscOpts.L10n()]; // initial locale plus dependencies + size_t read = 0; // index in files of next file to read + while (read < files.length) { + try { + IReader reader = dataDir.makeMTReader ("L10n/"~files[read++], PRIORITY.HIGH_LOW, null, true); + assert (reader.dataset.header); + auto dp = "depends" in reader.dataset.header._charAA; + if (dp) { // append, making sure no duplicates are inserted + f1: foreach (dep; *dp) { + foreach (f; files) + if (f == dep) + continue f1; + files ~= dep; + } + } + reader.dataSecCreator = delegate IDataSection(ID sec) { + auto p = sec in sections; + if (p) return *p; + return new Translation (sec); + }; + reader.read; + } catch (MTException e) { + logger.error ("Mergetag exception occurred:"); + logger.error (e.msg); + } + } + } + auto p = section in sections; + if (p is null) { + logger.warn ("Section "~section ~ " not found in files; strings will not be translated."); + return new Translation (section); + } + return *p; + } + Translation[char[]] sections; + } + + final char[] section; // ONLY used to log an error message alias entry opCall; /// Convenience alias @@ -96,60 +155,6 @@ } } - /** Load the translation for the requested module/package/... - * - * Options (mde.options) must have been loaded before this is run. - * - * Params: - * name The module/package/... to load strings for. - * - * Throws: - * If no localization exists for this name and the current locale (or any locale to be chain- - * loaded), or an error occurs while loading the database, a L10nLoadException will be thrown. - */ - static Translation load (char[] name) - { - bool[ID] loadedSecs; // set of all locales/sections loaded; used to prevent circular loading - ID[] secsToLoad // locales/sections to load (dependancies may be added) - = [cast(ID) miscOpts.L10n]; // start by loading the current locale - - Translation transl = new Translation (name, miscOpts.L10n()); - - IReader reader; - try { - reader = dataDir.makeMTReader (name, PRIORITY.HIGH_LOW); - /* Note: we don't want to load every translation section depended on to its own class - * instance, since we want to merge them. So make every mergetag section use the same - * instance. */ - reader.dataSecCreator = delegate IDataSection(ID) { - return transl; - }; - - while (secsToLoad.length) { // while we have sections left to load - ID sec = secsToLoad[0]; // take current section - secsToLoad = secsToLoad[1..$]; // and remove from list - - if (sec in loadedSecs) continue; // skip if it's already been loaded - loadedSecs[sec] = true; - - reader.read ([sec]); // Do the actual loading - - // Add dependancies to front of list: - secsToLoad = transl.depends ~ secsToLoad; - } - // When loop finishes, we're done loading. - } catch (MTException e) { - // If an error occurs, log a message but continue (strings will just be untranslated) - logger.error ("Mergetag exception occurred:"); - logger.error (e.msg); - } - - delete transl.depends; // Free memory - transl.depends = []; - - return transl; - } - static this() { logger = Log.getLogger ("mde.lookup.Translation"); } @@ -172,7 +177,7 @@ Entry entry = deserialize!(Entry) (dt); if (entry.name is null) { // This tag is invalid; ignore it - logger.error ("For name "~name~", L10n "~L10n~": tag with ID "~cast(char[])id~" has no data"); + logger.error ("In L10n/*.mtt section "~section~": tag with ID "~cast(char[])id~" has no data"); return; } entries[cast(char[]) id] = entry; @@ -194,12 +199,10 @@ } private: - /* Sets name and L10n. - * - * Also ensures only load() can create instances. */ - this (char[] n, char[] l) { - name = n; - L10n = l; + /* Sets name and ensures only Translation's static functions can create instances. */ + this (char[] n) { + section = n; + sections[n] = this; } //BEGIN Data @@ -211,42 +214,35 @@ //END Data debug (mdeUnitTest) unittest { - /* Relies on file: conf/L10n/i18nUnitTest.mtt - * Contents: - ********* - {MT01} - {test-1} - - - {test-2} - - - *********/ + // Relies on files in unittest/data/L10n: locale-x.mtt for x in 1..4 - // Hack a specific locale... - // Also to allow unittest to run without init. - TextContent realL10n = miscOpts.L10n; - miscOpts.L10n = new TextContent ("L10n", "test-1"); + // Hack a specific locale. Also to allow unittest to run without init. + StringContent realL10n = miscOpts.L10n; + miscOpts.L10n = new StringContent ("L10n", "locale-1"); - Translation transl = load ("unittest/Translation"); - - // Simple get-string, check dependancy's entry doesn't override - assert (transl.entry ("Str1") == "Test 1"); - - // Entry included from dependancy with description - char[] desc; - assert (transl.entry ("Str2", desc) == "Test 3"); - assert (desc == "Description"); - - // No entry: fallback to identifier string - assert (transl.entry ("Str3") == "Str3"); - - // No checks for version info since it's not functionality of this module. - // Only check extra entries are allowed but ignored. - + // Struct tests + Translation t = get ("section-2"); + Entry e = t.getStruct ("entry-1"); + assert (e.name == "Test 1"); + assert (e.desc == "Description"); + e = t.getStruct ("entry-2"); + assert (e.name == "Test 2"); + assert (e.desc is null); + + // Dependency tests. Priority should be 1,2,3,4 (entries should come from first file in list that they appear in). + t = get ("section-1"); + char[] d = "1"; + assert (t.entry ("file-1", d) == "locale-1"); + assert (d is null); + assert (t.entry ("file-2", d) == "locale-2"); + assert (d == "desc2"); + assert (t.entry ("file-3") == "locale-3"); + assert (t.entry ("file-4") == "locale-4"); + // Restore delete miscOpts.L10n; miscOpts.L10n = realL10n; + sections = null; logger.info ("Unittest complete."); } diff -r 7f7b40fed72b -r 20f7d813bb0f mde/mde.d --- a/mde/mde.d Sat Nov 29 16:43:44 2008 +0000 +++ b/mde/mde.d Sun Nov 30 17:17:56 2008 +0000 @@ -33,6 +33,7 @@ debug (mdeUnitTest) { // These modules contain unittests which wouldn't be run otherwise. import mde.file.ssi; import mde.file.mergetag.mdeUT; + import mde.lookup.Translation; } //BEGIN A simple drawable to print a message in the window. diff -r 7f7b40fed72b -r 20f7d813bb0f mde/setup/paths.d --- a/mde/setup/paths.d Sat Nov 29 16:43:44 2008 +0000 +++ b/mde/setup/paths.d Sun Nov 30 17:17:56 2008 +0000 @@ -139,17 +139,6 @@ { FilePath[] ret; - debug (mdeUnitTest) { - /* Alternate approach - just try from current directory. - * Really just for unittests, but with the if condition it shouldn't break anything else. */ - if (pathsLen == 0) { - FilePath file = findFile (filename); - if (file !is null) - ret ~= file; - return ret; - } - } - if (readOrder == PRIORITY.LOW_HIGH) { for (size_t i = 0; i < pathsLen; ++i) { FilePath file = findFile (paths[i]~filename); @@ -172,12 +161,14 @@ // Unconditionally add a path void addPath (char[] path) { + assert (pathsLen < MAX_PATHS); paths[pathsLen++] = path~'/'; } // Test a path and add if is a folder. bool tryPath (char[] path, bool create = false) { - FilePath fp = FilePath (path); + assert (pathsLen < MAX_PATHS); + FilePath fp = FilePath (path); if (fp.exists && fp.isFolder) { paths[pathsLen++] = path~'/'; return true; @@ -213,13 +204,17 @@ char[] logDir; /// Directory for log files //BEGIN Path resolution -// These are used several times: -const DATA = "/data"; -const CONF = "/conf"; - -/** Find at least one path for each required directory. -* -* Note: the logger cannot be used yet, so only output is exception messages. */ +/** Find at least one path for each required directory. */ +debug (mdeUnitTest) { + /** In unittest mode, add paths unittest/data and unittest/conf before init runs. */ + static this () { + dataDir.tryPath ("unittest/data"); + confDir.tryPath ("unittest/conf"); + if (!(dataDir.pathsLen && confDir.pathsLen)) + throw new mdeException ("Fatal: unittest/data and unittest/conf don't both exist"); + // Don't bother with real paths or logDir or font dir(s) for unittest. + } +} version (linux) { SortedMap!(char[],char[]) fontFiles; // key is file name, value is CString path /** Get the actual path of a font file, or throw NoFileException if not found. @@ -246,14 +241,14 @@ // Static data paths: dataDir.addPath (staticPath.toString); // we know this is valid anyway - dataDir.tryPath (userPath.toString ~ DATA); + dataDir.tryPath (userPath.toString ~ "/data"); if (extraDataPath) dataDir.tryPath (extraDataPath); if (!dataDir.pathsLen) throw new mdeException ("Fatal: no data path found!"); // Configuration paths: - confDir.tryPath (staticPath.toString ~ CONF); + confDir.tryPath (staticPath.toString ~ "/conf"); confDir.tryPath ("/etc/mde"); - confDir.tryPath (userPath.toString ~ CONF, true); + confDir.tryPath (userPath.toString ~ "/conf", true); if (extraConfPath) confDir.tryPath (extraConfPath); if (!confDir.pathsLen) throw new mdeException ("Fatal: no conf path found!"); @@ -293,14 +288,14 @@ // Static data paths: dataDir.addPath (staticPath.toString); // we know this is valid anyway - dataDir.tryPath (userPath.toString ~ DATA); + dataDir.tryPath (userPath.toString ~ "/data"); if (extraDataPath) dataDir.tryPath (extraDataPath); if (!dataDir.pathsLen) throw new mdeException ("Fatal: no data path found!"); // Configuration paths: - confDir.tryPath (staticPath.toString ~ CONF); + confDir.tryPath (staticPath.toString ~ "/conf"); confDir.tryPath (installPath.append("user").toString); - confDir.tryPath (userPath.toString ~ CONF, true); + confDir.tryPath (userPath.toString ~ "/conf", true); if (extraConfPath) confDir.tryPath (extraConfPath); if (!confDir.pathsLen) throw new mdeException ("Fatal: no conf path found!"); @@ -324,8 +319,7 @@ } } -// The maximum number of paths for any one "directory". -// There are NO CHECKS that this is not exceeded. + // The maximum number of paths for any one "directory". const MAX_PATHS = 4; /* Try each path in succession, returning the first to exist and be a folder. diff -r 7f7b40fed72b -r 20f7d813bb0f unittest/InputConfig.mtt --- a/unittest/InputConfig.mtt Sat Nov 29 16:43:44 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,13 +0,0 @@ -{MT01} -!{Config for the input.Input unittest} -{Default} - - - diff -r 7f7b40fed72b -r 20f7d813bb0f unittest/Translation.mtt --- a/unittest/Translation.mtt Sat Nov 29 16:43:44 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,7 +0,0 @@ -{MT01} -{test-1} - - -{test-2} - - diff -r 7f7b40fed72b -r 20f7d813bb0f unittest/conf/InputConfig.mtt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/unittest/conf/InputConfig.mtt Sun Nov 30 17:17:56 2008 +0000 @@ -0,0 +1,13 @@ +{MT01} +!{Config for the input.Input unittest} +{Default} + + + diff -r 7f7b40fed72b -r 20f7d813bb0f unittest/data/L10n/locale-1.mtt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/unittest/data/L10n/locale-1.mtt Sun Nov 30 17:17:56 2008 +0000 @@ -0,0 +1,7 @@ +{MT01} + +{section-1} + +{section-2} + + diff -r 7f7b40fed72b -r 20f7d813bb0f unittest/data/L10n/locale-2.mtt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/unittest/data/L10n/locale-2.mtt Sun Nov 30 17:17:56 2008 +0000 @@ -0,0 +1,5 @@ +{MT01} + +{section-1} + + diff -r 7f7b40fed72b -r 20f7d813bb0f unittest/data/L10n/locale-3.mtt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/unittest/data/L10n/locale-3.mtt Sun Nov 30 17:17:56 2008 +0000 @@ -0,0 +1,6 @@ +{MT01} + +{section-1} + + + diff -r 7f7b40fed72b -r 20f7d813bb0f unittest/data/L10n/locale-4.mtt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/unittest/data/L10n/locale-4.mtt Sun Nov 30 17:17:56 2008 +0000 @@ -0,0 +1,6 @@ +{MT01} +{section-1} + + + +