Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

documented and commented the Language.h and .cc file

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