--- /dev/null
+*.o
+*~
+/.sconsign.dblite
+/CMakeCache.txt
+/CMakeFiles/
+/Makefile
+/cmake_install.cmake
+/libtinygettext.so
+/src/libtinygettext.a
+/test/po_parser_test
+/test/tinygettext_test
+/tinygettext.pc
# 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
## build list of source files
-FILE(GLOB TINYGETTEXT_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} tinygettext/*.cpp)
-FILE(GLOB TINYGETTEXT_HEADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} tinygettext/*.hpp)
+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 tinygettext dir to search path
-INCLUDE_DIRECTORIES(${tinygettext_SOURCE_DIR})
+INCLUDE_DIRECTORIES(include/)
## Debug options
OPTION(WERROR "Stops on first compiler warning in debug mode" OFF)
IF(CMAKE_COMPILER_IS_GNUCC)
- ADD_DEFINITIONS(-O3 -Wall -Wextra -Weffc++ -pedantic)
+ ADD_DEFINITIONS(-std=c++0x -O3 -Wall -Wextra -Weffc++ -pedantic)
# -ansi fails in MinGW
OPTION(WARNINGS "Enable long list of warnings for compiler to check" ON)
IF(WARNINGS)
-Wsign-promo -Wswitch-enum
-Wcast-align -Wcast-qual
-Wdisabled-optimization
- -Wfloat-equal
+ -Wfloat-equal
-Wformat=2
- -Winit-self
+ -Winit-self
-Winvalid-pch -Wunsafe-loop-optimizations
- -Wlogical-op
- -Wmissing-format-attribute -Wmissing-include-dirs -Wmissing-noreturn
+ -Wlogical-op
+ -Wmissing-format-attribute -Wmissing-include-dirs -Wmissing-noreturn
-Wpacked
-Wredundant-decls
-Wshadow
## Extra definitions
-ADD_DEFINITIONS(-DVERSION=\\\"${VERSION}\\\")
+ADD_DEFINITIONS(-DVERSION=${VERSION})
## Generate test executables in the right place
DESTINATION include/tinygettext)
INSTALL(FILES ${tinygettext_BINARY_DIR}/tinygettext.pc
DESTINATION ${LIB_SUBDIR}/pkgconfig)
+
+# EOF #
# -*- python -*-
-env = Environment(CXXFLAGS=['-O0',
+import os
+
+env = Environment(ENV=os.environ,
+ CXX="g++",
+ CXXFLAGS=['-O0',
'-g3',
+ '-std=c++0x',
'-Wall',
+ '-Wextra',
'-Wcast-qual',
'-Wconversion',
'-Weffc++',
'-Wno-unused-parameter',
'-Wnon-virtual-dtor',
'-Wshadow',
- '-ansi',
+ # '-ansi', # conflicts with -std=c++0x
'-pedantic',
],
- CPPPATH=['tinygettext', '.'])
+ CPPPATH=['include', 'src'])
# env.ParseConfig("sdl-config --cflags --libs")
# env['CPPDEFINES'] += HAVE_SDL
-libtinygettext = env.StaticLibrary('tinygettext/tinygettext',
- ['tinygettext/tinygettext.cpp',
- 'tinygettext/language.cpp',
- 'tinygettext/plural_forms.cpp',
- 'tinygettext/dictionary.cpp',
- 'tinygettext/dictionary_manager.cpp',
- 'tinygettext/unix_file_system.cpp',
- 'tinygettext/po_parser.cpp',
- 'tinygettext/iconv.cpp',
- 'tinygettext/log.cpp'])
+libtinygettext = env.StaticLibrary('src/tinygettext',
+ ['src/tinygettext.cpp',
+ 'src/language.cpp',
+ 'src/plural_forms.cpp',
+ 'src/dictionary.cpp',
+ 'src/dictionary_manager.cpp',
+ 'src/unix_file_system.cpp',
+ 'src/po_parser.cpp',
+ 'src/iconv.cpp',
+ 'src/log.cpp'])
env.Program('test/tinygettext_test', ['test/tinygettext_test.cpp', libtinygettext])
env.Program('test/po_parser_test', ['test/po_parser_test.cpp', libtinygettext])
--- /dev/null
+// tinygettext - A gettext replacement that works directly on .po files
+// Copyright (C) 2006 Ingo Ruhnke <grumbel@gmx.de>
+//
+// 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_DICTIONARY_HPP
+#define HEADER_TINYGETTEXT_DICTIONARY_HPP
+
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+#include "plural_forms.hpp"
+
+namespace tinygettext {
+
+/** A simple dictionary class that mimics gettext() behaviour. Each
+ Dictionary only works for a single language, for managing multiple
+ languages and .po files at once use the DictionaryManager. */
+class Dictionary
+{
+private:
+ typedef std::unordered_map<std::string, std::vector<std::string> > Entries;
+ Entries entries;
+
+ typedef std::unordered_map<std::string, Entries> 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);
+
+public:
+ /** Constructs a dictionary converting to the specified \a charset (default UTF-8) */
+ Dictionary(const std::string& charset = "UTF-8");
+ ~Dictionary();
+
+ /** Return the charset used for this dictionary */
+ std::string get_charset() const;
+
+ void set_plural_forms(const PluralForms&);
+ PluralForms get_plural_forms() const;
+
+
+ /** Translate the string \a msgid. */
+ std::string translate(const std::string& msgid);
+
+ /** 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);
+
+ /** 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_plural(const std::string& msgctxt, const std::string& msgid, const std::string& msgidplural, int num);
+
+ /** 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
+ plural form and msgstrs a table of translations. The right
+ translation will be calculated based on the \a num argument to
+ translate(). */
+ void add_translation(const std::string& msgid, const std::string& msgid_plural,
+ const std::vector<std::string>& msgstrs);
+ void add_translation(const std::string& msgctxt,
+ const std::string& msgid, const std::string& msgid_plural,
+ const std::vector<std::string>& msgstrs);
+
+ /** Add a translation from \a msgid to \a msgstr to the
+ dictionary */
+ 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);
+
+ /** Iterate over all messages, Func is of type:
+ void func(const std::string& msgid, const std::vector<std::string>& msgstrs) */
+ template<class Func>
+ Func foreach(Func func)
+ {
+ for(Entries::iterator i = entries.begin(); i != entries.end(); ++i)
+ {
+ func(i->first, i->second);
+ }
+ return func;
+ }
+
+ /** Iterate over all messages with a context, Func is of type:
+ void func(const std::string& ctxt, const std::string& msgid, const std::vector<std::string>& msgstrs) */
+ template<class Func>
+ Func foreach_ctxt(Func func)
+ {
+ for(CtxtEntries::iterator i = ctxt_entries.begin(); i != ctxt_entries.end(); ++i)
+ {
+ for(Entries::iterator j = i->second.begin(); j != i->second.end(); ++j)
+ {
+ func(i->first, j->first, j->second);
+ }
+ }
+ return func;
+ }
+};
+
+} // namespace tinygettext
+
+#endif
+
+/* EOF */
--- /dev/null
+// tinygettext - A gettext replacement that works directly on .po files
+// Copyright (C) 2006 Ingo Ruhnke <grumbel@gmx.de>
+//
+// 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_DICTIONARY_MANAGER_HPP
+#define HEADER_TINYGETTEXT_DICTIONARY_MANAGER_HPP
+
+#include <memory>
+#include <set>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+#include "dictionary.hpp"
+#include "language.hpp"
+
+namespace tinygettext {
+
+class FileSystem;
+
+/** Manager class for dictionaries, you give it a bunch of directories
+ with .po files and it will then automatically load the right file
+ on demand depending on which language was set. */
+class DictionaryManager
+{
+private:
+ typedef std::unordered_map<Language, Dictionary*, Language_hash> Dictionaries;
+ Dictionaries dictionaries;
+
+ typedef std::vector<std::string> SearchPath;
+ SearchPath search_path;
+
+ std::string charset;
+ bool use_fuzzy;
+
+ Language current_language;
+ Dictionary* current_dict;
+
+ Dictionary empty_dict;
+
+ std::unique_ptr<FileSystem> filesystem;
+
+ void clear_cache();
+
+public:
+ DictionaryManager(const std::string& charset_ = "UTF-8");
+ ~DictionaryManager();
+
+ /** Return the currently active dictionary, if none is set, an empty
+ dictionary is returned. */
+ Dictionary& get_dictionary();
+
+ /** Get dictionary for language */
+ Dictionary& get_dictionary(const Language& language);
+
+ /** Set a language based on a four? letter country code */
+ void set_language(const Language& language);
+
+ /** returns the (normalized) country code of the currently used language */
+ Language get_language() const;
+
+ void set_use_fuzzy(bool t);
+ bool get_use_fuzzy() const;
+
+ /** Set a charset that will be set on the returned dictionaries */
+ 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);
+
+ /** Return a set of the available languages in their country code */
+ std::set<Language> get_languages();
+
+ void set_filesystem(std::unique_ptr<FileSystem> filesystem);
+
+private:
+ DictionaryManager (const DictionaryManager&);
+ DictionaryManager& operator= (const DictionaryManager&);
+};
+
+} // namespace tinygettext
+
+#endif
+
+/* EOF */
--- /dev/null
+// tinygettext - A gettext replacement that works directly on .po files
+// Copyright (C) 2009 Ingo Ruhnke <grumbel@gmx.de>
+//
+// 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
+
+#include <vector>
+#include <memory>
+#include <iosfwd>
+#include <string>
+
+namespace tinygettext {
+
+class FileSystem
+{
+public:
+ virtual ~FileSystem() {}
+
+ virtual std::vector<std::string> open_directory(const std::string& pathname) =0;
+ virtual std::unique_ptr<std::istream> open_file(const std::string& filename) =0;
+};
+
+} // namespace tinygettext
+
+#endif
+
+/* EOF */
+
--- /dev/null
+// tinygettext - A gettext replacement that works directly on .po files
+// Copyright (C) 2006 Ingo Ruhnke <grumbel@gmx.de>
+//
+// 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 3 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, see <http://www.gnu.org/licenses/>.
+
+#ifndef HEADER_TINYGETTEXT_ICONV_HPP
+#define HEADER_TINYGETTEXT_ICONV_HPP
+
+#include <string>
+
+#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 <iconv.h>
+
+# 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 */
--- /dev/null
+// tinygettext - A gettext replacement that works directly on .po files
+// Copyright (C) 2006 Ingo Ruhnke <grumbel@gmx.de>
+//
+// 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_LANGUAGE_HPP
+#define HEADER_TINYGETTEXT_LANGUAGE_HPP
+
+#include <string>
+#include <unordered_map>
+
+namespace tinygettext {
+
+struct LanguageSpec;
+
+/** Lightweight wrapper around LanguageSpec */
+class Language
+{
+private:
+ LanguageSpec* language_spec;
+
+ Language(LanguageSpec* language_spec);
+
+public:
+ /** Create a language from language and country code:
+ Example: Languge("de", "DE"); */
+ static Language from_spec(const std::string& language,
+ const std::string& country = std::string(),
+ const std::string& modifier = std::string());
+
+ /** Create a language from language and country code:
+ Example: Languge("deutsch");
+ Example: Languge("de_DE"); */
+ static Language from_name(const std::string& str);
+
+ /** 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 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);
+
+ /** Create an undefined Language object */
+ Language();
+
+ operator bool() const { return language_spec; }
+
+ /** Returns the language code (i.e. de, en, fr) */
+ std::string get_language() const;
+
+ /** Returns the country code (i.e. DE, AT, US) */
+ std::string get_country() const;
+
+ /** Returns the modifier of the language (i.e. latn or Latn for
+ Serbian with non-cyrilic characters) */
+ std::string get_modifier() const;
+
+ /** Returns the human readable name of the Language */
+ std::string get_name() const;
+
+ /** Returns the Language as string in the form of an environment
+ variable: {language}_{country}@{modifier} */
+ std::string str() const;
+
+ 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<size_t>(v.language_spec);
+ }
+};
+
+} // namespace tinygettext
+
+#endif
+
+/* EOF */
--- /dev/null
+// tinygettext - A gettext replacement that works directly on .po files
+// Copyright (C) 2009 Ingo Ruhnke <grumbel@gmx.de>
+//
+// 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_LOG_HPP
+#define HEADER_TINYGETTEXT_LOG_HPP
+
+#include <sstream>
+
+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 */
--- /dev/null
+// tinygettext - A gettext replacement that works directly on .po files
+// Copyright (C) 2009 Ingo Ruhnke <grumbel@gmx.de>
+//
+// 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_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 */
--- /dev/null
+// tinygettext - A gettext replacement that works directly on .po files
+// Copyright (C) 2006 Ingo Ruhnke <grumbel@gmx.de>
+//
+// 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
+
+#include <string>
+
+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;
+ }
+};
+
+} // namespace tinygettext
+
+#endif
+
+/* EOF */
--- /dev/null
+// tinygettext - A gettext replacement that works directly on .po files
+// Copyright (C) 2009 Ingo Ruhnke <grumbel@gmx.de>
+//
+// 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_PO_PARSER_HPP
+#define HEADER_TINYGETTEXT_PO_PARSER_HPP
+
+#include <iosfwd>
+
+#include "iconv.hpp"
+
+namespace tinygettext {
+
+class Dictionary;
+
+class POParser
+{
+private:
+ std::string filename;
+ std::istream& in;
+ Dictionary& dict;
+ bool use_fuzzy;
+
+ bool running;
+ bool eof;
+ bool big5;
+
+ int line_number;
+ std::string current_line;
+
+ IConv conv;
+
+ POParser(const std::string& filename, std::istream& in_, Dictionary& dict_, bool use_fuzzy = true);
+ ~POParser();
+
+ void parse_header(const std::string& header);
+ void parse();
+ void next_line();
+ std::string get_string(unsigned int skip);
+ void get_string_line(std::ostringstream& str, size_t skip);
+ bool is_empty_line();
+ bool prefix(const char* );
+ void error(const std::string& msg) __attribute__((__noreturn__));
+ void warning(const std::string& msg);
+
+public:
+ /** @param filename name of the istream, only used in error messages
+ @param in stream from which the PO file is read.
+ @param dict dictionary to which the strings are written */
+ static void parse(const std::string& filename, std::istream& in, Dictionary& dict);
+ static bool pedantic;
+
+private:
+ POParser (const POParser&);
+ POParser& operator= (const POParser&);
+};
+
+} // namespace tinygettext
+
+#endif
+
+/* EOF */
--- /dev/null
+// tinygettext - A gettext replacement that works directly on .po files
+// Copyright (C) 2006 Ingo Ruhnke <grumbel@gmx.de>
+//
+// 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 */
--- /dev/null
+// tinygettext - A gettext replacement that works directly on .po files
+// Copyright (C) 2009 Ingo Ruhnke <grumbel@gmx.de>
+//
+// 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_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<std::string> open_directory(const std::string& pathname);
+ std::unique_ptr<std::istream> open_file(const std::string& filename);
+};
+
+} // namespace tinygettext
+
+#endif
+
+/* EOF */
--- /dev/null
+// tinygettext - A gettext replacement that works directly on .po files
+// Copyright (C) 2006 Ingo Ruhnke <grumbel@gmx.de>
+//
+// 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.
+
+#include <assert.h>
+
+#include "tinygettext/log_stream.hpp"
+#include "tinygettext/dictionary.hpp"
+
+namespace tinygettext {
+\f
+Dictionary::Dictionary(const std::string& charset_) :
+ entries(),
+ ctxt_entries(),
+ charset(charset_),
+ plural_forms()
+{
+}
+
+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);
+ const std::vector<std::string>& msgstrs = i->second;
+
+ if (i != dict.end())
+ {
+ 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;
+ 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;
+ }
+}
+\f
+void
+Dictionary::add_translation(const std::string& msgid, const std::string& ,
+ const std::vector<std::string>& 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<std::string>& vec = entries[msgid];
+ if (vec.empty())
+ {
+ vec.push_back(msgstr);
+ }
+ else
+ {
+ 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<std::string>& msgstrs)
+{
+ std::vector<std::string>& vec = ctxt_entries[msgctxt][msgid];
+ if (vec.empty())
+ {
+ vec = msgstrs;
+ }
+ else
+ {
+ log_warning << "collision in add_translation(\"" << msgctxt << "\", \"" << msgid << "\", \"" << msgid_plural << "\")" << std::endl;
+ vec = msgstrs;
+ }
+}
+
+void
+Dictionary::add_translation(const std::string& msgctxt, const std::string& msgid, const std::string& msgstr)
+{
+ std::vector<std::string>& vec = ctxt_entries[msgctxt][msgid];
+ if (vec.empty())
+ {
+ vec.push_back(msgstr);
+ }
+ else
+ {
+ log_warning << "collision in add_translation(\"" << msgctxt << "\", \"" << msgid << "\")" << std::endl;
+ vec[0] = msgstr;
+ }
+}
+\f
+} // namespace tinygettext
+
+/* EOF */
--- /dev/null
+// tinygettext - A gettext replacement that works directly on .po files
+// Copyright (C) 2006 Ingo Ruhnke <grumbel@gmx.de>
+//
+// 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.
+
+#include "tinygettext/dictionary_manager.hpp"
+
+#include <memory>
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fstream>
+#include <algorithm>
+
+#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)
+{
+ if (lhs.length() < rhs.length())
+ return false;
+ else
+ return lhs.compare(lhs.length() - rhs.length(), rhs.length(), rhs) == 0;
+}
+
+DictionaryManager::DictionaryManager(const std::string& charset_) :
+ dictionaries(),
+ search_path(),
+ charset(charset_),
+ use_fuzzy(true),
+ current_language(),
+ current_dict(0),
+ empty_dict(),
+ filesystem(new UnixFileSystem)
+{
+}
+
+DictionaryManager::~DictionaryManager()
+{
+ for(Dictionaries::iterator i = dictionaries.begin(); i != dictionaries.end(); ++i)
+ {
+ delete i->second;
+ }
+}
+
+void
+DictionaryManager::clear_cache()
+{
+ for(Dictionaries::iterator i = dictionaries.begin(); i != dictionaries.end(); ++i)
+ {
+ delete i->second;
+ }
+ dictionaries.clear();
+
+ current_dict = 0;
+}
+
+Dictionary&
+DictionaryManager::get_dictionary()
+{
+ if (current_dict)
+ {
+ return *current_dict;
+ }
+ else
+ {
+ if (current_language)
+ {
+ current_dict = &get_dictionary(current_language);
+ return *current_dict;
+ }
+ else
+ {
+ return empty_dict;
+ }
+ }
+}
+
+Dictionary&
+DictionaryManager::get_dictionary(const Language& language)
+{
+ //log_debug << "Dictionary for language \"" << spec << "\" requested" << std::endl;
+ //log_debug << "...normalized as \"" << lang << "\"" << std::endl;
+ assert(language);
+
+ Dictionaries::iterator i = dictionaries.find(language);
+ if (i != dictionaries.end())
+ {
+ return *i->second;
+ }
+ else // Dictionary for languages lang isn't loaded, so we load it
+ {
+ //log_debug << "get_dictionary: " << lang << std::endl;
+ Dictionary* dict = new Dictionary(charset);
+
+ dictionaries[language] = dict;
+
+ for (SearchPath::reverse_iterator p = search_path.rbegin(); p != search_path.rend(); ++p)
+ {
+ std::vector<std::string> files = filesystem->open_directory(*p);
+
+ std::string best_filename;
+ int best_score = 0;
+
+ for(std::vector<std::string>::iterator filename = files.begin(); filename != files.end(); filename++)
+ {
+ // check if filename matches requested language
+ if (has_suffix(*filename, ".po"))
+ { // ignore anything that isn't a .po file
+ Language po_language = Language::from_env(filename->substr(0, filename->size()-3));
+
+ if (!po_language)
+ {
+ log_warning << *filename << ": warning: ignoring, unknown language" << std::endl;
+ }
+ else
+ {
+ int score = Language::match(language, po_language);
+
+ if (score > best_score)
+ {
+ best_score = score;
+ best_filename = *filename;
+ }
+ }
+ }
+ }
+
+ if (!best_filename.empty())
+ {
+ std::string pofile = *p + "/" + best_filename;
+ try
+ {
+ std::unique_ptr<std::istream> in = filesystem->open_file(pofile);
+ if (!in.get())
+ {
+ log_error << "error: failure opening: " << pofile << std::endl;
+ }
+ else
+ {
+ POParser::parse(pofile, *in, *dict);
+ }
+ }
+ catch(std::exception& e)
+ {
+ log_error << "error: failure parsing: " << pofile << std::endl;
+ log_error << e.what() << "" << std::endl;
+ }
+ }
+ }
+
+ return *dict;
+ }
+}
+
+std::set<Language>
+DictionaryManager::get_languages()
+{
+ std::set<Language> languages;
+
+ for (SearchPath::iterator p = search_path.begin(); p != search_path.end(); ++p)
+ {
+ std::vector<std::string> files = filesystem->open_directory(*p);
+
+ for(std::vector<std::string>::iterator file = files.begin(); file != files.end(); ++file)
+ {
+ if (has_suffix(*file, ".po"))
+ {
+ languages.insert(Language::from_env(file->substr(0, file->size()-3)));
+ }
+ }
+ }
+ return languages;
+}
+
+void
+DictionaryManager::set_language(const Language& language)
+{
+ if (current_language != language)
+ {
+ current_language = language;
+ current_dict = 0;
+ }
+}
+
+Language
+DictionaryManager::get_language() const
+{
+ return current_language;
+}
+
+void
+DictionaryManager::set_charset(const std::string& charset_)
+{
+ clear_cache(); // changing charset invalidates cache
+ charset = charset_;
+}
+
+void
+DictionaryManager::set_use_fuzzy(bool t)
+{
+ clear_cache();
+ use_fuzzy = t;
+}
+
+bool
+DictionaryManager::get_use_fuzzy() const
+{
+ return use_fuzzy;
+}
+
+void
+DictionaryManager::add_directory(const std::string& pathname)
+{
+ clear_cache(); // adding directories invalidates cache
+ search_path.push_back(pathname);
+}
+
+void
+DictionaryManager::set_filesystem(std::unique_ptr<FileSystem> filesystem_)
+{
+ filesystem = std::move(filesystem_);
+}
+
+} // namespace tinygettext
+
+/* EOF */
--- /dev/null
+// tinygettext - A gettext replacement that works directly on .po files
+// Copyright (C) 2009 Ingo Ruhnke <grumbel@gmx.de>
+//
+// 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.
+
+#include <ctype.h>
+#include <assert.h>
+#include <sstream>
+#include <errno.h>
+#include <stdexcept>
+#include <string.h>
+#include <stdlib.h>
+
+#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<char>(toupper(*i));
+
+ for(std::string::iterator i = from_charset.begin(); i != from_charset.end(); ++i)
+ *i = static_cast<char>(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<tinygettext_iconv_t>(-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<char*>(&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<size_t>(-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(!"tinygettext/iconv.cpp: E2BIG: This should never be reached");
+ }
+ else if (errno == EBADF)
+ {
+ assert(!"tinygettext/iconv.cpp: EBADF: This should never be reached");
+ }
+ else
+ {
+ assert(!"tinygettext/iconv.cpp: <unknown>: This should never be reached");
+ }
+ }
+
+ result.resize(4*text.size() - outbytesleft);
+
+ return result;
+ }
+}
+
+} // namespace tinygettext
+
+/* EOF */
--- /dev/null
+// tinygettext - A gettext replacement that works directly on .po files
+// Copyright (C) 2006 Ingo Ruhnke <grumbel@gmx.de>
+//
+// 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.
+
+#include "tinygettext/language.hpp"
+
+#include <assert.h>
+#include <unordered_map>
+#include <vector>
+
+namespace tinygettext {
+\f
+struct LanguageSpec {
+ /** Language code: "de", "en", ... */
+ const char* language;
+
+ /** Country code: "BR", "DE", ..., can be 0 */
+ const char* country;
+
+ /** Modifier/Varint: "Latn", "ije", "latin"..., can be 0 */
+ const char* modifier;
+
+ /** Language name: "German", "English", "French", ... */
+ const char* name;
+};
+\f
+/** Language Definitions */
+//*{
+LanguageSpec languages[] = {
+ { "aa", 0, 0, "Afar" },
+ { "af", 0, 0, "Afrikaans" },
+ { "af", "ZA", 0, "Afrikaans (South Africa)" },
+ { "am", 0, 0, "Amharic" },
+ { "ar", 0, 0, "Arabic" },
+ { "ar", "AR", 0, "Arabic (Argentina)" },
+ { "ar", "OM", 0, "Arabic (Oman)" },
+ { "ar", "SA", 0, "Arabic (Saudi Arabia)" },
+ { "ar", "SY", 0, "Arabic (Syrian Arab Republic)" },
+ { "ar", "TN", 0, "Arabic (Tunisia)" },
+ { "as", 0, 0, "Assamese" },
+ { "ast",0, 0, "Asturian" },
+ { "ay", 0, 0, "Aymara" },
+ { "az", 0, 0, "Azerbaijani" },
+ { "az", "IR", 0, "Azerbaijani (Iran)" },
+ { "be", 0, 0, "Belarusian" },
+ { "be", 0, "latin", "Belarusian" },
+ { "bg", 0, 0, "Bulgarian" },
+ { "bg", "BG", 0, "Bulgarian (Bulgaria)" },
+ { "bn", 0, 0, "Bengali" },
+ { "bn", "BD", 0, "Bengali (Bangladesh)" },
+ { "bn", "IN", 0, "Bengali (India)" },
+ { "bo", 0, 0, "Tibetan" },
+ { "br", 0, 0, "Breton" },
+ { "bs", 0, 0, "Bosnian" },
+ { "bs", "BA", 0, "Bosnian (Bosnia/Herzegovina)"},
+ { "bs", "BS", 0, "Bosnian (Bahamas)" },
+ { "ca", "ES", "valencia", "Catalan (valencia)" },
+ { "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)" },
+ { "cy", 0, 0, "Welsh" },
+ { "cy", "GB", 0, "Welsh (Great Britain)" },
+ { "cz", 0, 0, "Unknown language" },
+ { "da", 0, 0, "Danish" },
+ { "da", "DK", 0, "Danish (Denmark)" },
+ { "de", 0, 0, "German" },
+ { "de", "AT", 0, "German (Austria)" },
+ { "de", "CH", 0, "German (Switzerland)" },
+ { "de", "DE", 0, "German (Germany)" },
+ { "dk", 0, 0, "Unknown language" },
+ { "dz", 0, 0, "Dzongkha" },
+ { "el", 0, 0, "Greek" },
+ { "el", "GR", 0, "Greek (Greece)" },
+ { "en", 0, 0, "English" },
+ { "en", "AU", 0, "English (Australia)" },
+ { "en", "CA", 0, "English (Canada)" },
+ { "en", "GB", 0, "English (Great Britain)" },
+ { "en", "US", 0, "English (United States)" },
+ { "en", "ZA", 0, "English (South Africa)" },
+ { "en", 0, "boldquot", "English" },
+ { "en", 0, "quot", "English" },
+ { "en", "US", "piglatin", "English" },
+ { "eo", 0, 0, "Esperanto" },
+ { "es", 0, 0, "Spanish" },
+ { "es", "AR", 0, "Spanish (Argentina)" },
+ { "es", "CL", 0, "Spanish (Chile)" },
+ { "es", "CO", 0, "Spanish (Colombia)" },
+ { "es", "CR", 0, "Spanish (Costa Rica)" },
+ { "es", "DO", 0, "Spanish (Dominican Republic)"},
+ { "es", "EC", 0, "Spanish (Ecuador)" },
+ { "es", "ES", 0, "Spanish (Spain)" },
+ { "es", "GT", 0, "Spanish (Guatemala)" },
+ { "es", "HN", 0, "Spanish (Honduras)" },
+ { "es", "LA", 0, "Spanish (Laos)" },
+ { "es", "MX", 0, "Spanish (Mexico)" },
+ { "es", "NI", 0, "Spanish (Nicaragua)" },
+ { "es", "PA", 0, "Spanish (Panama)" },
+ { "es", "PE", 0, "Spanish (Peru)" },
+ { "es", "PR", 0, "Spanish (Puerto Rico)" },
+ { "es", "SV", 0, "Spanish (El Salvador)" },
+ { "es", "UY", 0, "Spanish (Uruguay)" },
+ { "es", "VE", 0, "Spanish (Venezuela)" },
+ { "et", 0, 0, "Estonian" },
+ { "et", "EE", 0, "Estonian (Estonia)" },
+ { "et", "ET", 0, "Estonian (Ethiopia)" },
+ { "eu", 0, 0, "Basque" },
+ { "eu", "ES", 0, "Basque (Spain)" },
+ { "fa", 0, 0, "Persian" },
+ { "fa", "AF", 0, "Persian (Afghanistan)" },
+ { "fa", "IR", 0, "Persian (Iran)" },
+ { "fi", 0, 0, "Finnish" },
+ { "fi", "FI", 0, "Finnish (Finland)" },
+ { "fo", 0, 0, "Faroese" },
+ { "fo", "FO", 0, "Faeroese (Faroe Islands)" },
+ { "fr", 0, 0, "French" },
+ { "fr", "CA", 0, "French (Canada)" },
+ { "fr", "CH", 0, "French (Switzerland)" },
+ { "fr", "FR", 0, "French (France)" },
+ { "fr", "LU", 0, "French (Luxembourg)" },
+ { "fy", 0, 0, "Frisian" },
+ { "ga", 0, 0, "Irish" },
+ { "gd", 0, 0, "Gaelic Scots" },
+ { "gl", 0, 0, "Galician" },
+ { "gl", "ES", 0, "Galician (Spain)" },
+ { "gn", 0, 0, "Guarani" },
+ { "gu", 0, 0, "Gujarati" },
+ { "gv", 0, 0, "Manx" },
+ { "ha", 0, 0, "Hausa" },
+ { "he", 0, 0, "Hebrew" },
+ { "he", "IL", 0, "Hebrew (Israel)" },
+ { "hi", 0, 0, "Hindi" },
+ { "hr", 0, 0, "Croatian" },
+ { "hr", "HR", 0, "Croatian (Croatia)" },
+ { "hu", 0, 0, "Hungarian" },
+ { "hu", "HU", 0, "Hungarian (Hungary)" },
+ { "hy", 0, 0, "Armenian" },
+ { "ia", 0, 0, "Interlingua" },
+ { "id", 0, 0, "Indonesian" },
+ { "id", "ID", 0, "Indonesian (Indonesia)" },
+ { "is", 0, 0, "Icelandic" },
+ { "is", "IS", 0, "Icelandic (Iceland)" },
+ { "it", 0, 0, "Italian" },
+ { "it", "CH", 0, "Italian (Switzerland)" },
+ { "it", "IT", 0, "Italian (Italy)" },
+ { "iu", 0, 0, "Inuktitut" },
+ { "ja", 0, 0, "Japanese" },
+ { "ja", "JP", 0, "Japanese (Japan)" },
+ { "ka", 0, 0, "Georgian" },
+ { "kk", 0, 0, "Kazakh" },
+ { "kl", 0, 0, "Kalaallisut" },
+ { "km", 0, 0, "Khmer" },
+ { "km", "KH", 0, "Khmer (Cambodia)" },
+ { "kn", 0, 0, "Kannada" },
+ { "ko", 0, 0, "Korean" },
+ { "ko", "KR", 0, "Korean (Korea)" },
+ { "ku", 0, 0, "Kurdish" },
+ { "kw", 0, 0, "Cornish" },
+ { "ky", 0, 0, "Kirghiz" },
+ { "la", 0, 0, "Latin" },
+ { "lo", 0, 0, "Lao" },
+ { "lt", 0, 0, "Lithuanian" },
+ { "lt", "LT", 0, "Lithuanian (Lithuania)" },
+ { "lv", 0, 0, "Latvian" },
+ { "lv", "LV", 0, "Latvian (Latvia)" },
+ { "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" },
+ { "mr", 0, 0, "Marathi" },
+ { "ms", 0, 0, "Malay" },
+ { "ms", "MY", 0, "Malay (Malaysia)" },
+ { "mt", 0, 0, "Maltese" },
+ { "my", 0, 0, "Burmese" },
+ { "my", "MM", 0, "Burmese (Myanmar)" },
+ { "nb", 0, 0, "Norwegian Bokmal" },
+ { "nb", "NO", 0, "Norwegian Bokmål (Norway)" },
+ { "ne", 0, 0, "Nepali" },
+ { "nl", 0, 0, "Dutch" },
+ { "nl", "BE", 0, "Dutch (Belgium)" },
+ { "nl", "NL", 0, "Dutch (Netherlands)" },
+ { "nn", 0, 0, "Norwegian Nynorsk" },
+ { "nn", "NO", 0, "Norwegian Nynorsk (Norway)" },
+ { "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" },
+ { "pa", 0, 0, "Punjabi" },
+ { "pl", 0, 0, "Polish" },
+ { "pl", "PL", 0, "Polish (Poland)" },
+ { "ps", 0, 0, "Pashto" },
+ { "pt", 0, 0, "Portuguese" },
+ { "pt", "BR", 0, "Brazilian" },
+ { "pt", "PT", 0, "Portuguese (Portugal)" },
+ { "qu", 0, 0, "Quechua" },
+ { "rm", 0, 0, "Rhaeto-Romance" },
+ { "ro", 0, 0, "Romanian" },
+ { "ro", "RO", 0, "Romanian (Romania)" },
+ { "ru", 0, 0, "Russian" },
+ { "ru", "RU", 0, "Russian (Russia" },
+ { "rw", 0, 0, "Kinyarwanda" },
+ { "sa", 0, 0, "Sanskrit" },
+ { "sd", 0, 0, "Sindhi" },
+ { "se", 0, 0, "Sami" },
+ { "se", "NO", 0, "Sami (Norway)" },
+ { "si", 0, 0, "Sinhalese" },
+ { "sk", 0, 0, "Slovak" },
+ { "sk", "SK", 0, "Slovak (Slovakia)" },
+ { "sl", 0, 0, "Slovenian" },
+ { "sl", "SI", 0, "Slovenian (Slovenia)" },
+ { "sl", "SL", 0, "Slovenian (Sierra Leone)" },
+ { "sm", 0, 0, "Samoan" },
+ { "so", 0, 0, "Somali" },
+ { "sp", 0, 0, "Unknown language" },
+ { "sq", 0, 0, "Albanian" },
+ { "sq", "AL", 0, "Albanian (Albania)" },
+ { "sr", 0, 0, "Serbian" },
+ { "sr", "YU", 0, "Serbian (Yugoslavia)" },
+ { "sr", 0,"ije", "Serbian" },
+ { "sr", 0, "latin", "Serbian" },
+ { "sr", 0, "Latn", "Serbian" },
+ { "ss", 0, 0, "Swati" },
+ { "st", 0, 0, "Sotho" },
+ { "sv", 0, 0, "Swedish" },
+ { "sv", "SE", 0, "Swedish (Sweden)" },
+ { "sv", "SV", 0, "Swedish (El Salvador)" },
+ { "sw", 0, 0, "Swahili" },
+ { "ta", 0, 0, "Tamil" },
+ { "te", 0, 0, "Telugu" },
+ { "tg", 0, 0, "Tajik" },
+ { "th", 0, 0, "Thai" },
+ { "th", "TH", 0, "Thai (Thailand)" },
+ { "ti", 0, 0, "Tigrinya" },
+ { "tk", 0, 0, "Turkmen" },
+ { "tl", 0, 0, "Tagalog" },
+ { "to", 0, 0, "Tonga" },
+ { "tr", 0, 0, "Turkish" },
+ { "tr", "TR", 0, "Turkish (Turkey)" },
+ { "ts", 0, 0, "Tsonga" },
+ { "tt", 0, 0, "Tatar" },
+ { "ug", 0, 0, "Uighur" },
+ { "uk", 0, 0, "Ukrainian" },
+ { "uk", "UA", 0, "Ukrainian (Ukraine)" },
+ { "ur", 0, 0, "Urdu" },
+ { "ur", "PK", 0, "Urdu (Pakistan)" },
+ { "uz", 0, 0, "Uzbek" },
+ { "uz", 0, "cyrillic", "Uzbek" },
+ { "vi", 0, 0, "Vietnamese" },
+ { "vi", "VN", 0, "Vietnamese (Vietnam)" },
+ { "wa", 0, 0, "Walloon" },
+ { "wo", 0, 0, "Wolof" },
+ { "xh", 0, 0, "Xhosa" },
+ { "yi", 0, 0, "Yiddish" },
+ { "yo", 0, 0, "Yoruba" },
+ { "zh", 0, 0, "Chinese" },
+ { "zh", "CN", 0, "Chinese (simplified)" },
+ { "zh", "HK", 0, "Chinese (Hong Kong)" },
+ { "zh", "TW", 0, "Chinese (traditional)" },
+ { "zu", 0, 0, "Zulu" },
+ { NULL, 0, 0, NULL }
+};
+//*}
+\f
+std::string
+resolve_language_alias(const std::string& name)
+{
+ typedef std::unordered_map<std::string, std::string> Aliases;
+ static Aliases language_aliases;
+ if (language_aliases.empty())
+ {
+ // FIXME: Many of those are not useful for us, since we leave
+ // encoding to the app, not to the language, we could/should
+ // also match against all language names, not just aliases from
+ // locale.alias
+
+ // Aliases taken from /etc/locale.alias
+ language_aliases["bokmal"] = "nb_NO.ISO-8859-1";
+ language_aliases["bokmål"] = "nb_NO.ISO-8859-1";
+ language_aliases["catalan"] = "ca_ES.ISO-8859-1";
+ language_aliases["croatian"] = "hr_HR.ISO-8859-2";
+ language_aliases["czech"] = "cs_CZ.ISO-8859-2";
+ language_aliases["danish"] = "da_DK.ISO-8859-1";
+ language_aliases["dansk"] = "da_DK.ISO-8859-1";
+ language_aliases["deutsch"] = "de_DE.ISO-8859-1";
+ language_aliases["dutch"] = "nl_NL.ISO-8859-1";
+ language_aliases["eesti"] = "et_EE.ISO-8859-1";
+ language_aliases["estonian"] = "et_EE.ISO-8859-1";
+ language_aliases["finnish"] = "fi_FI.ISO-8859-1";
+ language_aliases["français"] = "fr_FR.ISO-8859-1";
+ language_aliases["french"] = "fr_FR.ISO-8859-1";
+ language_aliases["galego"] = "gl_ES.ISO-8859-1";
+ language_aliases["galician"] = "gl_ES.ISO-8859-1";
+ language_aliases["german"] = "de_DE.ISO-8859-1";
+ language_aliases["greek"] = "el_GR.ISO-8859-7";
+ language_aliases["hebrew"] = "he_IL.ISO-8859-8";
+ language_aliases["hrvatski"] = "hr_HR.ISO-8859-2";
+ language_aliases["hungarian"] = "hu_HU.ISO-8859-2";
+ language_aliases["icelandic"] = "is_IS.ISO-8859-1";
+ language_aliases["italian"] = "it_IT.ISO-8859-1";
+ language_aliases["japanese"] = "ja_JP.eucJP";
+ language_aliases["japanese.euc"] = "ja_JP.eucJP";
+ language_aliases["ja_JP"] = "ja_JP.eucJP";
+ language_aliases["ja_JP.ujis"] = "ja_JP.eucJP";
+ language_aliases["japanese.sjis"] = "ja_JP.SJIS";
+ language_aliases["korean"] = "ko_KR.eucKR";
+ language_aliases["korean.euc"] = "ko_KR.eucKR";
+ language_aliases["ko_KR"] = "ko_KR.eucKR";
+ language_aliases["lithuanian"] = "lt_LT.ISO-8859-13";
+ language_aliases["no_NO"] = "nb_NO.ISO-8859-1";
+ language_aliases["no_NO.ISO-8859-1"] = "nb_NO.ISO-8859-1";
+ language_aliases["norwegian"] = "nb_NO.ISO-8859-1";
+ language_aliases["nynorsk"] = "nn_NO.ISO-8859-1";
+ language_aliases["polish"] = "pl_PL.ISO-8859-2";
+ language_aliases["portuguese"] = "pt_PT.ISO-8859-1";
+ language_aliases["romanian"] = "ro_RO.ISO-8859-2";
+ language_aliases["russian"] = "ru_RU.ISO-8859-5";
+ language_aliases["slovak"] = "sk_SK.ISO-8859-2";
+ language_aliases["slovene"] = "sl_SI.ISO-8859-2";
+ language_aliases["slovenian"] = "sl_SI.ISO-8859-2";
+ language_aliases["spanish"] = "es_ES.ISO-8859-1";
+ language_aliases["swedish"] = "sv_SE.ISO-8859-1";
+ language_aliases["thai"] = "th_TH.TIS-620";
+ language_aliases["turkish"] = "tr_TR.ISO-8859-9";
+ }
+
+ std::string name_lowercase;
+ name_lowercase.resize(name.size());
+ for(std::string::size_type i = 0; i < name.size(); ++i)
+ name_lowercase[i] = static_cast<char>(tolower(name[i]));
+
+ Aliases::iterator i = language_aliases.find(name_lowercase);
+ if (i != language_aliases.end())
+ {
+ return i->second;
+ }
+ else
+ {
+ return name;
+ }
+}
+\f
+Language
+Language::from_spec(const std::string& language, const std::string& country, const std::string& modifier)
+{
+ static std::unordered_map<std::string, std::vector<LanguageSpec*> > language_map;
+
+ if (language_map.empty())
+ { // Init language_map
+ for(int i = 0; languages[i].language != NULL; ++i)
+ language_map[languages[i].language].push_back(&languages[i]);
+ }
+
+ std::unordered_map<std::string, std::vector<LanguageSpec*> >::iterator i = language_map.find(language);
+ if (i != language_map.end())
+ {
+ std::vector<LanguageSpec*>& lst = i->second;
+
+ LanguageSpec tmpspec;
+ tmpspec.language = language.c_str();
+ tmpspec.country = country.c_str();
+ tmpspec.modifier = modifier.c_str();
+ Language tmplang(&tmpspec);
+
+ LanguageSpec* best_match = 0;
+ int best_match_score = 0;
+ for(std::vector<LanguageSpec*>::iterator j = lst.begin(); j != lst.end(); ++j)
+ { // Search for the language that best matches the given spec, value country more then modifier
+ int score = Language::match(Language(*j), tmplang);
+
+ if (score > best_match_score)
+ {
+ best_match = *j;
+ best_match_score = score;
+ }
+ }
+ assert(best_match);
+ return Language(best_match);
+ }
+ else
+ {
+ return Language();
+ }
+}
+
+Language
+Language::from_name(const std::string& spec_str)
+{
+ return from_env(resolve_language_alias(spec_str));
+}
+
+Language
+Language::from_env(const std::string& env)
+{
+ // Split LANGUAGE_COUNTRY.CODESET@MODIFIER into parts
+ std::string::size_type ln = env.find('_');
+ std::string::size_type dt = env.find('.');
+ std::string::size_type at = env.find('@');
+
+ std::string language;
+ std::string country;
+ std::string codeset;
+ std::string modifier;
+
+ //std::cout << ln << " " << dt << " " << at << std::endl;
+
+ language = env.substr(0, std::min(std::min(ln, dt), at));
+
+ 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));
+ }
+
+ if (dt != std::string::npos && dt+1 < env.size()) // .
+ {
+ codeset = env.substr(dt+1, (at == std::string::npos) ? std::string::npos : (at - (dt+1)));
+ }
+
+ if (at != std::string::npos && at+1 < env.size()) // @
+ {
+ modifier = env.substr(at+1);
+ }
+
+ return from_spec(language, country, modifier);
+}
+\f
+Language::Language(LanguageSpec* language_spec_)
+ : language_spec(language_spec_)
+{
+}
+
+Language::Language()
+ : language_spec(0)
+{
+}
+
+int
+Language::match(const Language& lhs, const Language& rhs)
+{
+ if (lhs.get_language() != rhs.get_language())
+ {
+ return 0;
+ }
+ else
+ {
+ static int match_tbl[3][3] = {
+ // modifier match, wildchard, miss
+ { 9, 8, 5 }, // country match
+ { 7, 6, 3 }, // country wildcard
+ { 4, 2, 1 }, // country miss
+ };
+
+ int c;
+ if (lhs.get_country() == rhs.get_country())
+ c = 0;
+ else if (lhs.get_country().empty() || rhs.get_country().empty())
+ c = 1;
+ else
+ c = 2;
+
+ int m;
+ if (lhs.get_modifier() == rhs.get_modifier())
+ m = 0;
+ else if (lhs.get_modifier().empty() || rhs.get_modifier().empty())
+ m = 1;
+ else
+ m = 2;
+
+ return match_tbl[c][m];
+ }
+}
+
+std::string
+Language::get_language() const
+{
+ if (language_spec)
+ return language_spec->language;
+ else
+ return "";
+}
+
+std::string
+Language::get_country() const
+{
+ if (language_spec && language_spec->country)
+ return language_spec->country;
+ else
+ return "";
+}
+
+std::string
+Language::get_modifier() const
+{
+ if (language_spec && language_spec->modifier)
+ return language_spec->modifier;
+ else
+ return "";
+}
+
+std::string
+Language::get_name() const
+{
+ if (language_spec)
+ return language_spec->name;
+ else
+ return "";
+}
+
+std::string
+Language::str() const
+{
+ if (language_spec)
+ {
+ std::string var;
+ var += language_spec->language;
+ if (language_spec->country)
+ {
+ var += "_";
+ var += language_spec->country;
+ }
+
+ if (language_spec->modifier)
+ {
+ var += "@";
+ var += language_spec->modifier;
+ }
+ return var;
+ }
+ else
+ {
+ return "";
+ }
+}
+
+bool
+Language::operator==(const Language& rhs) const
+{
+ return language_spec == rhs.language_spec;
+}
+
+bool
+Language::operator!=(const Language& rhs) const
+{
+ return language_spec != rhs.language_spec;
+}
+\f
+} // namespace tinygettext
+
+/* EOF */
--- /dev/null
+// tinygettext - A gettext replacement that works directly on .po files
+// Copyright (C) 2009 Ingo Ruhnke <grumbel@gmx.de>
+//
+// 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.
+
+#include <iostream>
+#include "tinygettext/log.hpp"
+
+namespace tinygettext {
+\f
+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;
+\f
+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;
+}
+\f
+Log::Log(log_callback_t callback_) :
+ callback(callback_),
+ out()
+{
+}
+
+Log::~Log()
+{
+ callback(out.str());
+}
+
+std::ostream&
+Log::get()
+{
+ return out;
+}
+\f
+} // namespace tinygettext
+
+/* EOF */
--- /dev/null
+// tinygettext - A gettext replacement that works directly on .po files
+// Copyright (C) 2006 Ingo Ruhnke <grumbel@gmx.de>
+//
+// 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.
+
+#include "tinygettext/plural_forms.hpp"
+
+#include <unordered_map>
+
+namespace tinygettext {
+\f
+/**
+ * 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<unsigned int>(n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2); }
+unsigned int plural3_ga(int n) { return static_cast<unsigned int>(n==1 ? 0 : n==2 ? 1 : 2); }
+unsigned int plural3_lt(int n) { return static_cast<unsigned int>(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<unsigned int>(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<unsigned int>( (n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2 ); }
+unsigned int plural3_pl(int n) { return static_cast<unsigned int>(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<unsigned int>(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3); }
+unsigned int plural4_ar(int n) { return static_cast<unsigned int>( n==1 ? 0 : n==2 ? 1 : n>=3 && n<=10 ? 2 : 3 ); }
+\f
+PluralForms
+PluralForms::from_string(const std::string& str)
+{
+ static std::unordered_map<std::string, struct PluralForms> 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?0:n==2?1:n>=3&&n<=10?2:3;"]=PluralForms(4, plural4_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];
+
+ std::unordered_map<std::string, struct PluralForms>::const_iterator it= plural_forms.find(space_less_str);
+ if (it != plural_forms.end())
+ {
+ return it->second;
+ }
+ else
+ {
+ return PluralForms();
+ }
+}
+
+} // namespace tinygettext
+
+/* EOF */
--- /dev/null
+// tinygettext - A gettext replacement that works directly on .po files
+// Copyright (C) 2009 Ingo Ruhnke <grumbel@gmx.de>
+//
+// 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.
+
+#include "tinygettext/po_parser.hpp"
+
+#include <iostream>
+#include <ctype.h>
+#include <string>
+#include <istream>
+#include <string.h>
+#include <unordered_map>
+#include <stdlib.h>
+
+#include "tinygettext/language.hpp"
+#include "tinygettext/log_stream.hpp"
+#include "tinygettext/iconv.hpp"
+#include "tinygettext/dictionary.hpp"
+#include "tinygettext/plural_forms.hpp"
+
+namespace tinygettext {
+
+bool POParser::pedantic = true;
+\f
+void
+POParser::parse(const std::string& filename, std::istream& in, Dictionary& dict)
+{
+ POParser parser(filename, in, dict);
+ parser.parse();
+}
+\f
+class POParserError {};
+
+POParser::POParser(const std::string& filename_, std::istream& in_, Dictionary& dict_, bool use_fuzzy_) :
+ filename(filename_),
+ in(in_),
+ dict(dict_),
+ use_fuzzy(use_fuzzy_),
+ running(false),
+ eof(false),
+ big5(false),
+ line_number(0),
+ current_line(),
+ conv()
+{
+}
+
+POParser::~POParser()
+{
+}
+
+void
+POParser::warning(const std::string& msg)
+{
+ 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 << filename << ":" << line_number << ": error: " << msg << ": " << current_line << std::endl;
+
+ // Try to recover from an error by searching for start of another entry
+ do
+ next_line();
+ while(!eof && !is_empty_line());
+
+ throw POParserError();
+}
+
+void
+POParser::next_line()
+{
+ line_number += 1;
+ if (!std::getline(in, current_line))
+ eof = true;
+}
+
+void
+POParser::get_string_line(std::ostringstream& out, size_t skip)
+{
+ if (skip+1 >= static_cast<unsigned int>(current_line.size()))
+ error("unexpected end of line");
+
+ if (current_line[skip] != '"')
+ error("expected start of string '\"'");
+
+ std::string::size_type i;
+ for(i = skip+1; current_line[i] != '\"'; ++i)
+ {
+ if (big5 && static_cast<unsigned char>(current_line[i]) >= 0x81 && static_cast<unsigned char>(current_line[i]) <= 0xfe)
+ {
+ out << current_line[i];
+
+ i += 1;
+
+ if (i >= current_line.size())
+ error("invalid big5 encoding");
+
+ out << current_line[i];
+ }
+ else if (i >= current_line.size())
+ {
+ error("unexpected end of string");
+ }
+ else if (current_line[i] == '\\')
+ {
+ i += 1;
+
+ if (i >= current_line.size())
+ error("unexpected end of string in handling '\\'");
+
+ switch (current_line[i])
+ {
+ case 'a': out << '\a'; break;
+ case 'b': out << '\b'; break;
+ case 'v': out << '\v'; break;
+ case 'n': out << '\n'; break;
+ case 't': out << '\t'; break;
+ case 'r': out << '\r'; break;
+ case '"': out << '"'; break;
+ case '\\': out << '\\'; break;
+ default:
+ std::ostringstream err;
+ err << "unhandled escape '\\" << current_line[i] << "'";
+ warning(err.str());
+
+ out << current_line[i-1] << current_line[i];
+ break;
+ }
+ }
+ else
+ {
+ out << current_line[i];
+ }
+ }
+
+ // process trailing garbage in line and warn if there is any
+ for(i = i+1; i < current_line.size(); ++i)
+ if (!isspace(current_line[i]))
+ {
+ warning("unexpected garbage after string ignoren");
+ break;
+ }
+}
+
+std::string
+POParser::get_string(unsigned int skip)
+{
+ std::ostringstream out;
+
+ if (skip+1 >= static_cast<unsigned int>(current_line.size()))
+ error("unexpected end of line");
+
+ if (current_line[skip] == ' ' && current_line[skip+1] == '"')
+ {
+ get_string_line(out, skip+1);
+ }
+ else
+ {
+ if (pedantic)
+ warning("keyword and string must be seperated by a single space");
+
+ for(;;)
+ {
+ if (skip >= static_cast<unsigned int>(current_line.size()))
+ error("unexpected end of line");
+ else if (current_line[skip] == '\"')
+ {
+ get_string_line(out, skip);
+ break;
+ }
+ else if (!isspace(current_line[skip]))
+ {
+ error("string must start with '\"'");
+ }
+ else
+ {
+ // skip space
+ }
+
+ skip += 1;
+ }
+ }
+
+next:
+ next_line();
+ for(std::string::size_type i = 0; i < current_line.size(); ++i)
+ {
+ if (current_line[i] == '"')
+ {
+ if (i == 1)
+ if (pedantic)
+ warning("leading whitespace before string");
+
+ get_string_line(out, i);
+ goto next;
+ }
+ else if (isspace(current_line[i]))
+ {
+ // skip
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ return out.str();
+}
+
+static bool has_prefix(const std::string& lhs, const std::string rhs)
+{
+ if (lhs.length() < rhs.length())
+ return false;
+ else
+ return lhs.compare(0, rhs.length(), rhs) == 0;
+}
+
+void
+POParser::parse_header(const std::string& header)
+{
+ std::string from_charset;
+ std::string::size_type start = 0;
+ for(std::string::size_type i = 0; i < header.length(); ++i)
+ {
+ if (header[i] == '\n')
+ {
+ std::string line = header.substr(start, i - start);
+
+ if (has_prefix(line, "Content-Type:"))
+ {
+ // from_charset = line.substr(len);
+ unsigned int len = strlen("Content-Type: text/plain; charset=");
+ if (line.compare(0, len, "Content-Type: text/plain; charset=") == 0)
+ {
+ from_charset = line.substr(len);
+
+ for(std::string::iterator ch = from_charset.begin(); ch != from_charset.end(); ++ch)
+ *ch = static_cast<char>(toupper(*ch));
+ }
+ else
+ {
+ warning("malformed Content-Type header");
+ }
+ }
+ else if (has_prefix(line, "Plural-Forms:"))
+ {
+ PluralForms plural_forms = PluralForms::from_string(line);
+ if (!plural_forms)
+ {
+ warning("unknown Plural-Forms given");
+ }
+ else
+ {
+ if (!dict.get_plural_forms())
+ {
+ dict.set_plural_forms(plural_forms);
+ }
+ else
+ {
+ if (dict.get_plural_forms() != plural_forms)
+ {
+ warning("Plural-Forms missmatch between .po file and dictionary");
+ }
+ }
+ }
+ }
+ start = i+1;
+ }
+ }
+
+ if (from_charset.empty() || from_charset == "CHARSET")
+ {
+ warning("charset not specified for .po, fallback to utf-8");
+ from_charset = "UTF-8";
+ }
+ else if (from_charset == "BIG5")
+ {
+ big5 = true;
+ }
+
+ conv.set_charsets(from_charset, dict.get_charset());
+}
+
+bool
+POParser::is_empty_line()
+{
+ if (current_line.empty())
+ {
+ return true;
+ }
+ else if (current_line[0] == '#')
+ { // handle comments as empty lines
+ if (current_line.size() == 1 || (current_line.size() >= 2 && isspace(current_line[1])))
+ return true;
+ else
+ return false;
+ }
+ else
+ {
+ for(std::string::iterator i = current_line.begin(); i != current_line.end(); ++i)
+ {
+ if (!isspace(*i))
+ return false;
+ }
+ }
+ return true;
+}
+
+bool
+POParser::prefix(const char* prefix_str)
+{
+ return current_line.compare(0, strlen(prefix_str), prefix_str) == 0;
+}
+
+void
+POParser::parse()
+{
+ next_line();
+
+ // 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<char>(0xef) &&
+ current_line[1] == static_cast<char>(0xbb) &&
+ current_line[2] == static_cast<char>(0xbf))
+ {
+ current_line = current_line.substr(3);
+ }
+
+ // Parser structure
+ while(!eof)
+ {
+ try
+ {
+ bool fuzzy = false;
+ bool has_msgctxt = false;
+ std::string msgctxt;
+ std::string msgid;
+
+ while(prefix("#"))
+ {
+ if (current_line.size() >= 2 && current_line[1] == ',')
+ {
+ // FIXME: Rather simplistic hunt for fuzzy flag
+ if (current_line.find("fuzzy", 2) != std::string::npos)
+ fuzzy = true;
+ }
+
+ next_line();
+ }
+
+ if (!is_empty_line())
+ {
+ if (prefix("msgctxt"))
+ {
+ has_msgctxt = true;
+ msgctxt = get_string(7);
+ }
+
+ if (prefix("msgid"))
+ msgid = get_string(5);
+ else
+ error("expected 'msgid'");
+
+ if (prefix("msgid_plural"))
+ {
+ std::string msgid_plural = get_string(12);
+ std::vector<std::string> msgstr_num;
+ bool saw_nonempty_msgstr = false;
+
+ next:
+ if (is_empty_line())
+ {
+ if (msgstr_num.empty())
+ error("expected 'msgstr[N] (0 <= N <= 9)'");
+ }
+ else if (prefix("msgstr[") &&
+ current_line.size() > 8 &&
+ isdigit(current_line[7]) && current_line[8] == ']')
+ {
+ unsigned int number = static_cast<unsigned int>(current_line[7] - '0');
+ std::string msgstr = get_string(9);
+
+ if(!msgstr.empty())
+ saw_nonempty_msgstr = true;
+
+ if (number >= msgstr_num.size())
+ msgstr_num.resize(number+1);
+
+ msgstr_num[number] = conv.convert(msgstr);
+ goto next;
+ }
+ else
+ {
+ error("expected 'msgstr[N]'");
+ }
+
+ if (!is_empty_line())
+ error("expected 'msgstr[N]' or empty line");
+
+ 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 (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<std::string>::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"))
+ {
+ std::string msgstr = get_string(6);
+
+ if (msgid.empty())
+ {
+ parse_header(msgstr);
+ }
+ else if(!msgstr.empty())
+ {
+ if (use_fuzzy || !fuzzy)
+ {
+ if (has_msgctxt)
+ dict.add_translation(msgctxt, msgid, conv.convert(msgstr));
+ else
+ dict.add_translation(msgid, conv.convert(msgstr));
+ }
+
+ if (0)
+ {
+ std::cout << (fuzzy?"fuzzy":"not-fuzzy") << std::endl;
+ std::cout << "msgid \"" << msgid << "\"" << std::endl;
+ std::cout << "msgstr \"" << conv.convert(msgstr) << "\"" << std::endl;
+ std::cout << std::endl;
+ }
+ }
+ }
+ else
+ {
+ error("expected 'msgstr' or 'msgid_plural'");
+ }
+ }
+
+ if (!is_empty_line())
+ error("expected empty line");
+
+ next_line();
+ }
+ catch(POParserError&)
+ {
+ }
+ }
+}
+
+} // namespace tinygettext
+
+/* EOF */
--- /dev/null
+// tinygettext - A gettext replacement that works directly on .po files
+// Copyright (C) 2006 Ingo Ruhnke <grumbel@gmx.de>
+//
+// 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 */
--- /dev/null
+// tinygettext - A gettext replacement that works directly on .po files
+// Copyright (C) 2009 Ingo Ruhnke <grumbel@gmx.de>
+//
+// 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.
+
+#include "tinygettext/unix_file_system.hpp"
+
+#include <sys/types.h>
+#include <fstream>
+#include <dirent.h>
+#include <stdlib.h>
+#include <dirent.h>
+#include <string.h>
+
+namespace tinygettext {
+
+UnixFileSystem::UnixFileSystem()
+{
+}
+
+std::vector<std::string>
+UnixFileSystem::open_directory(const std::string& pathname)
+{
+ DIR* dir = opendir(pathname.c_str());
+ if (!dir)
+ {
+ // FIXME: error handling
+ return std::vector<std::string>();
+ }
+ else
+ {
+ std::vector<std::string> files;
+
+ struct dirent* dp;
+ while((dp = readdir(dir)) != 0)
+ {
+ files.push_back(dp->d_name);
+ }
+ closedir(dir);
+
+ return files;
+ }
+}
+
+std::unique_ptr<std::istream>
+UnixFileSystem::open_file(const std::string& filename)
+{
+ return std::unique_ptr<std::istream>(new std::ifstream(filename.c_str()));
+}
+
+} // namespace tinygettext
+
+/* EOF */
+++ /dev/null
-// tinygettext - A gettext replacement that works directly on .po files
-// Copyright (C) 2006 Ingo Ruhnke <grumbel@gmx.de>
-//
-// 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.
-
-#include <assert.h>
-#include "log_stream.hpp"
-#include "dictionary.hpp"
-
-namespace tinygettext {
-\f
-Dictionary::Dictionary(const std::string& charset_) :
- entries(),
- ctxt_entries(),
- charset(charset_),
- plural_forms()
-{
-}
-
-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);
- const std::vector<std::string>& msgstrs = i->second;
-
- if (i != dict.end())
- {
- 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;
- 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;
- }
-}
-\f
-void
-Dictionary::add_translation(const std::string& msgid, const std::string& ,
- const std::vector<std::string>& 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<std::string>& vec = entries[msgid];
- if (vec.empty())
- {
- vec.push_back(msgstr);
- }
- else
- {
- 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<std::string>& msgstrs)
-{
- std::vector<std::string>& vec = ctxt_entries[msgctxt][msgid];
- if (vec.empty())
- {
- vec = msgstrs;
- }
- else
- {
- log_warning << "collision in add_translation(\"" << msgctxt << "\", \"" << msgid << "\", \"" << msgid_plural << "\")" << std::endl;
- vec = msgstrs;
- }
-}
-
-void
-Dictionary::add_translation(const std::string& msgctxt, const std::string& msgid, const std::string& msgstr)
-{
- std::vector<std::string>& vec = ctxt_entries[msgctxt][msgid];
- if (vec.empty())
- {
- vec.push_back(msgstr);
- }
- else
- {
- log_warning << "collision in add_translation(\"" << msgctxt << "\", \"" << msgid << "\")" << std::endl;
- vec[0] = msgstr;
- }
-}
-\f
-} // namespace tinygettext
-
-/* EOF */
+++ /dev/null
-// tinygettext - A gettext replacement that works directly on .po files
-// Copyright (C) 2006 Ingo Ruhnke <grumbel@gmx.de>
-//
-// 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_DICTIONARY_HPP
-#define HEADER_TINYGETTEXT_DICTIONARY_HPP
-
-#include <map>
-#include <vector>
-#include <string>
-#include "plural_forms.hpp"
-
-namespace tinygettext {
-
-/** A simple dictionary class that mimics gettext() behaviour. Each
- Dictionary only works for a single language, for managing multiple
- languages and .po files at once use the DictionaryManager. */
-class Dictionary
-{
-private:
- typedef std::map<std::string, std::vector<std::string> > Entries;
- Entries entries;
-
- typedef std::map<std::string, Entries> 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);
-
-public:
- /** Constructs a dictionary converting to the specified \a charset (default UTF-8) */
- Dictionary(const std::string& charset = "UTF-8");
- ~Dictionary();
-
- /** Return the charset used for this dictionary */
- std::string get_charset() const;
-
- void set_plural_forms(const PluralForms&);
- PluralForms get_plural_forms() const;
-
-
- /** Translate the string \a msgid. */
- std::string translate(const std::string& msgid);
-
- /** 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);
-
- /** 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_plural(const std::string& msgctxt, const std::string& msgid, const std::string& msgidplural, int num);
-
- /** 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
- plural form and msgstrs a table of translations. The right
- translation will be calculated based on the \a num argument to
- translate(). */
- void add_translation(const std::string& msgid, const std::string& msgid_plural,
- const std::vector<std::string>& msgstrs);
- void add_translation(const std::string& msgctxt,
- const std::string& msgid, const std::string& msgid_plural,
- const std::vector<std::string>& msgstrs);
-
- /** Add a translation from \a msgid to \a msgstr to the
- dictionary */
- 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);
-
- /** Iterate over all messages, Func is of type:
- void func(const std::string& msgid, const std::vector<std::string>& msgstrs) */
- template<class Func>
- Func foreach(Func func)
- {
- for(Entries::iterator i = entries.begin(); i != entries.end(); ++i)
- {
- func(i->first, i->second);
- }
- return func;
- }
-
- /** Iterate over all messages with a context, Func is of type:
- void func(const std::string& ctxt, const std::string& msgid, const std::vector<std::string>& msgstrs) */
- template<class Func>
- Func foreach_ctxt(Func func)
- {
- for(CtxtEntries::iterator i = ctxt_entries.begin(); i != ctxt_entries.end(); ++i)
- {
- for(Entries::iterator j = i->second.begin(); j != i->second.end(); ++j)
- {
- func(i->first, j->first, j->second);
- }
- }
- return func;
- }
-};
-
-} // namespace tinygettext
-
-#endif
-
-/* EOF */
+++ /dev/null
-// tinygettext - A gettext replacement that works directly on .po files
-// Copyright (C) 2006 Ingo Ruhnke <grumbel@gmx.de>
-//
-// 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.
-
-#include "dictionary_manager.hpp"
-
-#include <memory>
-#include <assert.h>
-#include <stdlib.h>
-#include <string.h>
-#include <fstream>
-#include <algorithm>
-
-#include "log_stream.hpp"
-#include "po_parser.hpp"
-#include "unix_file_system.hpp"
-
-namespace tinygettext {
-
-static bool has_suffix(const std::string& lhs, const std::string rhs)
-{
- if (lhs.length() < rhs.length())
- return false;
- else
- return lhs.compare(lhs.length() - rhs.length(), rhs.length(), rhs) == 0;
-}
-
-DictionaryManager::DictionaryManager(const std::string& charset_) :
- dictionaries(),
- search_path(),
- charset(charset_),
- use_fuzzy(true),
- current_language(),
- current_dict(0),
- empty_dict(),
- filesystem(new UnixFileSystem)
-{
-}
-
-DictionaryManager::~DictionaryManager()
-{
- for(Dictionaries::iterator i = dictionaries.begin(); i != dictionaries.end(); ++i)
- {
- delete i->second;
- }
-}
-
-void
-DictionaryManager::clear_cache()
-{
- for(Dictionaries::iterator i = dictionaries.begin(); i != dictionaries.end(); ++i)
- {
- delete i->second;
- }
- dictionaries.clear();
-
- current_dict = 0;
-}
-
-Dictionary&
-DictionaryManager::get_dictionary()
-{
- if (current_dict)
- {
- return *current_dict;
- }
- else
- {
- if (current_language)
- {
- current_dict = &get_dictionary(current_language);
- return *current_dict;
- }
- else
- {
- return empty_dict;
- }
- }
-}
-
-Dictionary&
-DictionaryManager::get_dictionary(const Language& language)
-{
- //log_debug << "Dictionary for language \"" << spec << "\" requested" << std::endl;
- //log_debug << "...normalized as \"" << lang << "\"" << std::endl;
- assert(language);
-
- Dictionaries::iterator i = dictionaries.find(language);
- if (i != dictionaries.end())
- {
- return *i->second;
- }
- else // Dictionary for languages lang isn't loaded, so we load it
- {
- //log_debug << "get_dictionary: " << lang << std::endl;
- Dictionary* dict = new Dictionary(charset);
-
- dictionaries[language] = dict;
-
- for (SearchPath::reverse_iterator p = search_path.rbegin(); p != search_path.rend(); ++p)
- {
- std::vector<std::string> files = filesystem->open_directory(*p);
-
- std::string best_filename;
- int best_score = 0;
-
- for(std::vector<std::string>::iterator filename = files.begin(); filename != files.end(); filename++)
- {
- // check if filename matches requested language
- if (has_suffix(*filename, ".po"))
- { // ignore anything that isn't a .po file
- Language po_language = Language::from_env(filename->substr(0, filename->size()-3));
-
- if (!po_language)
- {
- log_warning << *filename << ": warning: ignoring, unknown language" << std::endl;
- }
- else
- {
- int score = Language::match(language, po_language);
-
- if (score > best_score)
- {
- best_score = score;
- best_filename = *filename;
- }
- }
- }
- }
-
- if (!best_filename.empty())
- {
- std::string pofile = *p + "/" + best_filename;
- try
- {
- std::auto_ptr<std::istream> in = filesystem->open_file(pofile);
- if (!in.get())
- {
- log_error << "error: failure opening: " << pofile << std::endl;
- }
- else
- {
- POParser::parse(pofile, *in, *dict);
- }
- }
- catch(std::exception& e)
- {
- log_error << "error: failure parsing: " << pofile << std::endl;
- log_error << e.what() << "" << std::endl;
- }
- }
- }
-
- return *dict;
- }
-}
-
-std::set<Language>
-DictionaryManager::get_languages()
-{
- std::set<Language> languages;
-
- for (SearchPath::iterator p = search_path.begin(); p != search_path.end(); ++p)
- {
- std::vector<std::string> files = filesystem->open_directory(*p);
-
- for(std::vector<std::string>::iterator file = files.begin(); file != files.end(); ++file)
- {
- if (has_suffix(*file, ".po"))
- {
- languages.insert(Language::from_env(file->substr(0, file->size()-3)));
- }
- }
- }
- return languages;
-}
-
-void
-DictionaryManager::set_language(const Language& language)
-{
- if (current_language != language)
- {
- current_language = language;
- current_dict = 0;
- }
-}
-
-Language
-DictionaryManager::get_language() const
-{
- return current_language;
-}
-
-void
-DictionaryManager::set_charset(const std::string& charset_)
-{
- clear_cache(); // changing charset invalidates cache
- charset = charset_;
-}
-
-void
-DictionaryManager::set_use_fuzzy(bool t)
-{
- clear_cache();
- use_fuzzy = t;
-}
-
-bool
-DictionaryManager::get_use_fuzzy() const
-{
- return use_fuzzy;
-}
-
-void
-DictionaryManager::add_directory(const std::string& pathname)
-{
- clear_cache(); // adding directories invalidates cache
- search_path.push_back(pathname);
-}
-
-void
-DictionaryManager::set_filesystem(std::auto_ptr<FileSystem> filesystem_)
-{
- filesystem = filesystem_;
-}
-
-} // namespace tinygettext
-
-/* EOF */
+++ /dev/null
-// tinygettext - A gettext replacement that works directly on .po files
-// Copyright (C) 2006 Ingo Ruhnke <grumbel@gmx.de>
-//
-// 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_DICTIONARY_MANAGER_HPP
-#define HEADER_TINYGETTEXT_DICTIONARY_MANAGER_HPP
-
-#include <map>
-#include <set>
-#include <string>
-#include <vector>
-#include <memory>
-
-#include "dictionary.hpp"
-#include "language.hpp"
-
-namespace tinygettext {
-
-class FileSystem;
-
-/** Manager class for dictionaries, you give it a bunch of directories
- with .po files and it will then automatically load the right file
- on demand depending on which language was set. */
-class DictionaryManager
-{
-private:
- typedef std::map<Language, Dictionary*> Dictionaries;
- Dictionaries dictionaries;
-
- typedef std::vector<std::string> SearchPath;
- SearchPath search_path;
-
- std::string charset;
- bool use_fuzzy;
-
- Language current_language;
- Dictionary* current_dict;
-
- Dictionary empty_dict;
-
- std::auto_ptr<FileSystem> filesystem;
-
- void clear_cache();
-
-public:
- DictionaryManager(const std::string& charset_ = "UTF-8");
- ~DictionaryManager();
-
- /** Return the currently active dictionary, if none is set, an empty
- dictionary is returned. */
- Dictionary& get_dictionary();
-
- /** Get dictionary for language */
- Dictionary& get_dictionary(const Language& language);
-
- /** Set a language based on a four? letter country code */
- void set_language(const Language& language);
-
- /** returns the (normalized) country code of the currently used language */
- Language get_language() const;
-
- void set_use_fuzzy(bool t);
- bool get_use_fuzzy() const;
-
- /** Set a charset that will be set on the returned dictionaries */
- 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);
-
- /** Return a set of the available languages in their country code */
- std::set<Language> get_languages();
-
- void set_filesystem(std::auto_ptr<FileSystem> filesystem);
-
-private:
- DictionaryManager (const DictionaryManager&);
- DictionaryManager& operator= (const DictionaryManager&);
-};
-
-} // namespace tinygettext
-
-#endif
-
-/* EOF */
+++ /dev/null
-// tinygettext - A gettext replacement that works directly on .po files
-// Copyright (C) 2009 Ingo Ruhnke <grumbel@gmx.de>
-//
-// 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
-
-#include <vector>
-#include <memory>
-#include <iosfwd>
-#include <string>
-
-namespace tinygettext {
-
-class FileSystem
-{
-public:
- virtual ~FileSystem() {}
-
- virtual std::vector<std::string> open_directory(const std::string& pathname) =0;
- virtual std::auto_ptr<std::istream> open_file(const std::string& filename) =0;
-};
-
-} // namespace tinygettext
-
-#endif
-
-/* EOF */
-
+++ /dev/null
-// tinygettext - A gettext replacement that works directly on .po files
-// Copyright (C) 2009 Ingo Ruhnke <grumbel@gmx.de>
-//
-// 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.
-
-#include <ctype.h>
-#include <assert.h>
-#include <sstream>
-#include <errno.h>
-#include <stdexcept>
-#include <string.h>
-#include <stdlib.h>
-
-#include "iconv.hpp"
-#include "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<char>(toupper(*i));
-
- for(std::string::iterator i = from_charset.begin(); i != from_charset.end(); ++i)
- *i = static_cast<char>(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<tinygettext_iconv_t>(-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<char*>(&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<size_t>(-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(!"tinygettext/iconv.cpp: E2BIG: This should never be reached");
- }
- else if (errno == EBADF)
- {
- assert(!"tinygettext/iconv.cpp: EBADF: This should never be reached");
- }
- else
- {
- assert(!"tinygettext/iconv.cpp: <unknown>: This should never be reached");
- }
- }
-
- result.resize(4*text.size() - outbytesleft);
-
- return result;
- }
-}
-
-} // namespace tinygettext
-
-/* EOF */
+++ /dev/null
-// tinygettext - A gettext replacement that works directly on .po files
-// Copyright (C) 2006 Ingo Ruhnke <grumbel@gmx.de>
-//
-// 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 3 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, see <http://www.gnu.org/licenses/>.
-
-#ifndef HEADER_TINYGETTEXT_ICONV_HPP
-#define HEADER_TINYGETTEXT_ICONV_HPP
-
-#include <string>
-
-#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 <iconv.h>
-
-# 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 */
+++ /dev/null
-// tinygettext - A gettext replacement that works directly on .po files
-// Copyright (C) 2006 Ingo Ruhnke <grumbel@gmx.de>
-//
-// 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.
-
-#include "language.hpp"
-
-#include <map>
-#include <assert.h>
-#include <vector>
-
-namespace tinygettext {
-\f
-struct LanguageSpec {
- /** Language code: "de", "en", ... */
- const char* language;
-
- /** Country code: "BR", "DE", ..., can be 0 */
- const char* country;
-
- /** Modifier/Varint: "Latn", "ije", "latin"..., can be 0 */
- const char* modifier;
-
- /** Language name: "German", "English", "French", ... */
- const char* name;
-};
-\f
-/** Language Definitions */
-//*{
-LanguageSpec languages[] = {
- { "aa", 0, 0, "Afar" },
- { "af", 0, 0, "Afrikaans" },
- { "af", "ZA", 0, "Afrikaans (South Africa)" },
- { "am", 0, 0, "Amharic" },
- { "ar", 0, 0, "Arabic" },
- { "ar", "AR", 0, "Arabic (Argentina)" },
- { "ar", "OM", 0, "Arabic (Oman)" },
- { "ar", "SA", 0, "Arabic (Saudi Arabia)" },
- { "ar", "SY", 0, "Arabic (Syrian Arab Republic)" },
- { "ar", "TN", 0, "Arabic (Tunisia)" },
- { "as", 0, 0, "Assamese" },
- { "ast",0, 0, "Asturian" },
- { "ay", 0, 0, "Aymara" },
- { "az", 0, 0, "Azerbaijani" },
- { "az", "IR", 0, "Azerbaijani (Iran)" },
- { "be", 0, 0, "Belarusian" },
- { "be", 0, "latin", "Belarusian" },
- { "bg", 0, 0, "Bulgarian" },
- { "bg", "BG", 0, "Bulgarian (Bulgaria)" },
- { "bn", 0, 0, "Bengali" },
- { "bn", "BD", 0, "Bengali (Bangladesh)" },
- { "bn", "IN", 0, "Bengali (India)" },
- { "bo", 0, 0, "Tibetan" },
- { "br", 0, 0, "Breton" },
- { "bs", 0, 0, "Bosnian" },
- { "bs", "BA", 0, "Bosnian (Bosnia/Herzegovina)"},
- { "bs", "BS", 0, "Bosnian (Bahamas)" },
- { "ca", "ES", "valencia", "Catalan (valencia)" },
- { "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)" },
- { "cy", 0, 0, "Welsh" },
- { "cy", "GB", 0, "Welsh (Great Britain)" },
- { "cz", 0, 0, "Unknown language" },
- { "da", 0, 0, "Danish" },
- { "da", "DK", 0, "Danish (Denmark)" },
- { "de", 0, 0, "German" },
- { "de", "AT", 0, "German (Austria)" },
- { "de", "CH", 0, "German (Switzerland)" },
- { "de", "DE", 0, "German (Germany)" },
- { "dk", 0, 0, "Unknown language" },
- { "dz", 0, 0, "Dzongkha" },
- { "el", 0, 0, "Greek" },
- { "el", "GR", 0, "Greek (Greece)" },
- { "en", 0, 0, "English" },
- { "en", "AU", 0, "English (Australia)" },
- { "en", "CA", 0, "English (Canada)" },
- { "en", "GB", 0, "English (Great Britain)" },
- { "en", "US", 0, "English (United States)" },
- { "en", "ZA", 0, "English (South Africa)" },
- { "en", 0, "boldquot", "English" },
- { "en", 0, "quot", "English" },
- { "en", "US", "piglatin", "English" },
- { "eo", 0, 0, "Esperanto" },
- { "es", 0, 0, "Spanish" },
- { "es", "AR", 0, "Spanish (Argentina)" },
- { "es", "CL", 0, "Spanish (Chile)" },
- { "es", "CO", 0, "Spanish (Colombia)" },
- { "es", "CR", 0, "Spanish (Costa Rica)" },
- { "es", "DO", 0, "Spanish (Dominican Republic)"},
- { "es", "EC", 0, "Spanish (Ecuador)" },
- { "es", "ES", 0, "Spanish (Spain)" },
- { "es", "GT", 0, "Spanish (Guatemala)" },
- { "es", "HN", 0, "Spanish (Honduras)" },
- { "es", "LA", 0, "Spanish (Laos)" },
- { "es", "MX", 0, "Spanish (Mexico)" },
- { "es", "NI", 0, "Spanish (Nicaragua)" },
- { "es", "PA", 0, "Spanish (Panama)" },
- { "es", "PE", 0, "Spanish (Peru)" },
- { "es", "PR", 0, "Spanish (Puerto Rico)" },
- { "es", "SV", 0, "Spanish (El Salvador)" },
- { "es", "UY", 0, "Spanish (Uruguay)" },
- { "es", "VE", 0, "Spanish (Venezuela)" },
- { "et", 0, 0, "Estonian" },
- { "et", "EE", 0, "Estonian (Estonia)" },
- { "et", "ET", 0, "Estonian (Ethiopia)" },
- { "eu", 0, 0, "Basque" },
- { "eu", "ES", 0, "Basque (Spain)" },
- { "fa", 0, 0, "Persian" },
- { "fa", "AF", 0, "Persian (Afghanistan)" },
- { "fa", "IR", 0, "Persian (Iran)" },
- { "fi", 0, 0, "Finnish" },
- { "fi", "FI", 0, "Finnish (Finland)" },
- { "fo", 0, 0, "Faroese" },
- { "fo", "FO", 0, "Faeroese (Faroe Islands)" },
- { "fr", 0, 0, "French" },
- { "fr", "CA", 0, "French (Canada)" },
- { "fr", "CH", 0, "French (Switzerland)" },
- { "fr", "FR", 0, "French (France)" },
- { "fr", "LU", 0, "French (Luxembourg)" },
- { "fy", 0, 0, "Frisian" },
- { "ga", 0, 0, "Irish" },
- { "gd", 0, 0, "Gaelic Scots" },
- { "gl", 0, 0, "Galician" },
- { "gl", "ES", 0, "Galician (Spain)" },
- { "gn", 0, 0, "Guarani" },
- { "gu", 0, 0, "Gujarati" },
- { "gv", 0, 0, "Manx" },
- { "ha", 0, 0, "Hausa" },
- { "he", 0, 0, "Hebrew" },
- { "he", "IL", 0, "Hebrew (Israel)" },
- { "hi", 0, 0, "Hindi" },
- { "hr", 0, 0, "Croatian" },
- { "hr", "HR", 0, "Croatian (Croatia)" },
- { "hu", 0, 0, "Hungarian" },
- { "hu", "HU", 0, "Hungarian (Hungary)" },
- { "hy", 0, 0, "Armenian" },
- { "ia", 0, 0, "Interlingua" },
- { "id", 0, 0, "Indonesian" },
- { "id", "ID", 0, "Indonesian (Indonesia)" },
- { "is", 0, 0, "Icelandic" },
- { "is", "IS", 0, "Icelandic (Iceland)" },
- { "it", 0, 0, "Italian" },
- { "it", "CH", 0, "Italian (Switzerland)" },
- { "it", "IT", 0, "Italian (Italy)" },
- { "iu", 0, 0, "Inuktitut" },
- { "ja", 0, 0, "Japanese" },
- { "ja", "JP", 0, "Japanese (Japan)" },
- { "ka", 0, 0, "Georgian" },
- { "kk", 0, 0, "Kazakh" },
- { "kl", 0, 0, "Kalaallisut" },
- { "km", 0, 0, "Khmer" },
- { "km", "KH", 0, "Khmer (Cambodia)" },
- { "kn", 0, 0, "Kannada" },
- { "ko", 0, 0, "Korean" },
- { "ko", "KR", 0, "Korean (Korea)" },
- { "ku", 0, 0, "Kurdish" },
- { "kw", 0, 0, "Cornish" },
- { "ky", 0, 0, "Kirghiz" },
- { "la", 0, 0, "Latin" },
- { "lo", 0, 0, "Lao" },
- { "lt", 0, 0, "Lithuanian" },
- { "lt", "LT", 0, "Lithuanian (Lithuania)" },
- { "lv", 0, 0, "Latvian" },
- { "lv", "LV", 0, "Latvian (Latvia)" },
- { "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" },
- { "mr", 0, 0, "Marathi" },
- { "ms", 0, 0, "Malay" },
- { "ms", "MY", 0, "Malay (Malaysia)" },
- { "mt", 0, 0, "Maltese" },
- { "my", 0, 0, "Burmese" },
- { "my", "MM", 0, "Burmese (Myanmar)" },
- { "nb", 0, 0, "Norwegian Bokmal" },
- { "nb", "NO", 0, "Norwegian Bokmål (Norway)" },
- { "ne", 0, 0, "Nepali" },
- { "nl", 0, 0, "Dutch" },
- { "nl", "BE", 0, "Dutch (Belgium)" },
- { "nl", "NL", 0, "Dutch (Netherlands)" },
- { "nn", 0, 0, "Norwegian Nynorsk" },
- { "nn", "NO", 0, "Norwegian Nynorsk (Norway)" },
- { "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" },
- { "pa", 0, 0, "Punjabi" },
- { "pl", 0, 0, "Polish" },
- { "pl", "PL", 0, "Polish (Poland)" },
- { "ps", 0, 0, "Pashto" },
- { "pt", 0, 0, "Portuguese" },
- { "pt", "BR", 0, "Brazilian" },
- { "pt", "PT", 0, "Portuguese (Portugal)" },
- { "qu", 0, 0, "Quechua" },
- { "rm", 0, 0, "Rhaeto-Romance" },
- { "ro", 0, 0, "Romanian" },
- { "ro", "RO", 0, "Romanian (Romania)" },
- { "ru", 0, 0, "Russian" },
- { "ru", "RU", 0, "Russian (Russia" },
- { "rw", 0, 0, "Kinyarwanda" },
- { "sa", 0, 0, "Sanskrit" },
- { "sd", 0, 0, "Sindhi" },
- { "se", 0, 0, "Sami" },
- { "se", "NO", 0, "Sami (Norway)" },
- { "si", 0, 0, "Sinhalese" },
- { "sk", 0, 0, "Slovak" },
- { "sk", "SK", 0, "Slovak (Slovakia)" },
- { "sl", 0, 0, "Slovenian" },
- { "sl", "SI", 0, "Slovenian (Slovenia)" },
- { "sl", "SL", 0, "Slovenian (Sierra Leone)" },
- { "sm", 0, 0, "Samoan" },
- { "so", 0, 0, "Somali" },
- { "sp", 0, 0, "Unknown language" },
- { "sq", 0, 0, "Albanian" },
- { "sq", "AL", 0, "Albanian (Albania)" },
- { "sr", 0, 0, "Serbian" },
- { "sr", "YU", 0, "Serbian (Yugoslavia)" },
- { "sr", 0,"ije", "Serbian" },
- { "sr", 0, "latin", "Serbian" },
- { "sr", 0, "Latn", "Serbian" },
- { "ss", 0, 0, "Swati" },
- { "st", 0, 0, "Sotho" },
- { "sv", 0, 0, "Swedish" },
- { "sv", "SE", 0, "Swedish (Sweden)" },
- { "sv", "SV", 0, "Swedish (El Salvador)" },
- { "sw", 0, 0, "Swahili" },
- { "ta", 0, 0, "Tamil" },
- { "te", 0, 0, "Telugu" },
- { "tg", 0, 0, "Tajik" },
- { "th", 0, 0, "Thai" },
- { "th", "TH", 0, "Thai (Thailand)" },
- { "ti", 0, 0, "Tigrinya" },
- { "tk", 0, 0, "Turkmen" },
- { "tl", 0, 0, "Tagalog" },
- { "to", 0, 0, "Tonga" },
- { "tr", 0, 0, "Turkish" },
- { "tr", "TR", 0, "Turkish (Turkey)" },
- { "ts", 0, 0, "Tsonga" },
- { "tt", 0, 0, "Tatar" },
- { "ug", 0, 0, "Uighur" },
- { "uk", 0, 0, "Ukrainian" },
- { "uk", "UA", 0, "Ukrainian (Ukraine)" },
- { "ur", 0, 0, "Urdu" },
- { "ur", "PK", 0, "Urdu (Pakistan)" },
- { "uz", 0, 0, "Uzbek" },
- { "uz", 0, "cyrillic", "Uzbek" },
- { "vi", 0, 0, "Vietnamese" },
- { "vi", "VN", 0, "Vietnamese (Vietnam)" },
- { "wa", 0, 0, "Walloon" },
- { "wo", 0, 0, "Wolof" },
- { "xh", 0, 0, "Xhosa" },
- { "yi", 0, 0, "Yiddish" },
- { "yo", 0, 0, "Yoruba" },
- { "zh", 0, 0, "Chinese" },
- { "zh", "CN", 0, "Chinese (simplified)" },
- { "zh", "HK", 0, "Chinese (Hong Kong)" },
- { "zh", "TW", 0, "Chinese (traditional)" },
- { "zu", 0, 0, "Zulu" },
- { NULL, 0, 0, NULL }
-};
-//*}
-\f
-std::string
-resolve_language_alias(const std::string& name)
-{
- typedef std::map<std::string, std::string> Aliases;
- static Aliases language_aliases;
- if (language_aliases.empty())
- {
- // FIXME: Many of those are not useful for us, since we leave
- // encoding to the app, not to the language, we could/should
- // also match against all language names, not just aliases from
- // locale.alias
-
- // Aliases taken from /etc/locale.alias
- language_aliases["bokmal"] = "nb_NO.ISO-8859-1";
- language_aliases["bokmål"] = "nb_NO.ISO-8859-1";
- language_aliases["catalan"] = "ca_ES.ISO-8859-1";
- language_aliases["croatian"] = "hr_HR.ISO-8859-2";
- language_aliases["czech"] = "cs_CZ.ISO-8859-2";
- language_aliases["danish"] = "da_DK.ISO-8859-1";
- language_aliases["dansk"] = "da_DK.ISO-8859-1";
- language_aliases["deutsch"] = "de_DE.ISO-8859-1";
- language_aliases["dutch"] = "nl_NL.ISO-8859-1";
- language_aliases["eesti"] = "et_EE.ISO-8859-1";
- language_aliases["estonian"] = "et_EE.ISO-8859-1";
- language_aliases["finnish"] = "fi_FI.ISO-8859-1";
- language_aliases["français"] = "fr_FR.ISO-8859-1";
- language_aliases["french"] = "fr_FR.ISO-8859-1";
- language_aliases["galego"] = "gl_ES.ISO-8859-1";
- language_aliases["galician"] = "gl_ES.ISO-8859-1";
- language_aliases["german"] = "de_DE.ISO-8859-1";
- language_aliases["greek"] = "el_GR.ISO-8859-7";
- language_aliases["hebrew"] = "he_IL.ISO-8859-8";
- language_aliases["hrvatski"] = "hr_HR.ISO-8859-2";
- language_aliases["hungarian"] = "hu_HU.ISO-8859-2";
- language_aliases["icelandic"] = "is_IS.ISO-8859-1";
- language_aliases["italian"] = "it_IT.ISO-8859-1";
- language_aliases["japanese"] = "ja_JP.eucJP";
- language_aliases["japanese.euc"] = "ja_JP.eucJP";
- language_aliases["ja_JP"] = "ja_JP.eucJP";
- language_aliases["ja_JP.ujis"] = "ja_JP.eucJP";
- language_aliases["japanese.sjis"] = "ja_JP.SJIS";
- language_aliases["korean"] = "ko_KR.eucKR";
- language_aliases["korean.euc"] = "ko_KR.eucKR";
- language_aliases["ko_KR"] = "ko_KR.eucKR";
- language_aliases["lithuanian"] = "lt_LT.ISO-8859-13";
- language_aliases["no_NO"] = "nb_NO.ISO-8859-1";
- language_aliases["no_NO.ISO-8859-1"] = "nb_NO.ISO-8859-1";
- language_aliases["norwegian"] = "nb_NO.ISO-8859-1";
- language_aliases["nynorsk"] = "nn_NO.ISO-8859-1";
- language_aliases["polish"] = "pl_PL.ISO-8859-2";
- language_aliases["portuguese"] = "pt_PT.ISO-8859-1";
- language_aliases["romanian"] = "ro_RO.ISO-8859-2";
- language_aliases["russian"] = "ru_RU.ISO-8859-5";
- language_aliases["slovak"] = "sk_SK.ISO-8859-2";
- language_aliases["slovene"] = "sl_SI.ISO-8859-2";
- language_aliases["slovenian"] = "sl_SI.ISO-8859-2";
- language_aliases["spanish"] = "es_ES.ISO-8859-1";
- language_aliases["swedish"] = "sv_SE.ISO-8859-1";
- language_aliases["thai"] = "th_TH.TIS-620";
- language_aliases["turkish"] = "tr_TR.ISO-8859-9";
- }
-
- std::string name_lowercase;
- name_lowercase.resize(name.size());
- for(std::string::size_type i = 0; i < name.size(); ++i)
- name_lowercase[i] = static_cast<char>(tolower(name[i]));
-
- Aliases::iterator i = language_aliases.find(name_lowercase);
- if (i != language_aliases.end())
- {
- return i->second;
- }
- else
- {
- return name;
- }
-}
-\f
-Language
-Language::from_spec(const std::string& language, const std::string& country, const std::string& modifier)
-{
- static std::map<std::string, std::vector<LanguageSpec*> > language_map;
-
- if (language_map.empty())
- { // Init language_map
- for(int i = 0; languages[i].language != NULL; ++i)
- language_map[languages[i].language].push_back(&languages[i]);
- }
-
- std::map<std::string, std::vector<LanguageSpec*> >::iterator i = language_map.find(language);
- if (i != language_map.end())
- {
- std::vector<LanguageSpec*>& lst = i->second;
-
- LanguageSpec tmpspec;
- tmpspec.language = language.c_str();
- tmpspec.country = country.c_str();
- tmpspec.modifier = modifier.c_str();
- Language tmplang(&tmpspec);
-
- LanguageSpec* best_match = 0;
- int best_match_score = 0;
- for(std::vector<LanguageSpec*>::iterator j = lst.begin(); j != lst.end(); ++j)
- { // Search for the language that best matches the given spec, value country more then modifier
- int score = Language::match(Language(*j), tmplang);
-
- if (score > best_match_score)
- {
- best_match = *j;
- best_match_score = score;
- }
- }
- assert(best_match);
- return Language(best_match);
- }
- else
- {
- return Language();
- }
-}
-
-Language
-Language::from_name(const std::string& spec_str)
-{
- return from_env(resolve_language_alias(spec_str));
-}
-
-Language
-Language::from_env(const std::string& env)
-{
- // Split LANGUAGE_COUNTRY.CODESET@MODIFIER into parts
- std::string::size_type ln = env.find('_');
- std::string::size_type dt = env.find('.');
- std::string::size_type at = env.find('@');
-
- std::string language;
- std::string country;
- std::string codeset;
- std::string modifier;
-
- //std::cout << ln << " " << dt << " " << at << std::endl;
-
- language = env.substr(0, std::min(std::min(ln, dt), at));
-
- 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));
- }
-
- if (dt != std::string::npos && dt+1 < env.size()) // .
- {
- codeset = env.substr(dt+1, (at == std::string::npos) ? std::string::npos : (at - (dt+1)));
- }
-
- if (at != std::string::npos && at+1 < env.size()) // @
- {
- modifier = env.substr(at+1);
- }
-
- return from_spec(language, country, modifier);
-}
-\f
-Language::Language(LanguageSpec* language_spec_)
- : language_spec(language_spec_)
-{
-}
-
-Language::Language()
- : language_spec(0)
-{
-}
-
-int
-Language::match(const Language& lhs, const Language& rhs)
-{
- if (lhs.get_language() != rhs.get_language())
- {
- return 0;
- }
- else
- {
- static int match_tbl[3][3] = {
- // modifier match, wildchard, miss
- { 9, 8, 5 }, // country match
- { 7, 6, 3 }, // country wildcard
- { 4, 2, 1 }, // country miss
- };
-
- int c;
- if (lhs.get_country() == rhs.get_country())
- c = 0;
- else if (lhs.get_country().empty() || rhs.get_country().empty())
- c = 1;
- else
- c = 2;
-
- int m;
- if (lhs.get_modifier() == rhs.get_modifier())
- m = 0;
- else if (lhs.get_modifier().empty() || rhs.get_modifier().empty())
- m = 1;
- else
- m = 2;
-
- return match_tbl[c][m];
- }
-}
-
-std::string
-Language::get_language() const
-{
- if (language_spec)
- return language_spec->language;
- else
- return "";
-}
-
-std::string
-Language::get_country() const
-{
- if (language_spec && language_spec->country)
- return language_spec->country;
- else
- return "";
-}
-
-std::string
-Language::get_modifier() const
-{
- if (language_spec && language_spec->modifier)
- return language_spec->modifier;
- else
- return "";
-}
-
-std::string
-Language::get_name() const
-{
- if (language_spec)
- return language_spec->name;
- else
- return "";
-}
-
-std::string
-Language::str() const
-{
- if (language_spec)
- {
- std::string var;
- var += language_spec->language;
- if (language_spec->country)
- {
- var += "_";
- var += language_spec->country;
- }
-
- if (language_spec->modifier)
- {
- var += "@";
- var += language_spec->modifier;
- }
- return var;
- }
- else
- {
- return "";
- }
-}
-
-bool
-Language::operator==(const Language& rhs)
-{
- return language_spec == rhs.language_spec;
-}
-
-bool
-Language::operator!=(const Language& rhs)
-{
- return language_spec != rhs.language_spec;
-}
-\f
-} // namespace tinygettext
-
-/* EOF */
+++ /dev/null
-// tinygettext - A gettext replacement that works directly on .po files
-// Copyright (C) 2006 Ingo Ruhnke <grumbel@gmx.de>
-//
-// 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_LANGUAGE_HPP
-#define HEADER_TINYGETTEXT_LANGUAGE_HPP
-
-#include <string>
-
-namespace tinygettext {
-
-struct LanguageSpec;
-
-/** Lightweight wrapper around LanguageSpec */
-class Language
-{
-private:
- LanguageSpec* language_spec;
-
- Language(LanguageSpec* language_spec);
-
-public:
- /** Create a language from language and country code:
- Example: Languge("de", "DE"); */
- static Language from_spec(const std::string& language,
- const std::string& country = std::string(),
- const std::string& modifier = std::string());
-
- /** Create a language from language and country code:
- Example: Languge("deutsch");
- Example: Languge("de_DE"); */
- static Language from_name(const std::string& str);
-
- /** 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 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);
-
- /** Create an undefined Language object */
- Language();
-
- operator bool() const { return language_spec; }
-
- /** Returns the language code (i.e. de, en, fr) */
- std::string get_language() const;
-
- /** Returns the country code (i.e. DE, AT, US) */
- std::string get_country() const;
-
- /** Returns the modifier of the language (i.e. latn or Latn for
- Serbian with non-cyrilic characters) */
- std::string get_modifier() const;
-
- /** Returns the human readable name of the Language */
- std::string get_name() const;
-
- /** Returns the Language as string in the form of an environment
- variable: {language}_{country}@{modifier} */
- std::string str() const;
-
- bool operator==(const Language& rhs);
- bool operator!=(const Language& rhs);
-
- friend bool operator<(const Language& lhs, const Language& rhs);
-};
-
-inline bool operator<(const Language& lhs, const Language& rhs) {
- return lhs.language_spec < rhs.language_spec;
-}
-
-} // namespace tinygettext
-
-#endif
-
-/* EOF */
+++ /dev/null
-// tinygettext - A gettext replacement that works directly on .po files
-// Copyright (C) 2009 Ingo Ruhnke <grumbel@gmx.de>
-//
-// 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.
-
-#include <iostream>
-#include "log.hpp"
-
-namespace tinygettext {
-\f
-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;
-\f
-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;
-}
-\f
-Log::Log(log_callback_t callback_) :
- callback(callback_),
- out()
-{
-}
-
-Log::~Log()
-{
- callback(out.str());
-}
-
-std::ostream&
-Log::get()
-{
- return out;
-}
-\f
-} // namespace tinygettext
-
-/* EOF */
+++ /dev/null
-// tinygettext - A gettext replacement that works directly on .po files
-// Copyright (C) 2009 Ingo Ruhnke <grumbel@gmx.de>
-//
-// 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_LOG_HPP
-#define HEADER_TINYGETTEXT_LOG_HPP
-
-#include <sstream>
-
-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 */
+++ /dev/null
-// tinygettext - A gettext replacement that works directly on .po files
-// Copyright (C) 2009 Ingo Ruhnke <grumbel@gmx.de>
-//
-// 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_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 */
+++ /dev/null
-// tinygettext - A gettext replacement that works directly on .po files
-// Copyright (C) 2006 Ingo Ruhnke <grumbel@gmx.de>
-//
-// 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.
-
-#include "plural_forms.hpp"
-
-#include <map>
-
-namespace tinygettext {
-\f
-/**
- * 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<unsigned int>(n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2); }
-unsigned int plural3_ga(int n) { return static_cast<unsigned int>(n==1 ? 0 : n==2 ? 1 : 2); }
-unsigned int plural3_lt(int n) { return static_cast<unsigned int>(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<unsigned int>(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<unsigned int>( (n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2 ); }
-unsigned int plural3_pl(int n) { return static_cast<unsigned int>(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<unsigned int>(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3); }
-unsigned int plural4_ar(int n) { return static_cast<unsigned int>( n==1 ? 0 : n==2 ? 1 : n>=3 && n<=10 ? 2 : 3 ); }
-\f
-PluralForms
-PluralForms::from_string(const std::string& str)
-{
- static std::map<std::string, struct PluralForms> 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?0:n==2?1:n>=3&&n<=10?2:3;"]=PluralForms(4, plural4_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];
-
- std::map<std::string, struct PluralForms>::const_iterator it= plural_forms.find(space_less_str);
- if (it != plural_forms.end())
- {
- return it->second;
- }
- else
- {
- return PluralForms();
- }
-}
-
-} // namespace tinygettext
-
-/* EOF */
+++ /dev/null
-// tinygettext - A gettext replacement that works directly on .po files
-// Copyright (C) 2006 Ingo Ruhnke <grumbel@gmx.de>
-//
-// 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
-
-#include <string>
-
-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;
- }
-};
-
-} // namespace tinygettext
-
-#endif
-
-/* EOF */
+++ /dev/null
-// tinygettext - A gettext replacement that works directly on .po files
-// Copyright (C) 2009 Ingo Ruhnke <grumbel@gmx.de>
-//
-// 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.
-
-#include "po_parser.hpp"
-
-#include <iostream>
-#include <ctype.h>
-#include <string>
-#include <istream>
-#include <string.h>
-#include <map>
-#include <stdlib.h>
-
-#include "language.hpp"
-#include "log_stream.hpp"
-#include "iconv.hpp"
-#include "dictionary.hpp"
-#include "plural_forms.hpp"
-
-namespace tinygettext {
-
-bool POParser::pedantic = true;
-\f
-void
-POParser::parse(const std::string& filename, std::istream& in, Dictionary& dict)
-{
- POParser parser(filename, in, dict);
- parser.parse();
-}
-\f
-class POParserError {};
-
-POParser::POParser(const std::string& filename_, std::istream& in_, Dictionary& dict_, bool use_fuzzy_) :
- filename(filename_),
- in(in_),
- dict(dict_),
- use_fuzzy(use_fuzzy_),
- running(false),
- eof(false),
- big5(false),
- line_number(0),
- current_line(),
- conv()
-{
-}
-
-POParser::~POParser()
-{
-}
-
-void
-POParser::warning(const std::string& msg)
-{
- 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 << filename << ":" << line_number << ": error: " << msg << ": " << current_line << std::endl;
-
- // Try to recover from an error by searching for start of another entry
- do
- next_line();
- while(!eof && !is_empty_line());
-
- throw POParserError();
-}
-
-void
-POParser::next_line()
-{
- line_number += 1;
- if (!std::getline(in, current_line))
- eof = true;
-}
-
-void
-POParser::get_string_line(std::ostringstream& out,unsigned int skip)
-{
- if (skip+1 >= static_cast<unsigned int>(current_line.size()))
- error("unexpected end of line");
-
- if (current_line[skip] != '"')
- error("expected start of string '\"'");
-
- std::string::size_type i;
- for(i = skip+1; current_line[i] != '\"'; ++i)
- {
- if (big5 && static_cast<unsigned char>(current_line[i]) >= 0x81 && static_cast<unsigned char>(current_line[i]) <= 0xfe)
- {
- out << current_line[i];
-
- i += 1;
-
- if (i >= current_line.size())
- error("invalid big5 encoding");
-
- out << current_line[i];
- }
- else if (i >= current_line.size())
- {
- error("unexpected end of string");
- }
- else if (current_line[i] == '\\')
- {
- i += 1;
-
- if (i >= current_line.size())
- error("unexpected end of string in handling '\\'");
-
- switch (current_line[i])
- {
- case 'a': out << '\a'; break;
- case 'b': out << '\b'; break;
- case 'v': out << '\v'; break;
- case 'n': out << '\n'; break;
- case 't': out << '\t'; break;
- case 'r': out << '\r'; break;
- case '"': out << '"'; break;
- case '\\': out << '\\'; break;
- default:
- std::ostringstream err;
- err << "unhandled escape '\\" << current_line[i] << "'";
- warning(err.str());
-
- out << current_line[i-1] << current_line[i];
- break;
- }
- }
- else
- {
- out << current_line[i];
- }
- }
-
- // process trailing garbage in line and warn if there is any
- for(i = i+1; i < current_line.size(); ++i)
- if (!isspace(current_line[i]))
- {
- warning("unexpected garbage after string ignoren");
- break;
- }
-}
-
-std::string
-POParser::get_string(unsigned int skip)
-{
- std::ostringstream out;
-
- if (skip+1 >= static_cast<unsigned int>(current_line.size()))
- error("unexpected end of line");
-
- if (current_line[skip] == ' ' && current_line[skip+1] == '"')
- {
- get_string_line(out, skip+1);
- }
- else
- {
- if (pedantic)
- warning("keyword and string must be seperated by a single space");
-
- for(;;)
- {
- if (skip >= static_cast<unsigned int>(current_line.size()))
- error("unexpected end of line");
- else if (current_line[skip] == '\"')
- {
- get_string_line(out, skip);
- break;
- }
- else if (!isspace(current_line[skip]))
- {
- error("string must start with '\"'");
- }
- else
- {
- // skip space
- }
-
- skip += 1;
- }
- }
-
-next:
- next_line();
- for(std::string::size_type i = 0; i < current_line.size(); ++i)
- {
- if (current_line[i] == '"')
- {
- if (i == 1)
- if (pedantic)
- warning("leading whitespace before string");
-
- get_string_line(out, i);
- goto next;
- }
- else if (isspace(current_line[i]))
- {
- // skip
- }
- else
- {
- break;
- }
- }
-
- return out.str();
-}
-
-static bool has_prefix(const std::string& lhs, const std::string rhs)
-{
- if (lhs.length() < rhs.length())
- return false;
- else
- return lhs.compare(0, rhs.length(), rhs) == 0;
-}
-
-void
-POParser::parse_header(const std::string& header)
-{
- std::string from_charset;
- std::string::size_type start = 0;
- for(std::string::size_type i = 0; i < header.length(); ++i)
- {
- if (header[i] == '\n')
- {
- std::string line = header.substr(start, i - start);
-
- if (has_prefix(line, "Content-Type:"))
- {
- // from_charset = line.substr(len);
- unsigned int len = strlen("Content-Type: text/plain; charset=");
- if (line.compare(0, len, "Content-Type: text/plain; charset=") == 0)
- {
- from_charset = line.substr(len);
-
- for(std::string::iterator ch = from_charset.begin(); ch != from_charset.end(); ++ch)
- *ch = static_cast<char>(toupper(*ch));
- }
- else
- {
- warning("malformed Content-Type header");
- }
- }
- else if (has_prefix(line, "Plural-Forms:"))
- {
- PluralForms plural_forms = PluralForms::from_string(line);
- if (!plural_forms)
- {
- warning("unknown Plural-Forms given");
- }
- else
- {
- if (!dict.get_plural_forms())
- {
- dict.set_plural_forms(plural_forms);
- }
- else
- {
- if (dict.get_plural_forms() != plural_forms)
- {
- warning("Plural-Forms missmatch between .po file and dictionary");
- }
- }
- }
- }
- start = i+1;
- }
- }
-
- if (from_charset.empty() || from_charset == "CHARSET")
- {
- warning("charset not specified for .po, fallback to utf-8");
- from_charset = "UTF-8";
- }
- else if (from_charset == "BIG5")
- {
- big5 = true;
- }
-
- conv.set_charsets(from_charset, dict.get_charset());
-}
-
-bool
-POParser::is_empty_line()
-{
- if (current_line.empty())
- {
- return true;
- }
- else if (current_line[0] == '#')
- { // handle comments as empty lines
- if (current_line.size() == 1 || (current_line.size() >= 2 && isspace(current_line[1])))
- return true;
- else
- return false;
- }
- else
- {
- for(std::string::iterator i = current_line.begin(); i != current_line.end(); ++i)
- {
- if (!isspace(*i))
- return false;
- }
- }
- return true;
-}
-
-bool
-POParser::prefix(const char* prefix_str)
-{
- return current_line.compare(0, strlen(prefix_str), prefix_str) == 0;
-}
-
-void
-POParser::parse()
-{
- next_line();
-
- // 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<char>(0xef) &&
- current_line[1] == static_cast<char>(0xbb) &&
- current_line[2] == static_cast<char>(0xbf))
- {
- current_line = current_line.substr(3);
- }
-
- // Parser structure
- while(!eof)
- {
- try
- {
- bool fuzzy = false;
- bool has_msgctxt = false;
- std::string msgctxt;
- std::string msgid;
-
- while(prefix("#"))
- {
- if (current_line.size() >= 2 && current_line[1] == ',')
- {
- // FIXME: Rather simplistic hunt for fuzzy flag
- if (current_line.find("fuzzy", 2) != std::string::npos)
- fuzzy = true;
- }
-
- next_line();
- }
-
- if (!is_empty_line())
- {
- if (prefix("msgctxt"))
- {
- has_msgctxt = true;
- msgctxt = get_string(7);
- }
-
- if (prefix("msgid"))
- msgid = get_string(5);
- else
- error("expected 'msgid'");
-
- if (prefix("msgid_plural"))
- {
- std::string msgid_plural = get_string(12);
- std::vector<std::string> msgstr_num;
- bool saw_nonempty_msgstr = false;
-
- next:
- if (is_empty_line())
- {
- if (msgstr_num.empty())
- error("expected 'msgstr[N] (0 <= N <= 9)'");
- }
- else if (prefix("msgstr[") &&
- current_line.size() > 8 &&
- isdigit(current_line[7]) && current_line[8] == ']')
- {
- unsigned int number = static_cast<unsigned int>(current_line[7] - '0');
- std::string msgstr = get_string(9);
-
- if(!msgstr.empty())
- saw_nonempty_msgstr = true;
-
- if (number >= msgstr_num.size())
- msgstr_num.resize(number+1);
-
- msgstr_num[number] = conv.convert(msgstr);
- goto next;
- }
- else
- {
- error("expected 'msgstr[N]'");
- }
-
- if (!is_empty_line())
- error("expected 'msgstr[N]' or empty line");
-
- 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 (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<std::string>::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"))
- {
- std::string msgstr = get_string(6);
-
- if (msgid.empty())
- {
- parse_header(msgstr);
- }
- else if(!msgstr.empty())
- {
- if (use_fuzzy || !fuzzy)
- {
- if (has_msgctxt)
- dict.add_translation(msgctxt, msgid, conv.convert(msgstr));
- else
- dict.add_translation(msgid, conv.convert(msgstr));
- }
-
- if (0)
- {
- std::cout << (fuzzy?"fuzzy":"not-fuzzy") << std::endl;
- std::cout << "msgid \"" << msgid << "\"" << std::endl;
- std::cout << "msgstr \"" << conv.convert(msgstr) << "\"" << std::endl;
- std::cout << std::endl;
- }
- }
- }
- else
- {
- error("expected 'msgstr' or 'msgid_plural'");
- }
- }
-
- if (!is_empty_line())
- error("expected empty line");
-
- next_line();
- }
- catch(POParserError&)
- {
- }
- }
-}
-
-} // namespace tinygettext
-
-/* EOF */
+++ /dev/null
-// tinygettext - A gettext replacement that works directly on .po files
-// Copyright (C) 2009 Ingo Ruhnke <grumbel@gmx.de>
-//
-// 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_PO_PARSER_HPP
-#define HEADER_TINYGETTEXT_PO_PARSER_HPP
-
-#include <iosfwd>
-
-#include "iconv.hpp"
-
-namespace tinygettext {
-
-class Dictionary;
-
-class POParser
-{
-private:
- std::string filename;
- std::istream& in;
- Dictionary& dict;
- bool use_fuzzy;
-
- bool running;
- bool eof;
- bool big5;
-
- int line_number;
- std::string current_line;
-
- IConv conv;
-
- POParser(const std::string& filename, std::istream& in_, Dictionary& dict_, bool use_fuzzy = true);
- ~POParser();
-
- void parse_header(const std::string& header);
- void parse();
- void next_line();
- std::string get_string(unsigned int skip);
- void get_string_line(std::ostringstream& str,unsigned int skip);
- bool is_empty_line();
- bool prefix(const char* );
- void error(const std::string& msg) __attribute__((__noreturn__));
- void warning(const std::string& msg);
-
-public:
- /** @param filename name of the istream, only used in error messages
- @param in stream from which the PO file is read.
- @param dict dictionary to which the strings are written */
- static void parse(const std::string& filename, std::istream& in, Dictionary& dict);
- static bool pedantic;
-
-private:
- POParser (const POParser&);
- POParser& operator= (const POParser&);
-};
-
-} // namespace tinygettext
-
-#endif
-
-/* EOF */
+++ /dev/null
-// tinygettext - A gettext replacement that works directly on .po files
-// Copyright (C) 2006 Ingo Ruhnke <grumbel@gmx.de>
-//
-// 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 */
+++ /dev/null
-// tinygettext - A gettext replacement that works directly on .po files
-// Copyright (C) 2006 Ingo Ruhnke <grumbel@gmx.de>
-//
-// 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 */
+++ /dev/null
-// tinygettext - A gettext replacement that works directly on .po files
-// Copyright (C) 2009 Ingo Ruhnke <grumbel@gmx.de>
-//
-// 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.
-
-#include "unix_file_system.hpp"
-
-#include <sys/types.h>
-#include <fstream>
-#include <dirent.h>
-#include <stdlib.h>
-#include <dirent.h>
-#include <string.h>
-
-namespace tinygettext {
-
-UnixFileSystem::UnixFileSystem()
-{
-}
-
-std::vector<std::string>
-UnixFileSystem::open_directory(const std::string& pathname)
-{
- DIR* dir = opendir(pathname.c_str());
- if (!dir)
- {
- // FIXME: error handling
- return std::vector<std::string>();
- }
- else
- {
- std::vector<std::string> files;
-
- struct dirent* dp;
- while((dp = readdir(dir)) != 0)
- {
- files.push_back(dp->d_name);
- }
- closedir(dir);
-
- return files;
- }
-}
-
-std::auto_ptr<std::istream>
-UnixFileSystem::open_file(const std::string& filename)
-{
- return std::auto_ptr<std::istream>(new std::ifstream(filename.c_str()));
-}
-
-} // namespace tinygettext
-
-/* EOF */
+++ /dev/null
-// tinygettext - A gettext replacement that works directly on .po files
-// Copyright (C) 2009 Ingo Ruhnke <grumbel@gmx.de>
-//
-// 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_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<std::string> open_directory(const std::string& pathname);
- std::auto_ptr<std::istream> open_file(const std::string& filename);
-};
-
-} // namespace tinygettext
-
-#endif
-
-/* EOF */