Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 9869 was 8858, checked in by landauf, 13 years ago

merged output branch back to trunk.

Changes:

  • you have to include util/Output.h instead of util/Debug.h
  • COUT(x) is now called orxout(level)
  • output levels are now defined by an enum instead of numbers. see util/Output.h for the definition
  • it's possible to use output contexts with orxout(level, context). see util/Output.h for some common contexts. you can define more contexts
  • you must use 'endl' at the end of an output message, '\n' does not flush the message

Output levels:

  • instead of COUT(0) use orxout()
  • instead of COUT(1) use orxout(user_error) or orxout(internal_error)
  • instead of COUT(2) use orxout(user_warning) or orxout(internal_warning)
  • instead of COUT(3) use orxout(user_status/user_info) or orxout(internal_status/internal_info)
  • instead of COUT(4) use orxout(verbose)
  • instead of COUT(5) use orxout(verbose_more)
  • instead of COUT(6) use orxout(verbose_ultra)

Guidelines:

  • user_* levels are for the user, visible in the console and the log-file
  • internal_* levels are for developers, visible in the log-file
  • verbose_* levels are for debugging, only visible if the context of the output is activated

Usage in C++:

  • orxout() << "message" << endl;
  • orxout(level) << "message" << endl;
  • orxout(level, context) << "message" << endl;

Usage in Lua:

  • orxout("message")
  • orxout(orxonox.level.levelname, "message")
  • orxout(orxonox.level.levelname, "context", "message")

Usage in Tcl (and in the in-game-console):

  • orxout levelname message
  • orxout_context levelname context message
  • shortcuts: log message, error message, warning message, status message, info message, debug message
  • Property svn:eol-style set to native
File size: 12.2 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 "Core.h"
40#include "PathConfig.h"
41
42namespace orxonox
43{
44    // ###############################
45    // ###      LanguageEntry      ###
46    // ###############################
47    /**
48        @brief Constructor: Sets the default entry.
49        @param fallbackEntry The default entry
50    */
51    LanguageEntry::LanguageEntry(const std::string& fallbackEntry)
52    {
53        this->fallbackEntry_ = fallbackEntry;
54        this->localisedEntry_ = fallbackEntry; // Set the localisation to the fallback entry, for the case that no translation gets assigned
55        this->bLocalisationSet_ = false;
56    }
57
58    /**
59        @brief Sets the localisation of the entry.
60        @param localisation The localisation
61    */
62    void LanguageEntry::setLocalisation(const std::string& localisation)
63    {
64        // Check if the translation is more than just an empty string
65        if (!localisation.empty())
66        {
67            this->localisedEntry_ = localisation;
68            this->bLocalisationSet_ = true;
69        }
70        else
71            this->localisedEntry_ = this->fallbackEntry_;
72    }
73
74    /**
75        @brief Sets the default entry.
76        @param fallbackEntry The default entry
77    */
78    void LanguageEntry::setDefault(const std::string& fallbackEntry)
79    {
80        // If the default entry changes and the translation wasn't set yet, use the new default entry as translation
81        if (!this->bLocalisationSet_)
82            this->localisedEntry_ = fallbackEntry;
83
84        this->fallbackEntry_ = fallbackEntry;
85    }
86
87    // ###############################
88    // ###        Language         ###
89    // ###############################
90
91    Language* Language::singletonPtr_s = 0;
92
93    /**
94        @brief Constructor: Reads the default language file and sets some values.
95    */
96    Language::Language()
97    {
98        this->defaultLanguage_ = "default";
99        this->defaultLocalisation_ = "ERROR: LANGUAGE ENTRY DOESN'T EXIST!";
100
101        // Read the default language file to create all known LanguageEntry objects
102        this->readDefaultLanguageFile();
103    }
104
105    /**
106        @brief Destructor: Deletes all language entries.
107    */
108    Language::~Language()
109    {
110        for (std::map<std::string, LanguageEntry*>::iterator it = this->languageEntries_.begin(); it != this->languageEntries_.end(); ++it)
111            delete (it->second);
112    }
113
114    /**
115        @brief Creates a new LanguageEntry with a given label and a given default entry.
116        @param label The label of the entry
117        @param entry The default entry
118        @return The created LanguageEntry object
119    */
120    LanguageEntry* Language::createEntry(const LanguageEntryLabel& label, const std::string& entry)
121    {
122        std::map<std::string, LanguageEntry*>::const_iterator it = this->languageEntries_.find(label);
123
124        // Make sure we don't create a duplicate entry
125        if (it == this->languageEntries_.end())
126        {
127            LanguageEntry* newEntry = new LanguageEntry(entry);
128            newEntry->setLabel(label);
129            this->languageEntries_[label] = newEntry;
130            return newEntry;
131        }
132
133        orxout(internal_warning, context::language) << "Language entry " << label << " is duplicate in " << getFilename(this->defaultLanguage_) << '!' << endl;
134        return it->second;
135    }
136
137    /**
138        @brief Adds a new LanguageEntry, if it's not already existing.
139        @param label The label of the entry
140        @param entry The default entry
141    */
142    void Language::addEntry(const LanguageEntryLabel& label, const std::string& entry)
143    {
144        orxout(verbose, context::language) << "Called addEntry with" << '\n' << "label: " << label << '\n' << "entry: " <<  entry << endl;
145        std::map<std::string, LanguageEntry*>::const_iterator it = this->languageEntries_.find(label);
146        if (it == this->languageEntries_.end())
147        {
148            // The entry isn't available yet, meaning it's new, so create it
149            this->createEntry(label, entry);
150        }
151        else if (it->second->getDefault().compare(entry) == 0)
152        {
153            // The entry is available and the default string is the same, so return because everything is fine
154            return;
155        }
156        else
157        {
158            // The defined default entry is not the same as in the default language file - change it to the new entry
159            it->second->setDefault(entry);
160        }
161
162        // Write the default language file because either a new entry was created or an existing entry has changed
163        this->writeDefaultLanguageFile();
164
165    }
166
167    /**
168        @brief Returns the localisation of a given entry.
169        @param label The label of the entry
170        @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.
171        @return The localisation
172    */
173    const std::string& Language::getLocalisation(const LanguageEntryLabel& label, bool bError) const
174    {
175        std::map<std::string, LanguageEntry*>::const_iterator it = this->languageEntries_.find(label);
176        if (it != this->languageEntries_.end())
177            return it->second->getLocalisation();
178        else if (bError)
179        {
180            // Uh, oh, an undefined entry was requested: return the default string
181            orxout(internal_warning, context::language) << "Language entry \"" << label << "\" not found!" << endl;
182            return this->defaultLocalisation_;
183        }
184        else
185            return BLANKSTRING;
186    }
187
188    /**
189        @brief Creates the name of the language file out of the languages name.
190        @param language The name of the language
191        @return The filename
192    */
193    std::string Language::getFilename(const std::string& language)
194    {
195        return std::string("translation_" + language + ".lang");
196    }
197
198    /**
199        @brief Reads the default language file and creates a LanguageEntry objects for every entry.
200    */
201    void Language::readDefaultLanguageFile()
202    {
203        orxout(internal_info, context::language) << "Read default language file." << endl;
204
205        const std::string& filepath = PathConfig::getConfigPathString() + getFilename(this->defaultLanguage_);
206
207        // This creates the file if it's not existing
208        std::ofstream createFile;
209        createFile.open(filepath.c_str(), std::fstream::app);
210        createFile.close();
211
212        // Open the file
213        std::ifstream file;
214        file.open(filepath.c_str(), std::fstream::in);
215
216        if (!file.is_open())
217        {
218            orxout(internal_error, context::language) << "An error occurred in Language.cc:" << endl;
219            orxout(internal_error, context::language) << "Couldn't open file " << getFilename(this->defaultLanguage_) << " to read the default language entries!" << endl;
220            return;
221        }
222
223        // Iterate through the file and create the LanguageEntries
224        while (file.good() && !file.eof())
225        {
226            std::string lineString;
227            std::getline(file, lineString);
228
229            // Check if the line is empty
230            if (!lineString.empty())
231            {
232                size_t pos = lineString.find('=');
233
234                // Check if the length is at least 3 and if there's an entry before and behind the =
235                if (pos > 0 && pos < (lineString.size() - 1) && lineString.size() >= 3)
236                    this->createEntry(lineString.substr(0, pos), lineString.substr(pos + 1));
237                else
238                {
239                    orxout(internal_warning, context::language) << "Invalid language entry \"" << lineString << "\" in " << getFilename(this->defaultLanguage_) << endl;
240                }
241            }
242        }
243
244        file.close();
245    }
246
247    /**
248        @brief Reads the language file of the configured language and assigns the localisation to the corresponding LanguageEntry object.
249    */
250    void Language::readTranslatedLanguageFile()
251    {
252        orxout(internal_info, context::language) << "Read translated language file (" << Core::getInstance().getLanguage() << ")." << endl;
253
254        const std::string& filepath = PathConfig::getConfigPathString() + getFilename(Core::getInstance().getLanguage());
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(Core::getInstance().getLanguage()) << " to read the translated language entries!" << endl;
264            Core::getInstance().resetLanguage();
265            orxout(internal_info, context::language) << "Reset language to " << this->defaultLanguage_ << '.' << endl;
266            return;
267        }
268
269        // Iterate through the file and create the LanguageEntries
270        while (file.good() && !file.eof())
271        {
272            std::string lineString;
273            std::getline(file, lineString);
274
275            // Check if the line is empty
276            if (!lineString.empty())
277            {
278                size_t pos = lineString.find('=');
279
280                // Check if the length is at least 3 and if there's an entry before and behind the =
281                if (pos > 0 && pos < (lineString.size() - 1) && lineString.size() >= 3)
282                {
283                    std::map<std::string, LanguageEntry*>::const_iterator it = this->languageEntries_.find(lineString.substr(0, pos));
284
285                    // Check if the entry exists
286                    if (it != this->languageEntries_.end())
287                        it->second->setLocalisation(lineString.substr(pos + 1));
288                    else
289                        this->createEntry(lineString.substr(0, pos), this->defaultLocalisation_)->setLocalisation(lineString.substr(pos + 1));
290                }
291                else
292                {
293                    orxout(internal_warning, context::language) << "Invalid language entry \"" << lineString << "\" in " << getFilename(Core::getInstance().getLanguage()) << endl;
294                }
295            }
296        }
297
298        file.close();
299    }
300
301    /**
302        @brief Writes all default entries to the default language file.
303    */
304    void Language::writeDefaultLanguageFile() const
305    {
306        orxout(verbose, context::language) << "Write default language file." << endl;
307
308        const std::string& filepath = PathConfig::getConfigPathString() + getFilename(this->defaultLanguage_);
309
310        // Open the file
311        std::ofstream file;
312        file.open(filepath.c_str(), std::fstream::out);
313
314        if (!file.is_open())
315        {
316            orxout(internal_error, context::language) << "An error occurred in Language.cc:" << endl;
317            orxout(internal_error, context::language) << "Couldn't open file " << getFilename(this->defaultLanguage_) << " to write the default language entries!" << endl;
318            return;
319        }
320
321        // Iterate through the list an write the lines into the file
322        for (std::map<std::string, LanguageEntry*>::const_iterator it = this->languageEntries_.begin(); it != this->languageEntries_.end(); ++it)
323        {
324            file << it->second->getLabel() << '=' << it->second->getDefault() << endl;
325        }
326
327        file.close();
328    }
329}
Note: See TracBrowser for help on using the repository browser.