--- /dev/null
+#
+# TinyGetText build script
+# Copyright (C) 2006 Christoph Sommer <christoph.sommer@2006.expires.deltadevelopment.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
+#
+
+
+#
+# INSTRUCTIONS:
+# -------------
+#
+# Create a directory build/ and change to it. Run
+#
+# cmake ..
+#
+# This creates a set of Makefiles to build the project. Run
+#
+# make
+#
+
+
+CMAKE_POLICY(SET CMP0005 NEW)
+
+## Project name to use as command prefix
+
+PROJECT(tinygettext)
+SET(VERSION "0.1")
+
+### CMake configuration
+
+CMAKE_MINIMUM_REQUIRED(VERSION 2.4)
+IF(COMMAND cmake_policy)
+ CMAKE_POLICY(SET CMP0003 NEW)
+ENDIF(COMMAND cmake_policy)
+SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${tinygettext_SOURCE_DIR})
+
+# move some config clutter to the advanced section
+MARK_AS_ADVANCED(
+ CMAKE_BACKWARDS_COMPATIBILITY
+ CMAKE_BUILD_TYPE
+ CMAKE_INSTALL_PREFIX
+ EXECUTABLE_OUTPUT_PATH
+ CMAKE_OSX_ARCHITECTURES
+ CMAKE_OSX_SYSROOT
+)
+
+## Reveal library type choice to users
+OPTION(BUILD_SHARED_LIBS "Produce dynamic library instead of static archive" ON)
+
+## Add iconv to include directories
+
+FIND_PACKAGE(ICONV REQUIRED)
+INCLUDE_DIRECTORIES(${ICONV_INCLUDE_DIR})
+
+## Check iconv_const
+
+INCLUDE(CheckCXXSourceCompiles)
+
+SET(CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES} ${ICONV_INCLUDE_DIR})
+CHECK_CXX_SOURCE_COMPILES(
+ "
+ #include <iconv.h>
+ // this declaration will fail when there already exists a non const char** version which returns size_t
+ double iconv(iconv_t cd, char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft);
+ int main() { return 0; }
+ "
+ HAVE_ICONV_CONST
+)
+
+# TODO: better way of config
+
+IF(HAVE_ICONV_CONST)
+ ADD_DEFINITIONS(-DHAVE_ICONV_CONST)
+ELSE(HAVE_ICONV_CONST)
+ REMOVE_DEFINITIONS(-DHAVE_ICONV_CONST)
+ENDIF(HAVE_ICONV_CONST)
+
+## TinyGetText library compilation
+
+## build list of source files
+
+FILE(GLOB TINYGETTEXT_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} tinygettext/*.cpp)
+FILE(GLOB TINYGETTEXT_HEADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} tinygettext/*.hpp)
+
+## define a target for building the library
+
+ADD_LIBRARY(tinygettext ${TINYGETTEXT_SOURCES})
+
+## Add tinygettext dir to search path
+
+INCLUDE_DIRECTORIES(${tinygettext_SOURCE_DIR})
+
+## 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)
+ # -ansi fails in MinGW
+ OPTION(WARNINGS "Enable long list of warnings for compiler to check" ON)
+ IF(WARNINGS)
+ ADD_DEFINITIONS(
+ -Wabi -Wctor-dtor-privacy
+ -Wstrict-null-sentinel
+ -Wold-style-cast
+ -Woverloaded-virtual
+ -Wsign-promo -Wswitch-enum
+ -Wcast-align -Wcast-qual
+ -Wdisabled-optimization
+ -Wfloat-equal
+ -Wformat=2
+ -Winit-self
+ -Winvalid-pch -Wunsafe-loop-optimizations
+ -Wlogical-op
+ -Wmissing-format-attribute -Wmissing-include-dirs -Wmissing-noreturn
+ -Wpacked
+ -Wredundant-decls
+ -Wshadow
+ -Wsign-conversion -Wstack-protector
+ -Wstrict-overflow=5
+ -Wswitch-default -Wswitch-enum
+ -Wundef)
+ # Still left:
+ # -Wconversion (find alternative to using toupper(int) on char)
+ # -Wpadded (DictionaryManager has a bool that sticks out)
+ ENDIF(WARNINGS)
+ IF(WERROR)
+ ADD_DEFINITIONS(-Werror)
+ ENDIF(WERROR)
+ENDIF(CMAKE_COMPILER_IS_GNUCC)
+
+## Extra definitions
+
+ADD_DEFINITIONS(-DVERSION=\\\"${VERSION}\\\")
+
+## Generate test executables in the right place
+
+SET(EXECUTABLE_OUTPUT_PATH ${tinygettext_BINARY_DIR}/test)
+
+## Build tinygettext tests
+
+FOREACH(TEST tinygettext_test po_parser_test)
+ ## Add target for tinygettext test
+ ADD_EXECUTABLE(${TEST} test/${TEST}.cpp)
+ ## Link with tinygettext library
+ TARGET_LINK_LIBRARIES(${TEST} tinygettext)
+ TARGET_LINK_LIBRARIES(${TEST} ${ICONV_LIBRARY})
+ENDFOREACH(TEST)
+
+## Install tinygettext
+
+# use standardized variable name
+SET(LIB_SUBDIR "lib${LIB_SUFFIX}"
+ CACHE STRING "Subdirectory of prefix into which libraries are installed (e.g., lib32, lib64)")
+
+## prepare tinygettext.pc
+CONFIGURE_FILE(tinygettext.pc.in tinygettext.pc @ONLY)
+
+INSTALL(TARGETS tinygettext
+ ARCHIVE DESTINATION ${LIB_SUBDIR}
+ LIBRARY DESTINATION ${LIB_SUBDIR})
+INSTALL(FILES ${TINYGETTEXT_HEADERS}
+ DESTINATION include/tinygettext)
+INSTALL(FILES ${tinygettext_BINARY_DIR}/tinygettext.pc
+ DESTINATION ${LIB_SUBDIR}/pkgconfig)
--- /dev/null
+#
+# Copyright (c) 2006, Peter Kümmel, <syntheticpp@gmx.net>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. The name of the author may not be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+set(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS true)
+
+if (ICONV_INCLUDE_DIR)
+ # Already in cache, be silent
+ set(ICONV_FIND_QUIETLY TRUE)
+endif()
+
+find_path(ICONV_INCLUDE_DIR iconv.h
+ /usr/include
+ /usr/local/include)
+
+set(POTENTIAL_ICONV_LIBS iconv libiconv libiconv2)
+
+find_library(ICONV_LIBRARY NAMES ${POTENTIAL_ICONV_LIBS}
+ PATHS /usr/lib /usr/local/lib)
+
+if(WIN32)
+ set(ICONV_DLL_NAMES iconv.dll libiconv.dll libiconv2.dll)
+ find_file(ICONV_DLL
+ NAMES ${ICONV_DLL_NAMES}
+ PATHS ENV PATH
+ NO_DEFAULT_PATH)
+ find_file(ICONV_DLL_HELP
+ NAMES ${ICONV_DLL_NAMES}
+ PATHS ENV PATH
+ ${ICONV_INCLUDE_DIR}/../bin)
+ if(ICONV_FIND_REQUIRED)
+ if(NOT ICONV_DLL AND NOT ICONV_DLL_HELP)
+ message(FATAL_ERROR "Could not find iconv.dll, please add correct your PATH environment variable")
+ endif()
+ if(NOT ICONV_DLL AND ICONV_DLL_HELP)
+ get_filename_component(ICONV_DLL_HELP ${ICONV_DLL_HELP} PATH)
+ message(STATUS)
+ message(STATUS "Could not find iconv.dll in standard search path, please add ")
+ message(STATUS "${ICONV_DLL_HELP}")
+ message(STATUS "to your PATH environment variable.")
+ message(STATUS)
+ message(FATAL_ERROR "exit cmake")
+ endif()
+ endif()
+ if(ICONV_INCLUDE_DIR AND ICONV_LIBRARY AND ICONV_DLL)
+ set(ICONV_FOUND TRUE)
+ endif()
+else()
+ include(CheckFunctionExists)
+ check_function_exists(iconv HAVE_ICONV_IN_LIBC)
+ if(ICONV_INCLUDE_DIR AND HAVE_ICONV_IN_LIBC)
+ set(ICONV_FOUND TRUE)
+ set(ICONV_LIBRARY CACHE TYPE STRING FORCE)
+ endif()
+ if(ICONV_INCLUDE_DIR AND ICONV_LIBRARY)
+ set(ICONV_FOUND TRUE)
+ endif()
+endif()
+
+
+
+if(ICONV_FOUND)
+ if(NOT ICONV_FIND_QUIETLY)
+ message(STATUS "Found iconv library: ${ICONV_LIBRARY}")
+ #message(STATUS "Found iconv dll : ${ICONV_DLL}")
+ endif()
+else()
+ if(ICONV_FIND_REQUIRED)
+ message(STATUS "Looked for iconv library named ${POTENTIAL_ICONV_LIBS}.")
+ message(STATUS "Found no acceptable iconv library. This is fatal.")
+ message(STATUS "iconv header: ${ICONV_INCLUDE_DIR}")
+ message(STATUS "iconv lib : ${ICONV_LIBRARY}")
+ message(FATAL_ERROR "Could NOT find iconv library")
+ endif()
+endif()
+
+mark_as_advanced(ICONV_LIBRARY ICONV_INCLUDE_DIR)
--- /dev/null
+tinygettext 0.0.1 - (??. Feb 2009)
+==================================
+
+* initial release
+
+# EOF #
--- /dev/null
+tinygettext
+===========
+
+tinygettext is a minimal gettext() replacement written in C++. It can
+read .po files directly and doesn't need .mo files generated from .po.
+It also can read the .po files from arbitary locations, so its much
+better suited for non-Unix systems and situations in which one wants
+to store or distrubite .po files seperatly from the software itself.
+
+
+
+Detecting the locale setting
+============================
+
+Different operating systems store the default locale in different
+places; a portable way to find it is provided by FindLocale:
+
+ * http://icculus.org/~aspirin/findlocale/
+
+
+# EOF #
--- /dev/null
+# -*- python -*-
+
+env = Environment(CXXFLAGS=['-O0',
+ '-g3',
+ '-Wall',
+ '-Wcast-qual',
+ '-Wconversion',
+ '-Weffc++',
+ '-Werror',
+ '-Wextra',
+ '-Winit-self',
+ '-Wno-unused-parameter',
+ '-Wnon-virtual-dtor',
+ '-Wshadow',
+ '-ansi',
+ '-pedantic',
+ ],
+ CPPPATH=['tinygettext', '.'])
+
+# 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'])
+
+env.Program('test/tinygettext_test', ['test/tinygettext_test.cpp', libtinygettext])
+env.Program('test/po_parser_test', ['test/po_parser_test.cpp', libtinygettext])
+
+# EOF #
--- /dev/null
+tinygettext API related stuff:
+==============================
+
+* translate, translate_ctxt, translate_ctxt_plural, ... could be
+ unified via overloading, not sure if that is a good idea. For the
+ same reason add_translation() could be de-overloaded, to
+ add_translation_ctxt, ...
+
+* iconv handling needs cleanup and more flexibility, since some
+ systems don't provide iconv or only through SDL
+
+* Customizability could use grouping and documentation or other means
+ to make it more obvious:
+
+ - POParser::pedantic
+ - iconv (???)
+ - logging (log_callback(std::string))
+
+* handle errors better, not with log_* stream, cases of errors:
+
+ - couldn't translate
+ - collision while adding translation
+ - failure to open file or directory
+ - unknown language
+ - iconv failure to convert charset
+
+* ABI management/freezing. If tinygettext is to benefit other projects,
+ it should be able to provide a stable API (and, better, ABI).
+
+
+tinygettext implementation details:
+===================================
+
+* with PluralForms moved into Dictionary a lot of the Langugae stuff
+ is pointless
+
+* get rid of goto
+
+* POParser can handle Big5, but needs testing.
+ Big5 is one byte for ASCII letters and two bytes for chinese ones,
+ this means some two byte characters collide with '\', some .po files
+ seem to escape the \ properly so that the string can be read as
+ usual, while others don't.
+
+* _() -> getext() (gettext default)
+ N_(id) -> gettext_noop(id) (gettext default)
+ C_(ctxt, id) -> pgettext(ctxt, id) (Gnome does this: http://library.gnome.org/devel/glib/2.16/glib-I18N.html#Q-:CAPS)
+ NC_(ctxt, id) -> pgettext(ctxt, id) (Gnome does this: http://library.gnome.org/devel/glib/2.16/glib-I18N.html#Q-:CAPS)
+
+* figure out how up-to-date other tinygettext implementations in the
+ wild are (LinCity):
+
+ Pingus:
+ -------
+ dictionary.hpp (synced with Pingus)
+ dictionary_manager.hpp (PhysFS vs opendir())
+ language_def.hpp (synced with Pingus)
+ po_file_reader.hpp (UTF-8 0xef-'header', lots of stuff from mathner)
+ tinygettext.hpp (iconv vs convert)
+
+\f
+Random Unimportant Stuff
+========================
+
+* a hashmap instead of std::map might be a good idea
+
+* support for .gmo files would be cool
+\f
+tinygettext Documentation:
+==========================
+
+* recommend a way to handle translation of speech and other data files
+
+* document how to use tinygettext and make it work like gettext
+\f
+# EOF #
--- /dev/null
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR Free Software Foundation, Inc.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-01-30 08:01+0100\n"
+"PO-Revision-Date: 2009-01-30 08:39+0100\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: helloworld.cpp:7
+msgid "Short Hello World"
+msgstr "kurzes Hallo Welt
+
+#: helloworld.cpp:8 helloworld.cpp:14
+#, fuzzy
+msgid "Hello World"
+msgid_plural "Hello Worlds"
+msgstr[0] "Hallo Welt (singular)"
+msgstr[1] "Hallo Welt (plural)"
+msgstr[10] "Hallo Welt (plural)"
+
+#: helloworld.cpp:10 helloworld.cpp:16
+#, fuzzy
+msgctxt ""
+msgid "Hello World"
+msgid_plural "Hello Worlds"
+msgstr[0] Hallo Welt (singular) mit leerem Kontext"
+msgstr[1] "Hallo Welt (plural) mit leerem Kontext"
+
+#: helloworld.cpp:11 helloworld.cpp:17
+msgctxt "console"
+msgid "Hello World"
+msgid_plural "Hello Worlds"
+msgstr[0]"Hallo Welt (singular) in der Console"
+msgstr[1] "Hallo Welt (plural) in der Console"
+
+#: helloworld.cpp:13
+msgid "gui"
+msgid_plural "Hello World"
+msgstr[0] "Hallo Welt (singular)"
+msgstr[1] "Hallo Welt (plural)"
+
+#: helloworld.cpp:18
+#, fuzzy
+msgctxt "gui"
+msgid "Hello World"
+msgid_plural "Hello Worlds"
+msgstr[0] "Hallo Welt im GUI"
+msgstr[1] "Hallo Welt (plural) im GUI"
--- /dev/null
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR Free Software Foundation, Inc.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Pingus 0.6.0\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2004-04-09 18:37+0000\n"
+"PO-Revision-Date: 2003-04-15 17:31+0200\n"
+"Last-Translator: David Philippi <david@torangan.de>\n"
+"Language-Team: David Philippi <david@torangan.de>, Ingo Ruhnke <grumbel@gmx."
+"de>, Giray Devlet <giray@devlet.cc>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=ISO-8859-1\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: src/actions/bridger.cxx:48 src/actions/bridger.cxx:232
+#: src/pingu_enums.cxx:40
+msgid "Bridger"
+msgstr "Bridger"
+
+#: src/config.cxx:73
+msgid "Couldn't open: "
+msgstr "Datei oder Verzeichnis konnte nicht geöffnet werden: "
+
+#: src/config.cxx:172
+msgid "Unexpected char: '"
+msgstr "Unerwartetes Zeichen: '"
+
+#: src/config.cxx:206
+msgid "Unexpected char '"
+msgstr "Unerwartetes Zeichen: '"
+
+#: src/credits.cxx:48
+msgid "-Idea"
+msgstr "-Idee"
+
+#: src/credits.cxx:52
+msgid "-Maintaining"
+msgstr "-Verwaltung"
+
+#: src/credits.cxx:56
+msgid "-Programming"
+msgstr "-Programmierung"
+
+#: src/credits.cxx:62
+msgid "-Porting (Win32)"
+msgstr "-Portierung (Win32)"
+
+#: src/credits.cxx:70
+msgid "-Gfx"
+msgstr "-Grafiken"
+
+#: src/credits.cxx:82
+msgid "-Music"
+msgstr "-Musik"
+
+#: src/credits.cxx:88
+msgid "-Level Design"
+msgstr "-Level Design"
+
+#: src/credits.cxx:93
+msgid "-Story"
+msgstr "-Geschichte"
+
+#: src/credits.cxx:97
+msgid "-Translation"
+msgstr "-Übersetzung"
+
+#: src/credits.cxx:112
+msgid "-Special"
+msgstr "-Besonderen"
+
+#: src/credits.cxx:113
+msgid "-Thanks to"
+msgstr "-Dank an"
+
+#: src/credits.cxx:154
+msgid "_And a very Special Thanks"
+msgstr "_Und einen besonderen Dank"
+
+#: src/credits.cxx:155
+msgid "_to all the people who"
+msgstr "_an alle Leute die"
+
+#: src/credits.cxx:156
+msgid "_contribute to"
+msgstr "_an Freier Software"
+
+#: src/credits.cxx:157
+msgid "_Free Software!"
+msgstr "_mitarbeiten!"
+
+#: src/credits.cxx:163
+msgid "_Thank you for"
+msgstr "_Dankeschön fürs"
+
+#: src/credits.cxx:164
+msgid "_playing!"
+msgstr "_spielen!"
+
+#: src/editor/editor_event.cxx:588
+msgid "Enter filename to save as:"
+msgstr "Datei speichern als: "
+
+#: src/editor/editor_help_screen.cxx:43
+msgid "Editor Helpscreen (hide with F1)"
+msgstr "Editor Hilfe (ausblenden mit F1)"
+
+#: src/editor/editor_help_screen.cxx:51
+msgid "F1 - show/hide this help screen"
+msgstr "F1 - Hilfe anzeigen/verstecken"
+
+#: src/editor/editor_help_screen.cxx:52
+msgid "F2 - launch level building tutorial"
+msgstr "F2 - Starte Levelbau Tutorial"
+
+#: src/editor/editor_help_screen.cxx:53
+msgid "F3 - toggle background color"
+msgstr "F3 - Hintergrundfarbe aendern"
+
+#: src/editor/editor_help_screen.cxx:54
+msgid "F4 - play/test the level"
+msgstr "F4 - Level starten/testen"
+
+#: src/editor/editor_help_screen.cxx:55
+msgid "F5 - load a level"
+msgstr "Level Laden (F5)"
+
+#: src/editor/editor_help_screen.cxx:56
+msgid "F6 - save this level"
+msgstr "Level Speichern (F6)"
+
+#: src/editor/editor_help_screen.cxx:57
+msgid "F7 - [unset]"
+msgstr "F7 - [nicht belegt]"
+
+#: src/editor/editor_help_screen.cxx:58
+msgid "F8 - quick save/backup save?!"
+msgstr "F8 - Schnellspeichern/Backup"
+
+#: src/editor/editor_help_screen.cxx:59
+msgid "F9 - change level width and height"
+msgstr "F9 - Level Höhe und Breite ändern"
+
+#: src/editor/editor_help_screen.cxx:60
+msgid "F10 - [unset]"
+msgstr "F10 - [nicht belegt]"
+
+#: src/editor/editor_help_screen.cxx:61
+msgid "F11 - toggle fps counter"
+msgstr "F11 - fps Zähler an/aus"
+
+#: src/editor/editor_help_screen.cxx:62
+msgid "F12 - make screenshot"
+msgstr "F12 - Screenshot erstellen"
+
+#: src/editor/editor_help_screen.cxx:66
+msgid "Home - increase object size"
+msgstr "Einfg - Objekt vergrößern"
+
+#: src/editor/editor_help_screen.cxx:67
+msgid "End - decrease object size"
+msgstr "Ende - Objekt verkleinern"
+
+#: src/editor/editor_help_screen.cxx:68
+msgid "Cursor Keys - Move object"
+msgstr "Cursor Tasten - Objekt bewegen"
+
+#: src/editor/editor_help_screen.cxx:69
+msgid "Shift 'Cursor Keys' - Move objects fast "
+msgstr "Shift Cursor Tasten - Objekt schneller bewegen"
+
+#: src/editor/editor_help_screen.cxx:70
+msgid "PageUp - level object up"
+msgstr "Bild rauf - Objekt nach oben"
+
+#: src/editor/editor_help_screen.cxx:71
+msgid "PageDown - level object down"
+msgstr "Bild runter - Objekt nach unten"
+
+#: src/editor/editor_help_screen.cxx:72
+msgid "Shift PageUp - increase objects z-pos by 50"
+msgstr "Shift Bild rauf - Objekt nach oben"
+
+#: src/editor/editor_help_screen.cxx:73
+msgid "Shift PageDown - decrease objects z-pos by 50"
+msgstr "Shift Bild runter - Objekt nach unten"
+
+#: src/editor/editor_help_screen.cxx:74
+msgid "Enter - Set default zoom (1:1)"
+msgstr "Eingabe - Setze Standard Zoom (1:1)"
+
+#: src/editor/editor_help_screen.cxx:75
+msgid "d - duplicate object"
+msgstr "d - Objekt kopieren"
+
+#: src/editor/editor_help_screen.cxx:76
+msgid "a - mark all objects"
+msgstr "a - Alle Objekte markieren"
+
+#: src/editor/editor_help_screen.cxx:77
+msgid "shift leftmouseclick - add object to selection"
+msgstr "Shift + linke Maustaste - Objekt zur Auswahl tun"
+
+#: src/editor/editor_help_screen.cxx:78
+msgid "leftmouseclick - select object"
+msgstr "linke Maustaste - Objekt auswählen"
+
+#: src/editor/editor_help_screen.cxx:79
+msgid "Insert - insert new object"
+msgstr "Einfügen - neues Objekt einfügen"
+
+#: src/editor/editor_help_screen.cxx:80
+msgid "Remove - remove selected object"
+msgstr "Entfernen - entferne ausgewähltes Objekt"
+
+#: src/editor/editor_help_screen.cxx:81
+msgid "g - ungroup/group current selection"
+msgstr "g - Auswahl gruppieren / Gruppierung aufheben"
+
+#: src/editor/editor_help_screen.cxx:82
+msgid "Ctrl PageUp - increase objects z-pos by 1"
+msgstr "Strg Bild rauf - z-pos des Objekts um 1 erhöhen"
+
+#: src/editor/editor_help_screen.cxx:83
+msgid "Ctrl PageDown - decrease objects z-pos by 1"
+msgstr "Strg Bild runter - z-pos des Objekts um 1 senken"
+
+#: src/editor/editor_help_screen.cxx:89
+msgid "Naming Convention: <LEVELNAME><NUMBER>-<CREATOR>.plf"
+msgstr "Dateinamensvorgabe: <LEVELNAME><NUMMER>-<AUTOR>.pfl"
+
+#: src/editor/editor_help_screen.cxx:91
+msgid ""
+"When you have created a level and want to have it in the next Pingus "
+"release,\n"
+"please mail it to pingus-devel@nongnu.org."
+msgstr ""
+"Falls Du einen Level erstellt hast und ihn gerne im nächsten Pingus\n"
+"Release hättest, schicke ihn an pingus-devel@nongnu.org."
+
+#: src/editor/object_selector.cxx:106
+msgid "1 - guillotine"
+msgstr "1 - Guillotine"
+
+#: src/editor/object_selector.cxx:107
+msgid "2 - hammer"
+msgstr "2 - Hammer"
+
+#: src/editor/object_selector.cxx:108
+msgid "3 - spike"
+msgstr "3 - Stacheln"
+
+#: src/editor/object_selector.cxx:109
+msgid "4 - laser_exit"
+msgstr "4 - Laser Ausgang"
+
+#: src/editor/object_selector.cxx:110
+msgid "5 - fake_exit"
+msgstr "5 - Täusch Ausgang"
+
+#: src/editor/object_selector.cxx:111
+msgid "6 - smasher"
+msgstr "6 - Stampfer"
+
+#: src/editor/object_selector.cxx:112
+msgid "7 - bumper"
+msgstr "7 - Stosser"
+
+#: src/editor/object_selector.cxx:186
+msgid "Select a WorldObj"
+msgstr "Wähle ein WeltObjekt"
+
+#: src/editor/object_selector.cxx:187
+msgid "1 - teleporter"
+msgstr "1 - Teleporter"
+
+#: src/editor/object_selector.cxx:188
+msgid "2 - switch and door"
+msgstr "2 - Schalter und Tür"
+
+#: src/editor/object_selector.cxx:189
+msgid "3 - ConveyorBelt"
+msgstr "3 - Förderband"
+
+#: src/editor/object_selector.cxx:190
+msgid "4 - IceBlock"
+msgstr "4 - Eisblock"
+
+#: src/editor/object_selector.cxx:191
+msgid "5 - InfoBox"
+msgstr "5 - InfoBox"
+
+#: src/editor/object_selector.cxx:232
+msgid "Select a weather"
+msgstr "Wähle ein Wetter"
+
+#: src/editor/object_selector.cxx:233
+msgid "1 - snow"
+msgstr "1 - Schnee"
+
+#: src/editor/object_selector.cxx:234
+msgid "2 - rain"
+msgstr "2 - Regen"
+
+#: src/editor/object_selector.cxx:265
+msgid "Select an entrance"
+msgstr "Wähle einen Eingang"
+
+#: src/editor/object_selector.cxx:266
+msgid "1 - generic"
+msgstr "1 - allgemein"
+
+#: src/editor/object_selector.cxx:267
+msgid "2 - woodthing"
+msgstr "2 - hölzern"
+
+#: src/editor/object_selector.cxx:268
+msgid "3 - cloud"
+msgstr "3 - Wolke"
+
+#: src/editor/object_selector.cxx:269
+msgid "h - entrance surface (hotspot)"
+msgstr "h - Eingangs Grafik (hotspot)"
+
+#: src/editor/object_selector.cxx:343
+msgid "What object type do you want?"
+msgstr "Was für ein Objekt willst du?"
+
+#: src/editor/object_selector.cxx:344 src/editor/object_selector.cxx:400
+msgid "h - Hotspot"
+msgstr "h - Grafikelement (hotspot)"
+
+#: src/editor/object_selector.cxx:345
+msgid "g - Groundpiece (ground) [not implemented]"
+msgstr "g - Bodenstück (ground) [nicht implementiert]"
+
+#: src/editor/object_selector.cxx:394 src/editor/object_selector.cxx:562
+msgid "Which object do you want?"
+msgstr "Welches Objekt willst du?"
+
+#: src/editor/object_selector.cxx:395
+msgid "g - Groundpiece (ground)"
+msgstr "g - Bodenstück (ground)"
+
+#: src/editor/object_selector.cxx:396
+msgid "s - Groundpiece (solid)"
+msgstr "s - Bodenelement (Stahl)"
+
+#: src/editor/object_selector.cxx:397
+msgid "b - Groundpiece (bridge)"
+msgstr "b - Bodenelement (Bruecke)"
+
+#: src/editor/object_selector.cxx:398
+msgid "n - Groundpiece (transparent)"
+msgstr "n - Bodenelement (transparent)"
+
+#: src/editor/object_selector.cxx:399
+msgid "r - Groundpiece (remove)"
+msgstr "r - Bodenelement (entfernen)"
+
+#: src/editor/object_selector.cxx:401
+msgid "e - Entrance"
+msgstr "e - Eingang"
+
+#: src/editor/object_selector.cxx:402
+msgid "x - Exit"
+msgstr "x - Ausgang"
+
+#: src/editor/object_selector.cxx:403
+msgid "l - Liquid"
+msgstr "l - Flüssigkeit"
+
+#: src/editor/object_selector.cxx:404
+msgid "w - Weather"
+msgstr "w - Wetter"
+
+#: src/editor/object_selector.cxx:405
+msgid "t - Traps"
+msgstr "t - Falle"
+
+#: src/editor/object_selector.cxx:406
+msgid "o - WorldObject"
+msgstr "o - WeltObjekt"
+
+#: src/editor/object_selector.cxx:407
+msgid "z - Background"
+msgstr "z - Hintergrund"
+
+#: src/editor/object_selector.cxx:408
+msgid "p - Prefab (ObjectGroup)"
+msgstr "p - Prefab (Objekt Gruppe)"
+
+#: src/editor/object_selector.cxx:409
+msgid "f - something from file (~/.pingus/images/)"
+msgstr "f - etwas aus einer Datei (~/.pingus/images/)"
+
+#: src/editor/object_selector.cxx:498
+msgid "Which prefab do you want?"
+msgstr "Welche Prefab willst du?"
+
+#: src/editor/object_selector.cxx:563
+msgid "1 - Surface Background"
+msgstr "1 - Bild Hintergrund"
+
+#: src/editor/object_selector.cxx:564
+msgid "2 - Solid Color Background"
+msgstr "2 - Farb Hintergrund"
+
+#: src/editor/object_selector.cxx:565
+msgid "3 - Starfield Background"
+msgstr "3 - Sternen Hintergrund"
+
+#: src/editor/object_selector.cxx:566
+msgid "4 - Thunderstorm Background"
+msgstr "4 - Gewitter Hintergrund"
+
+#: src/editor/panel_icons.cxx:33
+msgid "Load a level (F5)"
+msgstr "Level laden (F5)"
+
+#: src/editor/panel_icons.cxx:46
+msgid "Exit the editor (Escape)"
+msgstr "Editor Beenden (Esc)"
+
+#: src/editor/panel_icons.cxx:58
+msgid "Save this level (F6)"
+msgstr "Level Speichern (F6)"
+
+#: src/editor/panel_icons.cxx:70
+msgid "Delete marked objects (delete)"
+msgstr "Markierte Objekte Löschen (Entfernen)"
+
+#: src/editor/panel_icons.cxx:82
+msgid "Duplicate current object (d)"
+msgstr "Aktuelles Object kopieren (d)"
+
+#: src/editor/panel_icons.cxx:94
+msgid "Edit Level Properties"
+msgstr "Leveleigenschaften ändern"
+
+#: src/editor/panel_icons.cxx:106
+msgid "Edit Object Properties"
+msgstr "Objekteigenschaften ändern"
+
+#: src/editor/panel_icons.cxx:118
+msgid "Start the level and test it (F4)"
+msgstr "Level starten und testen (F4)"
+
+#: src/editor/panel_icons.cxx:130
+msgid "Create a new level from scratch"
+msgstr "Neuen Level erstellen"
+
+#: src/editor/panel_icons.cxx:142
+msgid "Insert an object (Insert)"
+msgstr "Objekt einfuegen (Einfg)"
+
+#: src/editor/panel_icons.cxx:154
+msgid "Zoom into a region"
+msgstr "Einen Bereich vergrössern"
+
+#: src/editor/panel_icons.cxx:166
+msgid "Zoom in"
+msgstr "Vergroessern"
+
+#: src/editor/panel_icons.cxx:179
+msgid "Zoom out"
+msgstr "Verkleinern"
+
+#: src/editor/panel_icons.cxx:192
+msgid "Setup Number of Actions"
+msgstr "Stelle die Anzahl der Fähigkeiten ein"
+
+#: src/editor/panel_icons.cxx:204
+msgid "Display Help Screen (F1)"
+msgstr "Hilfe Anzeigen (F1)"
+
+#: src/exit_menu.cxx:48
+msgid "Yes"
+msgstr "Ja"
+
+#: src/exit_menu.cxx:81
+msgid "No"
+msgstr "Nein"
+
+#: src/exit_menu.cxx:114
+msgid "Exit Pingus?"
+msgstr "Pingus beenden?"
+
+#: src/fps_counter.cxx:48
+msgid "unknown"
+msgstr "unbekannt"
+
+#: src/game_time.cxx:70
+msgid "unlimited"
+msgstr "unbegrenzt"
+
+#: src/level_desc.cxx:74
+msgid "Designed by "
+msgstr "Erstellt von "
+
+#: src/level_desc.cxx:79
+#, c-format
+msgid "Pingus to Save: %d"
+msgstr "Zu rettende Pingus: %d"
+
+#: src/level_desc.cxx:81
+#, c-format
+msgid "Number of Pingus: %d"
+msgstr "Anzahl an Pingus: %d"
+
+#: src/level_desc.cxx:86
+msgid "Loading..."
+msgstr "Ladevorgang läuft..."
+
+#: src/level_desc.cxx:89
+msgid "Loading finished. Press a mouse button to start the level"
+msgstr ""
+"Ladevorgang abgeschlossen. Drücke eine Maus Taste um den Level zu starten"
+
+#: src/level_result.cxx:61
+msgid "Results:"
+msgstr "Ergebnisse:"
+
+#: src/level_result.cxx:67
+#, c-format
+msgid "Pingus saved: %3d/%3d"
+msgstr "Gerettete Pingus: %3d/%3d"
+
+#: src/level_result.cxx:72
+#, c-format
+msgid "Pingus died: %3d/%3d"
+msgstr "Tote Pingus: %3d/%3d"
+
+#: src/level_result.cxx:88
+msgid "Press button to continue..."
+msgstr "Knopf drücken um fortzufahren"
+
+#: src/level_result.cxx:102
+msgid ""
+"As many Pingus escaped as entered the level. That's going to be hard to "
+"beat.... unless this game becomes pornographic."
+msgstr ""
+"Es wurden alle Pingu dieses Levels gerettet. Das wird hart zu schlagen "
+"sein... es sei denn dieses Spiel wird pornographisch."
+
+#: src/level_result.cxx:104
+msgid "Very impressive indeed."
+msgstr "In der Tat sehr eindrucksvoll."
+
+#: src/level_result.cxx:106
+msgid "Good work. Still room for improvement though."
+msgstr "Gute Arbeit. Aber Übung macht den Meiser!"
+
+#: src/level_result.cxx:108
+msgid "Not too shabby, not too shabby at all."
+msgstr "Nicht schlecht, nicht schlecht!"
+
+#: src/level_result.cxx:110
+msgid ""
+"That was OK, but Pingu life insurance premiums have just gotten more "
+"expensive."
+msgstr ""
+"Das war ok, aber die Lebensversicherungsprämien für Pingus sind gerade "
+"gestiegen."
+
+#: src/level_result.cxx:112
+msgid "Maybe this level calls for a different strategy."
+msgstr "Möglicherweise verlangt dieser Level eine andere Strategie."
+
+#: src/level_result.cxx:114
+msgid "Exactly half. Are you saving only the female ones?"
+msgstr "Genau die Hälfte! Rettest du nur die Weibchen?"
+
+#: src/level_result.cxx:116
+msgid "If I were a Pingu, I never would have left that entrance."
+msgstr "Wenn ich ein Pingu wäre, hätte ich den Eingang nie verlassen."
+
+#: src/level_result.cxx:118
+msgid "Maybe you would feel more at home playing Quake."
+msgstr "Möglicherweise wäre es besser Quake zu spielen?"
+
+#: src/level_result.cxx:120
+msgid ""
+"Maybe this level calls for a different strategy. Like attempting to save "
+"them, for example."
+msgstr ""
+"Es kann sein, dass wir etwas anderes versuchen sollten. Vielleicht könnten "
+"wir ja die Pingus retten?"
+
+#: src/level_result.cxx:122
+msgid "Ever considered a career as a Pingu exterminator?"
+msgstr "Hast du mal über eine Karriere als Pingu Zerstörer nachgedacht?"
+
+#: src/level_result.cxx:124
+msgid "You missed one! What's your excuse!?"
+msgstr "Du hast einen vergessen! Was ist deine Entschuldigung?"
+
+#: src/level_result.cxx:126
+msgid "Please reassure me that you hit the Armageddon button."
+msgstr "Bestätige mir bitte, dass das die Armageddon Taste war."
+
+#: src/level_result.cxx:128
+msgid "You've got a negative save/total value, something is buggy."
+msgstr "Ein negativer Wert? Hier liegt ein Fehler vor."
+
+#: src/menu_button.cxx:181
+msgid "..:: The people who brought this game to you ::.."
+msgstr "..:: Die Leute, die fuer dieses Spiel verantwortlich sind... ::.."
+
+#: src/menu_button.cxx:184
+msgid "Credits"
+msgstr "Mitwirkende"
+
+#: src/menu_button.cxx:216
+msgid "..:: Takes you to the options menu ::.."
+msgstr "..:: Einstellungen, Cheats und Debugging stuff ::.."
+
+#: src/menu_button.cxx:219
+msgid "Options"
+msgstr "Einstellungen"
+
+#: src/menu_button.cxx:252
+msgid "..:: Bye, bye ::.."
+msgstr "..:: Auf Wiedersehen ::.."
+
+#: src/menu_button.cxx:255
+msgid "Exit"
+msgstr "Beenden"
+
+#: src/menu_button.cxx:306
+msgid "..:: Launch the level editor ::.."
+msgstr "..:: Erstelle deinen eigenen Level ::.."
+
+#: src/menu_button.cxx:309
+msgid "Create a"
+msgstr "Bau einen"
+
+#: src/menu_button.cxx:310
+msgid "Level"
+msgstr "Level"
+
+#: src/menu_button.cxx:344
+msgid "..:: Start the game ::.."
+msgstr "..:: das Spiel starten ::.."
+
+#: src/menu_button.cxx:345
+msgid "Start"
+msgstr "Start"
+
+#: src/menu_button.cxx:375
+msgid "..:: Start a contrib level ::.."
+msgstr "..:: Contrib level Spielen ::.."
+
+#: src/menu_button.cxx:377
+msgid "Contrib"
+msgstr "Levels"
+
+#: src/menu_button.cxx:399
+msgid "..:: Multiplayer Modes... experimental stuff ::.."
+msgstr "..:: Mehrspieler Modus ::.. Experimentelles Zeug ::.."
+
+#: src/menu_button.cxx:401
+msgid "Multi"
+msgstr "Multi"
+
+#: src/pingu_enums.cxx:35
+msgid "Angel"
+msgstr "Angel"
+
+#: src/pingu_enums.cxx:36
+msgid "Basher"
+msgstr "Basher"
+
+#: src/pingu_enums.cxx:37
+msgid "Blocker"
+msgstr "Blocker"
+
+#: src/pingu_enums.cxx:38
+msgid "Boarder"
+msgstr "Boarder"
+
+#: src/pingu_enums.cxx:39
+msgid "Bomber"
+msgstr "Bomber"
+
+#: src/pingu_enums.cxx:41
+msgid "Climber"
+msgstr "Climber"
+
+#: src/pingu_enums.cxx:42
+msgid "Digger"
+msgstr "Digger"
+
+#: src/pingu_enums.cxx:43
+msgid "Drown"
+msgstr "Drown"
+
+#: src/pingu_enums.cxx:44
+msgid "Exiter"
+msgstr "Exiter"
+
+#: src/pingu_enums.cxx:45
+msgid "Faller"
+msgstr "Faller"
+
+#: src/pingu_enums.cxx:46
+msgid "Floater"
+msgstr "Floater"
+
+#: src/pingu_enums.cxx:47
+msgid "Jumper"
+msgstr "Jumper"
+
+#: src/pingu_enums.cxx:48
+msgid "Laserkill"
+msgstr "Laserkill"
+
+#: src/pingu_enums.cxx:49
+msgid "Miner"
+msgstr "Miner"
+
+#: src/pingu_enums.cxx:50
+msgid "Rocketlauncher"
+msgstr "Rocketlauncher"
+
+#: src/pingu_enums.cxx:51
+msgid "Slider"
+msgstr "Slider"
+
+#: src/pingu_enums.cxx:52
+msgid "Smashed"
+msgstr "Smashed"
+
+#: src/pingu_enums.cxx:53
+msgid "Splashed"
+msgstr "Splashed"
+
+#: src/pingu_enums.cxx:54
+msgid "Superman"
+msgstr "Superman"
+
+#: src/pingu_enums.cxx:55
+msgid "Teleported"
+msgstr "Teleported"
+
+#: src/pingu_enums.cxx:56
+msgid "Waiter"
+msgstr "Waiter"
+
+#: src/pingu_enums.cxx:57
+msgid "Walker"
+msgstr "Walker"
+
+#: src/pingus_counter.cxx:52
+#, c-format
+msgid "Released:%3d/%-3d Out:%3d Saved:%3d/%-3d"
+msgstr "Rein: %3d/%-3d Raus: %3d Gerettet: %3d/%-3d"
+
+#: src/pingus_main.cxx:90
+msgid "| segfault_handler: catched a SIGSEGV."
+msgstr "| segfault_handler: SIGSEGV abgefangen."
+
+#: src/pingus_main.cxx:92
+msgid "| Woops, Pingus just crashed, congratulations you've found a bug."
+msgstr ""
+"| Woops, Pingus ist abgestürzt. Gratuliere, du hast einen Bug gefunden."
+
+#: src/pingus_main.cxx:93
+msgid ""
+"| Please write a little bug report to <grumbel@gmx.de>, include informations"
+msgstr ""
+"| Bitte schreibe einen kleinen Report an <pingus-devel@nongnu.org, mit "
+"Informationen,"
+
+#: src/pingus_main.cxx:94
+msgid "| where exacly the SIGSEGV occured and how to reproduce it."
+msgstr "| wo genau der SIGSEGV auftrat und wie man ihn reproduziert."
+
+#: src/pingus_main.cxx:95
+msgid "| Also try include a backtrace, you can get it like this:"
+msgstr "| Versuche auch einen backtrace zu erstellen, du bekommst ihn so:"
+
+#: src/pingus_main.cxx:101
+msgid "| If that doesn't work, try this:"
+msgstr "| Wenn das nicht geht, versuche dies:"
+
+#: src/pingus_main.cxx:105
+msgid "| [play until it crashes again]"
+msgstr "| [spiele bis es wieder crasht]"
+
+#: src/pingus_main.cxx:113
+msgid "| Warning: Pingus recieved a SIGINT, exiting now."
+msgstr "| Warnung: Pingus erhielt einen SIGINT, beende jetzt."
+
+#: src/pingus_main.cxx:301
+msgid "Warning: Larger resolution than 800x600 will result in visual problems"
+msgstr ""
+"Warnung: Auflösungen grösser als 800x600 können zu visuellen Problemen führen"
+
+#: src/pingus_main.cxx:488
+msgid "Unknow char: "
+msgstr "Unbekannter Buchstabe: "
+
+#: src/pingus_main.cxx:489
+msgid "Usage: "
+msgstr "Benutzung: "
+
+#: src/pingus_main.cxx:489
+msgid " [OPTIONS]... [LEVELFILE]"
+msgstr "[OPTIONEN]... [LEVELDATEI]"
+
+#: src/pingus_main.cxx:492
+msgid "Options:"
+msgstr "Einstellungen"
+
+#: src/pingus_main.cxx:494
+msgid "Set the resolution for pingus (default: 800x600)"
+msgstr "Setze die Auflösung für Pingus (Standard: 800x600)"
+
+#: src/pingus_main.cxx:495
+msgid "Displays this help"
+msgstr "Hilfe Anzeigen"
+
+#: src/pingus_main.cxx:496
+msgid "Disable intro"
+msgstr "Intro abschalten"
+
+#: src/pingus_main.cxx:497
+msgid "Use OpenGL"
+msgstr "OpenGL benutzen"
+
+#: src/pingus_main.cxx:499
+msgid "Start in Window Mode"
+msgstr "Pingus im Fenster starten"
+
+#: src/pingus_main.cxx:500
+msgid "Start in Fullscreen"
+msgstr "Pingus im Vollbild starten"
+
+#: src/pingus_main.cxx:504
+msgid "FILE "
+msgstr "Datei "
+
+#: src/pingus_main.cxx:504
+msgid "Load a custom level from FILE"
+msgstr "Einen Level aus DATEI laden"
+
+#: src/pingus_main.cxx:505
+msgid "FILE "
+msgstr "Datei "
+
+#: src/pingus_main.cxx:505
+msgid "Load a custom worldmap from FILE"
+msgstr "Eine Weltkarte aus DATEI laden"
+
+#: src/pingus_main.cxx:506
+msgid "Print some more messages to stdout, can be set"
+msgstr "Gibt mehr Nachrichten auf stdout aus, kann"
+
+#: src/pingus_main.cxx:507
+msgid "multiple times to increase verbosity"
+msgstr "mehrmals gesetzt werden, um die Genauigkeit zu erhöhen"
+
+#: src/pingus_main.cxx:508
+msgid "Prints version number and exit"
+msgstr "Version ausgeben und beenden"
+
+#: src/pingus_main.cxx:509
+msgid "Launch the Level editor (experimental)"
+msgstr "Level Editor starten (Experimentell)"
+
+#: src/pingus_main.cxx:510
+msgid "Disable automatic scrolling"
+msgstr "Automatisches Scrollen abschalten"
+
+#: src/pingus_main.cxx:512
+msgid "Enable software cursor"
+msgstr "Aktiviere Software Cursor"
+
+#: src/pingus_main.cxx:515
+msgid "Don't read ~/.pingus/config"
+msgstr "~/.pingus/config nicht einlesen"
+
+#: src/pingus_main.cxx:516
+msgid "FILE "
+msgstr "Datei "
+
+#: src/pingus_main.cxx:516
+msgid "Read config from FILE (default: ~/.pingus/config)"
+msgstr "Konfiguration aus DATEI lesen"
+
+#: src/pingus_main.cxx:517
+msgid "reduce CPU usage, might speed up the game on slower machines"
+msgstr ""
+"reduziere CPU Belastung, könnte das Spiel auf langsamen Rechnern "
+"beschleunigen"
+
+#: src/pingus_main.cxx:518
+msgid "Uses the controller given in FILE"
+msgstr "Controller aus FILE benutzen"
+
+#: src/pingus_main.cxx:520
+msgid "Debugging and experimental stuff:"
+msgstr "Debug und Experimentelles Zeug"
+
+#: src/pingus_main.cxx:521
+msgid "Enables some features, only interesting programmers"
+msgstr "Aktiviere einige Funktionen, nur für Programmierer"
+
+#: src/pingus_main.cxx:522
+msgid "Enable the output of debugging infos, possible"
+msgstr "Aktiviere die Ausgabe von Debug Informationen, mögliche"
+
+#: src/pingus_main.cxx:523
+msgid "OPTION's are tiles, gametime, actions, sound, resources, gui,"
+msgstr "Optionen sind tiles, gametime, actions, sound, resources, gui,"
+
+#: src/pingus_main.cxx:525
+msgid "Skip at least N frames, larger values speed the game up"
+msgstr ""
+"Überspringe mindestens N Bilder, größere Werte erhöhen die Geschwindigkeit"
+
+#: src/pingus_main.cxx:526
+msgid "Skip at most N frames"
+msgstr "Überspringe maximal N Bilder"
+
+#: src/pingus_main.cxx:527
+msgid "Set both min and max frameskip to N"
+msgstr "Setze sowohl minimalen als auch maximalen Bildsprung auf N"
+
+#: src/pingus_main.cxx:528
+msgid "Set the game speed (0=fastest, >0=slower)"
+msgstr "Setze die Geschwindigkeit (0=schnellste, >0=langsamer)"
+
+#: src/pingus_main.cxx:529
+msgid "Prints the fps to stdout"
+msgstr "Schreibe die fps auf stdout"
+
+#: src/pingus_main.cxx:530
+msgid "Set the size of the map tiles (default: 32)"
+msgstr "Setze die Größe der Kartenteile (Standard: 32)"
+
+#: src/pingus_main.cxx:531
+msgid "Disable some cpu intensive features"
+msgstr "Deaktivere einige CPU intensive Funktionen"
+
+#: src/pingus_main.cxx:532
+msgid "Reduces the CPU usage by issuing sleep()"
+msgstr "Reduziert die CPU Belastung durch Verwendung von sleep()"
+
+#: src/pingus_main.cxx:534
+msgid "Demo playing and recording:"
+msgstr "Demo aufzeichnung und wiedergabe:"
+
+#: src/pingus_main.cxx:535
+msgid "FILE "
+msgstr "Datei "
+
+#: src/pingus_main.cxx:535
+msgid "Plays a demo session from FILE"
+msgstr "Spielt eine Demo Sitzung aus FILE"
+
+#: src/pingus_main.cxx:537
+msgid "Record demos for each played level"
+msgstr "Nehme Demos für jeden gespielten Level auf"
+
+#: src/pingus_main.cxx:539
+msgid "Sound:"
+msgstr "Sound"
+
+#: src/pingus_main.cxx:540
+msgid "Disable sound"
+msgstr "Sound deaktivieren"
+
+#: src/pingus_main.cxx:541
+msgid "Disable music"
+msgstr "Musik deaktivieren"
+
+#: src/pingus_main.cxx:720
+msgid "clanVorbis support: ok"
+msgstr "clanVorbis Unterstützung: ok"
+
+#: src/pingus_main.cxx:722
+msgid "clanVoribs support: missing (.ogg music files will not be playable)"
+msgstr ""
+"clanVorbis Unterstützung: fehlt (.ogg Musik Datein können nicht abgespielt "
+"werden)"
+
+#: src/pingus_main.cxx:726
+msgid "clanMikMod support: ok"
+msgstr "clanMikMod Unterstützung: ok"
+
+#: src/pingus_main.cxx:728
+msgid "clanMikMod support: missing (music files will not be playable)"
+msgstr ""
+"clanMikMod Untersützung: fehlt (Musikdateien können nicht abgespielt werden)"
+
+#: src/pingus_main.cxx:732
+msgid "getext support: ok"
+msgstr "gettext Unterstützung: ok"
+
+#: src/pingus_main.cxx:733
+msgid "gettext language: english"
+msgstr "gettext Sprache: deutsch"
+
+#: src/pingus_main.cxx:739
+msgid "sound support: enabled"
+msgstr "Sound Unterstützung: an"
+
+#: src/pingus_main.cxx:741
+msgid "sound support: disabled"
+msgstr "Sound Unterstützung: aus"
+
+#: src/pingus_main.cxx:744
+msgid "music support: enabled"
+msgstr "Musik Unterstützung: an"
+
+#: src/pingus_main.cxx:746
+msgid "music support: disabled"
+msgstr "Musik Unterstützung: aus"
+
+#: src/pingus_main.cxx:748
+msgid "resolution set to: "
+msgstr "Auflösung: "
+
+#: src/pingus_main.cxx:749
+msgid "fullscreen: "
+msgstr "Vollbild: "
+
+#: src/pingus_main.cxx:750
+msgid " enabled"
+msgstr "aktiviert"
+
+#: src/pingus_main.cxx:750
+msgid "disabled"
+msgstr "deaktiviert"
+
--- /dev/null
+#include <iostream>
+
+#define _(x) gettext(x)
+
+int main()
+{
+ std::cout << _("Short Hello World") << std::endl;
+ std::cout << gettext("Hello World") << std::endl;
+ std::cout << gettext("Hello Worlds") << std::endl;
+
+ std::cout << pgettext("", "Hello World") << std::endl;
+ std::cout << pgettext("console", "Hello World") << std::endl;
+
+ std::cout << ngettext("gui", "Hello World") << std::endl;
+ std::cout << ngettext("Hello World", "Hello Worlds", 5) << std::endl;
+
+ std::cout << npgettext("", "Hello World", "Hello Worlds", 5) << std::endl;
+ std::cout << npgettext("console", "Hello World", "Hello Worlds", 5) << std::endl;
+ std::cout << npgettext("gui", "Hello World", "Hello Worlds", 5) << std::endl;
+
+ return 0;
+}
+
+/* EOF */
--- /dev/null
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR Free Software Foundation, Inc.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-01-30 08:01+0100\n"
+"PO-Revision-Date: 2009-01-30 08:39+0100\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: helloworld.cpp:7
+msgid "Short Hello World"
+msgstr "kurzes Hallo Welt"
+
+#: helloworld.cpp:8 helloworld.cpp:14
+#, fuzzy
+msgid "Hello World"
+msgid_plural "Hello Worlds"
+msgstr[0] "Hallo Welt (singular)"
+msgstr[1] "Hallo Welt (plural)"
+
+#: helloworld.cpp:10 helloworld.cpp:16
+#, fuzzy
+msgctxt ""
+msgid "Hello World"
+msgid_plural "Hello Worlds"
+msgstr[0] "Hallo Welt (singular) mit leerem Kontext"
+msgstr[1] "Hallo Welt (plural) mit leerem Kontext"
+
+#: helloworld.cpp:11 helloworld.cpp:17
+msgctxt "console"
+msgid "Hello World"
+msgid_plural "Hello Worlds"
+msgstr[0] "Hallo Welt (singular) in der Console"
+msgstr[1] "Hallo Welt (plural) in der Console"
+
+#: helloworld.cpp:13
+msgid "gui"
+msgid_plural "Hello World"
+msgstr[0] "Hallo Welt (singular)"
+msgstr[1] "Hallo Welt (plural)"
+
+#: helloworld.cpp:18
+#, fuzzy
+msgctxt "gui"
+msgid "Hello World"
+msgid_plural "Hello Worlds"
+msgstr[0] "Hallo Welt im GUI"
+msgstr[1] "Hallo Welt (plural) im GUI"
--- /dev/null
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-01-30 08:10+0100\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
+
+#: helloworld.cpp:7
+msgid "Short Hello World"
+msgstr ""
+
+#: helloworld.cpp:8 helloworld.cpp:14
+msgid "Hello World"
+msgid_plural "Hello Worlds"
+msgstr[0] ""
+msgstr[1] ""
+
+#: helloworld.cpp:10 helloworld.cpp:16
+msgctxt ""
+msgid "Hello World"
+msgid_plural "Hello Worlds"
+msgstr[0] ""
+msgstr[1] ""
+
+#: helloworld.cpp:11 helloworld.cpp:17
+msgctxt "console"
+msgid "Hello World"
+msgid_plural "Hello Worlds"
+msgstr[0] ""
+msgstr[1] ""
+
+#: helloworld.cpp:13
+msgid "gui"
+msgid_plural "Hello World"
+msgstr[0] ""
+msgstr[1] ""
+
+#: helloworld.cpp:18
+msgctxt "gui"
+msgid "Hello World"
+msgid_plural "Hello Worlds"
+msgstr[0] ""
+msgstr[1] ""
--- /dev/null
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR Free Software Foundation, Inc.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI +ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: src/pingus_main.cxx:760
+msgid "PingusMain: Starting Main: "
+msgstr "PingusMain: Hauptteil wird gestartet: "
+
+#: src/pingus_main.cxx:805
+msgid "PingusMain: Levelfile not found, ignoring: "
+msgstr "PingusMain: Leveldatei nicht gefunden, Fehler wird ignoriert: "
+
+#: src/pingus_main.cxx:909
+msgid "Error caught from ClanLib: "
+msgstr "ClanLib Fehler abgefangen: "
+
+#: src/pingus_main.cxx:913
+msgid "Error caught from Pingus: "
+msgstr "Pingus Fehler wurde abgefangen: "
+
+#: src/pingus_main.cxx:917
+msgid "Pingus: Out of memory!"
+msgstr "Pingus: Speicher ist ausgegangen"
+
+#: src/pingus_main.cxx:921
+msgid "Pingus: Standard exception caught!:\n"
+msgstr "Pingus: Standard Ausnahme abgefangen!:\n"
+
+#: src/pingus_main.cxx:925
+msgid "Pingus: Unknown throw caught!"
+msgstr "Pingus: Unbekannte Ausnahme abgefangen!"
+
+#: src/result_screen.cxx:99 src/start_screen.cxx:111
+msgid "Abort"
+msgstr "Abbruch"
+
+#: src/result_screen.cxx:167
+msgid "Retry"
+msgstr "Versuche erneut"
+
+#: src/result_screen.cxx:175
+msgid "Success!"
+msgstr "Erfolg!"
+
+#: src/result_screen.cxx:182
+msgid "Failure!"
+msgstr "Fehler!"
+
+#: src/result_screen.cxx:191
+msgid "Perfect! You saved everyone possible - great!"
+msgstr "Perfekt! Du hast alle gerettet!"
+
+#: src/result_screen.cxx:193
+msgid "No-one got killed, pretty good work."
+msgstr "Keiner wurde getötet, sehr gute Arbeit."
+
+#: src/result_screen.cxx:195
+msgid ""
+"You saved exactly what you needed - you made it, but\n"
+"maybe you can do better?"
+msgstr ""
+"Du hast so viele gerettet wie nötig. Du hast es\n"
+"geschafft, aber vielleicht kannst Du es noch besser?"
+
+#: src/result_screen.cxx:198
+msgid "Not everybody was saved, but still good work!"
+msgstr "Nicht alle wurden gerettet, aber trotzdem noch gute Arbeit!"
+
+#: src/result_screen.cxx:200
+msgid "What can I say, you made it - congratulations!"
+msgstr "Was soll ich sagen, Du hast es geschafft. Gratuliere!"
+
+#: src/result_screen.cxx:205
+msgid "You killed everybody, not good."
+msgstr "Du hast alle getötet, nicht gut."
+
+#: src/result_screen.cxx:207
+msgid "No-one got saved - I know you can do better."
+msgstr "Keiner wurde gerettet, ich weiß, dass du es besser kannst."
+
+#: src/result_screen.cxx:209
+msgid ""
+"You didn't save enough, but you saved a few. Next\n"
+"time you might do better."
+msgstr ""
+"Du hast nicht genug gerettet, aber immerhin ein paar.\n"
+"Nächstes Mal machst du es bestimmt besser."
+
+#: src/result_screen.cxx:212
+msgid "Only one more and you would have made it - try again!"
+msgstr "Einer mehr und du hast es, versuch es nochmal!"
+
+#: src/result_screen.cxx:214
+msgid "Only a handful more and you would have made it - try again!"
+msgstr "Nur ein paar mehr und du hättest es, versuch es nochmal!"
+
+#: src/result_screen.cxx:216
+msgid "Better luck next time!"
+msgstr "Mehr Glück fürs nächste Mal!"
+
+#: src/result_screen.cxx:232
+msgid "Saved: "
+msgstr "Gerettet: "
+
+#: src/result_screen.cxx:236
+msgid "Died: "
+msgstr "Getötet: "
+
+#: src/result_screen.cxx:240
+msgid "Time left: "
+msgstr "Verbliebene Zeit: "
+
+#: src/screenshot.cxx:45
+msgid "Screenshot: Saving screenshot to: "
+msgstr "Screenshot: Speichere Screenshot als: "
+
+#: src/screenshot.cxx:47
+msgid "Screenshot: Screenshot is done."
+msgstr "Screenshot: Screenshot wurde erstellt."
+
+#: src/screenshot.cxx:53
+msgid "Screenshot: Couldn't save screenshot"
+msgstr "Screenshot: Screenshot konnte nicht gespeichert werden"
+
+#: src/screenshot.cxx:138
+msgid "Screenshot: Couldn't write file: "
+msgstr "Screenshot: Datei konnte nicht geschrieben werden: "
+
+#: src/spot_map.cxx:286
+#, c-format
+msgid "Image has wrong color depth: %d"
+msgstr "Bild hat falsche Farbtiefe: %d"
+
+#: src/start_screen.cxx:75
+msgid "Ok"
+msgstr "Ok"
+
+#: src/start_screen.cxx:158
+msgid "Number of Pingus: "
+msgstr "Anzahl an Pingus: "
+
+#: src/start_screen.cxx:161
+msgid "Number to Save: "
+msgstr "Zu rettende Pingus: "
+
+#: src/start_screen.cxx:164
+msgid "Time: "
+msgstr "Zeit: "
+
+#: src/start_screen.cxx:167
+msgid "Difficulty:"
+msgstr "Schwierigkeitsgrad:"
+
+#: src/start_screen.cxx:175
+msgid "Author: "
+msgstr "Autor: "
+
+#: src/start_screen.cxx:178
+msgid "Filename: "
+msgstr "Dateiname: "
+
+#: src/story.cxx:41
+msgid "The Journey Continues"
+msgstr "Die Reise geht weiter"
+
+#: src/story.cxx:46
+msgid ""
+"Now after you and the Pingus have learned the basics and\n"
+"practiced a bit it is time to move on and begin the journey into\n"
+"the world. Since the ice floe with which the Pingus traveled to the\n"
+"Tutorial Island isn't going to hold on the whole way into the warmer\n"
+"climates the Pingus have to find something else to guide\n"
+"them on their journey.\n"
+msgstr ""
+"Nachdem Du und die Pingus nun die Grundlagen gelernt und\n"
+"ein wenig Übung haben, ist es an der Zeit, weiter zu gehen und die\n"
+"Reise in die Welt zu beginnen. Da die Scholle, mit der die Pingus zum\n"
+"Tutorial Island reisten, nicht den ganzen Weg in die wärmeren Regionen\n"
+"halten wird, müssen die Pingus etwas anderes finden, um sie auf der\n"
+"Reise zu begleiten.\n"
+
+#: src/story.cxx:58
+msgid ""
+"But as the eldest have said, the Tutorial Island provides not\n"
+"only a good way to practice, but it is also the starting point into\n"
+"the world. After some searching the Pingus discovered the meaning\n"
+"of this, and they found the large tree at the end of the island\n"
+"which gave them wood to construct a float.\n"
+msgstr ""
+"Aber wie die Weisen sagten, ist Tutorial Island nicht nur\n"
+"eine Möglichkeit zum üben, es ist auch der erste Schritt in\n"
+"die Welt, denn das Holz der Bäume am Ende der Insel liefert\n"
+"gutes Material, um ein Floß zu bauen.\n"
+
+#: src/story.cxx:69
+msgid ""
+"So the Pingus set out and constructed some large rafts, enough\n"
+"to carry them all. After also packing a bunch of provisions\n"
+"they were prepared to start their journey and leave\n"
+"their familiar ground and enter the unknown parts of the world.\n"
+msgstr ""
+"So gingen die Pingus hin und bauten ein paar große\n"
+"Flöße, genug, um alle zu tragen. Nachdem sie auch noch einigen\n"
+"Proviant eingepackt hatten, waren sie endlich bereit, ihre Reise zu\n"
+"beginnen, den bekannten Bereich zu verlassen und die unbekannten\n"
+"Bereiche der Welt zu betreten.\n"
+
+#: src/story.cxx:79
+msgid ""
+"So the Pingus sit on their raft, worrying about what's to come and\n"
+"where to go, while floating into the sunset.\n"
+"\n"
+"To be continued..."
+msgstr ""
+"So saßen die Pingus nur auf ihrem Floß und sorgten sich, was denn nun\n"
+"kommen möge, während sie in den Sonnenuntergang trieben.\n"
+"\n"
+"Fortsetzung folgt..."
+
+#: src/story.cxx:91
+msgid "The Journey Begins"
+msgstr "Die Reise beginnt"
+
+#: src/story.cxx:96
+msgid ""
+"For a long time, the Pingus have lived happily in peace on the\n"
+"South Pole along with all the other animals. Everything was in\n"
+"balance and it seemed like nothing could disrupt their peace. The\n"
+"Pingus were happy and it seemed like this could never end.\n"
+msgstr ""
+"Die Pingus lebten schon lange glücklich und in Frieden am Südpol,\n"
+"zusammen mit all den anderen Tieren. Alles war im Gleichgewicht und\n"
+"es schien, als könnte nichts ihren Frieden stören. Die Pingus waren\n"
+"glücklich und es schien, als würde dies niemals enden.\n"
+
+#: src/story.cxx:106
+msgid ""
+"But then one day, things began to change slowly: the sky got darker\n"
+"and the earth got warmer. Firstly, they thought this was just a\n"
+"normal fluctuation in the world's climate, but things seemed to get\n"
+"worse and worse with every year."
+msgstr ""
+"Aber dann, eines Tages, veränderten sich die Dinge langsam. Der\n"
+"Himmel wurde dunkler und die Erde wärmer. Zuerst dachten sie, dies\n"
+"wäre nur eine normale Schwankung im Klima, aber es wurde von Jahr \n"
+"zu Jahr immer schlimmer."
+
+#: src/story.cxx:117
+msgid ""
+"The snow began to melt away in a few areas and food became an\n"
+"issue. Other animals tried to leave the region to search\n"
+"for colder areas, but the Pingus knew that this wouldn't help:\n"
+"they knew that they had to do something about it."
+msgstr ""
+"Der Schnee begann in einigen Bereichen zu schmelzen und Nahrung\n"
+"wurde ein Problem. Andere Tiere begannen bereits, die Region zu\n"
+"verlassen, um kältere Gebiete zu suchen. Aber die Pingus wussten,\n"
+"dass dies nicht helfen würde, sie wussten, es musste etwas gegen\n"
+"dieses Problem getan werden."
+
+#: src/story.cxx:127
+msgid ""
+"So the circle of the eldest came together to decide what to do\n"
+"about it. They decided to send out an expedition around the world\n"
+"to find the cause of this warming. The expedition consisted of\n"
+"hundreds of the bravest Pingus on the South Pole."
+msgstr ""
+"Darum traf sich der Rat der Ältesten, um zu entscheiden, was dagegen\n"
+"getan werden sollte. Sie entschieden, eine Expedition um die Welt\n"
+"zu senden, um den Grund für die Erwärmung zu finden. Die Expedition\n"
+"bestand aus hunderten der mutigsten Pingus des ganzen Südpols."
+
+#: src/story.cxx:137
+msgid ""
+"And they picked you to lead them on their journey around the\n"
+"world. Since the journey will be dangerous and difficult, your\n"
+"first goal is the Island of Mogorok, also known as the Tutorial\n"
+"Island. According to the eldest, this island has always been the\n"
+"first stop of Pingus that were sent out into the world."
+msgstr ""
+"Und sie wählten dich, um sie auf der Reise um die Welt zu führen.\n"
+"Denn die Reise wird gefährlich und schwierig werden. Dein erstes Ziel ist\n"
+"die Insel Mogorok, auch bekannt als Tutorial Island. Den Weisen\n"
+"zufolge war diese Insel immer der erste Anlaufpunkt für Pingus,\n"
+"die in die Welt gesandt wurden."
+
+#: src/story.cxx:148
+msgid ""
+"The island consists of many areas that are ideal to teach the\n"
+"Pingus their abilities. The Pingus can learn to build\n"
+"bridges, climb, bash and use many other talents which they\n"
+"will need on their long and dangerous journey."
+msgstr ""
+"Die Insel besteht aus verschiedenen Regionen, die ideal sind, um die\n"
+"Fähigkeiten der Pingus zu trainieren. Sie können dort ihre Fähig-\n"
+"keiten im Brückenbau, klettern, graben und all die anderen Talente\n"
+"trainieren, die sie sicher auf der langen und gefährlichen Reise\n"
+"benötigen werden."
+
+#: src/story.cxx:158
+msgid ""
+"While there, you can practice your abilities in commanding\n"
+"and guiding the Pingus. You can also get familiar with\n"
+"all the abilities the Pingus provide and learn to master them,\n"
+"since you will need all of them on your journey around the\n"
+"world."
+msgstr ""
+"Währenddessen kannst Du auf der anderen Seite deine Fähigkeit, die\n"
+"Pingus zu leiten und zu führen, trainieren. Du kannst dich dort auch mit\n"
+"allen Fähigkeiten vertraut machen, die die Pingus besitzen und\n"
+"erlernen, sie zu meistern, denn du wirst sie sicher alle auf der\n"
+"Reise um die Welt benötigen."
+
+#: src/story.cxx:169
+msgid ""
+"Now that you and the Pingus have arrived at Tutorial Island it\n"
+"is time to take command and begin your mission.\n"
+"\n"
+"Good Luck!"
+msgstr ""
+"Nun da du und die Pingus im Tutorial Island angekommen sind,\n"
+"musst du das Kommando übernehmen und deine Mission beginnen.\n"
+"\n"
+"Viel Glück!"
+
+#: src/system.cxx:273
+msgid "Environment variable $HOME not set, fix that and start again."
+msgstr ""
+"Umgebungs Variable $HOME ist nicht gesetzt. Setze sie und starte erneut."
+
+#: src/worldmap/level_dot.cxx:174 src/worldmap/level_dot.cxx:184
+msgid "locked"
+msgstr "gesperrt"
+
+#: src/worldmap/manager.cxx:103
+msgid "Show Ending?"
+msgstr "Ende anzeigen?"
+
+#: src/worldmap/manager.cxx:133
+msgid "Show Story?"
+msgstr "Story zeigen?"
+
+#: src/worldmap/manager.cxx:161
+msgid "Leave?"
+msgstr "Verlassen?"
+
+#: src/worldmap/manager.cxx:201
+msgid "Enter?"
+msgstr "Betreten?"
+
+#: src/worldmap/worldmap.cxx:77
+msgid "WorldMap: File not found: "
+msgstr "Worldmap: Datei nicht gefunden: "
+
+#: src/worldmap/worldmap.cxx:261
+msgid "...walking..."
+msgstr "...laufe..."
+
+msgid "You got %d error.\n"
+msgid_plural "You got %d error.\n"
+msgstr[0] "Du hast %d fehler\n"
+msgstr[1] "Du hast %d fehlers\n"
+
+msgid "found %d fatal error"
+msgid_plural "found %d fatal errors"
+msgstr[0] "s'ha trobat %d error fatal"
+msgstr[1] "s'han trobat %d errors fatals"
+
--- /dev/null
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR Free Software Foundation, Inc.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Pingus 0.6.0\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2004-04-09 18:37+0000\n"
+"PO-Revision-Date: 2009-02-01 17:44+0100\n"
+"Last-Translator: David Philippi <david@torangan.de>\n"
+"Language-Team: David Philippi <david@torangan.de>, Ingo Ruhnke <grumbel@gmx.de>, Giray Devlet <giray@devlet.cc>\n"
+"MIME-Version: 1.0\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+msgid "umlaut"
+msgstr "ÄÖÜäöüß"
+
+#: src/actions/bridger.cxx:48 src/actions/bridger.cxx:232
+#: src/pingu_enums.cxx:40
+msgid "Bridger"
+msgstr "Bridger"
+
+#: src/config.cxx:73
+msgid "Couldn't open: "
+msgstr "Datei oder Verzeichnis konnte nicht geöffnet werden: "
+
+#: src/config.cxx:172
+msgid "Unexpected char: '"
+msgstr "Unerwartetes Zeichen: '"
+
+#: src/config.cxx:206
+msgid "Unexpected char '"
+msgstr "Unerwartetes Zeichen: '"
+
+#: src/credits.cxx:48
+msgid "-Idea"
+msgstr "-Idee"
+
+#: src/credits.cxx:52
+msgid "-Maintaining"
+msgstr "-Verwaltung"
+
+#: src/credits.cxx:56
+msgid "-Programming"
+msgstr "-Programmierung"
+
+#: src/credits.cxx:62
+msgid "-Porting (Win32)"
+msgstr "-Portierung (Win32)"
+
+#: src/credits.cxx:70
+msgid "-Gfx"
+msgstr "-Grafiken"
+
+#: src/credits.cxx:82
+msgid "-Music"
+msgstr "-Musik"
+
+#: src/credits.cxx:88
+msgid "-Level Design"
+msgstr "-Level Design"
+
+#: src/credits.cxx:93
+msgid "-Story"
+msgstr "-Geschichte"
+
+#: src/credits.cxx:97
+msgid "-Translation"
+msgstr "-Übersetzung"
+
+#: src/credits.cxx:112
+msgid "-Special"
+msgstr "-Besonderen"
+
+#: src/credits.cxx:113
+msgid "-Thanks to"
+msgstr "-Dank an"
+
+#: src/credits.cxx:154
+msgid "_And a very Special Thanks"
+msgstr "_Und einen besonderen Dank"
+
+#: src/credits.cxx:155
+msgid "_to all the people who"
+msgstr "_an alle Leute die"
+
+#: src/credits.cxx:156
+msgid "_contribute to"
+msgstr "_an Freier Software"
+
+#: src/credits.cxx:157
+msgid "_Free Software!"
+msgstr "_mitarbeiten!"
+
+#: src/credits.cxx:163
+msgid "_Thank you for"
+msgstr "_Dankeschön fürs"
+
+#: src/credits.cxx:164
+msgid "_playing!"
+msgstr "_spielen!"
+
+#: src/editor/editor_event.cxx:588
+msgid "Enter filename to save as:"
+msgstr "Datei speichern als: "
+
+#: src/editor/editor_help_screen.cxx:43
+msgid "Editor Helpscreen (hide with F1)"
+msgstr "Editor Hilfe (ausblenden mit F1)"
+
+#: src/editor/editor_help_screen.cxx:51
+msgid "F1 - show/hide this help screen"
+msgstr "F1 - Hilfe anzeigen/verstecken"
+
+#: src/editor/editor_help_screen.cxx:52
+msgid "F2 - launch level building tutorial"
+msgstr "F2 - Starte Levelbau Tutorial"
+
+#: src/editor/editor_help_screen.cxx:53
+msgid "F3 - toggle background color"
+msgstr "F3 - Hintergrundfarbe aendern"
+
+#: src/editor/editor_help_screen.cxx:54
+msgid "F4 - play/test the level"
+msgstr "F4 - Level starten/testen"
+
+#: src/editor/editor_help_screen.cxx:55
+msgid "F5 - load a level"
+msgstr "Level Laden (F5)"
+
+#: src/editor/editor_help_screen.cxx:56
+msgid "F6 - save this level"
+msgstr "Level Speichern (F6)"
+
+#: src/editor/editor_help_screen.cxx:57
+msgid "F7 - [unset]"
+msgstr "F7 - [nicht belegt]"
+
+#: src/editor/editor_help_screen.cxx:58
+msgid "F8 - quick save/backup save?!"
+msgstr "F8 - Schnellspeichern/Backup"
+
+#: src/editor/editor_help_screen.cxx:59
+msgid "F9 - change level width and height"
+msgstr "F9 - Level Höhe und Breite ändern"
+
+#: src/editor/editor_help_screen.cxx:60
+msgid "F10 - [unset]"
+msgstr "F10 - [nicht belegt]"
+
+#: src/editor/editor_help_screen.cxx:61
+msgid "F11 - toggle fps counter"
+msgstr "F11 - fps Zähler an/aus"
+
+#: src/editor/editor_help_screen.cxx:62
+msgid "F12 - make screenshot"
+msgstr "F12 - Screenshot erstellen"
+
+#: src/editor/editor_help_screen.cxx:66
+msgid "Home - increase object size"
+msgstr "Einfg - Objekt vergrößern"
+
+#: src/editor/editor_help_screen.cxx:67
+msgid "End - decrease object size"
+msgstr "Ende - Objekt verkleinern"
+
+#: src/editor/editor_help_screen.cxx:68
+msgid "Cursor Keys - Move object"
+msgstr "Cursor Tasten - Objekt bewegen"
+
+#: src/editor/editor_help_screen.cxx:69
+msgid "Shift 'Cursor Keys' - Move objects fast "
+msgstr "Shift Cursor Tasten - Objekt schneller bewegen"
+
+#: src/editor/editor_help_screen.cxx:70
+msgid "PageUp - level object up"
+msgstr "Bild rauf - Objekt nach oben"
+
+#: src/editor/editor_help_screen.cxx:71
+msgid "PageDown - level object down"
+msgstr "Bild runter - Objekt nach unten"
+
+#: src/editor/editor_help_screen.cxx:72
+msgid "Shift PageUp - increase objects z-pos by 50"
+msgstr "Shift Bild rauf - Objekt nach oben"
+
+#: src/editor/editor_help_screen.cxx:73
+msgid "Shift PageDown - decrease objects z-pos by 50"
+msgstr "Shift Bild runter - Objekt nach unten"
+
+#: src/editor/editor_help_screen.cxx:74
+msgid "Enter - Set default zoom (1:1)"
+msgstr "Eingabe - Setze Standard Zoom (1:1)"
+
+#: src/editor/editor_help_screen.cxx:75
+msgid "d - duplicate object"
+msgstr "d - Objekt kopieren"
+
+#: src/editor/editor_help_screen.cxx:76
+msgid "a - mark all objects"
+msgstr "a - Alle Objekte markieren"
+
+#: src/editor/editor_help_screen.cxx:77
+msgid "shift leftmouseclick - add object to selection"
+msgstr "Shift + linke Maustaste - Objekt zur Auswahl tun"
+
+#: src/editor/editor_help_screen.cxx:78
+msgid "leftmouseclick - select object"
+msgstr "linke Maustaste - Objekt auswählen"
+
+#: src/editor/editor_help_screen.cxx:79
+msgid "Insert - insert new object"
+msgstr "Einfügen - neues Objekt einfügen"
+
+#: src/editor/editor_help_screen.cxx:80
+msgid "Remove - remove selected object"
+msgstr "Entfernen - entferne ausgewähltes Objekt"
+
+#: src/editor/editor_help_screen.cxx:81
+msgid "g - ungroup/group current selection"
+msgstr "g - Auswahl gruppieren / Gruppierung aufheben"
+
+#: src/editor/editor_help_screen.cxx:82
+msgid "Ctrl PageUp - increase objects z-pos by 1"
+msgstr "Strg Bild rauf - z-pos des Objekts um 1 erhöhen"
+
+#: src/editor/editor_help_screen.cxx:83
+msgid "Ctrl PageDown - decrease objects z-pos by 1"
+msgstr "Strg Bild runter - z-pos des Objekts um 1 senken"
+
+#: src/editor/editor_help_screen.cxx:89
+msgid "Naming Convention: <LEVELNAME><NUMBER>-<CREATOR>.plf"
+msgstr "Dateinamensvorgabe: <LEVELNAME><NUMMER>-<AUTOR>.pfl"
+
+#: src/editor/editor_help_screen.cxx:91
+msgid ""
+"When you have created a level and want to have it in the next Pingus "
+"release,\n"
+"please mail it to pingus-devel@nongnu.org."
+msgstr ""
+"Falls Du einen Level erstellt hast und ihn gerne im nächsten Pingus\n"
+"Release hättest, schicke ihn an pingus-devel@nongnu.org."
+
+#: src/editor/object_selector.cxx:106
+msgid "1 - guillotine"
+msgstr "1 - Guillotine"
+
+#: src/editor/object_selector.cxx:107
+msgid "2 - hammer"
+msgstr "2 - Hammer"
+
+#: src/editor/object_selector.cxx:108
+msgid "3 - spike"
+msgstr "3 - Stacheln"
+
+#: src/editor/object_selector.cxx:109
+msgid "4 - laser_exit"
+msgstr "4 - Laser Ausgang"
+
+#: src/editor/object_selector.cxx:110
+msgid "5 - fake_exit"
+msgstr "5 - Täusch Ausgang"
+
+#: src/editor/object_selector.cxx:111
+msgid "6 - smasher"
+msgstr "6 - Stampfer"
+
+#: src/editor/object_selector.cxx:112
+msgid "7 - bumper"
+msgstr "7 - Stosser"
+
+#: src/editor/object_selector.cxx:186
+msgid "Select a WorldObj"
+msgstr "Wähle ein WeltObjekt"
+
+#: src/editor/object_selector.cxx:187
+msgid "1 - teleporter"
+msgstr "1 - Teleporter"
+
+#: src/editor/object_selector.cxx:188
+msgid "2 - switch and door"
+msgstr "2 - Schalter und Tür"
+
+#: src/editor/object_selector.cxx:189
+msgid "3 - ConveyorBelt"
+msgstr "3 - Förderband"
+
+#: src/editor/object_selector.cxx:190
+msgid "4 - IceBlock"
+msgstr "4 - Eisblock"
+
+#: src/editor/object_selector.cxx:191
+msgid "5 - InfoBox"
+msgstr "5 - InfoBox"
+
+#: src/editor/object_selector.cxx:232
+msgid "Select a weather"
+msgstr "Wähle ein Wetter"
+
+#: src/editor/object_selector.cxx:233
+msgid "1 - snow"
+msgstr "1 - Schnee"
+
+#: src/editor/object_selector.cxx:234
+msgid "2 - rain"
+msgstr "2 - Regen"
+
+#: src/editor/object_selector.cxx:265
+msgid "Select an entrance"
+msgstr "Wähle einen Eingang"
+
+#: src/editor/object_selector.cxx:266
+msgid "1 - generic"
+msgstr "1 - allgemein"
+
+#: src/editor/object_selector.cxx:267
+msgid "2 - woodthing"
+msgstr "2 - hölzern"
+
+#: src/editor/object_selector.cxx:268
+msgid "3 - cloud"
+msgstr "3 - Wolke"
+
+#: src/editor/object_selector.cxx:269
+msgid "h - entrance surface (hotspot)"
+msgstr "h - Eingangs Grafik (hotspot)"
+
+#: src/editor/object_selector.cxx:343
+msgid "What object type do you want?"
+msgstr "Was für ein Objekt willst du?"
+
+#: src/editor/object_selector.cxx:344 src/editor/object_selector.cxx:400
+msgid "h - Hotspot"
+msgstr "h - Grafikelement (hotspot)"
+
+#: src/editor/object_selector.cxx:345
+msgid "g - Groundpiece (ground) [not implemented]"
+msgstr "g - Bodenstück (ground) [nicht implementiert]"
+
+#: src/editor/object_selector.cxx:394 src/editor/object_selector.cxx:562
+msgid "Which object do you want?"
+msgstr "Welches Objekt willst du?"
+
+#: src/editor/object_selector.cxx:395
+msgid "g - Groundpiece (ground)"
+msgstr "g - Bodenstück (ground)"
+
+#: src/editor/object_selector.cxx:396
+msgid "s - Groundpiece (solid)"
+msgstr "s - Bodenelement (Stahl)"
+
+#: src/editor/object_selector.cxx:397
+msgid "b - Groundpiece (bridge)"
+msgstr "b - Bodenelement (Bruecke)"
+
+#: src/editor/object_selector.cxx:398
+msgid "n - Groundpiece (transparent)"
+msgstr "n - Bodenelement (transparent)"
+
+#: src/editor/object_selector.cxx:399
+msgid "r - Groundpiece (remove)"
+msgstr "r - Bodenelement (entfernen)"
+
+#: src/editor/object_selector.cxx:401
+msgid "e - Entrance"
+msgstr "e - Eingang"
+
+#: src/editor/object_selector.cxx:402
+msgid "x - Exit"
+msgstr "x - Ausgang"
+
+#: src/editor/object_selector.cxx:403
+msgid "l - Liquid"
+msgstr "l - Flüssigkeit"
+
+#: src/editor/object_selector.cxx:404
+msgid "w - Weather"
+msgstr "w - Wetter"
+
+#: src/editor/object_selector.cxx:405
+msgid "t - Traps"
+msgstr "t - Falle"
+
+#: src/editor/object_selector.cxx:406
+msgid "o - WorldObject"
+msgstr "o - WeltObjekt"
+
+#: src/editor/object_selector.cxx:407
+msgid "z - Background"
+msgstr "z - Hintergrund"
+
+#: src/editor/object_selector.cxx:408
+msgid "p - Prefab (ObjectGroup)"
+msgstr "p - Prefab (Objekt Gruppe)"
+
+#: src/editor/object_selector.cxx:409
+msgid "f - something from file (~/.pingus/images/)"
+msgstr "f - etwas aus einer Datei (~/.pingus/images/)"
+
+#: src/editor/object_selector.cxx:498
+msgid "Which prefab do you want?"
+msgstr "Welche Prefab willst du?"
+
+#: src/editor/object_selector.cxx:563
+msgid "1 - Surface Background"
+msgstr "1 - Bild Hintergrund"
+
+#: src/editor/object_selector.cxx:564
+msgid "2 - Solid Color Background"
+msgstr "2 - Farb Hintergrund"
+
+#: src/editor/object_selector.cxx:565
+msgid "3 - Starfield Background"
+msgstr "3 - Sternen Hintergrund"
+
+#: src/editor/object_selector.cxx:566
+msgid "4 - Thunderstorm Background"
+msgstr "4 - Gewitter Hintergrund"
+
+#: src/editor/panel_icons.cxx:33
+msgid "Load a level (F5)"
+msgstr "Level laden (F5)"
+
+#: src/editor/panel_icons.cxx:46
+msgid "Exit the editor (Escape)"
+msgstr "Editor Beenden (Esc)"
+
+#: src/editor/panel_icons.cxx:58
+msgid "Save this level (F6)"
+msgstr "Level Speichern (F6)"
+
+#: src/editor/panel_icons.cxx:70
+msgid "Delete marked objects (delete)"
+msgstr "Markierte Objekte Löschen (Entfernen)"
+
+#: src/editor/panel_icons.cxx:82
+msgid "Duplicate current object (d)"
+msgstr "Aktuelles Object kopieren (d)"
+
+#: src/editor/panel_icons.cxx:94
+msgid "Edit Level Properties"
+msgstr "Leveleigenschaften ändern"
+
+#: src/editor/panel_icons.cxx:106
+msgid "Edit Object Properties"
+msgstr "Objekteigenschaften ändern"
+
+#: src/editor/panel_icons.cxx:118
+msgid "Start the level and test it (F4)"
+msgstr "Level starten und testen (F4)"
+
+#: src/editor/panel_icons.cxx:130
+msgid "Create a new level from scratch"
+msgstr "Neuen Level erstellen"
+
+#: src/editor/panel_icons.cxx:142
+msgid "Insert an object (Insert)"
+msgstr "Objekt einfuegen (Einfg)"
+
+#: src/editor/panel_icons.cxx:154
+msgid "Zoom into a region"
+msgstr "Einen Bereich vergrössern"
+
+#: src/editor/panel_icons.cxx:166
+msgid "Zoom in"
+msgstr "Vergroessern"
+
+#: src/editor/panel_icons.cxx:179
+msgid "Zoom out"
+msgstr "Verkleinern"
+
+#: src/editor/panel_icons.cxx:192
+msgid "Setup Number of Actions"
+msgstr "Stelle die Anzahl der Fähigkeiten ein"
+
+#: src/editor/panel_icons.cxx:204
+msgid "Display Help Screen (F1)"
+msgstr "Hilfe Anzeigen (F1)"
+
+#: src/exit_menu.cxx:48
+msgid "Yes"
+msgstr "Ja"
+
+#: src/exit_menu.cxx:81
+msgid "No"
+msgstr "Nein"
+
+#: src/exit_menu.cxx:114
+msgid "Exit Pingus?"
+msgstr "Pingus beenden?"
+
+#: src/fps_counter.cxx:48
+msgid "unknown"
+msgstr "unbekannt"
+
+#: src/game_time.cxx:70
+msgid "unlimited"
+msgstr "unbegrenzt"
+
+#: src/level_desc.cxx:74
+msgid "Designed by "
+msgstr "Erstellt von "
+
+#: src/level_desc.cxx:79
+#, c-format
+msgid "Pingus to Save: %d"
+msgstr "Zu rettende Pingus: %d"
+
+#: src/level_desc.cxx:81
+#, c-format
+msgid "Number of Pingus: %d"
+msgstr "Anzahl an Pingus: %d"
+
+#: src/level_desc.cxx:86
+msgid "Loading..."
+msgstr "Ladevorgang läuft..."
+
+#: src/level_desc.cxx:89
+msgid "Loading finished. Press a mouse button to start the level"
+msgstr ""
+"Ladevorgang abgeschlossen. Drücke eine Maus Taste um den Level zu starten"
+
+#: src/level_result.cxx:61
+msgid "Results:"
+msgstr "Ergebnisse:"
+
+#: src/level_result.cxx:67
+#, c-format
+msgid "Pingus saved: %3d/%3d"
+msgstr "Gerettete Pingus: %3d/%3d"
+
+#: src/level_result.cxx:72
+#, c-format
+msgid "Pingus died: %3d/%3d"
+msgstr "Tote Pingus: %3d/%3d"
+
+#: src/level_result.cxx:88
+msgid "Press button to continue..."
+msgstr "Knopf drücken um fortzufahren"
+
+#: src/level_result.cxx:102
+msgid ""
+"As many Pingus escaped as entered the level. That's going to be hard to "
+"beat.... unless this game becomes pornographic."
+msgstr ""
+"Es wurden alle Pingu dieses Levels gerettet. Das wird hart zu schlagen "
+"sein... es sei denn dieses Spiel wird pornographisch."
+
+#: src/level_result.cxx:104
+msgid "Very impressive indeed."
+msgstr "In der Tat sehr eindrucksvoll."
+
+#: src/level_result.cxx:106
+msgid "Good work. Still room for improvement though."
+msgstr "Gute Arbeit. Aber Übung macht den Meiser!"
+
+#: src/level_result.cxx:108
+msgid "Not too shabby, not too shabby at all."
+msgstr "Nicht schlecht, nicht schlecht!"
+
+#: src/level_result.cxx:110
+msgid ""
+"That was OK, but Pingu life insurance premiums have just gotten more "
+"expensive."
+msgstr ""
+"Das war ok, aber die Lebensversicherungsprämien für Pingus sind gerade "
+"gestiegen."
+
+#: src/level_result.cxx:112
+msgid "Maybe this level calls for a different strategy."
+msgstr "Möglicherweise verlangt dieser Level eine andere Strategie."
+
+#: src/level_result.cxx:114
+msgid "Exactly half. Are you saving only the female ones?"
+msgstr "Genau die Hälfte! Rettest du nur die Weibchen?"
+
+#: src/level_result.cxx:116
+msgid "If I were a Pingu, I never would have left that entrance."
+msgstr "Wenn ich ein Pingu wäre, hätte ich den Eingang nie verlassen."
+
+#: src/level_result.cxx:118
+msgid "Maybe you would feel more at home playing Quake."
+msgstr "Möglicherweise wäre es besser Quake zu spielen?"
+
+#: src/level_result.cxx:120
+msgid ""
+"Maybe this level calls for a different strategy. Like attempting to save "
+"them, for example."
+msgstr ""
+"Es kann sein, dass wir etwas anderes versuchen sollten. Vielleicht könnten "
+"wir ja die Pingus retten?"
+
+#: src/level_result.cxx:122
+msgid "Ever considered a career as a Pingu exterminator?"
+msgstr "Hast du mal über eine Karriere als Pingu Zerstörer nachgedacht?"
+
+#: src/level_result.cxx:124
+msgid "You missed one! What's your excuse!?"
+msgstr "Du hast einen vergessen! Was ist deine Entschuldigung?"
+
+#: src/level_result.cxx:126
+msgid "Please reassure me that you hit the Armageddon button."
+msgstr "Bestätige mir bitte, dass das die Armageddon Taste war."
+
+#: src/level_result.cxx:128
+msgid "You've got a negative save/total value, something is buggy."
+msgstr "Ein negativer Wert? Hier liegt ein Fehler vor."
+
+#: src/menu_button.cxx:181
+msgid "..:: The people who brought this game to you ::.."
+msgstr "..:: Die Leute, die fuer dieses Spiel verantwortlich sind... ::.."
+
+#: src/menu_button.cxx:184
+msgid "Credits"
+msgstr "Mitwirkende"
+
+#: src/menu_button.cxx:216
+msgid "..:: Takes you to the options menu ::.."
+msgstr "..:: Einstellungen, Cheats und Debugging stuff ::.."
+
+#: src/menu_button.cxx:219
+msgid "Options"
+msgstr "Einstellungen"
+
+#: src/menu_button.cxx:252
+msgid "..:: Bye, bye ::.."
+msgstr "..:: Auf Wiedersehen ::.."
+
+#: src/menu_button.cxx:255
+msgid "Exit"
+msgstr "Beenden"
+
+#: src/menu_button.cxx:306
+msgid "..:: Launch the level editor ::.."
+msgstr "..:: Erstelle deinen eigenen Level ::.."
+
+#: src/menu_button.cxx:309
+msgid "Create a"
+msgstr "Bau einen"
+
+#: src/menu_button.cxx:310
+msgid "Level"
+msgstr "Level"
+
+#: src/menu_button.cxx:344
+msgid "..:: Start the game ::.."
+msgstr "..:: das Spiel starten ::.."
+
+#: src/menu_button.cxx:345
+msgid "Start"
+msgstr "Start"
+
+#: src/menu_button.cxx:375
+msgid "..:: Start a contrib level ::.."
+msgstr "..:: Contrib level Spielen ::.."
+
+#: src/menu_button.cxx:377
+msgid "Contrib"
+msgstr "Levels"
+
+#: src/menu_button.cxx:399
+msgid "..:: Multiplayer Modes... experimental stuff ::.."
+msgstr "..:: Mehrspieler Modus ::.. Experimentelles Zeug ::.."
+
+#: src/menu_button.cxx:401
+msgid "Multi"
+msgstr "Multi"
+
+#: src/pingu_enums.cxx:35
+msgid "Angel"
+msgstr "Angel"
+
+#: src/pingu_enums.cxx:36
+msgid "Basher"
+msgstr "Basher"
+
+#: src/pingu_enums.cxx:37
+msgid "Blocker"
+msgstr "Blocker"
+
+#: src/pingu_enums.cxx:38
+msgid "Boarder"
+msgstr "Boarder"
+
+#: src/pingu_enums.cxx:39
+msgid "Bomber"
+msgstr "Bomber"
+
+#: src/pingu_enums.cxx:41
+msgid "Climber"
+msgstr "Climber"
+
+#: src/pingu_enums.cxx:42
+msgid "Digger"
+msgstr "Digger"
+
+#: src/pingu_enums.cxx:43
+msgid "Drown"
+msgstr "Drown"
+
+#: src/pingu_enums.cxx:44
+msgid "Exiter"
+msgstr "Exiter"
+
+#: src/pingu_enums.cxx:45
+msgid "Faller"
+msgstr "Faller"
+
+#: src/pingu_enums.cxx:46
+msgid "Floater"
+msgstr "Floater"
+
+#: src/pingu_enums.cxx:47
+msgid "Jumper"
+msgstr "Jumper"
+
+#: src/pingu_enums.cxx:48
+msgid "Laserkill"
+msgstr "Laserkill"
+
+#: src/pingu_enums.cxx:49
+msgid "Miner"
+msgstr "Miner"
+
+#: src/pingu_enums.cxx:50
+msgid "Rocketlauncher"
+msgstr "Rocketlauncher"
+
+#: src/pingu_enums.cxx:51
+msgid "Slider"
+msgstr "Slider"
+
+#: src/pingu_enums.cxx:52
+msgid "Smashed"
+msgstr "Smashed"
+
+#: src/pingu_enums.cxx:53
+msgid "Splashed"
+msgstr "Splashed"
+
+#: src/pingu_enums.cxx:54
+msgid "Superman"
+msgstr "Superman"
+
+#: src/pingu_enums.cxx:55
+msgid "Teleported"
+msgstr "Teleported"
+
+#: src/pingu_enums.cxx:56
+msgid "Waiter"
+msgstr "Waiter"
+
+#: src/pingu_enums.cxx:57
+msgid "Walker"
+msgstr "Walker"
+
+#: src/pingus_counter.cxx:52
+#, c-format
+msgid "Released:%3d/%-3d Out:%3d Saved:%3d/%-3d"
+msgstr "Rein: %3d/%-3d Raus: %3d Gerettet: %3d/%-3d"
+
+#: src/pingus_main.cxx:90
+msgid "| segfault_handler: catched a SIGSEGV."
+msgstr "| segfault_handler: SIGSEGV abgefangen."
+
+#: src/pingus_main.cxx:92
+msgid "| Woops, Pingus just crashed, congratulations you've found a bug."
+msgstr ""
+"| Woops, Pingus ist abgestürzt. Gratuliere, du hast einen Bug gefunden."
+
+#: src/pingus_main.cxx:93
+msgid ""
+"| Please write a little bug report to <grumbel@gmx.de>, include informations"
+msgstr ""
+"| Bitte schreibe einen kleinen Report an <pingus-devel@nongnu.org, mit "
+"Informationen,"
+
+#: src/pingus_main.cxx:94
+msgid "| where exacly the SIGSEGV occured and how to reproduce it."
+msgstr "| wo genau der SIGSEGV auftrat und wie man ihn reproduziert."
+
+#: src/pingus_main.cxx:95
+msgid "| Also try include a backtrace, you can get it like this:"
+msgstr "| Versuche auch einen backtrace zu erstellen, du bekommst ihn so:"
+
+#: src/pingus_main.cxx:101
+msgid "| If that doesn't work, try this:"
+msgstr "| Wenn das nicht geht, versuche dies:"
+
+#: src/pingus_main.cxx:105
+msgid "| [play until it crashes again]"
+msgstr "| [spiele bis es wieder crasht]"
+
+#: src/pingus_main.cxx:113
+msgid "| Warning: Pingus recieved a SIGINT, exiting now."
+msgstr "| Warnung: Pingus erhielt einen SIGINT, beende jetzt."
+
+#: src/pingus_main.cxx:301
+msgid "Warning: Larger resolution than 800x600 will result in visual problems"
+msgstr ""
+"Warnung: Auflösungen grösser als 800x600 können zu visuellen Problemen führen"
+
+#: src/pingus_main.cxx:488
+msgid "Unknow char: "
+msgstr "Unbekannter Buchstabe: "
+
+#: src/pingus_main.cxx:489
+msgid "Usage: "
+msgstr "Benutzung: "
+
+#: src/pingus_main.cxx:489
+msgid " [OPTIONS]... [LEVELFILE]"
+msgstr "[OPTIONEN]... [LEVELDATEI]"
+
+#: src/pingus_main.cxx:492
+msgid "Options:"
+msgstr "Einstellungen"
+
+#: src/pingus_main.cxx:494
+msgid "Set the resolution for pingus (default: 800x600)"
+msgstr "Setze die Auflösung für Pingus (Standard: 800x600)"
+
+#: src/pingus_main.cxx:495
+msgid "Displays this help"
+msgstr "Hilfe Anzeigen"
+
+#: src/pingus_main.cxx:496
+msgid "Disable intro"
+msgstr "Intro abschalten"
+
+#: src/pingus_main.cxx:497
+msgid "Use OpenGL"
+msgstr "OpenGL benutzen"
+
+#: src/pingus_main.cxx:499
+msgid "Start in Window Mode"
+msgstr "Pingus im Fenster starten"
+
+#: src/pingus_main.cxx:500
+msgid "Start in Fullscreen"
+msgstr "Pingus im Vollbild starten"
+
+#: src/pingus_main.cxx:504
+msgid "FILE "
+msgstr "Datei "
+
+#: src/pingus_main.cxx:504
+msgid "Load a custom level from FILE"
+msgstr "Einen Level aus DATEI laden"
+
+#: src/pingus_main.cxx:505
+msgid "FILE "
+msgstr "Datei "
+
+#: src/pingus_main.cxx:505
+msgid "Load a custom worldmap from FILE"
+msgstr "Eine Weltkarte aus DATEI laden"
+
+#: src/pingus_main.cxx:506
+msgid "Print some more messages to stdout, can be set"
+msgstr "Gibt mehr Nachrichten auf stdout aus, kann"
+
+#: src/pingus_main.cxx:507
+msgid "multiple times to increase verbosity"
+msgstr "mehrmals gesetzt werden, um die Genauigkeit zu erhöhen"
+
+#: src/pingus_main.cxx:508
+msgid "Prints version number and exit"
+msgstr "Version ausgeben und beenden"
+
+#: src/pingus_main.cxx:509
+msgid "Launch the Level editor (experimental)"
+msgstr "Level Editor starten (Experimentell)"
+
+#: src/pingus_main.cxx:510
+msgid "Disable automatic scrolling"
+msgstr "Automatisches Scrollen abschalten"
+
+#: src/pingus_main.cxx:512
+msgid "Enable software cursor"
+msgstr "Aktiviere Software Cursor"
+
+#: src/pingus_main.cxx:515
+msgid "Don't read ~/.pingus/config"
+msgstr "~/.pingus/config nicht einlesen"
+
+#: src/pingus_main.cxx:516
+msgid "FILE "
+msgstr "Datei "
+
+#: src/pingus_main.cxx:516
+msgid "Read config from FILE (default: ~/.pingus/config)"
+msgstr "Konfiguration aus DATEI lesen"
+
+#: src/pingus_main.cxx:517
+msgid "reduce CPU usage, might speed up the game on slower machines"
+msgstr ""
+"reduziere CPU Belastung, könnte das Spiel auf langsamen Rechnern "
+"beschleunigen"
+
+#: src/pingus_main.cxx:518
+msgid "Uses the controller given in FILE"
+msgstr "Controller aus FILE benutzen"
+
+#: src/pingus_main.cxx:520
+msgid "Debugging and experimental stuff:"
+msgstr "Debug und Experimentelles Zeug"
+
+#: src/pingus_main.cxx:521
+msgid "Enables some features, only interesting programmers"
+msgstr "Aktiviere einige Funktionen, nur für Programmierer"
+
+#: src/pingus_main.cxx:522
+msgid "Enable the output of debugging infos, possible"
+msgstr "Aktiviere die Ausgabe von Debug Informationen, mögliche"
+
+#: src/pingus_main.cxx:523
+msgid "OPTION's are tiles, gametime, actions, sound, resources, gui,"
+msgstr "Optionen sind tiles, gametime, actions, sound, resources, gui,"
+
+#: src/pingus_main.cxx:525
+msgid "Skip at least N frames, larger values speed the game up"
+msgstr ""
+"Überspringe mindestens N Bilder, größere Werte erhöhen die Geschwindigkeit"
+
+#: src/pingus_main.cxx:526
+msgid "Skip at most N frames"
+msgstr "Überspringe maximal N Bilder"
+
+#: src/pingus_main.cxx:527
+msgid "Set both min and max frameskip to N"
+msgstr "Setze sowohl minimalen als auch maximalen Bildsprung auf N"
+
+#: src/pingus_main.cxx:528
+msgid "Set the game speed (0=fastest, >0=slower)"
+msgstr "Setze die Geschwindigkeit (0=schnellste, >0=langsamer)"
+
+#: src/pingus_main.cxx:529
+msgid "Prints the fps to stdout"
+msgstr "Schreibe die fps auf stdout"
+
+#: src/pingus_main.cxx:530
+msgid "Set the size of the map tiles (default: 32)"
+msgstr "Setze die Größe der Kartenteile (Standard: 32)"
+
+#: src/pingus_main.cxx:531
+msgid "Disable some cpu intensive features"
+msgstr "Deaktivere einige CPU intensive Funktionen"
+
+#: src/pingus_main.cxx:532
+msgid "Reduces the CPU usage by issuing sleep()"
+msgstr "Reduziert die CPU Belastung durch Verwendung von sleep()"
+
+#: src/pingus_main.cxx:534
+msgid "Demo playing and recording:"
+msgstr "Demo aufzeichnung und wiedergabe:"
+
+#: src/pingus_main.cxx:535
+msgid "FILE "
+msgstr "Datei "
+
+#: src/pingus_main.cxx:535
+msgid "Plays a demo session from FILE"
+msgstr "Spielt eine Demo Sitzung aus FILE"
+
+#: src/pingus_main.cxx:537
+msgid "Record demos for each played level"
+msgstr "Nehme Demos für jeden gespielten Level auf"
+
+#: src/pingus_main.cxx:539
+msgid "Sound:"
+msgstr "Sound"
+
+#: src/pingus_main.cxx:540
+msgid "Disable sound"
+msgstr "Sound deaktivieren"
+
+#: src/pingus_main.cxx:541
+msgid "Disable music"
+msgstr "Musik deaktivieren"
+
+#: src/pingus_main.cxx:720
+msgid "clanVorbis support: ok"
+msgstr "clanVorbis Unterstützung: ok"
+
+#: src/pingus_main.cxx:722
+msgid "clanVoribs support: missing (.ogg music files will not be playable)"
+msgstr ""
+"clanVorbis Unterstützung: fehlt (.ogg Musik Datein können nicht abgespielt "
+"werden)"
+
+#: src/pingus_main.cxx:726
+msgid "clanMikMod support: ok"
+msgstr "clanMikMod Unterstützung: ok"
+
+#: src/pingus_main.cxx:728
+msgid "clanMikMod support: missing (music files will not be playable)"
+msgstr ""
+"clanMikMod Untersützung: fehlt (Musikdateien können nicht abgespielt werden)"
+
+#: src/pingus_main.cxx:732
+msgid "getext support: ok"
+msgstr "gettext Unterstützung: ok"
+
+#: src/pingus_main.cxx:733
+msgid "gettext language: english"
+msgstr "gettext Sprache: deutsch"
+
+#: src/pingus_main.cxx:739
+msgid "sound support: enabled"
+msgstr "Sound Unterstützung: an"
+
+#: src/pingus_main.cxx:741
+msgid "sound support: disabled"
+msgstr "Sound Unterstützung: aus"
+
+#: src/pingus_main.cxx:744
+msgid "music support: enabled"
+msgstr "Musik Unterstützung: an"
+
+#: src/pingus_main.cxx:746
+msgid "music support: disabled"
+msgstr "Musik Unterstützung: aus"
+
+#: src/pingus_main.cxx:748
+msgid "resolution set to: "
+msgstr "Auflösung: "
+
+#: src/pingus_main.cxx:749
+msgid "fullscreen: "
+msgstr "Vollbild: "
+
+#: src/pingus_main.cxx:750
+msgid " enabled"
+msgstr "aktiviert"
+
+#: src/pingus_main.cxx:750
+msgid "disabled"
+msgstr "däktiviert"
+
+
+#: src/pingus_main.cxx:751
+msgid "reenabled"
+msgstr ""
--- /dev/null
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR Free Software Foundation, Inc.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"PO-Revision-Date: 2009-02-02 12:07+0100\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=( n != 1);\n"
+
+msgid "umlaut"
+msgstr "ÄÖÜäöü߀¢"
+
+msgid "You got %d error."
+msgid_plural "You got %d error."
+msgstr[0] "Du hast %d fehler"
+msgstr[1] "Du hast %d fehlers"
+
+msgid "found %d fatal error"
+msgid_plural "found %d fatal errors"
+msgstr[0] "s'ha trobat %d error fätal"
+msgstr[1] "s'han trobat %d errors fätals"
+
+
+msgid "I ate %d pizza."
+msgid_plural "I ate %d pizzas."
+msgstr[0] ""
--- /dev/null
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR Free Software Foundation, Inc.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"PO-Revision-Date: 2009-01-28 08:45+0100\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: src/actions/bridger.cxx:48 src/actions/bridger.cxx:232
+#: src/pingu_enums.cxx:40
+msgid "invalid"
+msgstr "ungütig"
+
--- /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 <errno.h>
+#include <string.h>
+#include <iostream>
+#include <fstream>
+#include <stdexcept>
+
+#include "tinygettext/po_parser.hpp"
+#include "tinygettext/tinygettext.hpp"
+#include "tinygettext/log.hpp"
+
+void my_log_callback(const std::string& err)
+{
+ std::cerr << err;
+}
+
+int main(int argc, char** argv)
+{
+ if (argc < 2)
+ {
+ std::cout << argv[0] << " FILENAME..." << std::endl;
+ }
+ else
+ {
+ tinygettext::Log::set_log_info_callback(my_log_callback);
+ tinygettext::Log::set_log_warning_callback(my_log_callback);
+ tinygettext::Log::set_log_error_callback(my_log_callback);
+
+ for(int i = 1; i < argc; ++i)
+ {
+ std::ifstream in(argv[i]);
+ if (!in)
+ {
+ std::cerr << argv[0] << ": cannot access " << argv[i] << ": " << strerror(errno) << std::endl;
+ }
+ else
+ {
+ try
+ {
+ tinygettext::Dictionary dict1;
+ tinygettext::POParser::parse(argv[i], in, dict1);
+
+ //tinygettext::Dictionary dict2;
+ //tinygettext::POFileReader::read(in, dict2);
+ }
+ catch(std::runtime_error& err)
+ {
+ std::cout << argv[i] << ": exception: " << err.what() << std::endl;
+ }
+ }
+ }
+ }
+}
+
+/* EOF */
--- /dev/null
+#!/bin/sh
+
+./tinygettext_test translate po/fr.po "invalid"
+./tinygettext_test directory po/ umlaut Deutsch
+./tinygettext_test directory po/ umlaut deutsch
+./tinygettext_test directory po/ umlaut de
+
+# EOF #
--- /dev/null
+// TinyGetText
+// 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 <string.h>
+#include <fstream>
+#include <stdlib.h>
+#include <iostream>
+#include <stdexcept>
+#include "tinygettext/po_parser.hpp"
+#include "tinygettext/tinygettext.hpp"
+
+using namespace tinygettext;
+
+void print_msg(const std::string& msgid, const std::vector<std::string>& msgstrs)
+{
+ std::cout << "Msgid: " << msgid << std::endl;
+ for(std::vector<std::string>::const_iterator i = msgstrs.begin(); i != msgstrs.end(); ++i)
+ {
+ std::cout << *i << std::endl;
+ }
+}
+
+void print_msg_ctxt(const std::string& ctxt, const std::string& msgid, const std::vector<std::string>& msgstrs)
+{
+ std::cout << "Msgctxt: " << ctxt << std::endl;
+ std::cout << "Msgid: " << msgid << std::endl;
+ for(std::vector<std::string>::const_iterator i = msgstrs.begin(); i != msgstrs.end(); ++i)
+ {
+ std::cout << *i << std::endl;
+ }
+}
+
+void print_usage(int /*argc*/, char** argv)
+{
+ std::cout << "Usage: " << argv[0] << " translate FILE MESSAGE" << std::endl;
+ std::cout << " " << argv[0] << " translate FILE MESSAGE_S MESSAGE_P NUM" << std::endl;
+ std::cout << " " << argv[0] << " directory DIRECTORY MESSAGE [LANG]" << std::endl;
+ std::cout << " " << argv[0] << " language LANGUAGE" << std::endl;
+ std::cout << " " << argv[0] << " language-dir DIR" << std::endl;
+ std::cout << " " << argv[0] << " list-msgstrs FILE" << std::endl;
+}
+
+void read_dictionary(const std::string& filename, Dictionary& dict)
+{
+ std::ifstream in(filename.c_str());
+
+ if (!in)
+ {
+ throw std::runtime_error("Couldn't open " + filename);
+ }
+ else
+ {
+ POParser::parse(filename, in, dict);
+ in.close();
+ }
+}
+
+int main(int argc, char** argv)
+{
+ try
+ {
+ if (argc == 3 && strcmp(argv[1], "language-dir") == 0)
+ {
+ DictionaryManager dictionary_manager;
+ dictionary_manager.add_directory(argv[2]);
+ const std::set<Language>& languages = dictionary_manager.get_languages();
+ std::cout << "Number of languages: " << languages.size() << std::endl;
+ for (std::set<Language>::const_iterator i = languages.begin(); i != languages.end(); ++i)
+ {
+ const Language& language = *i;
+ std::cout << "Env: " << language.str() << std::endl
+ << "Name: " << language.get_name() << std::endl
+ << "Language: " << language.get_language() << std::endl
+ << "Country: " << language.get_country() << std::endl
+ << "Modifier: " << language.get_modifier() << std::endl
+ << std::endl;
+ }
+ }
+ else if (argc == 3 && strcmp(argv[1], "language") == 0)
+ {
+ Language language = Language::from_name(argv[2]);
+
+ if (language)
+ std::cout << "Env: " << language.str() << std::endl
+ << "Name: " << language.get_name() << std::endl
+ << "Language: " << language.get_language() << std::endl
+ << "Country: " << language.get_country() << std::endl
+ << "Modifier: " << language.get_modifier() << std::endl;
+ else
+ std::cout << "not found" << std::endl;
+ }
+ else if (argc == 4 && strcmp(argv[1], "translate") == 0)
+ {
+ const char* filename = argv[2];
+ const char* message = argv[3];
+
+ Dictionary dict;
+ read_dictionary(filename, dict);
+ std::cout << "TRANSLATION: \"\"\"" << dict.translate(message) << "\"\"\""<< std::endl;
+ }
+ else if (argc == 5 && strcmp(argv[1], "translate") == 0)
+ {
+ const char* filename = argv[2];
+ const char* context = argv[3];
+ const char* message = argv[4];
+
+ Dictionary dict;
+ read_dictionary(filename, dict);
+ std::cout << dict.translate_ctxt(context, message) << std::endl;
+ }
+ else if (argc == 6 && strcmp(argv[1], "translate") == 0)
+ {
+ const char* filename = argv[2];
+ const char* message_singular = argv[3];
+ const char* message_plural = argv[4];
+ int num = atoi(argv[5]);
+
+ Dictionary dict;
+ read_dictionary(filename, dict);
+ std::cout << dict.translate_plural(message_singular, message_plural, num) << std::endl;
+ }
+ else if (argc == 7 && strcmp(argv[1], "translate") == 0)
+ {
+ const char* filename = argv[2];
+ const char* context = argv[3];
+ const char* message_singular = argv[4];
+ const char* message_plural = argv[5];
+ int num = atoi(argv[6]);
+
+ Dictionary dict;
+ read_dictionary(filename, dict);
+ std::cout << dict.translate_ctxt_plural(context, message_singular, message_plural, num) << std::endl;
+ }
+ else if ((argc == 4 || argc == 5) && strcmp(argv[1], "directory") == 0)
+ {
+ const char* directory = argv[2];
+ const char* message = argv[3];
+ const char* language = (argc == 5) ? argv[4] : NULL;
+
+ DictionaryManager manager;
+ manager.add_directory(directory);
+
+ if (language)
+ {
+ Language lang = Language::from_name(language);
+ if (lang)
+ {
+ manager.set_language(lang);
+ }
+ else
+ {
+ std::cout << "Unknown language: " << language << std::endl;
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ std::cout << "Directory: '" << directory << "'" << std::endl;
+ std::cout << "Message: '" << message << "'" << std::endl;
+ std::cout << "Language: '" << manager.get_language().str() << "' (name: '"
+ << manager.get_language().get_name() << "', language: '"
+ << manager.get_language().get_language() << "', country: '"
+ << manager.get_language().get_country() << "', modifier: '"
+ << manager.get_language().get_modifier() << "')"
+ << std::endl;
+ std::cout << "Translation: '" << manager.get_dictionary().translate(message) << "'" << std::endl;
+ }
+ else if ((argc == 3) && strcmp(argv[1], "list-msgstrs") == 0)
+ {
+ const char* filename = argv[2];
+
+ Dictionary dict;
+ read_dictionary(filename, dict);
+ dict.foreach(print_msg);
+ dict.foreach_ctxt(print_msg_ctxt);
+ }
+ else
+ {
+ print_usage(argc, argv);
+ }
+ }
+ catch(std::exception& err)
+ {
+ std::cout << "Exception: " << err.what() << std::endl;
+ }
+
+ return 0;
+}
+
+/* EOF */
--- /dev/null
+# Unfortunately, since this project is built with cmake,
+# these variables can't properly be set.
+
+prefix=@CMAKE_INSTALL_PREFIX@
+exec_prefix=${prefix}
+libdir=${exec_prefix}/@LIB_SUBDIR@
+includedir=${prefix}/include
+
+Name: @PROJECT_NAME@
+Description: tiny, minimal gettext replacement
+Version: @VERSION@
+URL: http://tinygettext.googlecode.com/
+Requires:
+Libs: -L${libdir} -ltinygettext
+Libs.private:
+Cflags: -I${includedir}
--- /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" },
+ { "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 */