00001
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #include "stdmisc.h"
00030
00031 #include "nel/misc/i18n.h"
00032
00033 using namespace std;
00034
00035 namespace NLMISC {
00036
00037 const char *CI18N::_LanguageFiles[] = { "english", "french" };
00038
00039 map<string, ucstring> CI18N::_StrMap;
00040 bool CI18N::_StrMapLoaded = false;
00041 string CI18N::_Path = "";
00042 string CI18N::_FileName = "";
00043
00044 vector<ucstring> CI18N::_LanguageNames;
00045 bool CI18N::_LanguagesNamesLoaded = false;
00046 sint32 CI18N::_SelectedLanguage = -1;
00047
00048 ucchar CI18N::eatChar (IStream &is)
00049 {
00050 uint8 c;
00051 ucchar code;
00052 sint iterations = 0;
00053
00054 is.serial (c);
00055 code = c;
00056
00057 if ((code & 0xFE) == 0xFC)
00058 {
00059 code &= 0x01;
00060 iterations = 5;
00061 }
00062 else if ((code & 0xFC) == 0xF8)
00063 {
00064 code &= 0x03;
00065 iterations = 4;
00066 }
00067 else if ((code & 0xF8) == 0xF0)
00068 {
00069 code &= 0x07;
00070 iterations = 3;
00071 }
00072 else if ((code & 0xF0) == 0xE0)
00073 {
00074 code &= 0x0F;
00075 iterations = 2;
00076 }
00077 else if ((code & 0xE0) == 0xC0)
00078 {
00079 code &= 0x1F;
00080 iterations = 1;
00081 }
00082 else if ((code & 0x80) == 0x80)
00083 {
00084 nlerror ("CI18N::eatChar(): Invalid UTF-8 character");
00085 }
00086 else
00087 {
00088 return code;
00089 }
00090
00091 for (sint i = 0; i < iterations; i++)
00092 {
00093 uint8 ch;
00094 is.serial (ch);
00095
00096 if ((ch & 0xC0) != 0x80)
00097 {
00098 nlerror ("CI18N::eatChar(): Invalid UTF-8 character");
00099 }
00100
00101 code <<= 6;
00102 code |= (ucchar)(ch & 0x3F);
00103 }
00104 return code;
00105 }
00106
00107 void CI18N::checkASCII7B (ucchar c)
00108 {
00109 if (c>0x7F)
00110 {
00111 nlerror ("CI18N::checkASCII7B: '%c' isn't ASCII 7bits", c);
00112 }
00113 }
00114
00115
00116 void CI18N::skipComment(IStream &is, int &line)
00117 {
00118
00119 ucchar c;
00120 bool longcomment = false;
00121
00122 c = eatChar (is);
00123 if (c == '/') longcomment = false;
00124 else if (c == '*') longcomment = true;
00125
00126 do
00127 {
00128 c = eatChar (is);
00129 if (!longcomment && c == '\n')
00130 {
00131 line++;
00132 return;
00133 }
00134 if (longcomment && c == '*')
00135 {
00136 c = eatChar (is);
00137 if (c == '/') return;
00138 }
00139 }
00140 while (true);
00141 }
00142
00143 ucchar CI18N::skipWS(IStream &is, int &line)
00144 {
00145 ucchar c;
00146 do
00147 {
00148 c = eatChar (is);
00149 if (c == '\n') line++;
00150 if (c == '/')
00151 {
00152 skipComment (is, line);
00153 c = eatChar (is);
00154 }
00155 }
00156 while (isspace (c));
00157 return c;
00158 }
00159
00160
00161 void CI18N::createLanguageFile (uint32 lid)
00162 {
00163 nlassert (lid >= 0 && lid < sizeof (_LanguageFiles)/sizeof(_LanguageFiles[0]));
00164
00165
00166 COFile cof;
00167 nlverify (cof.open (_Path + _LanguageFiles[lid] + ".uxt", true, true));
00168
00169 stringstream ss2;
00170 ss2 << "\"" << _LanguageFiles[lid] << "\"" << endl;
00171 cof.serialBuffer((uint8 *)(ss2.str().c_str()), ss2.str().size());
00172 cof.close ();
00173 }
00174
00175 void CI18N::createLanguageEntry (const string &lval, const string &rval)
00176 {
00177 sint i;
00178 for (i = 0; i < (sint)lval.size () ; i++)
00179 {
00180 unsigned char c = (unsigned char) lval[i];
00181 if (c>0x7F)
00182 {
00183 nlerror ("CI18N::createLanguageEntry(\"%s\"): your string must be ASCII 7bits ('%c' isn't ASCII 7bits)", lval.c_str(), c);
00184 }
00185 }
00186 for (i = 0; i < (sint)rval.size () ; i++)
00187 {
00188 unsigned char c = (unsigned char) rval[i];
00189 if (c>0x7F)
00190 {
00191 nlerror ("CI18N::createLanguageEntry(\"%s\"): your string must be ASCII 7bits ('%c' isn't ASCII 7bits)", rval.c_str(), c);
00192 }
00193 }
00194
00195 for (i = 0; i < (sint)(sizeof(_LanguageFiles)/sizeof(_LanguageFiles[0])); i++)
00196 {
00197 COFile cof;
00198 nlverify (cof.open (_Path + _LanguageFiles[i] + ".uxt", true, true));
00199
00200 stringstream ss2;
00201 ss2 << "\"";
00202 for (sint i = 0; i < (sint) lval.size (); i++)
00203 {
00204 if (lval[i] == '"')
00205 ss2 << '\\';
00206 ss2 << lval[i];
00207 }
00208 ss2 << "\" = \"";
00209 for (sint i2 = 0; i2 < (sint) rval.size(); i2++)
00210 {
00211 if (rval[i2] == '"')
00212 ss2 << '\\';
00213 ss2 << rval[i2];
00214 }
00215 ss2 << "\"" << endl;
00216 cof.serialBuffer((uint8 *)(ss2.str().c_str()), ss2.str().size());
00217 cof.close ();
00218 }
00219 }
00220
00221 void CI18N::setPath (const char* str)
00222 {
00223 _Path = str;
00224 }
00225
00226 void CI18N::load (uint32 lid)
00227 {
00228 nlassert (lid >= 0 && lid < sizeof (_LanguageFiles)/sizeof(_LanguageFiles[0]));
00229 nlassert (_LanguagesNamesLoaded);
00230
00231 _FileName = _Path + _LanguageFiles[lid] + ".uxt";
00232
00233 _SelectedLanguage = lid;
00234
00235 if (_StrMapLoaded) _StrMap.clear ();
00236 else _StrMapLoaded = true;
00237
00238 CIFile cf;
00239
00240 if (!cf.open (_FileName, true))
00241 {
00242 nlwarning ("Could not open file \"%s\" (this file should contain the %s language (lid:%d))", _FileName.c_str (), _LanguageNames[lid].toString().c_str(), lid);
00243 createLanguageFile (lid);
00244 return;
00245 }
00246 nldebug ("Loading file \"%s\" (this file should contain the %s language (lid:%d))", _FileName.c_str (), _LanguageNames[lid].toString ().c_str(), lid);
00247
00248 bool startstr = false, equal = false, second = false;
00249 int line = 1;
00250 try
00251 {
00252 ucchar c;
00253
00254 c = skipWS (cf, line);
00255 if (c != '"')
00256 {
00257 nlerror ("open '\"' missing in \"%s\" line %d", _FileName.c_str(), line);
00258 }
00259 do
00260 {
00261 c = eatChar (cf);
00262 if (c == '\\')
00263 {
00264 c = eatChar (cf);
00265 }
00266 else if (c == '"') break;
00267 else if (c == '\n') line++;
00268 }
00269 while (true);
00270
00271 while (true)
00272 {
00273 string codstr;
00274 ucstring trsstr;
00275 ucchar c;
00276
00277 codstr = "";
00278 trsstr = "";
00279
00280
00281 c = skipWS (cf, line);
00282 if (c != '"')
00283 {
00284 nlerror ("open '\"' missing in \"%s\" line %d", _FileName.c_str(), line);
00285 }
00286 startstr = true;
00287 do
00288 {
00289 c = eatChar (cf);
00290 if (c == '\\')
00291 {
00292 c = eatChar (cf);
00293 }
00294 else if (c == '"') break;
00295 else if (c == '\n') line++;
00296 checkASCII7B (c);
00297 codstr += (char) c;
00298 }
00299 while (true);
00300 startstr = false;
00301
00302 equal = true;
00303
00304 c = skipWS (cf, line);
00305 if (c != '=')
00306 {
00307 nlerror ("'=' missing in \"%s\" line %d", _FileName.c_str(), line);
00308 }
00309 equal = false;
00310
00311 second = true;
00312
00313 c = skipWS (cf, line);
00314 if (c != '"')
00315 {
00316 nlerror ("open '\"' missing in \"%s\" line %d", _FileName.c_str(), line);
00317 }
00318 startstr = true;
00319 do
00320 {
00321 c = eatChar (cf);
00322 if (c == '\\')
00323 {
00324 c = eatChar (cf);
00325 }
00326 else if (c == '"') break;
00327 else if (c == '\n') line++;
00328 trsstr += c;
00329 }
00330 while (true);
00331 startstr = false;
00332 second = false;
00333
00334
00335 pair<ItStrMap, bool> pr;
00336 pr = _StrMap.insert (ValueStrMap (codstr, trsstr));
00337 if (!pr.second)
00338 {
00339 nlwarning ("the string '%s' is duplicate in the langage file '%s' line %d, ignored the last one", codstr.c_str(), _FileName.c_str(), line);
00340 }
00341 }
00342 }
00343 catch (EReadError &)
00344 {
00345
00346 if (startstr)
00347 {
00348 nlerror ("a string didn't have the close '\"' in \"%s\" line %d", _FileName.c_str(), line);
00349 }
00350 if (equal)
00351 {
00352 nlerror ("'=' missing in \"%s\" line %d", _FileName.c_str(), line);
00353 }
00354 if (second)
00355 {
00356 nlerror ("open '\"' missing in \"%s\" line %d", _FileName.c_str(), line);
00357 }
00358 cf.close ();
00359 }
00360 }
00361
00362 const ucstring &CI18N::get (const char *str)
00363 {
00364 nlassert (_StrMapLoaded);
00365
00366 ItStrMap it = _StrMap.find (str);
00367
00368 if (it == _StrMap.end ())
00369 {
00370
00371 stringstream ss;
00372 ss << "<Not Translated>:" << str;
00373
00374 pair<ItStrMap, bool> pr;
00375
00376 pr = _StrMap.insert (ValueStrMap (str, ss.str()));
00377 nlassert (pr.second);
00378 it = pr.first;
00379
00380
00381 createLanguageEntry (str, ss.str());
00382
00383
00384 nlwarning ("\"%s\" is not in the \"%s\" language file, I add in all languages files.", str, _FileName.c_str());
00385 }
00386
00387 return it->second;
00388 }
00389
00390
00391 string CI18N::getCurrentLanguage ()
00392 {
00393 if (_SelectedLanguage == -1)
00394 return "<NoLanguage>";
00395 else
00396 return _LanguageFiles[_SelectedLanguage];
00397 }
00398
00399 const vector<ucstring> &CI18N::getLanguageNames()
00400 {
00401 CIFile cf;
00402
00403 if (!_LanguagesNamesLoaded)
00404 {
00405 for (int i = 0; i < (int)(sizeof(_LanguageFiles)/sizeof(_LanguageFiles[0])); i++)
00406 {
00407 string fn = _Path + _LanguageFiles[i] + ".uxt";
00408
00409 ucstring lg;
00410
00411 if (!cf.open (fn, true))
00412 {
00413 nlwarning ("Could not open file \"%s\" (lid:%d)", fn.c_str(), i);
00414 createLanguageFile (i);
00415 lg = _LanguageFiles[i];
00416 }
00417 else
00418 {
00419 int line = 1;
00420 try
00421 {
00422 ucchar c;
00423
00424 c = skipWS (cf, line);
00425 if (c != '"')
00426 {
00427 nlerror ("open '\"' missing in \"%s\" line %d", fn.c_str(), line);
00428 }
00429 do
00430 {
00431 c = eatChar (cf);
00432 if (c == '\\')
00433 {
00434 c = eatChar (cf);
00435 }
00436 else if (c == '"') break;
00437 else if (c == '\n') line++;
00438 lg += c;
00439 }
00440 while (true);
00441 }
00442 catch (EReadError)
00443 {
00444 nlerror ("Missing the language name in the beginning of the file %s", fn.c_str());
00445 }
00446 cf.close ();
00447 }
00448
00449 _LanguageNames.push_back (lg);
00450 nldebug ("add %d '%s' '%s'", i, fn.c_str (), _LanguageFiles[i]);
00451 }
00452 _LanguagesNamesLoaded = true;
00453 }
00454 return _LanguageNames;
00455 }
00456
00457
00458 }