00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include "tMemManager.h"
00029 #include "tLocale.h"
00030 #include "tConsole.h"
00031 #include "tDirectories.h"
00032 #include "tSafePTR.h"
00033
00034 #include <fstream>
00035 #include <string>
00036 #include <map>
00037
00038 class tLocaleSubItem;
00039
00040 static tArray<tString> st_TemplateParameters;
00041
00042 static tString s_gameName("Armagetron");
00043
00044 class tLocaleItem: public tReferencable< tLocaleItem >
00045 {
00046 friend class tLocaleSubItem;
00047
00048 tString identifier;
00049 tLocaleSubItem *items;
00050 bool istemplate;
00051
00052 public:
00053
00054
00055
00056
00057 operator const char *() const;
00058
00059 tLocaleItem(const char *identifier);
00060 ~tLocaleItem();
00061
00062 static void Load(const char *file, bool complete = true );
00063
00064 static void Clear();
00065
00066 static tLocaleItem& Find(const char *identifier);
00067 };
00068
00069
00070 static const tLanguage* st_firstLanguage = NULL;
00071 static const tLanguage* st_secondLanguage = NULL;
00072
00073 static tLanguage* st_languageAnchor = NULL;
00074
00075 typedef std::map< std::string, tJUST_CONTROLLED_PTR< tLocaleItem > > tLocaleItemMap;
00076
00077
00078
00079 static tLanguage *currentLanguage = NULL;
00080
00081
00082 class tLocaleSubItem: public tListItem<tLocaleSubItem>
00083 {
00084 public:
00085 const tLanguage *language;
00086 tString translation;
00087
00088 tLocaleSubItem(tLocaleItem *item)
00089 : tListItem<tLocaleSubItem>(item->items){}
00090 };
00091
00092
00093
00094 tLanguage::tLanguage(const tString& n)
00095 :tListItem<tLanguage>(st_languageAnchor),
00096 name(n)
00097 {
00098 }
00099
00100
00101 tLanguage* tLanguage::FirstLanguage()
00102 {
00103 return st_languageAnchor;
00104 }
00105
00106 void tLanguage::SetFirstLanguage() const
00107 {
00108 st_firstLanguage = this;
00109 Load();
00110 }
00111
00112 void tLanguage::SetSecondLanguage() const
00113 {
00114 st_secondLanguage = this;
00115 Load();
00116 }
00117
00118 void tLanguage::Load() const
00119 {
00120 if (file.Len() > 1)
00121 {
00122 tLocaleItem::Load( file );
00123 file.Clear();
00124 }
00125 }
00126
00127 void tLanguage::LoadLater( char const * file ) const
00128 {
00129
00130 this->file = file;
00131 }
00132
00133 tLanguage* tLanguage::Find(tString const & name )
00134 {
00135 tLanguage *ret = FindSloppy( name );
00136
00137 if (ret)
00138 return ret;
00139
00140 return tNEW(tLanguage(name));
00141 }
00142
00143 tLanguage* tLanguage::FindStrict(tString const & name )
00144 {
00145 tLanguage *ret = FindSloppy( name );
00146
00147 if (ret)
00148 return ret;
00149
00150 tERR_ERROR_INT("Language " << name << " not found.");
00151 return NULL;
00152 }
00153
00154 tLanguage* tLanguage::FindSloppy(tString const & name )
00155 {
00156 tLanguage *ret = st_languageAnchor;
00157 while (ret)
00158 {
00159 if (ret->name == name)
00160 return ret;
00161 ret = ret->Next();
00162 }
00163
00164 return NULL;
00165 }
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193 tLocaleItem::operator const char *() const
00194 {
00195 static tLanguage * english = tLanguage::FindStrict( tString("British English") );
00196
00197 tString *first = NULL, *second = NULL, *third = NULL, *fourth = NULL;
00198 const tString *ret = NULL;
00199
00200 tLocaleSubItem *run = items;
00201 while (run)
00202 {
00203 if (st_firstLanguage && run->language == st_firstLanguage)
00204 first = &run->translation;
00205
00206 if (st_secondLanguage && run->language == st_secondLanguage)
00207 second = &run->translation;
00208
00209 if (run->language == english)
00210 third = &run->translation;
00211
00212 fourth = &run->translation;
00213 run = run->Next();
00214 }
00215
00216 if (first)
00217 ret = first;
00218 else if (second)
00219 ret = second;
00220 else
00221 {
00222 if (third)
00223 ret = third;
00224 else
00225 {
00226
00227 static bool loadEnglish = true;
00228 if ( loadEnglish )
00229 {
00230 loadEnglish = false;
00231 english->Load();
00232 return *this;
00233 }
00234 }
00235
00236 if (!ret && fourth)
00237 ret = fourth;
00238 if (!ret)
00239 ret = &identifier;
00240 }
00241
00242 if (!istemplate)
00243 return *ret;
00244 else
00245 {
00246 const tString& temp = *ret;
00247 static tString replaced;
00248 replaced.Clear();
00249 for(int i = 0; i < temp.Len(); i++)
00250 {
00251 char c = temp(i);
00252 if (c != '\\')
00253 replaced += c;
00254 else if (i < temp.Len() - 1)
00255 {
00256 c = temp(i+1);
00257 if (c == 'g')
00258 replaced << s_gameName;
00259 else
00260 {
00261 int index = c-'0';
00262 if (index > 0 && index < 10)
00263 replaced << st_TemplateParameters[index];
00264 else if (temp(i+1) == '\\')
00265 replaced << '\n';
00266 }
00267 i++;
00268 }
00269 }
00270
00271 return replaced;
00272 }
00273 }
00274
00275
00276 tLocaleItem::tLocaleItem(const char *id)
00277
00278 :identifier(id), items(NULL), istemplate(false)
00279 {
00280 }
00281
00282 tLocaleItem::~tLocaleItem()
00283 {
00284 while (items)
00285 delete (items);
00286 }
00287
00288
00289 void tLocaleItem::Clear()
00290 {
00291
00292
00293
00294 while (st_languageAnchor)
00295 delete (st_languageAnchor);
00296 }
00297
00298
00299 tLocaleItem& tLocaleItem::Find(const char *nn)
00300 {
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315 static tLocaleItemMap st_localeMap;
00316
00317 tJUST_CONTROLLED_PTR< tLocaleItem > & ret = st_localeMap[ nn ];
00318
00319 if ( !ret )
00320 ret = tNEW(tLocaleItem(nn));
00321
00322 return *ret;
00323 }
00324
00325 static const tString LANGUAGE("language");
00326 static const tString INCLUDE("include");
00327
00328
00329 void tLocaleItem::Load(const char *file, bool complete)
00330 {
00331
00332 {
00333 tString f;
00334
00335 f << "language/" << file;
00336
00337 std::ifstream s;
00338 if ( tDirectories::Data().Open( s, f ) )
00339 {
00340 while (!s.eof() && s.good())
00341 {
00342 tString id;
00343 s >> id;
00344
00345 if (id.Len() <= 1 )
00346 {
00347 continue;
00348 }
00349
00350 if(id[0] == '#')
00351 {
00352 tString dummy;
00353 dummy.ReadLine(s);
00354 continue;
00355 }
00356
00357 if (LANGUAGE == id)
00358 {
00359 tString lang;
00360 lang.ReadLine(s);
00361 currentLanguage = tLanguage::Find(lang);
00362
00363
00364 if (!complete)
00365 {
00366 currentLanguage->LoadLater(file);
00367 return;
00368 }
00369 continue;
00370 }
00371
00372 if (INCLUDE == id)
00373 {
00374 tString inc;
00375 inc.ReadLine(s);
00376 Load(inc, complete);
00377 continue;
00378 }
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391 tLocaleItem &li = Find(id);
00392 tLocaleSubItem *r = li.items;
00393 bool done = false;
00394 while (r && !done)
00395 {
00396 if (r->language == currentLanguage)
00397 {
00398
00399 done = true;
00400 continue;
00401 }
00402 r = r->Next();
00403 }
00404
00405 if (!done)
00406 r = tNEW(tLocaleSubItem)(&li);
00407 else
00408 {
00409
00410
00411
00412 }
00413
00414 tString pre;
00415 pre.ReadLine(s);
00416 r->translation.Clear();
00417
00418 for (size_t i=0; i< pre.Size(); i++)
00419 {
00420 char c = pre(i);
00421 if (c != '\\')
00422 r->translation += c;
00423 else if (i < pre.Size())
00424 switch (pre(i+1))
00425 {
00426 case 'n':
00427 r->translation += '\n';
00428 i++;
00429 break;
00430
00431 case '1':
00432 case '2':
00433 case '3':
00434 case '4':
00435 case '5':
00436 case '6':
00437 case '7':
00438 case '8':
00439 case '9':
00440 case 'g':
00441 r->translation += '\\';
00442 li.istemplate = true;
00443 break;
00444
00445
00446
00447
00448
00449
00450
00451 default:
00452 r->translation += '\\';
00453 break;
00454 }
00455 }
00456
00457 r->language = currentLanguage;
00458
00459
00460
00461 }
00462 }
00463 }
00464
00465
00466
00467
00468
00469 }
00470
00471 class tOutputItemLocale: public tOutputItemBase
00472 {
00473 const tLocaleItem *element;
00474 public:
00475 tOutputItemLocale(tOutput& o, const tLocaleItem& e);
00476 virtual void Print(tString& target) const;
00477 virtual void Clone(tOutput& o) const;
00478 };
00479
00480 class tOutputItemSpace: public tOutputItemBase
00481 {
00482 public:
00483 tOutputItemSpace(tOutput& o);
00484 virtual void Print(tString& target) const;
00485 virtual void Clone(tOutput& o) const;
00486 };
00487
00488
00489 class tOutputItemTemplate: public tOutputItemBase
00490 {
00491 int num;
00492 tString parameter;
00493 public:
00494 tOutputItemTemplate(tOutput& o, int n, const char *p);
00495 virtual void Print(tString& target) const;
00496 virtual void Clone(tOutput& o) const;
00497 };
00498
00499
00500 tOutput::tOutput(): anchor(0){}
00501 tOutput::~tOutput()
00502 {
00503 while (anchor)
00504 delete anchor;
00505 }
00506
00507 void tOutput::Clear()
00508 {
00509 while (anchor)
00510 delete anchor;
00511 }
00512
00513
00514 static void getstring(tString &target, tOutputItemBase *item)
00515 {
00516 if (!item)
00517 return;
00518 getstring(target, item->Next());
00519 item->Print(target);
00520 }
00521
00522
00523
00524
00525
00526
00527
00528
00529
00530
00531
00532
00533
00534
00535
00536
00537
00538
00539
00540
00541
00542
00543
00544
00545
00546
00547
00548
00549
00550 tOutput::operator const char *() const
00551 {
00552 #ifdef DEBUG
00553 #ifndef WIN32
00554 static bool recursion = false;
00555 if (recursion)
00556 {
00557 tERR_ERROR_INT("Locale Recursion!");
00558 }
00559 recursion = true;
00560 #endif
00561 #endif
00562
00563
00564 static const int maxstrings = 5;
00565 static int current = 0;
00566 static tString buffers[maxstrings];
00567 tString & x = buffers[current];
00568 current = ( current + 1 ) % maxstrings;
00569
00570 x.Clear();
00571 getstring(x, anchor);
00572
00573 #ifdef DEBUG
00574 #ifndef WIN32
00575 recursion = false;
00576 #endif
00577 #endif
00578
00579 return x;
00580 }
00581
00582
00583 void tOutput::AddLiteral(const char *x)
00584 {
00585 tNEW(tOutputItem<tString>)(*this, tString(x));
00586 }
00587
00588 void tOutput::AddSpace()
00589 {
00590 tNEW(tOutputItemSpace)(*this);
00591 }
00592
00593 void tOutput::AddLocale(const char *x)
00594 {
00595 tNEW(tOutputItemLocale)(*this, tLocale::Find(x));
00596 }
00597
00598
00599 tOutput & tOutput::SetTemplateParameter(int num, const char *parameter)
00600 {
00601 tNEW(tOutputItemTemplate)(*this, num, parameter);
00602 return *this;
00603 }
00604
00605 tOutput & tOutput::SetTemplateParameter(int num, int parameter)
00606 {
00607 tString p;
00608 p << parameter;
00609 tNEW(tOutputItemTemplate)(*this, num, p);
00610
00611 return *this;
00612 }
00613
00614 tOutput & tOutput::SetTemplateParameter(int num, float parameter)
00615 {
00616 tString p;
00617 p << parameter;
00618 tNEW(tOutputItemTemplate)(*this, num, p);
00619
00620 return *this;
00621 }
00622
00623
00624 tOutput::tOutput(const std::string & x)
00625 :anchor(NULL)
00626 {
00627 tNEW(tOutputItem<tString>)(*this, x);
00628 }
00629
00630 tOutput::tOutput(const tString& x)
00631 :anchor(NULL)
00632 {
00633 tNEW(tOutputItem<tString>)(*this, x);
00634 }
00635
00636 tOutput::tOutput(const char * x)
00637 :anchor(NULL)
00638 {
00639 *this << x;
00640 }
00641
00642
00643 tOutput::tOutput(const tLocaleItem &locale)
00644 :anchor(NULL)
00645 {
00646 tNEW(tOutputItemLocale)(*this, locale);
00647 }
00648
00649
00650 static void copyrec(tOutput &targ, tOutputItemBase *it)
00651 {
00652 if (!it)
00653 return;
00654
00655 copyrec(targ, it->Next());
00656 it->Clone(targ);
00657 }
00658
00659 tOutput::tOutput(const tOutput &o)
00660 :anchor(NULL)
00661 {
00662 copyrec(*this, o.anchor);
00663 }
00664
00665 tOutput& tOutput::operator=(const tOutput &o)
00666 {
00667 Clear();
00668
00669 copyrec(*this, o.anchor);
00670
00671 return *this;
00672 }
00673
00674 void tOutput::Append(const tOutput &o)
00675 {
00676 copyrec(*this, o.anchor);
00677 }
00678
00679
00680 tOutputItemBase::tOutputItemBase(tOutput& o): tListItem<tOutputItemBase>(o.anchor){}
00681
00682 tOutputItemBase::~tOutputItemBase(){}
00683
00684
00685
00686 tOutputItemLocale::tOutputItemLocale(tOutput& o, const tLocaleItem& e)
00687 :tOutputItemBase(o),
00688 element(&e)
00689 {
00690 }
00691
00692 void tOutputItemLocale::Print(tString& target) const
00693 {
00694 target << *element;
00695 }
00696
00697 void tOutputItemLocale::Clone(tOutput& o) const
00698 {
00699 tNEW(tOutputItemLocale)(o, *element);
00700 }
00701
00702
00703 tOutputItemSpace::tOutputItemSpace(tOutput& o)
00704 :tOutputItemBase(o)
00705 {}
00706
00707 void tOutputItemSpace::Print(tString& target) const
00708 {
00709 target << ' ';
00710 }
00711
00712 void tOutputItemSpace::Clone(tOutput& o) const
00713 {
00714 tNEW(tOutputItemSpace)(o);
00715 }
00716
00717
00718 tOutputItemTemplate::tOutputItemTemplate(tOutput& o, int n, const char *p)
00719 :tOutputItemBase(o), num(n), parameter(p)
00720 {}
00721
00722 void tOutputItemTemplate::Print(tString& target) const
00723 {
00724 st_TemplateParameters[num] = parameter;
00725 }
00726
00727 void tOutputItemTemplate::Clone(tOutput& o) const
00728 {
00729 tNEW(tOutputItemTemplate)(o, num, parameter);
00730 }
00731
00732
00733 tOutput& operator << (tOutput &o, char *locale)
00734 {
00735 return operator<<(o, static_cast<const char *>(locale));
00736 }
00737
00738
00739 tOutput& operator << (tOutput &o, const char *locale){
00740 int len = strlen(locale);
00741 if (len == 0)
00742 return o;
00743 if (len == 1 && locale[0] == ' ')
00744 tNEW(tOutputItemSpace)(o);
00745 else if (locale[0] == '$')
00746 tNEW(tOutputItemLocale)(o, tLocale::Find(locale+1));
00747 else
00748 tNEW(tOutputItem<tString>)(o, tString(locale));
00749
00750 return o;
00751 }
00752
00753
00754 std::ostream& operator<< (std::ostream& s, const tOutput& o)
00755 {
00756 return s << tString(o);
00757 }
00758
00759
00760
00761
00762
00763
00764
00765
00766
00767 tString& operator<< (tString& s, const tOutput& o)
00768 {
00769 s << tString(o);
00770 return s;
00771 }
00772
00773
00774
00775
00776 const tLocaleItem& tLocale::Find(const char* id)
00777 {
00778 return tLocaleItem::Find(id);
00779 }
00780
00781 void tLocale::Load(const char* filename)
00782 {
00783 tLocaleItem::Load(filename, false);
00784
00785
00786 s_gameName.Clear();
00787 s_gameName << tOutput("$game_name");
00788 }
00789
00790 void tLocale::Clear()
00791 {
00792 tLocaleItem::Clear();
00793 }
00794
00795
00796
00797
00798
00799
00800
00801
00802
00803 std::ostream& operator<<(std::ostream& s, const tLocaleItem &t)
00804 {
00805 return s << static_cast<const char*>(t);
00806 }
00807
00808 tString& operator<< (tString& s, const tLocaleItem& o)
00809 {
00810 s << static_cast<const char *>(o);
00811 return s;
00812 }