diff --git a/CMakeLists.txt b/CMakeLists.txt index a9a6b5cf4..f077513f2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -261,6 +261,8 @@ endif() if(NOT SERVER_ONLY) add_subdirectory("${PROJECT_SOURCE_DIR}/lib/graphics_utils") include_directories("${PROJECT_SOURCE_DIR}/lib/graphics_utils") + add_subdirectory("${PROJECT_SOURCE_DIR}/lib/tinygettext") + include_directories("${PROJECT_SOURCE_DIR}/lib/tinygettext/include") endif() # Libmcpp @@ -646,7 +648,8 @@ if(NOT SERVER_ONLY) ${HARFBUZZ_LIBRARY} ${SDL2_LIBRARY} ${SHEENBIDI_LIBRARY} - graphics_utils) + graphics_utils + tinygettext) endif() if(UNIX AND NOT APPLE) diff --git a/android/Android.mk b/android/Android.mk index 69bea4958..f418e785f 100644 --- a/android/Android.mk +++ b/android/Android.mk @@ -157,6 +157,16 @@ include $(BUILD_STATIC_LIBRARY) include $(CLEAR_VARS) +# tinygettext +LOCAL_MODULE := tinygettext +LOCAL_PATH := . +LOCAL_CPP_FEATURES += rtti exceptions +LOCAL_SRC_FILES := $(wildcard ../lib/tinygettext/src/*.cpp) +LOCAL_CFLAGS := -I../lib/tinygettext/include +include $(BUILD_STATIC_LIBRARY) +include $(CLEAR_VARS) + + # Irrlicht LOCAL_MODULE := irrlicht LOCAL_PATH := . @@ -242,6 +252,7 @@ LOCAL_CFLAGS := -I../lib/angelscript/include \ -I../lib/graphics_utils \ -I../lib/mcpp \ -I../lib/sdl2/include \ + -I../lib/tinygettext/include \ -I../src \ -Iobj/curl/include \ -Iobj/freetype/include \ @@ -264,7 +275,8 @@ LOCAL_CPPFLAGS := -std=gnu++0x LOCAL_STATIC_LIBRARIES := irrlicht bullet enet ifaddrs angelscript mcpp SDL2 \ vorbisfile vorbis ogg openal curl libssl libcrypto \ - c++_static sheenbidi harfbuzz freetype graphics_utils + c++_static sheenbidi harfbuzz freetype \ + tinygettext graphics_utils include $(BUILD_SHARED_LIBRARY) include $(CLEAR_VARS) diff --git a/lib/tinygettext/CMakeLists.txt b/lib/tinygettext/CMakeLists.txt new file mode 100644 index 000000000..e3e59545e --- /dev/null +++ b/lib/tinygettext/CMakeLists.txt @@ -0,0 +1,95 @@ +# tinygettext - A gettext replacement that works directly on .po files +# Copyright (C) 2006 Christoph Sommer +# +# This software is provided 'as-is', without any express or implied +# warranty. In no event will the authors be held liable for any damages +# arising from the use of this software. +# +# Permission is granted to anyone to use this software for any purpose, +# including commercial applications, and to alter it and redistribute it +# freely, subject to the following restrictions: +# +# 1. The origin of this software must not be misrepresented; you must not +# claim that you wrote the original software. If you use this software +# in a product, an acknowledgement in the product documentation would be +# appreciated but is not required. +# 2. Altered source versions must be plainly marked as such, and must not be +# misrepresented as being the original software. +# 3. This notice may not be removed or altered from any source distribution. + +# +# INSTRUCTIONS: +# ------------- +# +# Create a directory build/ and change to it. Run +# +# cmake .. +# +# This creates a set of Makefiles to build the project. Run +# +# make +# + +cmake_policy(SET CMP0005 NEW) + +## Project name to use as command prefix + +project(tinygettext) +set(VERSION "0.1.0") + +### CMake configuration + +cmake_minimum_required(VERSION 2.4) +if(COMMAND cmake_policy) + CMAKE_POLICY(SET CMP0003 NEW) +endif(COMMAND cmake_policy) + +## Reveal library type choice to users +option(BUILD_SHARED_LIBS "Produce dynamic library instead of static archive" OFF) + +## Add iconv to include directories + +find_package(ICONV REQUIRED) +include_directories(${ICONV_INCLUDE_DIR}) + +## Check iconv_const + +include(CheckCXXSourceCompiles) + +set(CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES} ${ICONV_INCLUDE_DIR}) +check_cxx_source_compiles( + " + #include + // this declaration will fail when there already exists a non const char** version which returns size_t + double iconv(iconv_t cd, char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft); + int main() { return 0; } + " + HAVE_ICONV_CONST +) + +# TODO: better way of config + +if(HAVE_ICONV_CONST) + add_definitions(-DHAVE_ICONV_CONST) +else(HAVE_ICONV_CONST) + remove_definitions(-DHAVE_ICONV_CONST) +endif(HAVE_ICONV_CONST) + +## TinyGetText library compilation + +## build list of source files + +file(GLOB TINYGETTEXT_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} src/*.cpp) +file(GLOB TINYGETTEXT_HEADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} include/tinygettext/*.hpp) + +## define a target for building the library + +add_library(tinygettext ${TINYGETTEXT_SOURCES}) + +## Add tinygettext dir to search path + +include_directories(include/) + +add_definitions(-DVERSION=${VERSION}) + +# EOF # diff --git a/lib/tinygettext/LICENSE.md b/lib/tinygettext/LICENSE.md new file mode 100644 index 000000000..5c8e462b5 --- /dev/null +++ b/lib/tinygettext/LICENSE.md @@ -0,0 +1,34 @@ +tinygettext - A gettext replacement that works directly on .po files + +Copyright (c) 2004-2016 + +* Bastiaan Zapf +* Christoph Sommer +* Georg Kilzer (leper) +* Ingo Ruhnke +* Mathnerd314 +* Matt McCutchen +* Matthias Braun +* Nathan Phillip Brink +* Poren Chiang +* Ravu al Hemio +* Ryan Flegel +* Tim Goya +* Tobias Markus +* Wolfgang Becker + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgement in the product documentation would be + appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. diff --git a/src/tinygettext/dictionary.hpp b/lib/tinygettext/include/tinygettext/dictionary.hpp similarity index 71% rename from src/tinygettext/dictionary.hpp rename to lib/tinygettext/include/tinygettext/dictionary.hpp index 0357036fe..958f4a3f1 100644 --- a/src/tinygettext/dictionary.hpp +++ b/lib/tinygettext/include/tinygettext/dictionary.hpp @@ -1,29 +1,29 @@ -// tinygettext - A gettext replacement that works directly on .po files -// Copyright (C) 2006-2015 Ingo Ruhnke +// tinygettext - A gettext replacement that works directly on .po files +// Copyright (c) 2006 Ingo Ruhnke // -// 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 software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. // -// 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. +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: // -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgement in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. #ifndef HEADER_TINYGETTEXT_DICTIONARY_HPP #define HEADER_TINYGETTEXT_DICTIONARY_HPP -#ifndef SERVER_ONLY - -#include -#include #include -#include +#include +#include + #include "plural_forms.hpp" namespace tinygettext { @@ -34,17 +34,17 @@ namespace tinygettext { class Dictionary { private: - typedef std::map > Entries; + typedef std::unordered_map > Entries; Entries entries; - typedef std::map CtxtEntries; + typedef std::unordered_map CtxtEntries; CtxtEntries ctxt_entries; std::string charset; PluralForms plural_forms; - std::string translate(const Entries& dict, const std::string& msgid); - std::string translate_plural(const Entries& dict, const std::string& msgid, const std::string& msgidplural, int num); + std::string translate(const Entries& dict, const std::string& msgid) const; + std::string translate_plural(const Entries& dict, const std::string& msgid, const std::string& msgidplural, int num) const; bool m_has_fallback; Dictionary* m_fallback; @@ -62,21 +62,21 @@ public: /** Translate the string \a msgid. */ - std::string translate(const std::string& msgid); + std::string translate(const std::string& msgid) const; /** Translate the string \a msgid to its correct plural form, based on the number of items given by \a num. \a msgid_plural is \a msgid in plural form. */ - std::string translate_plural(const std::string& msgid, const std::string& msgidplural, int num); + std::string translate_plural(const std::string& msgid, const std::string& msgidplural, int num) const; /** Translate the string \a msgid that is in context \a msgctx. A context is a way to disambiguate msgids that contain the same letters, but different meaning. For example "exit" might mean to quit doing something or it might refer to a door that leads outside (i.e. 'Ausgang' vs 'Beenden' in german) */ - std::string translate_ctxt(const std::string& msgctxt, const std::string& msgid); + std::string translate_ctxt(const std::string& msgctxt, const std::string& msgid) const; - std::string translate_ctxt_plural(const std::string& msgctxt, const std::string& msgid, const std::string& msgidplural, int num); + std::string translate_ctxt_plural(const std::string& msgctxt, const std::string& msgid, const std::string& msgidplural, int num) const; /** Add a translation from \a msgid to \a msgstr to the dictionary, where \a msgid is the singular form of the message, msgid_plural the @@ -94,10 +94,6 @@ public: void add_translation(const std::string& msgid, const std::string& msgstr); void add_translation(const std::string& msgctxt, const std::string& msgid, const std::string& msgstr); - /** Write all unique character from current dictionary using in a c++ set which is useful for - specific character loading. */ - std::set get_all_used_chars(); - /** Iterate over all messages, Func is of type: void func(const std::string& msgid, const std::vector& msgstrs) */ template @@ -130,6 +126,10 @@ public: } return func; } + +private: + Dictionary(const Dictionary&) = delete; + Dictionary& operator=(const Dictionary&) = delete; }; } // namespace tinygettext @@ -137,4 +137,3 @@ public: #endif /* EOF */ -#endif diff --git a/src/tinygettext/dictionary_manager.hpp b/lib/tinygettext/include/tinygettext/dictionary_manager.hpp similarity index 58% rename from src/tinygettext/dictionary_manager.hpp rename to lib/tinygettext/include/tinygettext/dictionary_manager.hpp index 324c70776..67d8901de 100644 --- a/src/tinygettext/dictionary_manager.hpp +++ b/lib/tinygettext/include/tinygettext/dictionary_manager.hpp @@ -1,30 +1,30 @@ -// tinygettext - A gettext replacement that works directly on .po files -// Copyright (C) 2006-2015 Ingo Ruhnke +// tinygettext - A gettext replacement that works directly on .po files +// Copyright (c) 2006 Ingo Ruhnke // -// 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 software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. // -// 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. +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: // -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgement in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. #ifndef HEADER_TINYGETTEXT_DICTIONARY_MANAGER_HPP #define HEADER_TINYGETTEXT_DICTIONARY_MANAGER_HPP -#ifndef SERVER_ONLY - -#include +#include +#include #include #include -#include -#include +#include #include "dictionary.hpp" #include "language.hpp" @@ -39,11 +39,11 @@ class FileSystem; class DictionaryManager { private: - typedef std::map Dictionaries; + typedef std::unordered_map Dictionaries; Dictionaries dictionaries; - typedef std::vector Search_Path; - Search_Path search_path; + typedef std::deque SearchPath; + SearchPath search_path; std::string charset; bool use_fuzzy; @@ -57,10 +57,6 @@ private: void clear_cache(); -#ifdef DEBUG - unsigned int m_magic_number; -#endif - public: DictionaryManager(const std::string& charset_ = "UTF-8"); ~DictionaryManager(); @@ -85,8 +81,12 @@ public: void set_charset(const std::string& charset); /** Add a directory to the search path for dictionaries, earlier - added directories have higher priority then later added ones */ - void add_directory(const std::string& pathname); + added directories have higher priority then later added ones. + Set @p precedence to true to invert this for a single addition. */ + void add_directory(const std::string& pathname, bool precedence = false); + + /** Remove a directory from the search path */ + void remove_directory(const std::string& pathname); /** Return a set of the available languages in their country code */ std::set get_languages(); @@ -94,7 +94,6 @@ public: void set_filesystem(std::unique_ptr filesystem); std::string convertFilename2Language(const std::string &s_in) const; - private: DictionaryManager (const DictionaryManager&); DictionaryManager& operator= (const DictionaryManager&); @@ -105,4 +104,3 @@ private: #endif /* EOF */ -#endif diff --git a/lib/tinygettext/include/tinygettext/file_system.hpp b/lib/tinygettext/include/tinygettext/file_system.hpp new file mode 100644 index 000000000..654d53550 --- /dev/null +++ b/lib/tinygettext/include/tinygettext/file_system.hpp @@ -0,0 +1,44 @@ +// tinygettext - A gettext replacement that works directly on .po files +// Copyright (c) 2009 Ingo Ruhnke +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgement in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#ifndef HEADER_TINYGETTEXT_FILE_SYSTEM_HPP +#define HEADER_TINYGETTEXT_FILE_SYSTEM_HPP + +#include +#include +#include +#include + +namespace tinygettext { + +class FileSystem +{ +public: + virtual ~FileSystem() {} + + virtual std::vector open_directory(const std::string& pathname) =0; + virtual std::unique_ptr open_file(const std::string& filename) =0; +}; + +} // namespace tinygettext + +#endif + +/* EOF */ + diff --git a/lib/tinygettext/include/tinygettext/iconv.hpp b/lib/tinygettext/include/tinygettext/iconv.hpp new file mode 100644 index 000000000..95df1c607 --- /dev/null +++ b/lib/tinygettext/include/tinygettext/iconv.hpp @@ -0,0 +1,74 @@ +// tinygettext - A gettext replacement that works directly on .po files +// Copyright (c) 2006 Ingo Ruhnke +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgement in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#ifndef HEADER_TINYGETTEXT_ICONV_HPP +#define HEADER_TINYGETTEXT_ICONV_HPP + +#include + +#ifdef HAVE_SDL +# include "SDL.h" + +# define tinygettext_ICONV_CONST const +# define tinygettext_iconv_t SDL_iconv_t +# define tinygettext_iconv SDL_iconv +# define tinygettext_iconv_open SDL_iconv_open +# define tinygettext_iconv_close SDL_iconv_close +#else +# include + +# ifdef HAVE_ICONV_CONST +# define tinygettext_ICONV_CONST ICONV_CONST +# else +# define tinygettext_ICONV_CONST +# endif + +# define tinygettext_iconv_t iconv_t +# define tinygettext_iconv iconv +# define tinygettext_iconv_open iconv_open +# define tinygettext_iconv_close iconv_close +#endif + +namespace tinygettext { + +class IConv +{ +private: + std::string to_charset; + std::string from_charset; + tinygettext_iconv_t cd; + +public: + IConv(); + IConv(const std::string& fromcode, const std::string& tocode); + ~IConv(); + + void set_charsets(const std::string& fromcode, const std::string& tocode); + std::string convert(const std::string& text); + +private: + IConv (const IConv&); + IConv& operator= (const IConv&); +}; + +} // namespace tinygettext + +#endif + +/* EOF */ diff --git a/src/tinygettext/language.hpp b/lib/tinygettext/include/tinygettext/language.hpp similarity index 58% rename from src/tinygettext/language.hpp rename to lib/tinygettext/include/tinygettext/language.hpp index 4adc493d7..205d0db2a 100644 --- a/src/tinygettext/language.hpp +++ b/lib/tinygettext/include/tinygettext/language.hpp @@ -1,26 +1,27 @@ -// tinygettext - A gettext replacement that works directly on .po files -// Copyright (C) 2006-2015 Ingo Ruhnke +// tinygettext - A gettext replacement that works directly on .po files +// Copyright (c) 2006 Ingo Ruhnke // -// 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 software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. // -// 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. +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: // -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgement in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. #ifndef HEADER_TINYGETTEXT_LANGUAGE_HPP #define HEADER_TINYGETTEXT_LANGUAGE_HPP -#ifndef SERVER_ONLY - #include +#include namespace tinygettext { @@ -49,7 +50,7 @@ public: /** Create a language from an environment variable style string (e.g de_DE.UTF-8@modifier) */ static Language from_env(const std::string& env); - /** Compares two Languages, returns 0 on mismatch and a score + /** Compares two Languages, returns 0 on missmatch and a score between 1 and 9 on match, the higher the score the better the match */ static int match(const Language& lhs, const Language& rhs); @@ -57,7 +58,7 @@ public: /** Create an undefined Language object */ Language(); - operator bool() const { return language_spec!=NULL; } + explicit operator bool() const { return language_spec != NULL; } /** Returns the language code (i.e. de, en, fr) */ std::string get_language() const; @@ -76,20 +77,27 @@ public: variable: {language}_{country}@{modifier} */ std::string str() const; - bool operator==(const Language& rhs); - bool operator!=(const Language& rhs); + bool operator==(const Language& rhs) const; + bool operator!=(const Language& rhs) const; friend bool operator<(const Language& lhs, const Language& rhs); + friend struct Language_hash; }; inline bool operator<(const Language& lhs, const Language& rhs) { return lhs.language_spec < rhs.language_spec; } +struct Language_hash +{ + size_t operator()(const Language& v) const + { + return reinterpret_cast(v.language_spec); + } +}; + } // namespace tinygettext #endif /* EOF */ - -#endif diff --git a/lib/tinygettext/include/tinygettext/log.hpp b/lib/tinygettext/include/tinygettext/log.hpp new file mode 100644 index 000000000..cc576bab9 --- /dev/null +++ b/lib/tinygettext/include/tinygettext/log.hpp @@ -0,0 +1,58 @@ +// tinygettext - A gettext replacement that works directly on .po files +// Copyright (c) 2009 Ingo Ruhnke +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgement in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#ifndef HEADER_TINYGETTEXT_LOG_HPP +#define HEADER_TINYGETTEXT_LOG_HPP + +#include + +namespace tinygettext { + +class Log +{ +public: + typedef void (*log_callback_t)(const std::string&); + + static log_callback_t log_info_callback; + static log_callback_t log_warning_callback; + static log_callback_t log_error_callback; + + + static void default_log_callback(const std::string& str); + + static void set_log_info_callback(log_callback_t callback); + static void set_log_warning_callback(log_callback_t callback); + static void set_log_error_callback(log_callback_t callback); + +private: + log_callback_t callback; + std::ostringstream out; + +public: + Log(log_callback_t callback); + ~Log(); + + std::ostream& get(); +}; + +} // namespace tinygettext + +#endif + +/* EOF */ diff --git a/lib/tinygettext/include/tinygettext/log_stream.hpp b/lib/tinygettext/include/tinygettext/log_stream.hpp new file mode 100644 index 000000000..6ca9b3c28 --- /dev/null +++ b/lib/tinygettext/include/tinygettext/log_stream.hpp @@ -0,0 +1,36 @@ +// tinygettext - A gettext replacement that works directly on .po files +// Copyright (c) 2009 Ingo Ruhnke +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgement in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#ifndef HEADER_TINYGETTEXT_LOG_STREAM_HPP +#define HEADER_TINYGETTEXT_LOG_STREAM_HPP + +#include "log.hpp" + +namespace tinygettext { + +// FIXME: very bad to have such things in the API +#define log_error if (!Log::log_error_callback); else (Log(Log::log_error_callback)).get() +#define log_warning if (!Log::log_warning_callback); else (Log(Log::log_warning_callback)).get() +#define log_info if (!Log::log_info_callback); else (Log(Log::log_warning_callback)).get() + +} // namespace tinygettext + +#endif + +/* EOF */ diff --git a/lib/tinygettext/include/tinygettext/plural_forms.hpp b/lib/tinygettext/include/tinygettext/plural_forms.hpp new file mode 100644 index 000000000..7c203a2e4 --- /dev/null +++ b/lib/tinygettext/include/tinygettext/plural_forms.hpp @@ -0,0 +1,63 @@ +// tinygettext - A gettext replacement that works directly on .po files +// Copyright (c) 2006 Ingo Ruhnke +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgement in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#ifndef HEADER_TINYGETTEXT_PLURAL_FORMS_HPP +#define HEADER_TINYGETTEXT_PLURAL_FORMS_HPP + +#include + +namespace tinygettext { + +typedef unsigned int (*PluralFunc)(int n); + +class PluralForms +{ +private: + unsigned int nplural; + PluralFunc plural; + +public: + static PluralForms from_string(const std::string& str); + + PluralForms() + : nplural(0), + plural(0) + {} + + PluralForms(unsigned int nplural_, PluralFunc plural_) + : nplural(nplural_), + plural(plural_) + {} + + unsigned int get_nplural() const { return nplural; } + unsigned int get_plural(int n) const { if (plural) return plural(n); else return 0; } + + bool operator==(const PluralForms& other) const { return nplural == other.nplural && plural == other.plural; } + bool operator!=(const PluralForms& other) const { return !(*this == other); } + + explicit operator bool() const { + return plural != NULL; + } +}; + +} // namespace tinygettext + +#endif + +/* EOF */ diff --git a/src/tinygettext/po_parser.hpp b/lib/tinygettext/include/tinygettext/po_parser.hpp similarity index 53% rename from src/tinygettext/po_parser.hpp rename to lib/tinygettext/include/tinygettext/po_parser.hpp index 5c5c94571..99c03aabc 100644 --- a/src/tinygettext/po_parser.hpp +++ b/lib/tinygettext/include/tinygettext/po_parser.hpp @@ -1,27 +1,28 @@ -// tinygettext - A gettext replacement that works directly on .po files -// Copyright (C) 2009-2015 Ingo Ruhnke +// tinygettext - A gettext replacement that works directly on .po files +// Copyright (c) 2009 Ingo Ruhnke // -// 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 software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. // -// 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. +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: // -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgement in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. #ifndef HEADER_TINYGETTEXT_PO_PARSER_HPP #define HEADER_TINYGETTEXT_PO_PARSER_HPP -#ifndef SERVER_ONLY - #include -#include + +#include "iconv.hpp" namespace tinygettext { @@ -42,7 +43,7 @@ private: int line_number; std::string current_line; - //IConv conv; + IConv conv; POParser(const std::string& filename, std::istream& in_, Dictionary& dict_, bool use_fuzzy = true); ~POParser(); @@ -51,10 +52,10 @@ private: void parse(); void next_line(); std::string get_string(unsigned int skip); - void get_string_line(std::ostringstream& str,unsigned int skip); + void get_string_line(std::ostringstream& str, size_t skip); bool is_empty_line(); bool prefix(const char* ); -#ifdef WIN32 +#ifdef _WIN32 void error(const std::string& msg); #else void error(const std::string& msg) __attribute__((__noreturn__)); @@ -78,4 +79,3 @@ private: #endif /* EOF */ -#endif diff --git a/lib/tinygettext/include/tinygettext/tinygettext.hpp b/lib/tinygettext/include/tinygettext/tinygettext.hpp new file mode 100644 index 000000000..5553bc2b3 --- /dev/null +++ b/lib/tinygettext/include/tinygettext/tinygettext.hpp @@ -0,0 +1,29 @@ +// tinygettext - A gettext replacement that works directly on .po files +// Copyright (c) 2006 Ingo Ruhnke +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgement in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#ifndef HEADER_TINYGETTEXT_TINYGETTEXT_HPP +#define HEADER_TINYGETTEXT_TINYGETTEXT_HPP + +#include "dictionary.hpp" +#include "dictionary_manager.hpp" +#include "language.hpp" + +#endif + +/* EOF */ diff --git a/lib/tinygettext/include/tinygettext/unix_file_system.hpp b/lib/tinygettext/include/tinygettext/unix_file_system.hpp new file mode 100644 index 000000000..d4fef9cd1 --- /dev/null +++ b/lib/tinygettext/include/tinygettext/unix_file_system.hpp @@ -0,0 +1,40 @@ +// tinygettext - A gettext replacement that works directly on .po files +// Copyright (c) 2009 Ingo Ruhnke +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgement in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#ifndef HEADER_TINYGETTEXT_UNIX_FILE_SYSTEM_HPP +#define HEADER_TINYGETTEXT_UNIX_FILE_SYSTEM_HPP + +#include "file_system.hpp" + +namespace tinygettext { + +class UnixFileSystem : public FileSystem +{ +public: + UnixFileSystem(); + + std::vector open_directory(const std::string& pathname); + std::unique_ptr open_file(const std::string& filename); +}; + +} // namespace tinygettext + +#endif + +/* EOF */ diff --git a/lib/tinygettext/src/dictionary.cpp b/lib/tinygettext/src/dictionary.cpp new file mode 100644 index 000000000..b61d21584 --- /dev/null +++ b/lib/tinygettext/src/dictionary.cpp @@ -0,0 +1,246 @@ +// tinygettext - A gettext replacement that works directly on .po files +// Copyright (c) 2006 Ingo Ruhnke +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgement in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#include + +#include "tinygettext/log_stream.hpp" +#include "tinygettext/dictionary.hpp" + +namespace tinygettext { + +namespace { + +std::ostream& operator<<(std::ostream& o, const std::vector& v) +{ + for (std::vector::const_iterator it = v.begin(); it != v.end(); ++it) + { + if (it != v.begin()) + o << ", "; + o << "'" << *it << "'"; + } + return o; +} + +} // namespace + +Dictionary::Dictionary(const std::string& charset_) : + entries(), + ctxt_entries(), + charset(charset_), + plural_forms(), + m_has_fallback(false), + m_fallback() +{ +} + +Dictionary::~Dictionary() +{ +} + +std::string +Dictionary::get_charset() const +{ + return charset; +} + +void +Dictionary::set_plural_forms(const PluralForms& plural_forms_) +{ + plural_forms = plural_forms_; +} + +PluralForms +Dictionary::get_plural_forms() const +{ + return plural_forms; +} + +std::string +Dictionary::translate_plural(const std::string& msgid, const std::string& msgid_plural, int num) const +{ + return translate_plural(entries, msgid, msgid_plural, num); +} + +std::string +Dictionary::translate_plural(const Entries& dict, const std::string& msgid, const std::string& msgid_plural, int count) const +{ + Entries::const_iterator it = dict.find(msgid); + if (it != dict.end()) + { + unsigned int n = plural_forms.get_plural(count); + const std::vector& msgstrs = it->second; + if (n >= msgstrs.size()) + { + log_error << "Plural translation not available (and not set to empty): '" << msgid << "'" << std::endl; + log_error << "Missing plural form: " << n << std::endl; + return msgid; + } + + if (!msgstrs[n].empty()) + return msgstrs[n]; + else + if (count == 1) // default to english rules + return msgid; + else + return msgid_plural; + } + else + { + log_info << "Couldn't translate: " << msgid << std::endl; + log_info << "Candidates: " << std::endl; + for (it = dict.begin(); it != dict.end(); ++it) + log_info << "'" << it->first << "'" << std::endl; + + if (count == 1) // default to english rules + return msgid; + else + return msgid_plural; + } +} + +std::string +Dictionary::translate(const std::string& msgid) const +{ + return translate(entries, msgid); +} + +std::string +Dictionary::translate(const Entries& dict, const std::string& msgid) const +{ + Entries::const_iterator i = dict.find(msgid); + if (i != dict.end() && !i->second.empty()) + { + return i->second[0]; + } + else + { + log_info << "Couldn't translate: " << msgid << std::endl; + + if (m_has_fallback) return m_fallback->translate(msgid); + else return msgid; + } +} + +std::string +Dictionary::translate_ctxt(const std::string& msgctxt, const std::string& msgid) const +{ + CtxtEntries::const_iterator i = ctxt_entries.find(msgctxt); + if (i != ctxt_entries.end()) + { + return translate(i->second, msgid); + } + else + { + log_info << "Couldn't translate: " << msgid << std::endl; + return msgid; + } +} + +std::string +Dictionary::translate_ctxt_plural(const std::string& msgctxt, + const std::string& msgid, const std::string& msgidplural, int num) const +{ + CtxtEntries::const_iterator i = ctxt_entries.find(msgctxt); + if (i != ctxt_entries.end()) + { + return translate_plural(i->second, msgid, msgidplural, num); + } + else + { + log_info << "Couldn't translate: " << msgid << std::endl; + if (num != 1) // default to english + return msgidplural; + else + return msgid; + } +} + +void +Dictionary::add_translation(const std::string& msgid, const std::string& msgid_plural, + const std::vector& msgstrs) +{ + std::vector& vec = entries[msgid]; + if (vec.empty()) + { + vec = msgstrs; + } + else if (vec != msgstrs) + { + log_warning << "collision in add_translation: '" + << msgid << "', '" << msgid_plural + << "' -> [" << vec << "] vs [" << msgstrs << "]" << std::endl; + vec = msgstrs; + } +} + +void +Dictionary::add_translation(const std::string& msgid, const std::string& msgstr) +{ + std::vector& vec = entries[msgid]; + if (vec.empty()) + { + vec.push_back(msgstr); + } + else if (vec[0] != msgstr) + { + log_warning << "collision in add_translation: '" + << msgid << "' -> '" << msgstr << "' vs '" << vec[0] << "'" << std::endl; + vec[0] = msgstr; + } +} + +void +Dictionary::add_translation(const std::string& msgctxt, + const std::string& msgid, const std::string& msgid_plural, + const std::vector& msgstrs) +{ + std::vector& vec = ctxt_entries[msgctxt][msgid]; + if (vec.empty()) + { + vec = msgstrs; + } + else if (vec != msgstrs) + { + log_warning << "collision in add_translation: '" + << msgctxt << "', '" << msgid << "', '" << msgid_plural + << "' -> [" << vec << "] vs [" << msgstrs << "]" << std::endl; + vec = msgstrs; + } +} + +void +Dictionary::add_translation(const std::string& msgctxt, const std::string& msgid, const std::string& msgstr) +{ + std::vector& vec = ctxt_entries[msgctxt][msgid]; + if (vec.empty()) + { + vec.push_back(msgstr); + } + else if (vec[0] != msgstr) + { + log_warning << "collision in add_translation: '" + << msgctxt << "', '" << msgid + << "' -> '" << vec[0] << "' vs '" << msgstr << "'" << std::endl; + vec[0] = msgstr; + } +} + +} // namespace tinygettext + +/* EOF */ diff --git a/src/tinygettext/dictionary_manager.cpp b/lib/tinygettext/src/dictionary_manager.cpp similarity index 67% rename from src/tinygettext/dictionary_manager.cpp rename to lib/tinygettext/src/dictionary_manager.cpp index 3b43c4b38..0b2fbd1df 100644 --- a/src/tinygettext/dictionary_manager.cpp +++ b/lib/tinygettext/src/dictionary_manager.cpp @@ -1,25 +1,23 @@ -// tinygettext - A gettext replacement that works directly on .po files -// Copyright (C) 2006-2015 Ingo Ruhnke +// tinygettext - A gettext replacement that works directly on .po files +// Copyright (c) 2006 Ingo Ruhnke // -// 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 software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. // -// 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. +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: // -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgement in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. -#ifndef SERVER_ONLY - -#include "dictionary_manager.hpp" - -#include "utils/log.hpp" +#include "tinygettext/dictionary_manager.hpp" #include #include @@ -28,12 +26,13 @@ #include #include -#include "po_parser.hpp" -#include "stk_file_system.hpp" +#include "tinygettext/log_stream.hpp" +#include "tinygettext/po_parser.hpp" +#include "tinygettext/unix_file_system.hpp" namespace tinygettext { -static bool has_suffix(const std::string& lhs, const std::string &rhs) +static bool has_suffix(const std::string& lhs, const std::string& rhs) { if (lhs.length() < rhs.length()) return false; @@ -49,19 +48,12 @@ DictionaryManager::DictionaryManager(const std::string& charset_) : current_language(), current_dict(0), empty_dict(), - filesystem(new StkFileSystem) + filesystem(new UnixFileSystem) { -#ifdef DEBUG - m_magic_number = 0xD1C70471; -#endif } DictionaryManager::~DictionaryManager() { -#ifdef DEBUG - assert(m_magic_number == 0xD1C70471); - m_magic_number = 0xDEADBEEF; -#endif for(Dictionaries::iterator i = dictionaries.begin(); i != dictionaries.end(); ++i) { delete i->second; @@ -120,14 +112,14 @@ DictionaryManager::get_dictionary(const Language& language) dictionaries[language] = dict; - for (Search_Path::reverse_iterator p = search_path.rbegin(); p != search_path.rend(); ++p) + for (SearchPath::reverse_iterator p = search_path.rbegin(); p != search_path.rend(); ++p) { std::vector files = filesystem->open_directory(*p); - std::string best_filename = ""; + std::string best_filename; int best_score = 0; - for(std::vector::iterator filename = files.begin(); filename != files.end(); filename++) + for (std::vector::iterator filename = files.begin(); filename != files.end(); ++filename) { // check if filename matches requested language if (has_suffix(*filename, ".po")) @@ -137,8 +129,7 @@ DictionaryManager::get_dictionary(const Language& language) if (!po_language) { - Log::warn("tinygettext", "%s: warning: ignoring, unknown language", - filename->c_str()); + log_warning << *filename << ": warning: ignoring, unknown language" << std::endl; } else { @@ -161,8 +152,7 @@ DictionaryManager::get_dictionary(const Language& language) std::unique_ptr in = filesystem->open_file(pofile); if (!in.get()) { - Log::error("tinygettext", "error: failure opening: '%s'.", - pofile.c_str()); + log_error << "error: failure opening: " << pofile << std::endl; } else { @@ -171,15 +161,15 @@ DictionaryManager::get_dictionary(const Language& language) } catch(std::exception& e) { - Log::error("tinygettext", "error: failure parsing: '%s'.", pofile.c_str()); - Log::error("tinygettext", "%s", e.what()); + log_error << "error: failure parsing: " << pofile << std::endl; + log_error << e.what() << "" << std::endl; } } } - if (language.get_country().size() > 0) + if (!language.get_country().empty()) { - Log::info("tinygettext", "Adding language fallback %s\n", language.get_language().c_str()); + // printf("Adding language fallback %s\n", language.get_language().c_str()); dict->addFallback( &get_dictionary(Language::from_spec(language.get_language())) ); } return *dict; @@ -191,7 +181,7 @@ DictionaryManager::get_languages() { std::set languages; - for (Search_Path::iterator p = search_path.begin(); p != search_path.end(); ++p) + for (SearchPath::iterator p = search_path.begin(); p != search_path.end(); ++p) { std::vector files = filesystem->open_directory(*p); @@ -199,12 +189,7 @@ DictionaryManager::get_languages() { if (has_suffix(*file, ".po")) { - Language po_language = Language::from_env(file->substr(0, file->size()-3)); - - if (po_language) - { - languages.insert(po_language); - } + languages.insert(Language::from_env(file->substr(0, file->size()-3))); } } } @@ -248,10 +233,24 @@ DictionaryManager::get_use_fuzzy() const } void -DictionaryManager::add_directory(const std::string& pathname) +DictionaryManager::add_directory(const std::string& pathname, bool precedence /* = false */) { clear_cache(); // adding directories invalidates cache - search_path.push_back(pathname); + if (precedence) + search_path.push_front(pathname); + else + search_path.push_back(pathname); +} + +void +DictionaryManager::remove_directory(const std::string& pathname) +{ + SearchPath::iterator it = std::find(search_path.begin(), search_path.end(), pathname); + if (it != search_path.end()) + { + clear_cache(); // removing directories invalidates cache + search_path.erase(it); + } } void @@ -286,7 +285,7 @@ std::string DictionaryManager::convertFilename2Language(const std::string &s_in) // of filename. if(!::isalpha(s[i])) break; - s[i]=::toupper(s[i]); + s[i] = static_cast(::toupper(s[i])); } else underscore_found = s[i]=='_'; @@ -299,4 +298,3 @@ std::string DictionaryManager::convertFilename2Language(const std::string &s_in) /* EOF */ -#endif diff --git a/lib/tinygettext/src/iconv.cpp b/lib/tinygettext/src/iconv.cpp new file mode 100644 index 000000000..19b11d17f --- /dev/null +++ b/lib/tinygettext/src/iconv.cpp @@ -0,0 +1,150 @@ +// tinygettext - A gettext replacement that works directly on .po files +// Copyright (c) 2009 Ingo Ruhnke +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgement in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#include +#include +#include +#include +#include +#include +#include + +#include "tinygettext/iconv.hpp" +#include "tinygettext/log_stream.hpp" + +namespace tinygettext { + +#ifndef tinygettext_ICONV_CONST +# define tinygettext_ICONV_CONST +#endif + +IConv::IConv() + : to_charset(), + from_charset(), + cd(0) +{} + +IConv::IConv(const std::string& from_charset_, const std::string& to_charset_) + : to_charset(), + from_charset(), + cd(0) +{ + set_charsets(from_charset_, to_charset_); +} + +IConv::~IConv() +{ + if (cd) + tinygettext_iconv_close(cd); +} + +void +IConv::set_charsets(const std::string& from_charset_, const std::string& to_charset_) +{ + if (cd) + tinygettext_iconv_close(cd); + + from_charset = from_charset_; + to_charset = to_charset_; + + for(std::string::iterator i = to_charset.begin(); i != to_charset.end(); ++i) + *i = static_cast(toupper(*i)); + + for(std::string::iterator i = from_charset.begin(); i != from_charset.end(); ++i) + *i = static_cast(toupper(*i)); + + if (to_charset == from_charset) + { + cd = 0; + } + else + { + cd = tinygettext_iconv_open(to_charset.c_str(), from_charset.c_str()); + if (cd == reinterpret_cast(-1)) + { + if(errno == EINVAL) + { + std::ostringstream str; + str << "IConv construction failed: conversion from '" << from_charset + << "' to '" << to_charset << "' not available"; + throw std::runtime_error(str.str()); + } + else + { + std::ostringstream str; + str << "IConv: construction failed: " << strerror(errno); + throw std::runtime_error(str.str()); + } + } + } +} + +/// Convert a string from encoding to another. +std::string +IConv::convert(const std::string& text) +{ + if (!cd) + { + return text; + } + else + { + size_t inbytesleft = text.size(); + size_t outbytesleft = 4*inbytesleft; // Worst case scenario: ASCII -> UTF-32? + + // We try to avoid to much copying around, so we write directly into + // a std::string + tinygettext_ICONV_CONST char* inbuf = const_cast(&text[0]); + std::string result(outbytesleft, 'X'); + char* outbuf = &result[0]; + + // Try to convert the text. + size_t ret = tinygettext_iconv(cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft); + if (ret == static_cast(-1)) + { + if (errno == EILSEQ || errno == EINVAL) + { // invalid multibyte sequence + tinygettext_iconv(cd, NULL, NULL, NULL, NULL); // reset state + + // FIXME: Could try to skip the invalid byte and continue + log_error << "error: tinygettext:iconv: invalid multibyte sequence in: \"" << text << "\"" << std::endl; + } + else if (errno == E2BIG) + { // output buffer to small + assert(false && "tinygettext/iconv.cpp: E2BIG: This should never be reached"); + } + else if (errno == EBADF) + { + assert(false && "tinygettext/iconv.cpp: EBADF: This should never be reached"); + } + else + { + assert(false && "tinygettext/iconv.cpp: : This should never be reached"); + } + } + + result.resize(4*text.size() - outbytesleft); + + return result; + } +} + +} // namespace tinygettext + +/* EOF */ diff --git a/src/tinygettext/language.cpp b/lib/tinygettext/src/language.cpp similarity index 91% rename from src/tinygettext/language.cpp rename to lib/tinygettext/src/language.cpp index 086ca3d10..a05c9b0a2 100644 --- a/src/tinygettext/language.cpp +++ b/lib/tinygettext/src/language.cpp @@ -1,28 +1,26 @@ -// tinygettext - A gettext replacement that works directly on .po files -// Copyright (C) 2006-2015 Ingo Ruhnke +// tinygettext - A gettext replacement that works directly on .po files +// Copyright (c) 2006 Ingo Ruhnke // -// 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 software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. // -// 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. +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: // -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgement in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. -#ifndef SERVER_ONLY +#include "tinygettext/language.hpp" -#include "language.hpp" - -#include "utils/string_utils.hpp" - -#include #include +#include #include #include @@ -76,6 +74,7 @@ static const LanguageSpec languages[] = { { "ca", "ES", 0, "Catalan (Spain)" }, { "ca", 0, "valencia", "Catalan (valencia)" }, { "ca", 0, 0, "Catalan" }, + { "cmn", 0, 0, "Mandarin" }, { "co", 0, 0, "Corsican" }, { "cs", 0, 0, "Czech" }, { "cs", "CZ", 0, "Czech (Czech Republic)" }, @@ -166,7 +165,6 @@ static const LanguageSpec languages[] = { { "iu", 0, 0, "Inuktitut" }, { "ja", 0, 0, "Japanese" }, { "ja", "JP", 0, "Japanese (Japan)" }, - { "jbo",0, 0, "Lojban" }, { "ka", 0, 0, "Georgian" }, { "kk", 0, 0, "Kazakh" }, { "kl", 0, 0, "Kalaallisut" }, @@ -175,7 +173,6 @@ static const LanguageSpec languages[] = { { "kn", 0, 0, "Kannada" }, { "ko", 0, 0, "Korean" }, { "ko", "KR", 0, "Korean (Korea)" }, - { "krl",0, 0, "Karelian" }, { "ku", 0, 0, "Kurdish" }, { "kw", 0, 0, "Cornish" }, { "ky", 0, 0, "Kirghiz" }, @@ -185,13 +182,13 @@ static const LanguageSpec languages[] = { { "lt", "LT", 0, "Lithuanian (Lithuania)" }, { "lv", 0, 0, "Latvian" }, { "lv", "LV", 0, "Latvian (Latvia)" }, + { "jbo", 0, 0, "Lojban" }, { "mg", 0, 0, "Malagasy" }, { "mi", 0, 0, "Maori" }, { "mk", 0, 0, "Macedonian" }, { "mk", "MK", 0, "Macedonian (Macedonia)" }, { "ml", 0, 0, "Malayalam" }, { "mn", 0, 0, "Mongolian" }, - { "mn", "MN", 0, "Mongolian (Mongolia)" }, { "mr", 0, 0, "Marathi" }, { "ms", 0, 0, "Malay" }, { "ms", "MY", 0, "Malay (Malaysia)" }, @@ -206,19 +203,16 @@ static const LanguageSpec languages[] = { { "nl", "NL", 0, "Dutch (Netherlands)" }, { "nn", 0, 0, "Norwegian Nynorsk" }, { "nn", "NO", 0, "Norwegian Nynorsk (Norway)" }, - // DEPRECATED - //{ "no", 0, 0, "Norwegian" }, - //{ "no", "NO", 0, "Norwegian (Norway)" }, - //{ "no", "NY", 0, "Norwegian (NY)" }, + { "no", 0, 0, "Norwegian" }, + { "no", "NO", 0, "Norwegian (Norway)" }, + { "no", "NY", 0, "Norwegian (NY)" }, { "nr", 0, 0, "Ndebele, South" }, { "oc", 0, 0, "Occitan post 1500" }, { "om", 0, 0, "Oromo" }, { "or", 0, 0, "Oriya" }, - { "os", 0, 0, "Ossetian" }, { "pa", 0, 0, "Punjabi" }, { "pl", 0, 0, "Polish" }, { "pl", "PL", 0, "Polish (Poland)" }, - { "pms",0, 0, "Piedmontese" }, { "ps", 0, 0, "Pashto" }, { "pt", 0, 0, "Portuguese" }, { "pt", "BR", 0, "Portuguese (Brazil)" }, @@ -231,8 +225,6 @@ static const LanguageSpec languages[] = { { "ru", "RU", 0, "Russian (Russia" }, { "rw", 0, 0, "Kinyarwanda" }, { "sa", 0, 0, "Sanskrit" }, - { "sc", 0, 0, "Sardinian" }, - { "sco",0, 0, "Scots" }, { "sd", 0, 0, "Sindhi" }, { "se", 0, 0, "Sami" }, { "se", "NO", 0, "Sami (Norway)" }, @@ -258,7 +250,6 @@ static const LanguageSpec languages[] = { { "sv", "SE", 0, "Swedish (Sweden)" }, { "sv", "SV", 0, "Swedish (El Salvador)" }, { "sw", 0, 0, "Swahili" }, - { "szl", 0, 0, "Silesian" }, { "ta", 0, 0, "Tamil" }, { "te", 0, 0, "Telugu" }, { "tg", 0, 0, "Tajik" }, @@ -295,10 +286,12 @@ static const LanguageSpec languages[] = { }; //*} +namespace { + std::string resolve_language_alias(const std::string& name) { - typedef std::map Aliases; + typedef std::unordered_map Aliases; static Aliases language_aliases; if (language_aliases.empty()) { @@ -373,10 +366,13 @@ resolve_language_alias(const std::string& name) } } +} // namespace + Language Language::from_spec(const std::string& language, const std::string& country, const std::string& modifier) { - static std::map > language_map; + typedef std::unordered_map > LanguageSpecMap; + static LanguageSpecMap language_map; if (language_map.empty()) { // Init language_map @@ -384,7 +380,7 @@ Language::from_spec(const std::string& language, const std::string& country, con language_map[languages[i].language].push_back(&languages[i]); } - std::map >::iterator i = language_map.find(language); + LanguageSpecMap::iterator i = language_map.find(language); if (i != language_map.end()) { std::vector& lst = i->second; @@ -441,9 +437,7 @@ Language::from_env(const std::string& env) if (ln != std::string::npos && ln+1 < env.size()) // _ { - country = env.substr(ln+1, (std::min(dt, at) == std::string::npos) - ? std::string::npos : std::min(dt, at) - (ln+1)); - country = StringUtils::toUpperCase(country); + country = env.substr(ln+1, (std::min(dt, at) == std::string::npos) ? std::string::npos : std::min(dt, at) - (ln+1)); } if (dt != std::string::npos && dt+1 < env.size()) // . @@ -568,13 +562,13 @@ Language::str() const } bool -Language::operator==(const Language& rhs) +Language::operator==(const Language& rhs) const { return language_spec == rhs.language_spec; } bool -Language::operator!=(const Language& rhs) +Language::operator!=(const Language& rhs) const { return language_spec != rhs.language_spec; } @@ -582,5 +576,3 @@ Language::operator!=(const Language& rhs) } // namespace tinygettext /* EOF */ - -#endif diff --git a/lib/tinygettext/src/log.cpp b/lib/tinygettext/src/log.cpp new file mode 100644 index 000000000..531deb1e8 --- /dev/null +++ b/lib/tinygettext/src/log.cpp @@ -0,0 +1,72 @@ +// tinygettext - A gettext replacement that works directly on .po files +// Copyright (c) 2009 Ingo Ruhnke +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgement in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#include +#include "tinygettext/log.hpp" + +namespace tinygettext { + +Log::log_callback_t Log::log_info_callback = &Log::default_log_callback; +Log::log_callback_t Log::log_warning_callback = &Log::default_log_callback; +Log::log_callback_t Log::log_error_callback = &Log::default_log_callback; + +void +Log::default_log_callback(const std::string& str) +{ + std::cerr << "tinygettext: " << str; +} + +void +Log::set_log_info_callback(log_callback_t callback) +{ + log_info_callback = callback; +} + +void +Log::set_log_warning_callback(log_callback_t callback) +{ + log_warning_callback = callback; +} + +void +Log::set_log_error_callback(log_callback_t callback) +{ + log_error_callback = callback; +} + +Log::Log(log_callback_t callback_) : + callback(callback_), + out() +{ +} + +Log::~Log() +{ + callback(out.str()); +} + +std::ostream& +Log::get() +{ + return out; +} + +} // namespace tinygettext + +/* EOF */ diff --git a/lib/tinygettext/src/plural_forms.cpp b/lib/tinygettext/src/plural_forms.cpp new file mode 100644 index 000000000..9bfba363c --- /dev/null +++ b/lib/tinygettext/src/plural_forms.cpp @@ -0,0 +1,98 @@ +// tinygettext - A gettext replacement that works directly on .po files +// Copyright (c) 2006 Ingo Ruhnke +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgement in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#include "tinygettext/plural_forms.hpp" + +#include + +namespace tinygettext { + +namespace { + +/** + * Plural functions are used to select a string that matches a given + * count. \a n is the count and the return value is the string index + * used in the .po file, for example: + * + * msgstr[0] = "You got %d error"; + * msgstr[1] = "You got %d errors"; + * ^-- return value of plural function + */ +unsigned int plural1(int ) { return 0; } +unsigned int plural2_1(int n) { return (n != 1); } +unsigned int plural2_2(int n) { return (n > 1); } +unsigned int plural2_mk(int n) { return n==1 || n%10==1 ? 0 : 1; } +unsigned int plural3_lv(int n) { return static_cast(n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2); } +unsigned int plural3_ga(int n) { return static_cast(n==1 ? 0 : n==2 ? 1 : 2); } +unsigned int plural3_lt(int n) { return static_cast(n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2); } +unsigned int plural3_1(int n) { return static_cast(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2); } +unsigned int plural3_sk(int n) { return static_cast( (n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2 ); } +unsigned int plural3_pl(int n) { return static_cast(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2); } +unsigned int plural3_sl(int n) { return static_cast(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3); } +unsigned int plural4_gd(int n) { return static_cast( n==1 || n==11) ? 0 : (n==2 || n==12) ? 1 : (n > 2 && n < 20) ? 2 : 3; } +unsigned int plural6_ar(int n) { return static_cast( n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 ? 4 : 5); } + +} // namespace + +PluralForms +PluralForms::from_string(const std::string& str) +{ + typedef std::unordered_map PluralFormsMap; + static PluralFormsMap plural_forms; + + if (plural_forms.empty()) + { + // Note that the plural forms here shouldn't contain any spaces + plural_forms["Plural-Forms:nplurals=1;plural=0;"] = PluralForms(1, plural1); + plural_forms["Plural-Forms:nplurals=2;plural=(n!=1);"] = PluralForms(2, plural2_1); + plural_forms["Plural-Forms:nplurals=2;plural=n!=1;"] = PluralForms(2, plural2_1); + plural_forms["Plural-Forms:nplurals=2;plural=(n>1);"] = PluralForms(2, plural2_2); + plural_forms["Plural-Forms:nplurals=2;plural=n==1||n%10==1?0:1;"] = PluralForms(2, plural2_mk); + plural_forms["Plural-Forms:nplurals=3;plural=n%10==1&&n%100!=11?0:n!=0?1:2);"] = PluralForms(2, plural3_lv); + plural_forms["Plural-Forms:nplurals=3;plural=n==1?0:n==2?1:2;"] = PluralForms(3, plural3_ga); + plural_forms["Plural-Forms:nplurals=3;plural=(n%10==1&&n%100!=11?0:n%10>=2&&(n%100<10||n%100>=20)?1:2);"] = PluralForms(3, plural3_lt); + plural_forms["Plural-Forms:nplurals=3;plural=(n%10==1&&n%100!=11?0:n%10>=2&&n%10<=4&&(n%100<10||n%100>=20)?1:2);"] = PluralForms(3, plural3_1); + plural_forms["Plural-Forms:nplurals=3;plural=(n==1)?0:(n>=2&&n<=4)?1:2;"] = PluralForms(3, plural3_sk); + plural_forms["Plural-Forms:nplurals=3;plural=(n==1?0:n%10>=2&&n%10<=4&&(n%100<10||n%100>=20)?1:2);"] = PluralForms(3, plural3_pl); + plural_forms["Plural-Forms:nplurals=3;plural=(n%100==1?0:n%100==2?1:n%100==3||n%100==4?2:3);"] = PluralForms(3, plural3_sl); + + plural_forms["Plural-Forms:nplurals=4;plural=(n==1||n==11)?0:(n==2||n==12)?1:(n>2&&n<20)?2:3;"]=PluralForms(4, plural4_gd); + plural_forms["Plural-Forms:nplurals=6;plural=n==0?0:n==1?1:n==2?2:n%100>=3&&n%100<=10?3:n%100>=11?4:5"]=PluralForms(6, plural6_ar); + } + + // Remove spaces from string before lookup + std::string space_less_str; + for(std::string::size_type i = 0; i < str.size(); ++i) + if (!isspace(str[i])) + space_less_str += str[i]; + + PluralFormsMap::const_iterator it= plural_forms.find(space_less_str); + if (it != plural_forms.end()) + { + return it->second; + } + else + { + return PluralForms(); + } +} + +} // namespace tinygettext + +/* EOF */ diff --git a/src/tinygettext/po_parser.cpp b/lib/tinygettext/src/po_parser.cpp similarity index 70% rename from src/tinygettext/po_parser.cpp rename to lib/tinygettext/src/po_parser.cpp index a9a678b29..c2893ab51 100644 --- a/src/tinygettext/po_parser.cpp +++ b/lib/tinygettext/src/po_parser.cpp @@ -1,38 +1,37 @@ -// tinygettext - A gettext replacement that works directly on .po files -// Copyright (C) 2009-2015 Ingo Ruhnke +// tinygettext - A gettext replacement that works directly on .po files +// Copyright (c) 2009 Ingo Ruhnke // -// 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 software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. // -// 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. +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: // -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgement in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. -#ifndef SERVER_ONLY - -#include "po_parser.hpp" +#include "tinygettext/po_parser.hpp" #include #include #include #include #include -#include -#include +#include #include -#include "language.hpp" -#include "dictionary.hpp" -#include "plural_forms.hpp" - -#include "utils/log.hpp" +#include "tinygettext/language.hpp" +#include "tinygettext/log_stream.hpp" +#include "tinygettext/iconv.hpp" +#include "tinygettext/dictionary.hpp" +#include "tinygettext/plural_forms.hpp" namespace tinygettext { @@ -56,8 +55,8 @@ POParser::POParser(const std::string& filename_, std::istream& in_, Dictionary& eof(false), big5(false), line_number(0), - current_line()//, - //conv() + current_line(), + conv() { } @@ -68,15 +67,14 @@ POParser::~POParser() void POParser::warning(const std::string& msg) { - Log::warn("tinygettext", "%s line %d %s: \"%s\"", - filename.c_str(), line_number, msg.c_str(), current_line.c_str()); + log_warning << filename << ":" << line_number << ": warning: " << msg << ": " << current_line << std::endl; + //log_warning << "Line: " << current_line << std::endl; } void POParser::error(const std::string& msg) { - Log::error("tinygettext", "%s line %d %s: \"%s\"", - filename.c_str(), line_number, msg.c_str(), current_line.c_str()); + log_error << filename << ":" << line_number << ": error: " << msg << ": " << current_line << std::endl; // Try to recover from an error by searching for start of another entry do @@ -95,7 +93,7 @@ POParser::next_line() } void -POParser::get_string_line(std::ostringstream& out,unsigned int skip) +POParser::get_string_line(std::ostringstream& out, size_t skip) { if (skip+1 >= static_cast(current_line.size())) error("unexpected end of line"); @@ -177,7 +175,7 @@ POParser::get_string(unsigned int skip) else { if (pedantic) - warning("keyword and string must be separated by a single space"); + warning("keyword and string must be seperated by a single space"); for(;;) { @@ -211,7 +209,7 @@ next: if (pedantic) warning("leading whitespace before string"); - get_string_line(out, (unsigned int) i); + get_string_line(out, i); goto next; } else if (isspace(current_line[i])) @@ -227,7 +225,7 @@ next: return out.str(); } -static bool has_prefix(const std::string& lhs, const std::string &rhs) +static bool has_prefix(const std::string& lhs, const std::string& rhs) { if (lhs.length() < rhs.length()) return false; @@ -249,7 +247,7 @@ POParser::parse_header(const std::string& header) if (has_prefix(line, "Content-Type:")) { // from_charset = line.substr(len); - unsigned int len = (unsigned int) strlen("Content-Type: text/plain; charset="); + size_t len = strlen("Content-Type: text/plain; charset="); if (line.compare(0, len, "Content-Type: text/plain; charset=") == 0) { from_charset = line.substr(len); @@ -279,7 +277,7 @@ POParser::parse_header(const std::string& header) { if (dict.get_plural_forms() != plural_forms) { - warning("Plural-Forms mismatch between .po file and dictionary"); + warning("Plural-Forms missmatch between .po file and dictionary"); } } } @@ -298,7 +296,7 @@ POParser::parse_header(const std::string& header) big5 = true; } - //conv.set_charsets(from_charset, dict.get_charset()); + conv.set_charsets(from_charset, dict.get_charset()); } bool @@ -340,9 +338,9 @@ POParser::parse() // skip UTF-8 intro that some text editors produce // see http://en.wikipedia.org/wiki/Byte-order_mark if (current_line.size() >= 3 && - current_line[0] == static_cast(0xef) && - current_line[1] == static_cast(0xbb) && - current_line[2] == static_cast(0xbf)) + current_line[0] == static_cast(0xef) && + current_line[1] == static_cast(0xbb) && + current_line[2] == static_cast(0xbf)) { current_line = current_line.substr(3); } @@ -386,7 +384,7 @@ POParser::parse() { std::string msgid_plural = get_string(12); std::vector msgstr_num; - bool saw_nonempty_msgstr = false; + bool saw_nonempty_msgstr = false; next: if (is_empty_line()) @@ -399,15 +397,15 @@ POParser::parse() isdigit(current_line[7]) && current_line[8] == ']') { unsigned int number = static_cast(current_line[7] - '0'); - std::string msgstr = get_string(9); + std::string msgstr = get_string(9); - if(!msgstr.empty()) - saw_nonempty_msgstr = true; + if(!msgstr.empty()) + saw_nonempty_msgstr = true; if (number >= msgstr_num.size()) msgstr_num.resize(number+1); - msgstr_num[number] = msgstr; //conv.convert(msgstr); + msgstr_num[number] = conv.convert(msgstr); goto next; } else @@ -418,38 +416,38 @@ POParser::parse() if (!is_empty_line()) error("expected 'msgstr[N]' or empty line"); - if (saw_nonempty_msgstr) - { - if (use_fuzzy || !fuzzy) + if (saw_nonempty_msgstr) + { + if (use_fuzzy || !fuzzy) { - if (!dict.get_plural_forms()) - { - warning("msgstr[N] seen, but no Plural-Forms given"); - } - else - { - if (msgstr_num.size() != dict.get_plural_forms().get_nplural()) - { - warning("msgstr[N] count doesn't match Plural-Forms.nplural"); - } - } + if (!dict.get_plural_forms()) + { + warning("msgstr[N] seen, but no Plural-Forms given"); + } + else + { + if (msgstr_num.size() != dict.get_plural_forms().get_nplural()) + { + warning("msgstr[N] count doesn't match Plural-Forms.nplural"); + } + } - if (has_msgctxt) - dict.add_translation(msgctxt, msgid, msgid_plural, msgstr_num); - else - dict.add_translation(msgid, msgid_plural, msgstr_num); - } + if (has_msgctxt) + dict.add_translation(msgctxt, msgid, msgid_plural, msgstr_num); + else + dict.add_translation(msgid, msgid_plural, msgstr_num); + } - if (0) - { - std::cout << (fuzzy?"fuzzy":"not-fuzzy") << std::endl; - std::cout << "msgid \"" << msgid << "\"" << std::endl; - std::cout << "msgid_plural \"" << msgid_plural << "\"" << std::endl; - for(std::vector::size_type i = 0; i < msgstr_num.size(); ++i) - std::cout << "msgstr[" << i << "] \"" << msgstr_num[i] /*conv.convert(msgstr_num[i])*/ << "\"" << std::endl; - std::cout << std::endl; - } - } + if ((false)) + { + std::cout << (fuzzy?"fuzzy":"not-fuzzy") << std::endl; + std::cout << "msgid \"" << msgid << "\"" << std::endl; + std::cout << "msgid_plural \"" << msgid_plural << "\"" << std::endl; + for(std::vector::size_type i = 0; i < msgstr_num.size(); ++i) + std::cout << "msgstr[" << i << "] \"" << conv.convert(msgstr_num[i]) << "\"" << std::endl; + std::cout << std::endl; + } + } } else if (prefix("msgstr")) { @@ -464,16 +462,16 @@ POParser::parse() if (use_fuzzy || !fuzzy) { if (has_msgctxt) - dict.add_translation(msgctxt, msgid, msgstr /*conv.convert(msgstr)*/); + dict.add_translation(msgctxt, msgid, conv.convert(msgstr)); else - dict.add_translation(msgid, msgstr /*conv.convert(msgstr)*/); + dict.add_translation(msgid, conv.convert(msgstr)); } - if (0) + if ((false)) { std::cout << (fuzzy?"fuzzy":"not-fuzzy") << std::endl; std::cout << "msgid \"" << msgid << "\"" << std::endl; - std::cout << "msgstr \"" << msgstr /*conv.convert(msgstr)*/ << "\"" << std::endl; + std::cout << "msgstr \"" << conv.convert(msgstr) << "\"" << std::endl; std::cout << std::endl; } } @@ -498,4 +496,3 @@ POParser::parse() } // namespace tinygettext /* EOF */ -#endif diff --git a/lib/tinygettext/src/tinygettext.cpp b/lib/tinygettext/src/tinygettext.cpp new file mode 100644 index 000000000..0a126d75f --- /dev/null +++ b/lib/tinygettext/src/tinygettext.cpp @@ -0,0 +1,24 @@ +// tinygettext - A gettext replacement that works directly on .po files +// Copyright (c) 2006 Ingo Ruhnke +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgement in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +namespace tinygettext { + +} // namespace tinygettext + +/* EOF */ diff --git a/lib/tinygettext/src/unix_file_system.cpp b/lib/tinygettext/src/unix_file_system.cpp new file mode 100644 index 000000000..43fc00f96 --- /dev/null +++ b/lib/tinygettext/src/unix_file_system.cpp @@ -0,0 +1,66 @@ +// tinygettext - A gettext replacement that works directly on .po files +// Copyright (c) 2009 Ingo Ruhnke +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgement in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#include "tinygettext/unix_file_system.hpp" + +#include +#include +#include +#include +#include + +namespace tinygettext { + +UnixFileSystem::UnixFileSystem() +{ +} + +std::vector +UnixFileSystem::open_directory(const std::string& pathname) +{ + DIR* dir = opendir(pathname.c_str()); + if (!dir) + { + // FIXME: error handling + return std::vector(); + } + else + { + std::vector files; + + struct dirent* dp; + while((dp = readdir(dir)) != 0) + { + files.push_back(dp->d_name); + } + closedir(dir); + + return files; + } +} + +std::unique_ptr +UnixFileSystem::open_file(const std::string& filename) +{ + return std::unique_ptr(new std::ifstream(filename.c_str())); +} + +} // namespace tinygettext + +/* EOF */ diff --git a/src/tinygettext/dictionary.cpp b/src/tinygettext/dictionary.cpp deleted file mode 100644 index c608444d1..000000000 --- a/src/tinygettext/dictionary.cpp +++ /dev/null @@ -1,251 +0,0 @@ -// tinygettext - A gettext replacement that works directly on .po files -// Copyright (C) 2006-2015 Ingo Ruhnke -// -// 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; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -#ifndef SERVER_ONLY - -#include -#include "dictionary.hpp" - -#include "utils/log.hpp" -#include "utils/string_utils.hpp" -#include "utils/translation.hpp" - -namespace tinygettext { - -Dictionary::Dictionary(const std::string& charset_) : - entries(), - ctxt_entries(), - charset(charset_), - plural_forms() -{ - m_has_fallback = false; -} - -Dictionary::~Dictionary() -{ -} - -std::string -Dictionary::get_charset() const -{ - return charset; -} - -void -Dictionary::set_plural_forms(const PluralForms& plural_forms_) -{ - plural_forms = plural_forms_; -} - -PluralForms -Dictionary::get_plural_forms() const -{ - return plural_forms; -} - -std::string -Dictionary::translate_plural(const std::string& msgid, const std::string& msgid_plural, int num) -{ - return translate_plural(entries, msgid, msgid_plural, num); -} - -std::string -Dictionary::translate_plural(const Entries& dict, const std::string& msgid, const std::string& msgid_plural, int count) -{ - Entries::const_iterator i = dict.find(msgid); - - if (i != dict.end()) - { - const std::vector& msgstrs = i->second; - unsigned int n = 0; - n = plural_forms.get_plural(count); - assert(/*n >= 0 &&*/ n < msgstrs.size()); - - if (!msgstrs[n].empty()) - return msgstrs[n]; - else - if (count == 1) // default to english rules - return msgid; - else - return msgid_plural; - } - else - { - //log_info << "Couldn't translate: " << msgid << std::endl; - //log_info << "Candidates: " << std::endl; - //for (i = dict.begin(); i != dict.end(); ++i) - // log_info << "'" << i->first << "'" << std::endl; - - if (count == 1) // default to english rules - return msgid; - else - return msgid_plural; - } -} - -std::string -Dictionary::translate(const std::string& msgid) -{ - return translate(entries, msgid); -} - -std::string -Dictionary::translate(const Entries& dict, const std::string& msgid) -{ - Entries::const_iterator i = dict.find(msgid); - if (i != dict.end() && !i->second.empty()) - { - return i->second[0]; - } - else - { - //log_info << "Couldn't translate: " << msgid << std::endl; - - if (m_has_fallback) return m_fallback->translate(msgid); - else return msgid; - } -} - -std::string -Dictionary::translate_ctxt(const std::string& msgctxt, const std::string& msgid) -{ - CtxtEntries::iterator i = ctxt_entries.find(msgctxt); - if (i != ctxt_entries.end()) - { - return translate(i->second, msgid); - } - else - { - //log_info << "Couldn't translate: " << msgid << std::endl; - return msgid; - } -} - -std::string -Dictionary::translate_ctxt_plural(const std::string& msgctxt, - const std::string& msgid, const std::string& msgidplural, int num) -{ - CtxtEntries::iterator i = ctxt_entries.find(msgctxt); - if (i != ctxt_entries.end()) - { - return translate_plural(i->second, msgid, msgidplural, num); - } - else - { - //log_info << "Couldn't translate: " << msgid << std::endl; - if (num != 1) // default to english - return msgidplural; - else - return msgid; - } -} - -void -Dictionary::add_translation(const std::string& msgid, const std::string& , - const std::vector& msgstrs) -{ - // Do we need msgid2 for anything? its after all supplied to the - // translate call, so we just throw it away here - entries[msgid] = msgstrs; -} - -void -Dictionary::add_translation(const std::string& msgid, const std::string& msgstr) -{ - std::vector& vec = entries[msgid]; - if (vec.empty()) - { - vec.push_back(msgstr); - } - else - { - Log::warn("tinygettext", - "Collision in add translation: '%s' -> '%s' vs '%s'.", - msgid.c_str(), msgstr.c_str(), vec[0].c_str()); - vec[0] = msgstr; - } -} - -void -Dictionary::add_translation(const std::string& msgctxt, - const std::string& msgid, const std::string& msgid_plural, - const std::vector& msgstrs) -{ - std::vector& vec = ctxt_entries[msgctxt][msgid]; - if (vec.empty()) - { - vec = msgstrs; - } - else - { - Log::warn("tinygettext", - "collision in add_translation(\"%s\", \"%s\", \"%s\")", - msgctxt.c_str(), msgid.c_str(), msgid_plural.c_str()); - vec = msgstrs; - } -} - -void -Dictionary::add_translation(const std::string& msgctxt, const std::string& msgid, const std::string& msgstr) -{ - std::vector& vec = ctxt_entries[msgctxt][msgid]; - if (vec.empty()) - { - vec.push_back(msgstr); - } - else - { - Log::warn("tinygettext", "collision in add_translation(\"%s\", \"%s\")", - msgctxt.c_str(), msgid.c_str()); - vec[0] = msgstr; - } -} - -std::set Dictionary::get_all_used_chars() -{ - std::set UsedChars; - for (Entries::const_iterator i = entries.begin(); i != entries.end(); ++i) - { - const std::vector& msgstrs = i->second; - for (unsigned int k = 0; k < msgstrs.size(); k++) - { - irr::core::stringw ws = StringUtils::utf8ToWide(msgstrs[k]); - for (unsigned int l = 0; l < ws.size(); ++l) - UsedChars.insert(ws[l]); - } - } - - for (CtxtEntries::const_iterator i = ctxt_entries.begin(); i != ctxt_entries.end(); ++i) - { - for (Entries::const_iterator j = i->second.begin(); j != i->second.end(); ++j) - { - const std::vector& msgstrs = j->second; - for (unsigned int k = 0; k < msgstrs.size(); k++) - { - irr::core::stringw ws = StringUtils::utf8ToWide(msgstrs[k]); - for (unsigned int l = 0; l < ws.size(); ++l) - UsedChars.insert(ws[l]); - } - } - } - return UsedChars; -} - -} // namespace tinygettext - -/* EOF */ -#endif diff --git a/src/tinygettext/file_system.hpp b/src/tinygettext/file_system.hpp deleted file mode 100644 index f72f44c85..000000000 --- a/src/tinygettext/file_system.hpp +++ /dev/null @@ -1,44 +0,0 @@ -// tinygettext - A gettext replacement that works directly on .po files -// Copyright (C) 2009-2015 Ingo Ruhnke -// -// 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; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -#ifndef HEADER_TINYGETTEXT_FILE_SYSTEM_HPP -#define HEADER_TINYGETTEXT_FILE_SYSTEM_HPP - -#ifndef SERVER_ONLY - -#include -#include -#include -#include - -namespace tinygettext { - -class FileSystem -{ -public: - virtual ~FileSystem() {} - - virtual std::vector open_directory(const std::string& pathname) =0; - virtual std::unique_ptr open_file(const std::string& filename) =0; -}; - -} // namespace tinygettext - -#endif - -/* EOF */ -#endif diff --git a/src/tinygettext/plural_forms.cpp b/src/tinygettext/plural_forms.cpp deleted file mode 100644 index aa82afa82..000000000 --- a/src/tinygettext/plural_forms.cpp +++ /dev/null @@ -1,124 +0,0 @@ -// tinygettext - A gettext replacement that works directly on .po files -// Copyright (C) 2006-2015 Ingo Ruhnke -// -// 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; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -#ifndef SERVER_ONLY - -#include "plural_forms.hpp" - -#include - -namespace tinygettext { - -/** - * Plural functions are used to select a string that matches a given - * count. \a n is the count and the return value is the string index - * used in the .po file, for example: - * - * msgstr[0] = "You got %d error"; - * msgstr[1] = "You got %d errors"; - * ^-- return value of plural function - */ -// Base on Unicode CLDR (http://mlocati.github.io/cldr-to-gettext-plural-rules/) -unsigned int plural1(int ) { return 0; } - -unsigned int plural2_1(int n) { return (n != 1); } -unsigned int plural2_2(int n) { return (n > 1); } -unsigned int plural2_is(int n) { return n % 10 != 1 || n % 100 == 11; } -unsigned int plural2_mk(int n) { return n==1 || n%10==1 ? 0 : 1; } - -unsigned int plural3_be(int n) { return static_cast(n % 10 == 1 && n % 100 != 11) ? 0 : ((n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 12 || n % 100 > 14)) ? 1 : 2); } -unsigned int plural3_kw(int n) { return static_cast(n == 1) ? 0 : ((n == 2) ? 1 : 2); } -unsigned int plural3_lv(int n) { return static_cast(n % 10 == 0 || (n % 100 >= 11 && n % 100 <= 19)) ? 0 : ((n % 10 == 1 && n % 100 != 11) ? 1 : 2); } -unsigned int plural3_lt(int n) { return static_cast(n % 10 == 1 && (n % 100 < 11 || n % 100 > 19)) ? 0 : ((n % 10 >= 2 && n % 10 <= 9 && (n % 100 < 11 || n % 100 > 19)) ? 1 : 2); } -unsigned int plural3_pl(int n) { return static_cast(n == 1) ? 0 : ((n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 12 || n % 100 > 14)) ? 1 : 2); } -unsigned int plural3_ro(int n) { return static_cast(n == 1) ? 0 : ((n == 0 || (n != 1 && n % 100 >= 1 && n % 100 <= 19)) ? 1 : 2); } -unsigned int plural3_sk(int n) { return static_cast(n == 1) ? 0 : ((n >= 2 && n <= 4) ? 1 : 2); } - -unsigned int plural4_gd(int n) { return static_cast(n == 1 || n == 11) ? 0 : ((n == 2 || n == 12) ? 1 : (((n >= 3 && n <= 10) || (n >= 13 && n <= 19)) ? 2 : 3)); } -unsigned int plural4_sl(int n) { return static_cast(n % 100 == 1) ? 0 : ((n % 100 == 2) ? 1 : ((n % 100 == 3 || n % 100 == 4) ? 2 : 3)); } - -unsigned int plural5_ga(int n) { return static_cast(n == 1) ? 0 : ((n == 2) ? 1 : ((n >= 3 && n <= 6) ? 2 : ((n >= 7 && n <= 10) ? 3 : 4))); } - -unsigned int plural6_ar(int n) { return static_cast(n == 0) ? 0 : ((n == 1) ? 1 : ((n == 2) ? 2 : ((n % 100 >= 3 && n % 100 <= 10) ? 3 : ((n % 100 >= 11 && n % 100 <= 99) ? 4 : 5)))); } - -typedef std::map tPluralForms; - -PluralForms -PluralForms::from_string(const std::string& str) -{ - static tPluralForms plural_forms; - - if (plural_forms.empty()) - { - // Note that the plural forms here shouldn't contain any spaces - // Some strings are specific to STK po file - // TODO in the future, map language code to plural form instead? - plural_forms["Plural-Forms:nplurals=1;plural=0;"] = PluralForms(1, plural1); - - plural_forms["Plural-Forms:nplurals=2;plural=(n!=1);"] = PluralForms(2, plural2_1); - plural_forms["Plural-Forms:nplurals=2;plural=n!=1;"] = PluralForms(2, plural2_1); - plural_forms["Plural-Forms:nplurals=2;plural=(n>1);"] = PluralForms(2, plural2_2); - plural_forms["Plural-Forms:nplurals=2;plural=(n%10!=1||n%100==11);"] = PluralForms(2, plural2_is); - plural_forms["Plural-Forms:nplurals=2;plural=n==1||n%10==1?0:1;"] = PluralForms(2, plural2_mk); - - //FIXME wrong plural equation in be/ru translation files! (transifex error?) nplurals of be/ru is 3 indeed. - plural_forms["Plural-Forms:nplurals=4;plural=(n%10==1&&n%100!=11?0:n%10>=2&&n%10<=4&&(n%100<12||n%100>14)?1:n%10==0||(n%10>=5&&n%10<=9)||(n%100>=11&&n%100<=14)?2:3);"] = PluralForms(4, plural3_be); - plural_forms["Plural-Forms:nplurals=4;plural=(n%1==0&&n%10==1&&n%100!=11?0:n%1==0&&n%10>=2&&n%10<=4&&(n%100<12||n%100>14)?1:n%1==0&&(n%10==0||(n%10>=5&&n%10<=9)||(n%100>=11&&n%100<=14))?2:3);"] = PluralForms(4, plural3_be); - plural_forms["Plural-Forms:nplurals=3;plural=n%10==1&&n%100!=11?0:n%10>=2&&n%10<=4&&(n%100<10||n%100>=20)?1:2;"] = PluralForms(3, plural3_be); - plural_forms["Plural-Forms:nplurals=3;plural=(n%10==1&&n%100!=11?0:n%10>=2&&n%10<=4&&(n%100<10||n%100>=20)?1:2);"] = PluralForms(3, plural3_be); - //FIXME wrong again - plural_forms["Plural-Forms:nplurals=4;plural=(n==1)?0:(n==2)?1:(n==3)?2:3;"] = PluralForms(4, plural3_kw); - plural_forms["Plural-Forms:nplurals=3;plural=(n==1?0:n==2?1:2);"] = PluralForms(3, plural3_kw); - plural_forms["Plural-Forms:nplurals=3;plural=(n%10==1&&n%100!=11?0:n!=0?1:2);"] = PluralForms(3, plural3_lv); - plural_forms["Plural-Forms:nplurals=3;plural=(n%10==1&&n%100!=11?0:n%10>=2&&(n%100<10||n%100>=20)?1:2);"] = PluralForms(3, plural3_lt); - plural_forms["Plural-Forms:nplurals=4;plural=(n%10==1&&(n%100>19||n%100<11)?0:(n%10>=2&&n%10<=9)&&(n%100>19||n%100<11)?1:n%1!=0?2:3);"] = PluralForms(4, plural3_lt); - plural_forms["Plural-Forms:nplurals=3;plural=(n==1?0:n%10>=2&&n%10<=4&&(n%100<10||n%100>=20)?1:2);"] = PluralForms(3, plural3_pl); - plural_forms["Plural-Forms:nplurals=4;plural=(n==1?0:(n%10>=2&&n%10<=4)&&(n%100<12||n%100>14)?1:n!=1&&(n%10>=0&&n%10<=1)||(n%10>=5&&n%10<=9)||(n%100>=12&&n%100<=14)?2:3);"] = PluralForms(4, plural3_pl); - plural_forms["Plural-Forms:nplurals=3;plural=(n==1?0:(((n%100>19)||((n%100==0)&&(n!=0)))?2:1));"] = PluralForms(3, plural3_ro); - plural_forms["Plural-Forms:nplurals=3;plural=(n==1)?0:(n>=2&&n<=4)?1:2;"] = PluralForms(3, plural3_sk); - plural_forms["Plural-Forms:nplurals=4;plural=(n%1==0&&n==1?0:n%1==0&&n>=2&&n<=4?1:n%1!=0?2:3);"] = PluralForms(4, plural3_sk); - plural_forms["Plural-Forms:nplurals=4;plural=(n==1&&n%1==0)?0:(n>=2&&n<=4&&n%1==0)?1:(n%1!=0)?2:3;"] = PluralForms(4, plural3_sk); - - plural_forms["Plural-Forms:nplurals=4;plural=(n%100==1?0:n%100==2?1:n%100==3||n%100==4?2:3);"] = PluralForms(4, plural4_sl); - plural_forms["Plural-Forms:nplurals=4;plural=(n==1||n==11)?0:(n==2||n==12)?1:(n>2&&n<20)?2:3;"] = PluralForms(4, plural4_gd); - - plural_forms["Plural-Forms:nplurals=5;plural=(n==1?0:n==2?1:n<7?2:n<11?3:4);"] = PluralForms(5, plural5_ga); - - plural_forms["Plural-Forms:nplurals=6;plural=n==0?0:n==1?1:n==2?2:n%100>=3&&n%100<=10?3:n%100>=11&&n%100<=99?4:5;"] = PluralForms(6, plural6_ar); - } - - // Remove spaces from string before lookup - std::string space_less_str; - for(std::string::size_type i = 0; i < str.size(); ++i) - if (!isspace(str[i])) - space_less_str += str[i]; - - tPluralForms::const_iterator it= plural_forms.find(space_less_str); - if (it != plural_forms.end()) - { - return it->second; - } - else - { - return PluralForms(); - } -} - -} // namespace tinygettext - -/* EOF */ -#endif diff --git a/src/tinygettext/plural_forms.hpp b/src/tinygettext/plural_forms.hpp deleted file mode 100644 index 6fc2a7a02..000000000 --- a/src/tinygettext/plural_forms.hpp +++ /dev/null @@ -1,64 +0,0 @@ -// tinygettext - A gettext replacement that works directly on .po files -// Copyright (C) 2006-2015 Ingo Ruhnke -// -// 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; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -#ifndef HEADER_TINYGETTEXT_PLURAL_FORMS_HPP -#define HEADER_TINYGETTEXT_PLURAL_FORMS_HPP - -#ifndef SERVER_ONLY - -#include - -namespace tinygettext { - -typedef unsigned int (*PluralFunc)(int n); - -class PluralForms -{ -private: - unsigned int nplural; - PluralFunc plural; - -public: - static PluralForms from_string(const std::string& str); - - PluralForms() - : nplural(0), - plural(0) - {} - - PluralForms(unsigned int nplural_, PluralFunc plural_) - : nplural(nplural_), - plural(plural_) - {} - - unsigned int get_nplural() const { return nplural; } - unsigned int get_plural(int n) const { if (plural) return plural(n); else return 0; } - - bool operator==(const PluralForms& other) { return nplural == other.nplural && plural == other.plural; } - bool operator!=(const PluralForms& other) { return !(*this == other); } - - operator bool() const { - return plural!=NULL; - } -}; - -} // namespace tinygettext - -#endif - -/* EOF */ -#endif diff --git a/src/tinygettext/stk_file_system.cpp b/src/tinygettext/stk_file_system.cpp deleted file mode 100644 index c8b60f722..000000000 --- a/src/tinygettext/stk_file_system.cpp +++ /dev/null @@ -1,61 +0,0 @@ -// tinygettext - A gettext replacement that works directly on .po files -// Copyright (C) 2009-2015 Ingo Ruhnke -// -// 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; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -#ifndef SERVER_ONLY - -#include "stk_file_system.hpp" - -#include -#include -#include -#include - -#include "io/file_manager.hpp" -#include "utils/file_utils.hpp" - -namespace tinygettext { - -StkFileSystem::StkFileSystem() -{ -} - -std::vector -StkFileSystem::open_directory(const std::string& pathname) -{ - std::set result; - - file_manager->listFiles(result, pathname); - std::vector files; - for(std::set::iterator i=result.begin(); i!=result.end(); i++) - { - files.push_back(*i); - } - return files; -} - -std::unique_ptr -StkFileSystem::open_file(const std::string& filename) -{ - return std::unique_ptr(new std::ifstream( - FileUtils::getPortableReadingPath(filename))); -} - -} // namespace tinygettext - -/* EOF */ - -#endif diff --git a/src/tinygettext/stk_file_system.hpp b/src/tinygettext/stk_file_system.hpp deleted file mode 100644 index 28526d7b8..000000000 --- a/src/tinygettext/stk_file_system.hpp +++ /dev/null @@ -1,42 +0,0 @@ -// tinygettext - A gettext replacement that works directly on .po files -// Copyright (C) 2009-2015 Ingo Ruhnke -// -// 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; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -#ifndef HEADER_TINYGETTEXT_STK_FILE_SYSTEM_HPP -#define HEADER_TINYGETTEXT_STK_FILE_SYSTEM_HPP - -#ifndef SERVER_ONLY - -#include "file_system.hpp" - -namespace tinygettext { - -class StkFileSystem : public FileSystem -{ -public: - StkFileSystem(); - - std::vector open_directory(const std::string& pathname); - std::unique_ptr open_file(const std::string& filename); -}; - -} // namespace tinygettext - -#endif - -/* EOF */ - -#endif diff --git a/src/tinygettext/tinygettext.cpp b/src/tinygettext/tinygettext.cpp deleted file mode 100644 index eaf17567e..000000000 --- a/src/tinygettext/tinygettext.cpp +++ /dev/null @@ -1,22 +0,0 @@ -// tinygettext - A gettext replacement that works directly on .po files -// Copyright (C) 2006-2015 Ingo Ruhnke -// -// 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; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -namespace tinygettext { - -} // namespace tinygettext - -/* EOF */ diff --git a/src/tinygettext/tinygettext.hpp b/src/tinygettext/tinygettext.hpp deleted file mode 100644 index c481112eb..000000000 --- a/src/tinygettext/tinygettext.hpp +++ /dev/null @@ -1,27 +0,0 @@ -// tinygettext - A gettext replacement that works directly on .po files -// Copyright (C) 2006-2015 Ingo Ruhnke -// -// 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; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -#ifndef HEADER_TINYGETTEXT_TINYGETTEXT_HPP -#define HEADER_TINYGETTEXT_TINYGETTEXT_HPP - -#include "dictionary.hpp" -#include "dictionary_manager.hpp" -#include "language.hpp" - -#endif - -/* EOF */ diff --git a/src/utils/translation.cpp b/src/utils/translation.cpp index e87476b5b..c6823f950 100644 --- a/src/utils/translation.cpp +++ b/src/utils/translation.cpp @@ -402,7 +402,7 @@ Translations::Translations() //: m_dictionary_manager("UTF-16") { Log::verbose("translation", "Language '%s'.", l.get_name().c_str()); - m_dictionary = m_dictionary_manager.get_dictionary(l); + m_dictionary = &m_dictionary_manager.get_dictionary(l); break; } } @@ -418,7 +418,7 @@ Translations::Translations() //: m_dictionary_manager("UTF-16") } if (!l) { - m_dictionary = m_dictionary_manager.get_dictionary(); + m_dictionary = &m_dictionary_manager.get_dictionary(); } } else @@ -431,7 +431,7 @@ Translations::Translations() //: m_dictionary_manager("UTF-16") m_current_language_name = "Default language"; m_current_language_name_code = "en"; m_current_language_tag = "en"; - m_dictionary = m_dictionary_manager.get_dictionary(); + m_dictionary = &m_dictionary_manager.get_dictionary(); } else { @@ -445,7 +445,7 @@ Translations::Translations() //: m_dictionary_manager("UTF-16") m_current_language_tag += tgtLang.get_country(); } Log::verbose("translation", "Language '%s'.", m_current_language_name.c_str()); - m_dictionary = m_dictionary_manager.get_dictionary(tgtLang); + m_dictionary = &m_dictionary_manager.get_dictionary(tgtLang); } } } @@ -454,7 +454,7 @@ Translations::Translations() //: m_dictionary_manager("UTF-16") m_current_language_name = "Default language"; m_current_language_name_code = "en"; m_current_language_tag = m_current_language_name_code; - m_dictionary = m_dictionary_manager.get_dictionary(); + m_dictionary = &m_dictionary_manager.get_dictionary(); } #endif @@ -497,8 +497,8 @@ irr::core::stringw Translations::w_gettext(const char* original, const char* con #endif const std::string& original_t = (context == NULL ? - m_dictionary.translate(original) : - m_dictionary.translate_ctxt(context, original)); + m_dictionary->translate(original) : + m_dictionary->translate_ctxt(context, original)); // print //for (int n=0;; n+=4) const irr::core::stringw wide = StringUtils::utf8ToWide(original_t); @@ -545,8 +545,8 @@ irr::core::stringw Translations::w_ngettext(const char* singular, const char* pl #else const std::string& res = (context == NULL ? - m_dictionary.translate_plural(singular, plural, num) : - m_dictionary.translate_ctxt_plural(context, singular, plural, num)); + m_dictionary->translate_plural(singular, plural, num) : + m_dictionary->translate_ctxt_plural(context, singular, plural, num)); const irr::core::stringw wide = StringUtils::utf8ToWide(res); const wchar_t* out_ptr = wide.c_str(); @@ -565,7 +565,7 @@ irr::core::stringw Translations::w_ngettext(const char* singular, const char* pl #ifndef SERVER_ONLY std::set Translations::getCurrentAllChar() { - return m_dictionary.get_all_used_chars(); + return m_dictionary->get_all_used_chars(); } // getCurrentAllChar // ---------------------------------------------------------------------------- diff --git a/src/utils/translation.hpp b/src/utils/translation.hpp index a161fdcf7..847aaacba 100644 --- a/src/utils/translation.hpp +++ b/src/utils/translation.hpp @@ -49,7 +49,7 @@ class Translations private: #ifndef SERVER_ONLY tinygettext::DictionaryManager m_dictionary_manager; - tinygettext::Dictionary m_dictionary; + tinygettext::Dictionary* m_dictionary; static std::map m_localized_name; static std::map > m_localized_country_codes;