diff options
-rw-r--r-- | src/base/language.cpp | 111 | ||||
-rw-r--r-- | src/base/language.hpp | 16 | ||||
-rw-r--r-- | test/base/language.cpp | 86 |
3 files changed, 190 insertions, 23 deletions
diff --git a/src/base/language.cpp b/src/base/language.cpp index 74766795..9112c388 100644 --- a/src/base/language.cpp +++ b/src/base/language.cpp @@ -24,8 +24,12 @@ * $Id$ */ +#include <exception> #include <boost/filesystem.hpp> +#include <boost/algorithm/string.hpp> + #include "language.hpp" +#include "utils/file.hpp" // namespace alias for shorter class names namespace fs = boost::filesystem; @@ -34,6 +38,9 @@ namespace usdx { Language* Language::instance = NULL; + log4cxx::LoggerPtr Language::log = + log4cxx::Logger::getLogger("usdx.base.language"); + LanguageNotFound::LanguageNotFound(const std::wstring& language) : BaseException("Language not found!"), language(language) @@ -46,7 +53,7 @@ namespace usdx } - Language::Language(void) + Language::Language(void) : current_translation(NULL), default_translation(NULL) { } @@ -80,15 +87,77 @@ namespace usdx return instance; } + void Language::parse_translation(const std::wstring& line, std::map<std::wstring, std::wstring>& map) + { + size_t found = line.find(L"="); + if (found != std::wstring::npos) { + // copy the substring until '=' and + // transform to upper case + std:: wstring key(found, L' '); + std::transform(line.begin(), line.begin() + found, + key.begin(), toupper); + boost::trim(key); + + std::wstring value(line.substr(found + 1)); + boost::trim_if(value, boost::is_cntrl()); + boost::trim(value); + + LOG4CXX_TRACE(log, L"Found translation from " << + key << L" to " << value); + + map[key] = value; + } + } + void Language::load_language(const std::wstring& language) { - // TODO + fs::wpath source_path = language_dir / (language + L".ini"); + + if (exists(source_path)) { + std::map<std::wstring, std::wstring> *map = + new std::map<std::wstring, std::wstring>(); + + File source(source_path); + + bool started = false; + std::wstring line; + + while (source.stream().good()) { + getline(source.stream(), line); + + if (started) { + if (line[0] == L'[' && line[line.length() - 1] == L']') { + break; + } + + parse_translation(line, *map); + } + else { + if (line.compare(L"[Text]")) { + started = true; + } + } + } + + translations[basename(source_path)] = map; + } + } + + void Language::load_default_language(const std::wstring& default_language) + { + std::map<std::wstring, std::map<std::wstring, std::wstring>*>::iterator it = translations.find(default_language); + if (it != translations.end()) { + LOG4CXX_DEBUG(log, L"Loading default language: " << default_language); + load_language(default_language); + current_translation = default_translation = translations[default_language]; + current_language = default_language; + } } - void Language::init(const fs::wpath& language_dir) + void Language::init(const fs::wpath& language_dir, const std::wstring& default_language) { if (!is_directory(language_dir)) { - return; + throw std::invalid_argument("language_dir should be a directory"); } this->language_dir = language_dir; @@ -97,14 +166,14 @@ namespace usdx fs::wdirectory_iterator end_it; for (fs::wdirectory_iterator it(language_dir); it != end_it; ++it) { - if (!is_directory(it->status())) + if (!is_directory(it->status()) && + extension(it->path()) == L".ini") { - if (extension(it->path()) == L".ini") - { - translations[basename(it->path())] = NULL; - } + translations[basename(it->path())] = NULL; } } + + load_default_language(default_language); } void Language::set_language(const std::wstring& language) @@ -118,28 +187,32 @@ namespace usdx load_language(language); } - current_language_name = std::wstring(language); - current_language = translations[current_language_name]; + current_language = std::wstring(language); + current_translation = translations[current_language]; } const std::wstring& Language::get_language(void) const { - return current_language_name; + return current_language; } const std::wstring& Language::translate(const std::wstring& source) const { - - std::map<std::wstring, std::wstring>::iterator it = current_language->find(source); - if (it != current_language->end()) { - return it->second; + if (current_translation) { + std::map<std::wstring, std::wstring>::iterator it = current_translation->find(source); + if (it != current_translation->end()) { + return it->second; + } } - it = default_language->find(source); - if (it != default_language->end()) { - return it->second; + if (default_translation) { + std::map<std::wstring, std::wstring>::iterator it = default_translation->find(source); + if (it != default_translation->end()) { + return it->second; + } } + return source; } }; diff --git a/src/base/language.hpp b/src/base/language.hpp index 3c496ab1..b3aff24d 100644 --- a/src/base/language.hpp +++ b/src/base/language.hpp @@ -30,6 +30,7 @@ #include <map> #include <string> #include <boost/filesystem.hpp> +#include <log4cxx/logger.h> #include "utils/base_exception.hpp" /** @@ -53,16 +54,22 @@ namespace usdx class Language { private: + static log4cxx::LoggerPtr log; + boost::filesystem::wpath language_dir; - std::map<std::wstring, std::wstring>* current_language; - std::wstring current_language_name; + std::map<std::wstring, std::wstring>* current_translation; + std::wstring current_language; - std::map<std::wstring, std::wstring>* default_language; + std::map<std::wstring, std::wstring>* default_translation; std::map<std::wstring, std::map<std::wstring, std::wstring>*> translations; + void parse_translation(const std::wstring& line, + std::map<std::wstring, std::wstring>& map); + void load_language(const std::wstring& language); + void load_default_language(const std::wstring& language); Language(); @@ -72,7 +79,8 @@ namespace usdx static Language* get_instance(); - void init(const boost::filesystem::wpath& language_dir); + void init(const boost::filesystem::wpath& language_dir, + const std::wstring& default_language = L"English"); void set_language(const std::wstring& language); const std::wstring& get_language(void) const; diff --git a/test/base/language.cpp b/test/base/language.cpp new file mode 100644 index 00000000..0e20c1c3 --- /dev/null +++ b/test/base/language.cpp @@ -0,0 +1,86 @@ +/* + * UltraStar Deluxe - Karaoke Game + * + * UltraStar Deluxe is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + */ + +#include "language.hpp" + +#include <exception> +#include <cppunit/extensions/HelperMacros.h> +#include <log4cxx/logger.h> + +namespace usdx +{ + class LanguageTest : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(LanguageTest); + CPPUNIT_TEST(testInit); + CPPUNIT_TEST_EXCEPTION(testLangDirIsFile, std::invalid_argument); + CPPUNIT_TEST_EXCEPTION(testLangDirNotExists, std::invalid_argument); + CPPUNIT_TEST(testNoInit); + CPPUNIT_TEST_SUITE_END(); + private: + static log4cxx::LoggerPtr log; + public: + void setUp() + { + } + + void tearDown() + { + delete Language::get_instance(); + } + + void testInit() + { + Language::get_instance()->init(L"../game/languages/"); + LOG4CXX_DEBUG(log, L" -" << _(L"SING_SONG_SELECTION_DESC") << "-"); + CPPUNIT_ASSERT(_(L"SING_SONG_SELECTION_DESC") == L"choose your song"); + + Language::get_instance()->set_language(L"German"); + LOG4CXX_DEBUG(log, L" -" << _(L"SING_SONG_SELECTION_DESC") << "-"); + CPPUNIT_ASSERT(_(L"SING_SONG_SELECTION_DESC") == L"Wähle deinen Song"); + } + + void testLangDirIsFile() + { + Language::get_instance()->init(L"../game/languages/English.ini"); + } + + void testLangDirNotExists() + { + Language::get_instance()->init(L"../foo/blub/"); + } + + void testNoInit() + { + LOG4CXX_DEBUG(log, L" -" << _(L"SING_SONG_SELECTION_DESC") << "-"); + CPPUNIT_ASSERT(_(L"SING_SONG_SELECTION_DESC") == L"SING_SONG_SELECTION_DESC"); + } + }; + + log4cxx::LoggerPtr LanguageTest::log = + log4cxx::Logger::getLogger("test.usdx.base.language"); + + CPPUNIT_TEST_SUITE_REGISTRATION(LanguageTest); +}; |