Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/core2/src/orxonox/core/Language.cc @ 967

Last change on this file since 967 was 931, checked in by landauf, 16 years ago

expanded Executor

File size: 12.5 KB
RevLine 
[704]1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
3 *
4 *
5 *   License notice:
6 *
7 *   This program is free software; you can redistribute it and/or
8 *   modify it under the terms of the GNU General Public License
9 *   as published by the Free Software Foundation; either version 2
10 *   of the License, or (at your option) any later version.
11 *
12 *   This program is distributed in the hope that it will be useful,
13 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
14 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 *   GNU General Public License for more details.
16 *
17 *   You should have received a copy of the GNU General Public License
18 *   along with this program; if not, write to the Free Software
19 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
20 *
21 *   Author:
22 *      Fabian 'x3n' Landau
23 *   Co-authors:
24 *      ...
25 *
26 */
27
[871]28/**
[720]29    @file Language.cc
30    @brief Implementation of the Language and the LanguageEntry class.
31*/
32
[704]33#include <fstream>
34
[708]35#include "CoreIncludes.h"
[704]36#include "Language.h"
37
38namespace orxonox
39{
40    // ###############################
41    // ###      LanguageEntry      ###
42    // ###############################
[720]43    /**
44        @brief Constructor: Sets the default entry.
45        @param fallbackEntry The default entry
46    */
[715]47    LanguageEntry::LanguageEntry(const std::string& fallbackEntry)
[704]48    {
49        RegisterRootObject(LanguageEntry);
50
51        this->fallbackEntry_ = fallbackEntry;
[871]52        this->localisedEntry_ = fallbackEntry; // Set the localisation to the fallback entry, for the case that no translation gets assigned
53        this->bLocalisationSet_ = false;
[704]54    }
55
[720]56    /**
[871]57        @brief Sets the localisation of the entry.
58        @param localisation The localisation
[720]59    */
[871]60    void LanguageEntry::setLocalisation(const std::string& localisation)
[704]61    {
[720]62        // Check if the translation is more than just an empty string
[931]63        if ((localisation != "") && (localisation.size() > 0))
[725]64        {
[871]65            this->localisedEntry_ = localisation;
66            this->bLocalisationSet_ = true;
[725]67        }
[704]68        else
[871]69            this->localisedEntry_ = this->fallbackEntry_;
[704]70    }
71
[720]72    /**
73        @brief Sets the default entry.
74        @param fallbackEntry The default entry
75    */
[715]76    void LanguageEntry::setDefault(const std::string& fallbackEntry)
[704]77    {
[720]78        // If the default entry changes and the translation wasn't set yet, use the new default entry as translation
[871]79        if (!this->bLocalisationSet_)
80            this->localisedEntry_ = fallbackEntry;
[704]81
82        this->fallbackEntry_ = fallbackEntry;
83    }
84
85    // ###############################
86    // ###        Language         ###
87    // ###############################
[720]88    /**
89        @brief Constructor: Reads the default language file and sets some values.
90    */
[704]91    Language::Language()
92    {
93        RegisterRootObject(Language);
[720]94
[704]95        this->defaultLanguage_ = "default";
[871]96        this->defaultLocalisation_ = "ERROR: LANGUAGE ENTRY DOESN'T EXIST!";
[720]97
98        // Read the default language file to create all known LanguageEntry objects
[704]99        this->readDefaultLanguageFile();
100    }
101
[720]102    /**
103        @brief Function to collect the SetConfigValue-macro calls.
104    */
[704]105    void Language::setConfigValues()
106    {
[719]107        SetConfigValue(language_, this->defaultLanguage_).description("The language of the ingame text");
[720]108
109        // Read the translation file after the language was configured
[704]110        this->readTranslatedLanguageFile();
111    }
112
[720]113    /**
114        @brief Returns a reference to the only existing instance of the Language class and calls the setConfigValues() function.
115        @return The reference to the only existing instance
116    */
[704]117    Language& Language::getLanguage()
118    {
[720]119        // Use static variables to avoid conflicts while executing this code before main()
[704]120        static Language theOnlyLanguageObject = Language();
[719]121        static bool bCreatingTheOnlyLanguageObject = true;
122
[720]123        // This workaround is used to set a description of the own config value without creating an infinite recursion
[719]124        if (bCreatingTheOnlyLanguageObject)
125        {
126            bCreatingTheOnlyLanguageObject = false;
127            theOnlyLanguageObject.setConfigValues();
128        }
129
[704]130        return theOnlyLanguageObject;
131    }
132
[720]133    /**
[871]134        @brief Creates a new LanguageEntry with a given label and a given default entry.
135        @param label The label of the entry
[720]136        @param entry The default entry
[725]137        @return The created LanguageEntry object
[720]138    */
[871]139    LanguageEntry* Language::createEntry(const LanguageEntryLabel& label, const std::string& entry)
[704]140    {
[871]141        std::map<std::string, LanguageEntry*>::const_iterator it = this->languageEntries_.find(label);
[725]142
[720]143        // Make sure we don't create a duplicate entry
[728]144        if (it == this->languageEntries_.end())
[704]145        {
146            LanguageEntry* newEntry = new LanguageEntry(entry);
[871]147            newEntry->setLabel(label);
148            this->languageEntries_[label] = newEntry;
[725]149            return newEntry;
[704]150        }
[725]151
[871]152        COUT(2) << "Warning: Language entry " << label << " is duplicate in " << getFileName(this->defaultLanguage_) << "!" << std::endl;
[725]153        return it->second;
[704]154    }
155
[720]156    /**
157        @brief Adds a new LanguageEntry, if it's not already existing.
[871]158        @param label The label of the entry
[720]159        @param entry The default entry
160    */
[871]161    void Language::addEntry(const LanguageEntryLabel& label, const std::string& entry)
[704]162    {
[871]163        COUT(5) << "Language: Called addEntry with\n  label: " << label << "\n  entry: " <<  entry << std::endl;
164        std::map<std::string, LanguageEntry*>::const_iterator it = this->languageEntries_.find(label);
[728]165        if (it == this->languageEntries_.end())
[720]166        {
167            // The entry isn't available yet, meaning it's new, so create it
[871]168            this->createEntry(label, entry);
[720]169        }
[704]170        else if (it->second->getDefault().compare(entry) == 0)
[720]171        {
172            // The entry is available and the default string is the same, so return because everything is fine
[704]173            return;
[720]174        }
[704]175        else
[720]176        {
177            // The defined default entry is not the same as in the default language file - change it to the new entry
[704]178            it->second->setDefault(entry);
[720]179        }
[704]180
[720]181        // Write the default language file because either a new entry was created or an existing entry has changed
[704]182        this->writeDefaultLanguageFile();
[728]183
[704]184    }
185
[720]186    /**
[871]187        @brief Returns the localisation of a given entry.
188        @param label The label of the entry
189        @return The localisation
[720]190    */
[871]191    const std::string& Language::getLocalisation(const LanguageEntryLabel& label) const
[704]192    {
[871]193        std::map<std::string, LanguageEntry*>::const_iterator it = this->languageEntries_.find(label);
[728]194        if (it != this->languageEntries_.end())
[871]195            return it->second->getLocalisation();
[704]196        else
197        {
[720]198            // Uh, oh, an undefined entry was requested: return the default string
[871]199            COUT(2) << "Warning: Language entry \"" << label << "\" not found!" << std::endl;
200            return this->defaultLocalisation_;
[704]201        }
202    }
203
[720]204    /**
205        @brief Creates the name of the language file out of the languages name.
206        @param language The name of the language
207        @return The filename
208    */
[715]209    const std::string Language::getFileName(const std::string& language)
[704]210    {
[715]211        return std::string("translation_" + language + ".lang");
[704]212    }
213
[720]214    /**
215        @brief Reads the default language file and creates a LanguageEntry objects for every entry.
216    */
[704]217    void Language::readDefaultLanguageFile()
218    {
219        COUT(4) << "Read default language file." << std::endl;
220
221        // This creates the file if it's not existing
222        std::ofstream createFile;
223        createFile.open(getFileName(this->defaultLanguage_).c_str(), std::fstream::app);
224        createFile.close();
225
226        // Open the file
227        std::ifstream file;
228        file.open(getFileName(this->defaultLanguage_).c_str(), std::fstream::in);
229
230        if (!file.is_open())
231        {
[871]232            COUT(1) << "An error occurred in Language.cc:" << std::endl;
[704]233            COUT(1) << "Error: Couldn't open file " << getFileName(this->defaultLanguage_) << " to read the default language entries!" << std::endl;
234            return;
235        }
236
237        char line[1024];
238
239        // Iterate through the file and create the LanguageEntries
240        while (file.good() && !file.eof())
241        {
242            file.getline(line, 1024);
[715]243            std::string lineString = std::string(line);
[720]244
245            // Check if the line is empty
[931]246            if ((lineString != "") && (lineString.size() > 0))
[704]247            {
[782]248                unsigned int pos = lineString.find('=');
[720]249
250                // Check if the length is at least 3 and if there's an entry before and behind the =
251                if (pos > 0 && pos < (lineString.size() - 1) && lineString.size() >= 3)
[704]252                    this->createEntry(lineString.substr(0, pos), lineString.substr(pos + 1));
253                else
254                    COUT(2) << "Warning: Invalid language entry \"" << lineString << "\" in " << getFileName(this->defaultLanguage_) << std::endl;
255            }
256        }
257
258        file.close();
259    }
260
[720]261    /**
[871]262        @brief Reads the language file of the configured language and assigns the localisation to the corresponding LanguageEntry object.
[720]263    */
[704]264    void Language::readTranslatedLanguageFile()
265    {
266        COUT(4) << "Read translated language file (" << this->language_ << ")." << std::endl;
267
268        // Open the file
269        std::ifstream file;
270        file.open(getFileName(this->language_).c_str(), std::fstream::in);
271
272        if (!file.is_open())
273        {
[871]274            COUT(1) << "An error occurred in Language.cc:" << std::endl;
[704]275            COUT(1) << "Error: Couldn't open file " << getFileName(this->language_) << " to read the translated language entries!" << std::endl;
276            ResetConfigValue(language_);
277            COUT(3) << "Info: Reset language to " << this->defaultLanguage_ << "." << std::endl;
278            return;
279        }
280
281        char line[1024];
282
283        // Iterate through the file and create the LanguageEntries
284        while (file.good() && !file.eof())
285        {
286            file.getline(line, 1024);
[715]287            std::string lineString = std::string(line);
[720]288
289            // Check if the line is empty
[931]290            if ((lineString != "") && (lineString.size() > 0))
[704]291            {
[782]292                unsigned int pos = lineString.find('=');
[720]293
294                // Check if the length is at least 3 and if there's an entry before and behind the =
295                if (pos > 0 && pos < (lineString.size() - 1) && lineString.size() >= 3)
[704]296                {
[715]297                    std::map<std::string, LanguageEntry*>::const_iterator it = this->languageEntries_.find(lineString.substr(0, pos));
[720]298
299                    // Check if the entry exists
[728]300                    if (it != this->languageEntries_.end())
[871]301                        it->second->setLocalisation(lineString.substr(pos + 1));
[704]302                    else
[871]303                        this->createEntry(lineString.substr(0, pos), this->defaultLocalisation_)->setLocalisation(lineString.substr(pos + 1));
[704]304                }
305                else
306                    COUT(2) << "Warning: Invalid language entry \"" << lineString << "\" in " << getFileName(this->language_) << std::endl;
307            }
308        }
309
310        file.close();
311    }
312
[720]313    /**
314        @brief Writes all default entries to the default language file.
315    */
[704]316    void Language::writeDefaultLanguageFile() const
317    {
[871]318        COUT(4) << "Language: Write default language file." << std::endl;
[704]319
320        // Open the file
321        std::ofstream file;
322        file.open(getFileName(this->defaultLanguage_).c_str(), std::fstream::out);
323
324        if (!file.is_open())
325        {
[871]326            COUT(1) << "An error occurred in Language.cc:" << std::endl;
[704]327            COUT(1) << "Error: Couldn't open file " << getFileName(this->defaultLanguage_) << " to write the default language entries!" << std::endl;
328            return;
329        }
330
331        // Iterate through the list an write the lines into the file
332        for (Iterator<LanguageEntry> it = ObjectList<LanguageEntry>::start(); it; ++it)
333        {
[871]334            file << it->getLabel() << "=" << it->getDefault() << std::endl;
[704]335        }
336
337        file.close();
338    }
339}
Note: See TracBrowser for help on using the repository browser.