1 /* This file is part of the Amalthea library. 2 * 3 * Copyright (C) 2018-2022, 2024 Eugene 'Vindex' Stulin 4 * 5 * Distributed under the Boost Software License 1.0 or (at your option) 6 * the GNU Lesser General Public License 3.0 or later. 7 */ 8 9 module amalthea.langlocal; 10 11 import std.array, std.process; 12 13 public import amalthea.libcore; 14 import amalthea.csv; 15 16 17 static string[][] localeStrings; 18 static string[string] langconformity; 19 static string currentLanguage = "en_US"; 20 21 22 /******************************************************************************* 23 * Current system language. 24 */ 25 string getSystemLanguage() { 26 auto lang = environment.get("LANG", "en_US.UTF-8"); 27 return lang.split(".")[0]; 28 } 29 30 31 /******************************************************************************* 32 * Current application language by langlocal settings. 33 */ 34 string getCurrentLanguage() { 35 return currentLanguage; 36 } 37 38 39 /******************************************************************************* 40 * Initializes localization by a two-dimensional array of strings. 41 * Titles of columns (first line - index 0) must be locales 42 * in Linux style without encoding (en_US, en_GB, eo, fr_CA, ru_RU, etc.), 43 * first locale is en_US always. 44 * 45 * Params: 46 * stringsWithLocalizations = Two-dimensional array containing columns 47 * of strings in different languages. 48 * language = New current language (system language by default). 49 * 50 */ 51 void initLocalization( 52 in string[][] stringsWithLocalizations, 53 string language = "" 54 ) { 55 localeStrings = cast(string[][])stringsWithLocalizations; 56 if (localeStrings[0][0] != "en_US") { 57 throw new LocalizationsTableException( 58 "Error: array in cell [0][0] must consist en_US" 59 ); 60 } 61 if (language == "") { 62 language = getSystemLanguage; 63 } 64 chooseLanguage(language); 65 } 66 67 68 /******************************************************************************* 69 * Initializes localization by a CSV file with translations. 70 * Titles of columns (first line - index 0) must be locales in Linux style 71 * without encoding (en_US, en_GB, eo, fr_CA, ru_RU, etc.), 72 * first locale is en_US always. 73 * 74 * Params: 75 * csvPath = A path to a CSV file with translations. 76 * language = A new current language (system language by default). 77 * 78 */ 79 void initLocalization(string csvPath, string language = "") { 80 auto csv = CSV(csvPath); 81 initLocalization(csv.getTable(), language); 82 } 83 84 85 /******************************************************************************* 86 * This function allows to choose current locale for application. 87 */ 88 void chooseLanguage(string language) { 89 if (localeStrings.empty) return; 90 foreach(i, locale; localeStrings[0]) { 91 if (language != locale) continue; 92 currentLanguage = language; 93 size_t currentTableColumn = i; 94 foreach(row; localeStrings) { 95 if (row[currentTableColumn] == "") { 96 langconformity[row[0]] = row[0]; 97 } else { 98 langconformity[row[0]] = row[currentTableColumn]; 99 } 100 } 101 return; 102 } 103 currentLanguage = "en_US"; 104 } 105 106 107 /******************************************************************************* 108 * This function returns string corresponding to the English (en_US) version, 109 * according to the current localization selected. 110 */ 111 string s_(string englishString) { 112 return langconformity.get(englishString, englishString); 113 } 114 alias _s = s_; 115 116 117 unittest { 118 initLocalization([ 119 ["en_US", "ru_RU", "eo"], 120 ["Hello", "Привет", "Saluton"], 121 ["Orange", "Апельсин", "Oranĝo"], 122 ["Language", "Язык", "Lingvo"], 123 ["Computer", "Компьютер", "Komputilo"] 124 ]); 125 126 chooseLanguage("ru_RU"); 127 assert(s_("Orange") == "Апельсин"); 128 assert("Untranslated string"._s == "Untranslated string"); 129 assert("Other text" == "Other text".s_); 130 131 chooseLanguage("eo"); 132 assert("Language"._s == "Lingvo"); 133 chooseLanguage("Quenya"); // invalid 134 assert(getCurrentLanguage == "en_US"); 135 } 136 137 138 /******************************************************************************* 139 * Exception for incorrect localization tables. 140 */ 141 class LocalizationsTableException : Exception { 142 this(string msg) { 143 super(msg); 144 } 145 } 146