1 /*
2  *  This file is part of RawTherapee.
3  *
4  *  Copyright (c) 2004-2010 Gabor Horvath <hgabor@rawtherapee.com>
5  *
6  *  RawTherapee is free software: you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation, either version 3 of the License, or
9  *  (at your option) any later version.
10  *
11  *  RawTherapee is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with RawTherapee.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 #include "multilangmgr.h"
20 
21 #include <fstream>
22 #include <glib.h>
23 #ifdef WIN32
24 #include <windows.h>
25 #include <winnls.h>
26 #endif
27 
28 namespace
29 {
30 
31 // Maps standard locales to languages, e.g. "de-DE" to "Deutsch".
32 struct LocaleToLang : private std::map<std::pair<Glib::ustring, Glib::ustring>, Glib::ustring>
33 {
key__anon1e30759d0111::LocaleToLang34     static const std::pair<Glib::ustring, Glib::ustring> key (const Glib::ustring& major, const Glib::ustring& minor = Glib::ustring ())
35     {
36         return std::make_pair (major, minor);
37     }
38 
LocaleToLang__anon1e30759d0111::LocaleToLang39     LocaleToLang ()
40     {
41         emplace (key ("ca", "ES"), "Catala");
42         emplace (key ("cs", "CZ"), "Czech");
43         emplace (key ("da", "DK"), "Dansk");
44         emplace (key ("de", "DE"), "Deutsch");
45 #ifdef __APPLE__
46         emplace (key ("en", "UK"), "English (UK)");
47 #else
48         emplace (key ("en", "GB"), "English (UK)");
49 #endif
50         emplace (key ("en", "US"), "English (US)");
51         emplace (key ("es", "ES"), "Espanol");
52         emplace (key ("eu", "ES"), "Euskara");
53         emplace (key ("fr", "FR"), "Francais");
54         emplace (key ("el", "GR"), "Greek");
55         emplace (key ("he", "IL"), "Hebrew");
56         emplace (key ("it", "IT"), "Italiano");
57         emplace (key ("ja", "JP"), "Japanese");
58         emplace (key ("lv", "LV"), "Latvian");
59         emplace (key ("hu", "HU"), "Magyar");
60         emplace (key ("nl", "NL"), "Nederlands");
61         emplace (key ("nn", "NO"), "Norsk BM");
62         emplace (key ("nb", "NO"), "Norsk BM");
63         emplace (key ("pl", "PL"), "Polish");
64         emplace (key ("pt", "PT"), "Portugues (Brasil)");
65         emplace (key ("ru", "RU"), "Russian");
66         emplace (key ("sr", "RS"), "Serbian (Cyrilic Characters)");
67         emplace (key ("sk", "SK"), "Slovak");
68         emplace (key ("fi", "FI"), "Suomi");
69         emplace (key ("sv", "SE"), "Swedish");
70         emplace (key ("tr", "TR"), "Turkish");
71         emplace (key ("zh", "CN"), "Chinese (Simplified)");
72         emplace (key ("zh", "SG"), "Chinese (Traditional)");
73     }
74 
operator ()__anon1e30759d0111::LocaleToLang75     Glib::ustring operator() (const Glib::ustring& locale) const
76     {
77         Glib::ustring major, minor;
78 
79         if (locale.length () >= 2) {
80             major = locale.substr (0, 2).lowercase ();
81         }
82 
83         if (locale.length () >= 5) {
84             minor = locale.substr (3, 2).uppercase ();
85         }
86 
87         // Look for matching language and country.
88         auto iterator = find (key (major, minor));
89 
90         if (iterator != end ()) {
91             return iterator->second;
92         }
93 
94         // Look for matching language only.
95         iterator = find (key (major, major.uppercase()));
96 
97         if (iterator != end ()) {
98             return iterator->second;
99         }
100 
101         return "default";
102     }
103 
getLocale__anon1e30759d0111::LocaleToLang104     std::string getLocale(const Glib::ustring &language) const
105     {
106         for (auto &p : *this) {
107             if (p.second == language) {
108                 std::string ret = p.first.first;
109                 if (!p.first.second.empty()) {
110                     ret += "_" + p.first.second;
111                 }
112                 return ret;
113             }
114         }
115         return "C";
116     }
117 };
118 
119 const LocaleToLang localeToLang;
120 
setGtkLanguage(const Glib::ustring & language)121 void setGtkLanguage(const Glib::ustring &language)
122 {
123     if(language != "default") { // nothing to change when using default
124         std::string lang = localeToLang.getLocale(language);
125         const gchar *env_langc = g_getenv("LANG");
126         if(env_langc) {
127             const std::string env_lang(env_langc);
128             if (!env_lang.empty()) {
129                 const std::string::size_type suffix_pos = env_lang.find_first_of(".");
130                 if (suffix_pos != std::string::npos) {
131                     lang += env_lang.substr(suffix_pos);
132                 }
133             }
134         }
135 
136         g_setenv("LANG", lang.c_str(), true);
137     }
138 }
139 
140 }
141 
142 MultiLangMgr langMgr;
143 
MultiLangMgr()144 MultiLangMgr::MultiLangMgr ()
145 {
146 }
147 
load(const Glib::ustring & language,const std::vector<Glib::ustring> & fnames)148 void MultiLangMgr::load(const Glib::ustring &language, const std::vector<Glib::ustring> &fnames)
149 {
150     setGtkLanguage(language);
151 
152     translations.clear();
153 
154     for (const auto& fname : fnames) {
155         if(fname.empty()) {
156             continue;
157         }
158 
159         std::ifstream file(fname.c_str());
160         if (!file.is_open()) {
161             continue;
162         }
163 
164         std::string entry;
165         auto hint = translations.begin();
166         while (std::getline(file, entry)) {
167 
168             if (entry.empty() || entry.front() == '#' || entry.front() == '!') {
169                 continue;
170             }
171 
172             std::string key, value;
173 
174             std::istringstream line(entry);
175 
176             if(std::getline(line, key, ';') && translations.find(key) == translations.end() && std::getline(line, value)) {
177                 size_t pos = 0;
178                 while((pos = value.find("\\n", pos)) != std::string::npos) {
179                      value.replace(pos, 2, "\n");
180                      pos++;
181                 }
182                 hint = translations.emplace_hint(hint, key, value);
183             }
184         }
185     }
186 }
187 
getStr(const std::string & key) const188 Glib::ustring MultiLangMgr::getStr (const std::string& key) const
189 {
190     const auto iterator = translations.find(key);
191 
192     if (iterator != translations.end()) {
193         return iterator->second;
194     }
195 
196     return key;
197 }
198 
isOSLanguageDetectSupported()199 bool MultiLangMgr::isOSLanguageDetectSupported ()
200 {
201 #if defined (WIN32) || defined (__linux__) || defined (__APPLE__)
202     return true;
203 #else
204     return false;
205 #endif
206 }
207 
getOSUserLanguage()208 Glib::ustring MultiLangMgr::getOSUserLanguage ()
209 {
210     Glib::ustring langName ("default");
211 
212 #if defined (WIN32)
213 
214     const LCID localeID = GetUserDefaultLCID ();
215     TCHAR localeName[18];
216 
217     const int langLen = GetLocaleInfo (localeID, LOCALE_SISO639LANGNAME, localeName, 9);
218     if (langLen <= 0) {
219         return langName;
220     }
221 
222     localeName[langLen - 1] = '-';
223 
224     const int countryLen = GetLocaleInfo (localeID, LOCALE_SISO3166CTRYNAME, &localeName[langLen], 9);
225     if (countryLen <= 0) {
226         return langName;
227     }
228 
229     langName = localeToLang (localeName);
230 
231 #elif defined (__linux__) || defined (__APPLE__)
232 
233     // Query the current locale and force decimal point to dot.
234     const char *locale = getenv("LANG");
235     if (locale || (locale = setlocale (LC_CTYPE, ""))) {
236         langName = localeToLang (locale);
237     }
238 
239     setlocale (LC_NUMERIC, "C");
240 
241 #endif
242 
243     return langName;
244 }
245