Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

changed ConfigValueContainer to use ConfigFileManager, but there is still an error

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