Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/libraries/core/Language.cc @ 12018

Last change on this file since 12018 was 11071, checked in by landauf, 9 years ago

merged branch cpp11_v3 back to trunk

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