1 /** 2 * A library for i18n in D 3 * Author: KonstantIMP <mihedovkos@gmail.com> 4 * Date: 22 Aug 2021 5 */ 6 module di.i18n; 7 8 import std.json, std.file, std.exception; 9 10 ///> Aliases for better use 11 alias _ = I18n.get; 12 alias _f = I18n.getFallback; 13 14 /** 15 * An exception for I18n errors 16 */ 17 public class I18nException : Exception { 18 /** 19 * Creates and throws new I18nException 20 * Params: 21 * err = Error message for the exception 22 */ 23 public this (string err) { super (err); } 24 } 25 26 /** 27 * Struct for locale description 28 * To load locale use JSON file with the struct : 29 * { "name" : "locale`s name", "tr" : [{"id" : "id for the text", "tr" : "translation for the id"}, ...] } 30 */ 31 private struct Locale { 32 ///> Locale`s name (like 'en') 33 public string name = ""; 34 ///> Loaded translations for this locale 35 public string [string] tr; 36 } 37 38 /** 39 * Class for actual i18n 40 */ 41 public static class I18n { 42 ///> List of the loaded locales 43 private static Locale [string] loadedLocales; 44 ///> Currently used locale 45 private static string currentLocale; 46 47 /** 48 * Inits the I18n module 49 */ 50 public static this () { 51 import core.stdc.locale : setlocale, LC_ALL; 52 import std.conv : to; 53 54 currentLocale = ""; 55 56 foreach (f; ["./i18n/", "./po/", "./locale/"]) { 57 try loadLocales(f); 58 catch (Exception) {} 59 } 60 61 string tmp = (to!string(setlocale(LC_ALL, "")))[0 .. 2]; 62 if (tmp in loadedLocales) currentLocale = tmp; 63 else if (loadedLocales.keys.length) currentLocale = loadedLocales.keys[0]; 64 } 65 66 /** 67 * Loads locale from JSON file 68 * Params: 69 * path = Path to the JSON locale 70 * Throws: 71 * FileException if the file doesn`t exsists 72 * I18nException if was given incorrect locale file 73 */ 74 public static void loadLocale (string path) { 75 import std.conv : to; 76 loadLocaleFromMemory (to!string(read (path))); 77 } 78 79 /** 80 * Loads locale from data 81 * Params: 82 * data = Data for loading 83 * Throws: 84 * I18nException if was given incorrect locale file 85 * JSONException if was given incorrect locale file 86 */ 87 public static void loadLocaleFromMemory (string data) { 88 JSONValue lj = parseJSON ((data)); 89 90 Locale ll; ll.name = lj["name"].str(); 91 92 foreach (tr; lj["tr"].array) { 93 ll.tr[tr["id"].str()] = tr["tr"].str(); 94 } 95 96 loadedLocales[ll.name] = ll; 97 } 98 99 /** 100 * Loads all locales from the folder (non recursive) 101 * Params: 102 * path = Path to the folder for loading 103 * Throws: 104 * FileException if cannot read a file with the locale 105 * I18nException if was found an incorrect locale file 106 */ 107 public static void loadLocales (string path) { 108 foreach (DirEntry en; dirEntries (path, SpanMode.shallow)) { 109 if (en.isFile) loadLocale (en.name); 110 } 111 } 112 113 /** 114 * Getter for the translation 115 * Params: 116 * id = ID for the translation 117 * locale = Locale for translation getting 118 * Returns: Translation for the ID 119 * Throws: I18nException if cannot find locale or id 120 */ 121 public static string get (string id, string locale = currentLocale) { 122 if (locale !in loadedLocales) throw new I18nException("Cannot find locale : " ~ locale); 123 if (id !in loadedLocales[locale].tr) throw new I18nException("Cannot find the id : " ~ id); 124 return loadedLocales[locale].tr[id]; 125 } 126 127 /** 128 * Getter for the translation 129 * Params: 130 * id = ID for the translation 131 * fallback = Translation if the error was catched 132 * locale = Locale for translation getting 133 * Returns: Translation for the ID or fallback 134 */ 135 public static string getFallback (string id, string fallback, string locale = currentLocale) { 136 if (locale !in loadedLocales) return fallback; 137 if (id !in loadedLocales[locale].tr) return fallback; 138 return loadedLocales[locale].tr[id]; 139 } 140 141 /** 142 * Returns: List of the loaded locales 143 */ 144 public static string [] getLoadedLocales () { return loadedLocales.keys; } 145 146 /** 147 * Returns: Currently used locale 148 */ 149 public static string getCurrentLocale () { return currentLocale; } 150 }