Mercurial > projects > mde
diff mde/lookup/Translation.d @ 107:20f7d813bb0f
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.
author | Diggory Hardy <diggory.hardy@gmail.com> |
---|---|
date | Sun, 30 Nov 2008 17:17:56 +0000 |
parents | 42e241e7be3e |
children | 6acd96f8685f |
line wrap: on
line diff
--- 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 <char[][]|depends=[...]>. + * + * 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} - <entry|Str1=["Test 1"]> - <char[][]|depends=["test-2"]> - {test-2} - <entry|Str1=["Test 2"]> - <entry|Str2=["Test 3","Description",bogus,"entries",56]> - *********/ + // 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."); }