Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/FICN/src/orxonox/core/Language.cc @ 768

Last change on this file since 768 was 729, checked in by rgrieder, 17 years ago
  • fixed multiple template instantiation problem under windows
  • removed some warnings by introducing explicit casts
File size: 12.2 KB
Line 
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
28/*!
29    @file Language.cc
30    @brief Implementation of the Language and the LanguageEntry class.
31*/
32
33#include <fstream>
34
35#include "CoreIncludes.h"
36#include "Language.h"
37
38namespace orxonox
39{
40    // ###############################
41    // ###      LanguageEntry      ###
42    // ###############################
43    /**
44        @brief Constructor: Sets the default entry.
45        @param fallbackEntry The default entry
46    */
47    LanguageEntry::LanguageEntry(const std::string& fallbackEntry)
48    {
49        RegisterRootObject(LanguageEntry);
50
51        this->fallbackEntry_ = fallbackEntry;
52        this->translatedEntry_ = fallbackEntry; // Set the translation to the fallback entry, for the case that no translation gets assigned
53        this->bTranslationSet_ = false;
54    }
55
56    /**
57        @brief Sets the translation of the entry.
58        @param translation The translation
59    */
60    void LanguageEntry::setTranslation(const std::string& translation)
61    {
62        // Check if the translation is more than just an empty string
63        if (translation.compare("") != 0)
64        {
65            this->translatedEntry_ = translation;
66            this->bTranslationSet_ = true;
67        }
68        else
69            this->translatedEntry_ = this->fallbackEntry_;
70    }
71
72    /**
73        @brief Sets the default entry.
74        @param fallbackEntry The default entry
75    */
76    void LanguageEntry::setDefault(const std::string& fallbackEntry)
77    {
78        // If the default entry changes and the translation wasn't set yet, use the new default entry as translation
79        if (!this->bTranslationSet_)
80            this->translatedEntry_ = fallbackEntry;
81
82        this->fallbackEntry_ = fallbackEntry;
83    }
84
85    // ###############################
86    // ###        Language         ###
87    // ###############################
88    /**
89        @brief Constructor: Reads the default language file and sets some values.
90    */
91    Language::Language()
92    {
93        RegisterRootObject(Language);
94
95        this->defaultLanguage_ = "default";
96        this->defaultTranslation_ = "ERROR: LANGUAGE ENTRY DOESN'T EXIST!";
97
98        // Read the default language file to create all known LanguageEntry objects
99        this->readDefaultLanguageFile();
100    }
101
102    /**
103        @brief Function to collect the SetConfigValue-macro calls.
104    */
105    void Language::setConfigValues()
106    {
107        SetConfigValue(language_, this->defaultLanguage_).description("The language of the ingame text");
108
109        // Read the translation file after the language was configured
110        this->readTranslatedLanguageFile();
111    }
112
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    */
117    Language& Language::getLanguage()
118    {
119        // Use static variables to avoid conflicts while executing this code before main()
120        static Language theOnlyLanguageObject = Language();
121        static bool bCreatingTheOnlyLanguageObject = true;
122
123        // This workaround is used to set a description of the own config value without creating an infinite recursion
124        if (bCreatingTheOnlyLanguageObject)
125        {
126            bCreatingTheOnlyLanguageObject = false;
127            theOnlyLanguageObject.setConfigValues();
128        }
129
130        return theOnlyLanguageObject;
131    }
132
133    /**
134        @brief Creates a new LanguageEntry with a given name and a given default entry.
135        @param name The name of the entry
136        @param entry The default entry
137        @return The created LanguageEntry object
138    */
139    LanguageEntry* Language::createEntry(const LanguageEntryName& name, const std::string& entry)
140    {
141        std::map<std::string, LanguageEntry*>::const_iterator it = this->languageEntries_.find(name);
142
143        // Make sure we don't create a duplicate entry
144        if (it == this->languageEntries_.end())
145        {
146            LanguageEntry* newEntry = new LanguageEntry(entry);
147            newEntry->setName(name);
148            this->languageEntries_[name] = newEntry;
149            return newEntry;
150        }
151
152        COUT(2) << "Warning: Language entry " << name << " is duplicate in " << getFileName(this->defaultLanguage_) << "!" << std::endl;
153        return it->second;
154    }
155
156    /**
157        @brief Adds a new LanguageEntry, if it's not already existing.
158        @param name The name of the entry
159        @param entry The default entry
160    */
161    void Language::addEntry(const LanguageEntryName& name, const std::string& entry)
162    {
163        COUT(5) << "Called addEntry with\n  name: " << name << "\n  entry: " <<  entry << std::endl;
164        std::map<std::string, LanguageEntry*>::const_iterator it = this->languageEntries_.find(name);
165        if (it == this->languageEntries_.end())
166        {
167            // The entry isn't available yet, meaning it's new, so create it
168            this->createEntry(name, entry);
169        }
170        else if (it->second->getDefault().compare(entry) == 0)
171        {
172            // The entry is available and the default string is the same, so return because everything is fine
173            return;
174        }
175        else
176        {
177            // The defined default entry is not the same as in the default language file - change it to the new entry
178            it->second->setDefault(entry);
179        }
180
181        // Write the default language file because either a new entry was created or an existing entry has changed
182        this->writeDefaultLanguageFile();
183
184    }
185
186    /**
187        @brief Returns the translation of a given entry.
188        @param name The name of the entry
189        @return The translation
190    */
191    const std::string& Language::getTranslation(const LanguageEntryName& name) const
192    {
193        std::map<std::string, LanguageEntry*>::const_iterator it = this->languageEntries_.find(name);
194        if (it != this->languageEntries_.end())
195            return it->second->getTranslation();
196        else
197        {
198            // Uh, oh, an undefined entry was requested: return the default string
199            COUT(2) << "Error: Language entry \"" << name << "\" not found!" << std::endl;
200            return this->defaultTranslation_;
201        }
202    }
203
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    */
209    const std::string Language::getFileName(const std::string& language)
210    {
211        return std::string("translation_" + language + ".lang");
212    }
213
214    /**
215        @brief Reads the default language file and creates a LanguageEntry objects for every entry.
216    */
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        {
232            COUT(1) << "Error: Couldn't open file " << getFileName(this->defaultLanguage_) << " to read the default language entries!" << std::endl;
233            return;
234        }
235
236        char line[1024];
237
238        // Iterate through the file and create the LanguageEntries
239        while (file.good() && !file.eof())
240        {
241            file.getline(line, 1024);
242            std::string lineString = std::string(line);
243
244            // Check if the line is empty
245            if (lineString.compare("") != 0)
246            {
247                unsigned int pos = (unsigned int)lineString.find('=');
248
249                // Check if the length is at least 3 and if there's an entry before and behind the =
250                if (pos > 0 && pos < (lineString.size() - 1) && lineString.size() >= 3)
251                    this->createEntry(lineString.substr(0, pos), lineString.substr(pos + 1));
252                else
253                    COUT(2) << "Warning: Invalid language entry \"" << lineString << "\" in " << getFileName(this->defaultLanguage_) << std::endl;
254            }
255        }
256
257        file.close();
258    }
259
260    /**
261        @brief Reads the language file of the configured language and assigns the translations to the corresponding LanguageEntry object.
262    */
263    void Language::readTranslatedLanguageFile()
264    {
265        COUT(4) << "Read translated language file (" << this->language_ << ")." << std::endl;
266
267        // Open the file
268        std::ifstream file;
269        file.open(getFileName(this->language_).c_str(), std::fstream::in);
270
271        if (!file.is_open())
272        {
273            COUT(1) << "Error: Couldn't open file " << getFileName(this->language_) << " to read the translated language entries!" << std::endl;
274            ResetConfigValue(language_);
275            COUT(3) << "Info: Reset language to " << this->defaultLanguage_ << "." << std::endl;
276            return;
277        }
278
279        char line[1024];
280
281        // Iterate through the file and create the LanguageEntries
282        while (file.good() && !file.eof())
283        {
284            file.getline(line, 1024);
285            std::string lineString = std::string(line);
286
287            // Check if the line is empty
288            if (lineString.compare("") != 0)
289            {
290                unsigned int pos = (unsigned int)lineString.find('=');
291
292                // Check if the length is at least 3 and if there's an entry before and behind the =
293                if (pos > 0 && pos < (lineString.size() - 1) && lineString.size() >= 3)
294                {
295                    std::map<std::string, LanguageEntry*>::const_iterator it = this->languageEntries_.find(lineString.substr(0, pos));
296
297                    // Check if the entry exists
298                    if (it != this->languageEntries_.end())
299                        it->second->setTranslation(lineString.substr(pos + 1));
300                    else
301                        this->createEntry(lineString.substr(0, pos), this->defaultTranslation_)->setTranslation(lineString.substr(pos + 1));
302                }
303                else
304                    COUT(2) << "Warning: Invalid language entry \"" << lineString << "\" in " << getFileName(this->language_) << std::endl;
305            }
306        }
307
308        file.close();
309    }
310
311    /**
312        @brief Writes all default entries to the default language file.
313    */
314    void Language::writeDefaultLanguageFile() const
315    {
316        COUT(4) << "Write default language file." << std::endl;
317
318        // Open the file
319        std::ofstream file;
320        file.open(getFileName(this->defaultLanguage_).c_str(), std::fstream::out);
321
322        if (!file.is_open())
323        {
324            COUT(1) << "Error: Couldn't open file " << getFileName(this->defaultLanguage_) << " to write the default language entries!" << std::endl;
325            return;
326        }
327
328        // Iterate through the list an write the lines into the file
329        for (Iterator<LanguageEntry> it = ObjectList<LanguageEntry>::start(); it; ++it)
330        {
331            file << it->getName() << "=" << it->getDefault() << std::endl;
332        }
333
334        file.close();
335    }
336}
Note: See TracBrowser for help on using the repository browser.