/* * Modification History * * 2004-October-7 Jason Rohrer * Created. * * 2006-February-19 Jason Rohrer * Fixed an inconsistency in memory management. * * 2008-September-17 Jason Rohrer * Support for setting language data directly. * * 2010-March-21 Jason Rohrer * Fixed crash if default language file not found. * * 2010-May-14 Jason Rohrer * String parameters as const to fix warnings. */ #include "TranslationManager.h" #include #include "minorGems/io/file/File.h" // will be destroyed automatically at program termination TranslationManagerStaticMembers TranslationManager::mStaticMembers; void TranslationManager::setDirectoryName( const char *inName ) { mStaticMembers.setDirectoryAndLanguage( inName, mStaticMembers.mLanguageName ); } char *TranslationManager::getDirectoryName() { return stringDuplicate( mStaticMembers.mDirectoryName ); } char **TranslationManager::getAvailableLanguages( int *outNumLanguages ) { File *languageDirectory = new File( NULL, mStaticMembers.mDirectoryName ); if( languageDirectory->exists() && languageDirectory->isDirectory() ) { int numChildFiles; File **childFiles = languageDirectory->getChildFiles( &numChildFiles ); if( childFiles != NULL ) { SimpleVector *languageNames = new SimpleVector(); for( int i=0; igetFileName(); char *extensionPointer = strstr( name, ".txt" ); if( extensionPointer != NULL ) { // terminate string, cutting off extension extensionPointer[0] = '\0'; languageNames->push_back( stringDuplicate( name ) ); } delete [] name; delete childFiles[i]; } delete [] childFiles; char **returnArray = languageNames->getElementArray(); *outNumLanguages = languageNames->size(); delete languageNames; delete languageDirectory; return returnArray; } } delete languageDirectory; // default, if we didn't return above *outNumLanguages = 0; return new char*[0]; } void TranslationManager::setLanguage( const char *inLanguageName ) { mStaticMembers.setDirectoryAndLanguage( mStaticMembers.mDirectoryName, inLanguageName ); } void TranslationManager::setLanguageData( const char *inData ) { mStaticMembers.setTranslationData( inData ); } const char *TranslationManager::translate( const char *inTranslationKey ) { char *translatedString = NULL; SimpleVector *keys = mStaticMembers.mTranslationKeys; SimpleVector *naturalLanguageStrings = mStaticMembers.mNaturalLanguageStrings; if( keys != NULL ) { int numKeys = keys->size(); for( int i=0; igetElement( i ) ) ) == 0 ) { // keys match translatedString = *( naturalLanguageStrings->getElement( i ) ); } } } if( translatedString == NULL ) { // no translation exists // the translation for this key is the key itself // add it to our translation table char *key = stringDuplicate( inTranslationKey ); char *value = stringDuplicate( inTranslationKey ); keys->push_back( key ); naturalLanguageStrings->push_back( value ); // thus, we return a value from our table, just as if a translation // had existed for this string translatedString = value; } return translatedString; } TranslationManagerStaticMembers::TranslationManagerStaticMembers() : mDirectoryName( NULL ), mLanguageName( NULL ), mTranslationKeys( NULL ), mNaturalLanguageStrings( NULL ) { // default setDirectoryAndLanguage( "languages", "English" ); } TranslationManagerStaticMembers::~TranslationManagerStaticMembers() { if( mDirectoryName != NULL ) { delete [] mDirectoryName; } if( mLanguageName != NULL ) { delete [] mLanguageName; } if( mTranslationKeys != NULL ) { int numKeys = mTranslationKeys->size(); for( int i=0; igetElement( i ) ); } delete mTranslationKeys; } if( mNaturalLanguageStrings != NULL ) { int numKeys = mNaturalLanguageStrings->size(); for( int i=0; igetElement( i ) ); } delete mNaturalLanguageStrings; } } void TranslationManagerStaticMembers::setDirectoryAndLanguage( const char *inDirectoryName, const char *inLanguageName ) { // save temp copies first to allow caller to pass our own members in to us char *tempDirectoryName = stringDuplicate( inDirectoryName ); char *tempLanguageName = stringDuplicate( inLanguageName ); if( mDirectoryName != NULL ) { delete [] mDirectoryName; } if( mLanguageName != NULL ) { delete [] mLanguageName; } mDirectoryName = tempDirectoryName; mLanguageName = tempLanguageName; char dataSet = false; File *directoryFile = new File( NULL, mDirectoryName ); if( directoryFile->exists() && directoryFile->isDirectory() ) { char *languageFileName = autoSprintf( "%s.txt", mLanguageName ); File *languageFile = directoryFile->getChildFile( languageFileName ); delete [] languageFileName; if( languageFile != NULL ) { char *languageData = languageFile->readFileContents(); if( languageData != NULL ) { dataSet = true; setTranslationData( languageData ); delete [] languageData; } delete languageFile; } } delete directoryFile; if( !dataSet ) { // failed to open file... // set blank data to ensure that vectors are created setTranslationData( "" ); } } static inline char *stringSkip( const char *inString, int inNumChars ) { return (char *)( &( inString[ inNumChars ] ) ); } void TranslationManagerStaticMembers::setTranslationData( const char *inData ) { // clear the old translation table if( mTranslationKeys != NULL ) { int numKeys = mTranslationKeys->size(); for( int i=0; igetElement( i ) ); } delete mTranslationKeys; } if( mNaturalLanguageStrings != NULL ) { int numKeys = mNaturalLanguageStrings->size(); for( int i=0; igetElement( i ) ); } delete mNaturalLanguageStrings; } // now read in the translation table mTranslationKeys = new SimpleVector(); mNaturalLanguageStrings = new SimpleVector(); char readError = false; while( ! readError ) { char *key = new char[ 100 ]; int numRead = sscanf( inData, "%99s", key ); if( numRead == 1 ) { inData = stringSkip( inData, strlen( key ) ); // skip the first " int readChar = ' '; while( readChar != '"' && readChar != '\0' ) { readChar = inData[0]; inData = stringSkip( inData, 1 ); } if( readChar != EOF ) { char *naturalLanguageString = new char[1000]; // scan a string of up to 999 characters, stopping // at the first " character numRead = sscanf( inData, "%999[^\"]", naturalLanguageString ); if( numRead == 1 ) { inData = stringSkip( inData, strlen( naturalLanguageString ) ); // trim the key and string and save them mTranslationKeys->push_back( stringDuplicate( key ) ); mNaturalLanguageStrings->push_back( stringDuplicate( naturalLanguageString ) ); } else { readError = true; } delete [] naturalLanguageString; // skip the trailing " readChar = ' '; while( readChar != '"' && readChar != '\0' ) { readChar = inData[0]; inData = stringSkip( inData, 1 ); } } else { readError = true; } } else { readError = true; } delete [] key; } }