# Home    # nevrax.com   
Nevrax
Nevrax.org
#News
#Mailing-list
#Documentation
#CVS
#Bugs
#License
Docs
 
Documentation  
Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages   Search  

i18n.cpp

Go to the documentation of this file.
00001 
00009 /* Copyright, 2000 Nevrax Ltd.
00010  *
00011  * This file is part of NEVRAX NEL.
00012  * NEVRAX NEL is free software; you can redistribute it and/or modify
00013  * it under the terms of the GNU General Public License as published by
00014  * the Free Software Foundation; either version 2, or (at your option)
00015  * any later version.
00016 
00017  * NEVRAX NEL is distributed in the hope that it will be useful, but
00018  * WITHOUT ANY WARRANTY; without even the implied warranty of
00019  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00020  * General Public License for more details.
00021 
00022  * You should have received a copy of the GNU General Public License
00023  * along with NEVRAX NEL; see the file COPYING. If not, write to the
00024  * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
00025  * MA 02111-1307, USA.
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         // the first '/' is already eated
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         // write the new string in the file
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         // if the file does not exist, it'll be create automatically
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                 // get the language name
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                         // get the coder string
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                         // get the '='
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                         // get the translated string
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                         // Insert the node.
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                 // always comes here when it's the end of file
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                 // str not found, add it in the map and in the file
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                 // write the new string in all files
00381                 createLanguageEntry (str, ss.str());
00382 
00383                 // warn the user
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                                         // get the language name
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                         // add the language name
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 } // NLMISC