1 module i18n.tr; 2 import i18n.mo; 3 import i18n.culture; 4 import std.path; 5 import std.file : read; 6 import std.uni : toLower; 7 import std.format : format; 8 9 package(i18n) { 10 struct TREntry { 11 string source; 12 string[] targets; 13 const(char)*[] cTargets; 14 } 15 } 16 17 private { 18 MOFile* loadedLanguage; 19 20 enum TLFormats { 21 none, 22 gettext 23 } 24 25 TLFormats currentFormat = TLFormats.none; 26 TREntry[string] lookuptable; 27 } 28 29 /** 30 Gets the name of the language 31 */ 32 string i18nGetLanguageName(string file) { 33 import std.path : baseName, stripExtension; 34 35 // Load language file 36 auto f = i18nMOLoad(cast(ubyte[])read(file)); 37 38 // Try to read language from LANG_NAME strid 39 string langName = f.i18nMOStr("LANG_NAME").dup; 40 destroy!false(f); 41 42 // Not found? Then get (inaccurate) fallback name from internal list 43 if (langName == "LANG_NAME") langName = i18nGetCultureNativeLanguageEstimate(file.baseName.stripExtension); 44 45 // Not found? Then get fallback from english name list 46 if (langName == "LANG_NAME") langName = i18nGetCultureLanguage(file.baseName.stripExtension); 47 48 // Not found? Okay we give up, throw some text to know we don't know what the heck to do 49 if (!langName) return "<UNKNOWN LANGUAGE>"; 50 51 // Return whatever we got 52 return langName; 53 } 54 55 /** 56 Clears currently loaded language 57 */ 58 void i18nClearLanguage() { 59 lookuptable.clear(); 60 loadedLanguage = null; 61 } 62 63 /** 64 Loads a language 65 */ 66 bool i18nLoadLanguage(string file) { 67 68 // Empty path/null = unload 69 if (file.length == 0) { 70 i18nClearLanguage(); 71 return true; 72 } 73 74 // Actually load 75 lookuptable.clear(); 76 switch(file.extension.toLower) { 77 case ".mo": 78 try { 79 loadedLanguage = i18nMOLoad(cast(ubyte[])read(file)); 80 81 lookuptable = i18nMOGenStrings(loadedLanguage); 82 currentFormat = TLFormats.gettext; 83 } catch (Exception ex) { 84 return false; 85 } 86 return true; 87 default: 88 throw new Exception("i18n: Invalid file format %s".format(file.extension)); 89 } 90 } 91 92 /** 93 Returns D string translation of iText 94 */ 95 string _(string iText) { 96 97 // If in lookup table, return from lookup table 98 if (iText in lookuptable) 99 return lookuptable[iText].targets[0]; 100 101 // Otherwise try just in case from file. 102 switch(currentFormat) { 103 case TLFormats.gettext: 104 if (loadedLanguage) return loadedLanguage.i18nMOStr(iText); 105 return iText; 106 default: 107 return iText; 108 } 109 } 110 111 /** 112 Returns C string translation of iText 113 */ 114 const(char)* __(string iText) { 115 import std.string : toStringz; 116 117 // If in lookup table, return from lookup table 118 if (iText in lookuptable) 119 return lookuptable[iText].cTargets[0]; 120 121 // Otherwise try just in case from file. 122 switch(currentFormat) { 123 case TLFormats.gettext: 124 if (loadedLanguage) return loadedLanguage.i18nMOStrC(iText); 125 return iText.toStringz; 126 default: 127 return iText.toStringz; 128 } 129 }