lang.cpp

Engine/source/i18n/lang.cpp

More...

Public Functions

bool
ConsoleDocClass(LangTable , "@brief Provides the code necessary <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> handle the low level management " "of the string tables <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">localization\n\n</a>" "One <a href="/coding/class/classlangtable/">LangTable</a> is created <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> each mod, as well as one <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> the C++code. " "<a href="/coding/class/classlangtable/">LangTable</a> is responsible <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> obtaining the correct strings from each " "and relaying it <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the appropriate <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">controls.\n\n</a>" " @see Localization <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> full <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">description\n\n</a>" " @ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Localization\n</a>" )
DefineEngineFunction(CompileLanguage , void , (const char *inputFile, bool createMap) , (false) , "@brief Compiles <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> LSO language file." " <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> createIndex is true)
DefineEngineMethod(LangTable , addLanguage , S32 , (String filename, String languageName) , ("", "") , "(string filename, [string languageName])" "@brief Adds <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> language <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">table\n\n</a>" "@param filename Name and path <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the language <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">file\n</a>" "@param languageName Optional name <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> assign <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> language <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">entry\n\n</a>" "@return True If <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> was successfully found and language <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">created\n</a>" )
DefineEngineMethod(LangTable , getCurrentLanguage , S32 , () , "()" "@brief Get the ID of the current language <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">table\n\n</a>" "@return Numerical ID of the current language table" )
DefineEngineMethod(LangTable , getLangName , const char * , (S32 langId) , "(int language)" "@brief Return the readable name of the language <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">table\n\n</a>" "@param language Numerical ID of the language table <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">access\n\n</a>" "@return <a href="/coding/class/classstring/">String</a> containing the name of the table, <a href="/coding/file/typesx86unix_8h/#typesx86unix_8h_1a070d2ce7b6bb7e5c05602aa8c308d0c4">NULL</a> <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> ID was invalid or name was never specified" )
DefineEngineMethod(LangTable , getNumLang , S32 , () , "()" "@brief Used <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> find out how many languages are in the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">table\n\n</a>" "@return Size of the vector containing the languages, numerical" )
DefineEngineMethod(LangTable , getString , const char * , (U32 id) , "(string filename)" "@brief Grabs <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> string from the specified <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">table\n\n</a>" "If an invalid is passed, the function will attempt <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> " "<a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> grab from the default <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">table\n\n</a>" " @param filename Name of the language table <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">access\n\n</a>" " @return Text from the specified language table, \"\" <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> ID was invalid and default table is not set" )
DefineEngineMethod(LangTable , setCurrentLanguage , void , (S32 langId) , "(int language)" "@brief Sets the current language table <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> grabbing <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">text\n\n</a>" "@param language ID of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">table\n</a>" )
DefineEngineMethod(LangTable , setDefaultLanguage , void , (S32 langId) , "(int language)" "@brief Sets the default language <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">table\n\n</a>" "@param language ID of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">table\n</a>" )
UTF8 *
getCurrentModVarName(UTF8 * buffer, U32 bufsize)
UTF8 *
sanitiseVarName(const UTF8 * varName, UTF8 * buffer, U32 bufsize)

Detailed Description

Public Functions

compiledFileNeedsUpdate(UTF8 * filename)

ConsoleDocClass(LangTable , "@brief Provides the code necessary <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> handle the low level management " "of the string tables <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">localization\n\n</a>" "One <a href="/coding/class/classlangtable/">LangTable</a> is created <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> each mod, as well as one <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> the C++code. " "<a href="/coding/class/classlangtable/">LangTable</a> is responsible <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> obtaining the correct strings from each " "and relaying it <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the appropriate <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">controls.\n\n</a>" " @see Localization <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> full <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">description\n\n</a>" " @ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Localization\n</a>" )

DefineEngineFunction(CompileLanguage , void , (const char *inputFile, bool createMap) , (false) , "@brief Compiles <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> LSO language file." " <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> createIndex is true)

DefineEngineMethod(LangTable , addLanguage , S32 , (String filename, String languageName) , ("", "") , "(string filename, [string languageName])" "@brief Adds <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> language <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">table\n\n</a>" "@param filename Name and path <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the language <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">file\n</a>" "@param languageName Optional name <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> assign <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> language <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">entry\n\n</a>" "@return True If <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> was successfully found and language <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">created\n</a>" )

DefineEngineMethod(LangTable , getCurrentLanguage , S32 , () , "()" "@brief Get the ID of the current language <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">table\n\n</a>" "@return Numerical ID of the current language table" )

DefineEngineMethod(LangTable , getLangName , const char * , (S32 langId) , "(int language)" "@brief Return the readable name of the language <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">table\n\n</a>" "@param language Numerical ID of the language table <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">access\n\n</a>" "@return <a href="/coding/class/classstring/">String</a> containing the name of the table, <a href="/coding/file/typesx86unix_8h/#typesx86unix_8h_1a070d2ce7b6bb7e5c05602aa8c308d0c4">NULL</a> <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> ID was invalid or name was never specified" )

DefineEngineMethod(LangTable , getNumLang , S32 , () , "()" "@brief Used <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> find out how many languages are in the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">table\n\n</a>" "@return Size of the vector containing the languages, numerical" )

DefineEngineMethod(LangTable , getString , const char * , (U32 id) , "(string filename)" "@brief Grabs <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> string from the specified <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">table\n\n</a>" "If an invalid is passed, the function will attempt <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> " "<a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> grab from the default <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">table\n\n</a>" " @param filename Name of the language table <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">access\n\n</a>" " @return Text from the specified language table, \"\" <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> ID was invalid and default table is not set" )

DefineEngineMethod(LangTable , setCurrentLanguage , void , (S32 langId) , "(int language)" "@brief Sets the current language table <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> grabbing <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">text\n\n</a>" "@param language ID of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">table\n</a>" )

DefineEngineMethod(LangTable , setDefaultLanguage , void , (S32 langId) , "(int language)" "@brief Sets the default language <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">table\n\n</a>" "@param language ID of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">table\n</a>" )

getCurrentModLangTable()

getCurrentModVarName(UTF8 * buffer, U32 bufsize)

getModLangTable(const UTF8 * mod)

IMPLEMENT_CONOBJECT(LangTable )

sanitiseVarName(const UTF8 * varName, UTF8 * buffer, U32 bufsize)

  1
  2//-----------------------------------------------------------------------------
  3// Copyright (c) 2012 GarageGames, LLC
  4//
  5// Permission is hereby granted, free of charge, to any person obtaining a copy
  6// of this software and associated documentation files (the "Software"), to
  7// deal in the Software without restriction, including without limitation the
  8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  9// sell copies of the Software, and to permit persons to whom the Software is
 10// furnished to do so, subject to the following conditions:
 11//
 12// The above copyright notice and this permission notice shall be included in
 13// all copies or substantial portions of the Software.
 14//
 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 21// IN THE SOFTWARE.
 22//-----------------------------------------------------------------------------
 23
 24#include "platform/platform.h"
 25#include "core/stream/stream.h"
 26#include "core/stream/fileStream.h"
 27#include "console/console.h"
 28#include "console/consoleInternal.h"
 29#include "console/ast.h"
 30#include "console/compiler.h"
 31#include "core/util/safeDelete.h"
 32#include "console/engineAPI.h"
 33
 34#include "i18n/lang.h"
 35
 36//-----------------------------------------------------------------------------
 37// LangFile Class
 38//-----------------------------------------------------------------------------
 39
 40LangFile::LangFile(const UTF8 *langName /* = NULL */)
 41{
 42   VECTOR_SET_ASSOCIATION( mStringTable );
 43
 44   if(langName)
 45   {
 46      dsize_t langNameLen = dStrlen(langName) + 1;
 47      mLangName = new UTF8 [langNameLen];
 48      dStrcpy(mLangName, langName, langNameLen);
 49   }
 50   else
 51      mLangName = NULL;
 52
 53   mLangFile = NULL;
 54}
 55
 56LangFile::~LangFile()
 57{
 58   // [tom, 3/1/2005] Note: If this is freed in FreeTable() then when the file
 59   // is loaded, the language name will be blitzed.
 60   // Programming after 36 hours without sleep != good.
 61
 62   SAFE_DELETE_ARRAY(mLangName);
 63   SAFE_DELETE_ARRAY(mLangFile);
 64   freeTable();
 65}
 66
 67void LangFile::freeTable()
 68{
 69   U32 i;
 70   for(i = 0;i < mStringTable.size();i++)
 71   {
 72      if(mStringTable[i])
 73         delete [] mStringTable[i];
 74   }
 75   mStringTable.clear();
 76}
 77
 78bool LangFile::load(const UTF8 *filename)
 79{
 80   FileStream * stream;
 81   if((stream = FileStream::createAndOpen( filename, Torque::FS::File::Read )) == NULL)
 82      return false;
 83
 84   bool ret = load(stream);
 85   delete stream;
 86   return ret;
 87}
 88
 89bool LangFile::load(Stream *s)
 90{
 91   freeTable();
 92
 93   while (s->getStatus() == Stream::Ok)
 94   {
 95      char buf[2048];
 96      s->readLongString(2048, buf);
 97      if (s->getStatus() == Stream::Ok)
 98         addString((const UTF8*)buf);
 99   }
100   return true;
101}
102
103bool LangFile::save(const UTF8 *filename)
104{
105   FileStream *fs;
106   
107   if(!isLoaded())
108      return false;
109
110   if((fs = FileStream::createAndOpen( filename, Torque::FS::File::Write )) == NULL)
111      return false;
112
113   bool ret = save(fs);
114   delete fs;
115
116   return ret;
117}
118
119bool LangFile::save(Stream *s)
120{
121   if (!isLoaded())
122      return false;
123
124   U32 i;
125   for (i = 0; i < mStringTable.size(); i++)
126   {
127      s->writeLongString(2048, (char*)mStringTable[i]); //irei1as_ lang
128   }
129   return true;
130}
131
132const UTF8 * LangFile::getString(U32 id)
133{
134   if(id == LANG_INVALID_ID || id >= mStringTable.size())
135      return NULL;
136   return mStringTable[id];
137}
138
139U32 LangFile::addString(const UTF8 *str)
140{
141   dsize_t newstrLen = dStrlen(str) + 1;
142   UTF8 *newstr = new UTF8 [newstrLen];
143   dStrcpy(newstr, str, newstrLen);
144   mStringTable.push_back(newstr);
145   return mStringTable.size() - 1;
146}
147
148void LangFile::setString(U32 id, const UTF8 *str)
149{
150   if(id >= mStringTable.size())
151   {
152      U32 oldsize = mStringTable.size();
153      mStringTable.setSize(id+1);
154      for( U32 i=oldsize; i<mStringTable.size(); ++i )
155      {
156         mStringTable[i] = NULL;
157      }
158   }
159
160   SAFE_DELETE_ARRAY(mStringTable[id]);
161
162   dsize_t newstrLen = dStrlen(str) + 1;
163   UTF8 *newstr = new UTF8 [newstrLen];
164   dStrcpy(newstr, str, newstrLen);
165   mStringTable[id] = newstr;
166}
167
168void LangFile::setLangName(const UTF8 *newName)
169{
170   if(mLangName)
171      delete [] mLangName;
172   
173   dsize_t langNameLen = dStrlen(newName) + 1;
174   mLangName = new UTF8 [langNameLen];
175   dStrcpy(mLangName, newName, langNameLen);
176}
177
178void LangFile::setLangFile(const UTF8 *langFile)
179{
180   if(mLangFile)
181      delete [] mLangFile;
182   
183   dsize_t langFileLen = dStrlen(langFile) + 1;
184   mLangFile = new UTF8 [langFileLen];
185   dStrcpy(mLangFile, langFile, langFileLen);
186}
187
188bool LangFile::activateLanguage()
189{
190   if(isLoaded())
191      return true;
192
193   if(mLangFile)
194   {
195      return load(mLangFile);
196   }
197   return false;
198}
199
200void LangFile::deactivateLanguage()
201{
202   if(mLangFile && isLoaded())
203      freeTable();
204}
205
206//-----------------------------------------------------------------------------
207// LangTable Class
208//-----------------------------------------------------------------------------
209
210IMPLEMENT_CONOBJECT(LangTable);
211
212ConsoleDocClass( LangTable,
213   "@brief Provides the code necessary to handle the low level management "
214   "of the string tables for localization\n\n"
215   
216   "One LangTable is created for each mod, as well as one for the C++ code. "
217   "LangTable is responsible for obtaining the correct strings from each "
218   "and relaying it to the appropriate controls.\n\n"
219
220   "@see Localization for a full description\n\n"
221
222   "@ingroup Localization\n"
223);
224
225LangTable::LangTable() : mDefaultLang(-1), mCurrentLang(-1)
226{
227   VECTOR_SET_ASSOCIATION( mLangTable );
228}
229
230LangTable::~LangTable()
231{
232   S32 i;
233
234   for(i = 0;i < mLangTable.size();i++)
235   {
236      if(mLangTable[i])
237         delete mLangTable[i];
238   }
239   mLangTable.clear();
240}
241
242S32 LangTable::addLanguage(LangFile *lang, const UTF8 *name /* = NULL */)
243{
244   if(name)
245      lang->setLangName(name);
246
247   mLangTable.push_back(lang);
248
249   if(mDefaultLang == -1)
250      setDefaultLanguage(mLangTable.size() - 1);
251   if(mCurrentLang == -1)
252      setCurrentLanguage(mLangTable.size() - 1);
253
254   return mLangTable.size() - 1;
255}
256
257S32 LangTable::addLanguage(const UTF8 *filename, const UTF8 *name /* = NULL */)
258{
259   LangFile * lang = new LangFile(name);
260
261   if(Torque::FS::IsFile(filename))
262   {
263      lang->setLangFile(filename);
264         
265      S32 ret = addLanguage(lang);
266      if(ret >= 0)
267         return ret;
268   }
269   delete lang;
270
271   return -1;
272}
273
274const UTF8 *LangTable::getString(const U32 id) const
275{
276   const UTF8 *s = NULL;
277
278   if(mCurrentLang >= 0)
279      s = mLangTable[mCurrentLang]->getString(id);
280   if(s == NULL && mDefaultLang >= 0 && mDefaultLang != mCurrentLang)
281      s = mLangTable[mDefaultLang]->getString(id);
282
283   return s;
284}
285
286const U32 LangTable::getStringLength(const U32 id) const
287{
288   const UTF8 *s = getString(id);
289   if(s)
290      return dStrlen(s);
291   
292   return 0;
293}
294
295void LangTable::setDefaultLanguage(S32 langid)
296{
297   if(langid >= 0 && langid < mLangTable.size())
298   {
299      if(mLangTable[langid]->activateLanguage())
300      {
301         if(mDefaultLang >= 0)
302            mLangTable[mDefaultLang]->deactivateLanguage();
303         
304         mDefaultLang = langid;
305      }
306   }
307}
308
309void LangTable::setCurrentLanguage(S32 langid)
310{
311   if(langid >= 0 && langid < mLangTable.size())
312   {
313      if(mLangTable[langid]->activateLanguage())
314      {
315         Con::printf("Language %s [%s] activated.", mLangTable[langid]->getLangName(), mLangTable[langid]->getLangFile());
316
317         if(mCurrentLang >= 0 && mCurrentLang != mDefaultLang)
318         {
319            mLangTable[mCurrentLang]->deactivateLanguage();
320            Con::printf("Language %s [%s] deactivated.", mLangTable[mCurrentLang]->getLangName(), mLangTable[mCurrentLang]->getLangFile());
321         }
322         mCurrentLang = langid;
323      }
324   }
325}
326
327//-----------------------------------------------------------------------------
328// LangTable Console Methods
329//-----------------------------------------------------------------------------
330
331
332
333DefineEngineMethod(LangTable, addLanguage, S32, (String filename, String languageName), ("", ""), 
334           "(string filename, [string languageName])"
335           "@brief Adds a language to the table\n\n"
336           "@param filename Name and path to the language file\n"
337           "@param languageName Optional name to assign to the new language entry\n\n"
338           "@return True If file was successfully found and language created\n"
339           )
340{
341   UTF8 scriptFilenameBuffer[1024];
342   
343   Con::expandScriptFilename((char*)scriptFilenameBuffer, sizeof(scriptFilenameBuffer), filename);
344   return object->addLanguage(scriptFilenameBuffer, (const UTF8*)languageName);
345}
346
347DefineEngineMethod(LangTable, getString, const char *, (U32 id), , 
348           "(string filename)"
349           "@brief Grabs a string from the specified table\n\n"
350           "If an invalid is passed, the function will attempt to "
351           "to grab from the default table\n\n"
352           "@param filename Name of the language table to access\n\n"
353           "@return Text from the specified language table, \"\" if ID was invalid and default table is not set")
354{
355   const char * str =   (const char*)object->getString(id);
356   if(str != NULL)
357   {
358      dsize_t retLen = dStrlen(str) + 1;
359      char * ret = Con::getReturnBuffer(retLen);
360      dStrcpy(ret, str, retLen);
361      return ret;
362   }
363   
364   return "";
365}
366
367DefineEngineMethod(LangTable, setDefaultLanguage, void, (S32 langId), , "(int language)"
368           "@brief Sets the default language table\n\n"
369           "@param language ID of the table\n")
370{
371   object->setDefaultLanguage(langId);
372}
373
374DefineEngineMethod(LangTable, setCurrentLanguage, void, (S32 langId), , 
375           "(int language)"
376           "@brief Sets the current language table for grabbing text\n\n"
377           "@param language ID of the table\n")
378{
379   object->setCurrentLanguage(langId);
380}
381
382DefineEngineMethod(LangTable, getCurrentLanguage, S32, (), , "()"
383           "@brief Get the ID of the current language table\n\n"
384           "@return Numerical ID of the current language table")
385{
386   return object->getCurrentLanguage();
387}
388
389DefineEngineMethod(LangTable, getLangName, const char *, (S32 langId), , "(int language)"
390           "@brief Return the readable name of the language table\n\n"
391           "@param language Numerical ID of the language table to access\n\n"
392           "@return String containing the name of the table, NULL if ID was invalid or name was never specified")
393{
394   const char * str = (const char*)object->getLangName(langId);
395   if(str != NULL)
396   {
397      dsize_t retLen = dStrlen(str) + 1;
398      char * ret = Con::getReturnBuffer(retLen);
399      dStrcpy(ret, str, retLen);
400      return ret;
401   }
402   
403   return "";
404}
405
406DefineEngineMethod(LangTable, getNumLang, S32, (), , "()"
407           "@brief Used to find out how many languages are in the table\n\n"
408           "@return Size of the vector containing the languages, numerical")
409{
410   return object->getNumLang();
411}
412
413//-----------------------------------------------------------------------------
414// Support Functions
415//-----------------------------------------------------------------------------
416
417UTF8 *sanitiseVarName(const UTF8 *varName, UTF8 *buffer, U32 bufsize)
418{
419   if(! varName || bufsize < 10) // [tom, 3/3/2005] bufsize check gives room to be lazy below
420   {
421      *buffer = 0;
422      return NULL;
423   }
424   
425   dStrcpy(buffer, (const UTF8*)"I18N::", bufsize);
426   
427   UTF8 *dptr = buffer + 6;
428   const UTF8 *sptr = varName;
429   while(*sptr)
430   {
431      if(dIsalnum(*sptr))
432         *dptr++ = *sptr++;
433      else
434      {
435         if(*(dptr - 1) != '_')
436            *dptr++ = '_';
437         sptr++;
438      }
439      
440      if((dptr - buffer) >= (bufsize - 1))
441         break;
442   }
443   *dptr = 0;
444   
445   return buffer;
446}
447
448UTF8 *getCurrentModVarName(UTF8 *buffer, U32 bufsize)
449{
450   char varName[256];
451   StringTableEntry cbName = CodeBlock::getCurrentCodeBlockName();
452   
453   const UTF8 *slash = (const UTF8*)dStrchr(cbName, '/');
454   if (slash == NULL)
455   {
456      Con::errorf("Illegal CodeBlock path detected in sanitiseVarName() (no mod directory): %s", cbName);
457      return NULL;
458   }
459   
460   dStrncpy(varName, cbName, slash - (const UTF8*)cbName);
461   varName[slash - (const UTF8*)cbName] = 0;
462
463   return sanitiseVarName((UTF8*)varName, buffer, bufsize);
464}
465
466const LangTable *getCurrentModLangTable()
467{
468   UTF8 saneVarName[256];
469   
470   if(getCurrentModVarName(saneVarName, sizeof(saneVarName)))
471   {
472      const LangTable *lt = dynamic_cast<LangTable *>(Sim::findObject(Con::getIntVariable((const char*)saneVarName)));
473      return lt;
474   }
475   return NULL;
476}
477
478const LangTable *getModLangTable(const UTF8 *mod)
479{
480   UTF8 saneVarName[256];
481
482   if(sanitiseVarName(mod, saneVarName, sizeof(saneVarName)))
483   {
484      const LangTable *lt = dynamic_cast<LangTable *>(Sim::findObject(Con::getIntVariable((const char*)saneVarName)));
485      return lt;
486   }
487   return NULL;
488}
489
490//lang_ localization
491bool compiledFileNeedsUpdate(UTF8* filename)
492{
493   Torque::Path filePath = Torque::Path(filename);
494   Torque::FS::FileNodeRef sourceFile = Torque::FS::GetFileNode(filePath);
495   Torque::Path compiledPath = Torque::Path(filePath);
496   compiledPath.setExtension("lso");
497   Torque::FS::FileNodeRef compiledFile = Torque::FS::GetFileNode(compiledPath);
498
499   Torque::Time sourceModifiedTime, compiledModifiedTime;
500
501   if (sourceFile != NULL)
502      sourceModifiedTime = sourceFile->getModifiedTime();
503
504   if (compiledFile != NULL)
505      compiledModifiedTime = compiledFile->getModifiedTime();
506
507   if (sourceModifiedTime > compiledModifiedTime)
508      return true;
509   return false;
510}
511
512DefineEngineFunction(CompileLanguage, void, (const char* inputFile, bool createMap), (false), 
513   "@brief Compiles a LSO language file."
514   " if createIndex is true, will also create languageMap." TORQUE_SCRIPT_EXTENSION " with"
515   " the global variables for each string index."
516   " The input file must follow this example layout:"
517   " TXT_HELLO_WORLD = Hello world in english!")
518{
519   UTF8 scriptFilenameBuffer[1024];
520   Con::expandScriptFilename((char*)scriptFilenameBuffer, sizeof(scriptFilenameBuffer), inputFile);
521
522   if (!Torque::FS::IsFile(scriptFilenameBuffer))
523   {
524      Con::errorf("CompileLanguage - file %s not found", scriptFilenameBuffer);
525      return;
526   }
527
528   FileObject file;
529   if (!file.readMemory(scriptFilenameBuffer))
530   {
531      Con::errorf("CompileLanguage - couldn't read file %s", scriptFilenameBuffer);
532      return;
533   }
534
535   if (compiledFileNeedsUpdate(scriptFilenameBuffer))
536   {
537      FileStream *mapStream = NULL;
538      if (createMap)
539      {
540         Torque::Path mapPath = scriptFilenameBuffer;
541         mapPath.setFileName("languageMap");
542         mapPath.setExtension(TORQUE_SCRIPT_EXTENSION);
543         if ((mapStream = FileStream::createAndOpen(mapPath, Torque::FS::File::Write)) == NULL)
544            Con::errorf("CompileLanguage - failed creating languageMap." TORQUE_SCRIPT_EXTENSION);
545      }
546
547      LangFile langFile;
548      const U8* inLine = NULL;
549      const char* separatorStr = " = ";
550      S32 stringId = 0;
551      while ((inLine = file.readLine())[0] != 0)
552      {
553         char* line;
554         chompUTF8BOM((const char *)inLine, &line);
555         char* div = dStrstr(line, separatorStr);
556         if (div == NULL)
557         {
558            Con::errorf("Separator %s not found in line: %s", separatorStr, line);
559            Con::errorf("Could not determine string name ID");
560            continue;
561         }
562         *div = 0;
563         char* text = div + dStrlen(separatorStr);
564
565         langFile.addString((const UTF8*)text);
566
567         if (mapStream)
568         {
569            String mapLine = String::ToString("$%s = %i;", line, stringId);
570            mapStream->writeLine((const U8*)mapLine.c_str());
571            String commentLine = String::ToString("// %s", text);
572            mapStream->writeLine((const U8*)commentLine.c_str());
573         }
574
575         stringId++;
576      }
577
578      Torque::Path lsoPath = scriptFilenameBuffer;
579      lsoPath.setExtension("lso");
580      langFile.save(lsoPath.getFullPath());
581
582      if (mapStream)
583         delete mapStream;
584   }
585}
586//end lang_ localization
587