[glom] Move po file (gettext) import and export into libglom and test it.
- From: Murray Cumming <murrayc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glom] Move po file (gettext) import and export into libglom and test it.
- Date: Sun, 8 Jan 2012 00:15:16 +0000 (UTC)
commit ffd6bd9a6e2dfbb9fbbd0b464b812352eb9a7595
Author: Murray Cumming <murrayc murrayc com>
Date: Sat Jan 7 23:05:00 2012 +0100
Move po file (gettext) import and export into libglom and test it.
* glom/mode_design/translation/window_translations.[h|cc]:
load_from_document(), save_to_document(): Move the collecting of
translatable items to:
* glom/libglom/document/document.[h|cc]: get_translatable_items();
Also move the gettext/po import/export to:
* Makefile_libglom.am:
* glom/libglom/filelist.am:
* glom/libglom/translations_po.[h|cc]: write_translations_to_po_file()
and import_translations_from_po_file().
* Makefile_tests.am
* tests/translations_po/data/test.po:
* tests/translations_po/test_document_export_po.cc:
* tests/translations_po/test_document_import_po.cc: Add tests of the new
libglom functions.
* Makefile_glom.am
* glom/glom_export_po.cc: Added a new command-line tool that uses the
new libglom API.
ChangeLog | 24 +
Makefile_glom.am | 1 -
Makefile_libglom.am | 10 +-
Makefile_tests.am | 25 +-
glom/glom_export_po.cc | 183 +++
glom/libglom/document/document.cc | 63 ++
glom/libglom/document/document.h | 6 +-
glom/libglom/filelist.am | 5 +-
glom/libglom/translations_po.cc | 263 +++++
glom/libglom/translations_po.h | 35 +
.../mode_design/translation/window_translations.cc | 381 +------
glom/mode_design/translation/window_translations.h | 4 +-
po/POTFILES.in | 2 +
tests/test_document_load_translations.cc | 78 ++
tests/translations_po/data/test.po | 1163 ++++++++++++++++++++
tests/translations_po/test_document_export_po.cc | 120 ++
tests/translations_po/test_document_import_po.cc | 128 +++
17 files changed, 2141 insertions(+), 350 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index d0276ba..946d1d6 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,29 @@
2012-01-07 Murray Cumming <murrayc murrayc com>
+ Move po file (gettext) import and export into libglom and test it.
+
+ * glom/mode_design/translation/window_translations.[h|cc]:
+ load_from_document(), save_to_document(): Move the collecting of
+ translatable items to:
+ * glom/libglom/document/document.[h|cc]: get_translatable_items();
+ Also move the gettext/po import/export to:
+ * Makefile_libglom.am:
+ * glom/libglom/filelist.am:
+ * glom/libglom/translations_po.[h|cc]: write_translations_to_po_file()
+ and import_translations_from_po_file().
+
+ * Makefile_tests.am
+ * tests/translations_po/data/test.po:
+ * tests/translations_po/test_document_export_po.cc:
+ * tests/translations_po/test_document_import_po.cc: Add tests of the new
+ libglom functions.
+
+ * Makefile_glom.am
+ * glom/glom_export_po.cc: Added a new command-line tool that uses the
+ new libglom API.
+
+2012-01-07 Murray Cumming <murrayc murrayc com>
+
test_document_load: Fix a typo.
* tests/test_document_load.cc: Check the correct variable.
diff --git a/Makefile_glom.am b/Makefile_glom.am
index e59d9f6..0c3adb3 100644
--- a/Makefile_glom.am
+++ b/Makefile_glom.am
@@ -399,7 +399,6 @@ glom_glom_SOURCES = \
glom_all_libs = $(win_resfile) \
glom/libglom/libglom-$(GLOM_ABI_VERSION).la $(libglom_all_libs) \
$(GLOM_LIBS) $(INTLLIBS)
-glom_all_libs += -lgettextpo
glom_glom_LDADD = $(glom_all_libs)
diff --git a/Makefile_libglom.am b/Makefile_libglom.am
index f0a39c7..71d7510 100644
--- a/Makefile_libglom.am
+++ b/Makefile_libglom.am
@@ -47,7 +47,7 @@ libglom_d_b_view_include_HEADERS = $(libglom_d_b_view_headers)
glom_libglom_libglom_ GLOM_ABI_VERSION@_la_SOURCES = $(libglom_sources)
-libglom_all_libs = $(LIBGLOM_LIBS) $(PYTHON_LIBS) $(BOOST_PYTHON_LIBS) $(GCOV_CFLAGS)
+libglom_all_libs = $(LIBGLOM_LIBS) $(PYTHON_LIBS) $(BOOST_PYTHON_LIBS) -lgettextpo $(GCOV_CFLAGS)
glom_libglom_libglom_ GLOM_ABI_VERSION@_la_LIBADD = $(libglom_all_libs)
if HOST_WIN32
@@ -85,7 +85,9 @@ pkgconfig_DATA = glom/libglom/glom- GLOM_ABI_VERSION@.pc
glom_commandline_ldadd = glom/libglom/libglom-$(GLOM_ABI_VERSION).la $(libglom_all_libs)
glom_commandline_cppflags = $(glom_includes) $(LIBGLOM_CFLAGS) $(PYTHON_CPPFLAGS) $(BOOST_PYTHON_CFLAGS) $(glom_defines)
-bin_PROGRAMS = glom/glom_create_from_example glom/glom_test_connection
+bin_PROGRAMS = glom/glom_create_from_example \
+ glom/glom_test_connection \
+ glom/glom_export_po
glom_glom_create_from_example_SOURCES = glom/glom_create_from_example.cc
glom_glom_create_from_example_LDADD = $(glom_commandline_ldadd)
@@ -94,3 +96,7 @@ glom_glom_create_from_example_CPPFLAGS = $(glom_commandline_cppflags)
glom_glom_test_connection_SOURCES = glom/glom_test_connection.cc
glom_glom_test_connection_LDADD = $(glom_commandline_ldadd)
glom_glom_test_connection_CPPFLAGS = $(glom_commandline_cppflags)
+
+glom_glom_export_po_SOURCES = glom/glom_export_po.cc
+glom_glom_export_po_LDADD = $(glom_commandline_ldadd)
+glom_glom_export_po_CPPFLAGS = $(glom_commandline_cppflags)
diff --git a/Makefile_tests.am b/Makefile_tests.am
index afddd79..b106767 100644
--- a/Makefile_tests.am
+++ b/Makefile_tests.am
@@ -47,7 +47,9 @@ check_PROGRAMS = \
tests/test_selfhosting_new_then_change_columns \
tests/test_selfhosting_sqlinjection \
tests/import/test_parsing \
- tests/import/test_signals
+ tests/import/test_signals \
+ tests/translations_po/test_document_export_po \
+ tests/translations_po/test_document_import_po
TESTS = tests/test_document_load \
tests/test_document_load_and_change \
@@ -78,7 +80,10 @@ TESTS = tests/test_document_load \
tests/test_selfhosting_new_then_change_columns \
tests/test_selfhosting_sqlinjection \
tests/import/test_parsing \
- tests/import/test_signals
+ tests/import/test_signals \
+ tests/translations_po/test_document_export_po \
+ tests/translations_po/test_document_import_po
+
# We also set this in Makefile.am, with +=,
# but this is the first use, where we must use =
@@ -155,12 +160,16 @@ tests_python_test_python_module_CPPFLAGS = $(tests_cppflags)
# Distribute the tests data:
dist_noinst_DATA = \
tests/import/data/albums.csv \
+ tests/translations_po/data/test.po \
tests/test_image.jpg
-# Let the .cc source code know about this path: TODO: Actually use this.
+# Let the .cc source code know about this path:
glom_test_import_defines = -DGLOM_TESTS_IMPORT_DATA_NOTINSTALLED=\""$(abs_top_srcdir)/tests/import/data/"\"
glom_test_image_defines = -DGLOM_TESTS_IMAGE_DATA_NOTINSTALLED=\""$(abs_top_srcdir)/tests/"\"
+# Let the .cc source code know about this path:
+glom_test_translations_po_defines = -DGLOM_TESTS_TRANSLATIONS_PO_DATA_NOTINSTALLED=\""$(abs_top_srcdir)/tests/translations_po/data/"\"
+
tests_import_test_parsing_SOURCES = \
glom/import_csv/csv_parser.cc \
@@ -180,6 +189,16 @@ tests_import_test_signals_SOURCES = \
tests_import_test_signals_LDADD = $(tests_ldadd)
tests_import_test_signals_CPPFLAGS = $(tests_cppflags)
+tests_translations_po_test_document_export_po_SOURCES = \
+ tests/translations_po/test_document_export_po.cc
+tests_translations_po_test_document_export_po_LDADD = $(tests_ldadd)
+tests_translations_po_test_document_export_po_CPPFLAGS = $(tests_cppflags)
+
+tests_translations_po_test_document_import_po_SOURCES = \
+ tests/translations_po/test_document_import_po.cc
+tests_translations_po_test_document_import_po_LDADD = $(tests_ldadd)
+tests_translations_po_test_document_import_po_CPPFLAGS = $(tests_cppflags) $(glom_test_translations_po_defines)
+
# Note that wherever we use this we must also use glom_test_image_defines.
sources_test_utils = tests/test_utils.h \
tests/test_utils.cc
diff --git a/glom/glom_export_po.cc b/glom/glom_export_po.cc
new file mode 100644
index 0000000..06443a3
--- /dev/null
+++ b/glom/glom_export_po.cc
@@ -0,0 +1,183 @@
+/* Glom
+ *
+ * Copyright (C) 2012 Openismus GmbH
+ *
+ * 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
+71 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+// For instance:
+// glom_export_po /opt/gnome30/share/doc/glom/examples/example_music_collection.glom --output="/home/someone/something.po"
+
+#include "config.h"
+
+#include <libglom/init.h>
+#include <libglom/translations_po.h>
+#include <giomm/file.h>
+#include <glibmm/optioncontext.h>
+#include <glibmm/convert.h>
+#include <glibmm/miscutils.h>
+#include <iostream>
+
+#include <glibmm/i18n.h>
+
+class GlomCreateOptionGroup : public Glib::OptionGroup
+{
+public:
+ GlomCreateOptionGroup();
+
+ //These instances should live as long as the OptionGroup to which they are added,
+ //and as long as the OptionContext to which those OptionGroups are added.
+ std::string m_arg_filepath_output;
+ bool m_arg_version;
+};
+
+GlomCreateOptionGroup::GlomCreateOptionGroup()
+: Glib::OptionGroup("glom_export_po", _("Glom options"), _("Command-line options")),
+ m_arg_version(false)
+{
+ Glib::OptionEntry entry;
+ entry.set_long_name("output-path");
+ entry.set_short_name('o');
+ entry.set_description(_("The path at which to save the created .po file, such as /home/someuser/somefile.po ."));
+ add_entry_filename(entry, m_arg_filepath_output);
+
+ entry.set_long_name("version");
+ entry.set_short_name('V');
+ entry.set_description(_("The version of this application."));
+ add_entry(entry, m_arg_version);
+}
+
+int main(int argc, char* argv[])
+{
+ Glom::libglom_init();
+
+ Glib::OptionContext context;
+ GlomCreateOptionGroup group;
+ context.set_main_group(group);
+
+ try
+ {
+ context.parse(argc, argv);
+ }
+ catch(const Glib::OptionError& ex)
+ {
+ std::cout << _("Error while parsing command-line options: ") << std::endl << ex.what() << std::endl;
+ std::cout << _("Use --help to see a list of available command-line options.") << std::endl;
+ return 0;
+ }
+ catch(const Glib::Error& ex)
+ {
+ std::cout << "Error: " << ex.what() << std::endl;
+ return 0;
+ }
+
+ if(group.m_arg_version)
+ {
+ std::cout << PACKAGE_STRING << std::endl;
+ return 0;
+ }
+
+ // Get a URI for a glom file:
+ Glib::ustring input_uri;
+
+ // The GOption documentation says that options without names will be returned to the application as "rest arguments".
+ // I guess this means they will be left in the argv. Murray.
+ if(input_uri.empty() && (argc > 1))
+ {
+ const char* pch = argv[1];
+ if(pch)
+ input_uri = pch;
+ }
+
+ if(input_uri.empty())
+ {
+ std::cerr << "Please specify a glom file." << std::endl;
+ std::cerr << std::endl << context.get_help() << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ //Get a URI (file://something) from the filepath:
+ Glib::RefPtr<Gio::File> file_input = Gio::File::create_for_commandline_arg(input_uri);
+
+ //Make sure it is really a URI:
+ input_uri = file_input->get_uri();
+
+ if(!file_input->query_exists())
+ {
+ std::cerr << _("Glom: The file does not exist.") << std::endl;
+ std::cerr << "uri: " << input_uri << std::endl;
+
+ std::cerr << std::endl << context.get_help() << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ const Gio::FileType file_type = file_input->query_file_type();
+ if(file_type == Gio::FILE_TYPE_DIRECTORY)
+ {
+ std::cerr << _("Glom: The file path is a directory instead of a file.") << std::endl;
+ std::cerr << std::endl << context.get_help() << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ //Check the output path:
+ if(group.m_arg_filepath_output.empty())
+ {
+ std::cerr << "Please specify an output path." << std::endl;
+ std::cerr << std::endl << context.get_help() << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ //Get a URI (file://something) from the filepath:
+ Glib::RefPtr<Gio::File> file_output = Gio::File::create_for_commandline_arg(group.m_arg_filepath_output);
+ const Glib::ustring ouput_uri = file_output->get_uri();
+
+ if(file_output->query_exists())
+ {
+ std::cerr << _("Glom: The output file aready exists.") << std::endl;
+ std::cerr << "uri: " << ouput_uri << std::endl;
+
+ std::cerr << std::endl << context.get_help() << std::endl;
+ return EXIT_FAILURE;
+ }
+
+
+ // Load the document:
+ Glom::Document document;
+ document.set_file_uri(input_uri);
+ int failure_code = 0;
+ const bool test = document.load(failure_code);
+ //std::cout << "Document load result=" << test << std::endl;
+
+ if(!test)
+ {
+ std::cerr << "Document::load() failed with failure_code=" << failure_code << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ const bool succeeded =
+ Glom::write_translations_to_po_file(&document, ouput_uri, "de_DE");
+ if(!succeeded)
+ {
+ std::cerr << "Po file creation failed." << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ std::cout << "Po file created at: " << ouput_uri << std::endl;
+
+ Glom::libglom_deinit();
+
+ return EXIT_SUCCESS;
+}
diff --git a/glom/libglom/document/document.cc b/glom/libglom/document/document.cc
index 4028529..7f95bfb 100644
--- a/glom/libglom/document/document.cc
+++ b/glom/libglom/document/document.cc
@@ -4405,6 +4405,69 @@ std::vector<Glib::ustring> Document::get_translation_available_locales() const
return m_translation_available_locales;
}
+Document::type_list_translatables Document::get_translatable_items()
+{
+ type_list_translatables result;
+
+ //Add tables:
+ type_listTableInfo tables = get_tables();
+ for(type_listTableInfo::const_iterator iter = tables.begin(); iter != tables.end(); ++iter)
+ {
+ sharedptr<TableInfo> tableinfo = *iter;
+ if(!tableinfo)
+ continue;
+
+ result.push_back(tableinfo);
+
+ const Glib::ustring table_name = tableinfo->get_name();
+
+ //The table's field titles:
+ type_vec_fields fields = get_table_fields(table_name);
+ for(type_vec_fields::iterator iter = fields.begin(); iter != fields.end(); ++iter)
+ {
+ sharedptr<Field> field = *iter;
+ if(!field)
+ continue;
+
+ result.push_back(field);
+
+ //Custom Choices, if any:
+ if(field->get_glom_type() == Field::TYPE_TEXT) //Choices for other field types could not be translated.
+ {
+ type_list_translatables list_choice_items;
+ Document::fill_translatable_custom_choices(field->m_default_formatting, list_choice_items);
+ result.insert(result.end(), list_choice_items.begin(), list_choice_items.end());
+ }
+ }
+
+ //The table's relationships:
+ type_vec_relationships relationships = get_relationships(table_name);
+ result.insert(result.end(), relationships.begin(), relationships.end());
+
+ //The table's report titles:
+ type_listReports listReports = get_report_names(table_name);
+ for(type_listReports::iterator iter = listReports.begin(); iter != listReports.end(); ++iter)
+ {
+ const Glib::ustring report_name = *iter;
+ sharedptr<Report> report = get_report(table_name, report_name);
+ if(!report)
+ continue;
+
+ result.push_back(report);
+
+ //Translatable report items:
+ type_list_translatables list_layout_items = get_translatable_report_items(table_name, report_name);
+ result.insert(result.end(), list_layout_items.begin(), list_layout_items.end());
+ }
+
+ //The table's translatable layout items:
+ type_list_translatables list_layout_items = get_translatable_layout_items(table_name);
+ result.insert(result.end(), list_layout_items.begin(), list_layout_items.end());
+ } //for
+
+ return result;
+}
+
Document::type_list_translatables Document::get_translatable_layout_items(const Glib::ustring& table_name)
{
type_list_translatables result;
diff --git a/glom/libglom/document/document.h b/glom/libglom/document/document.h
index 1107bbf..266b4db 100644
--- a/glom/libglom/document/document.h
+++ b/glom/libglom/document/document.h
@@ -258,8 +258,7 @@ public:
type_list_layout_groups get_data_layout_groups_default(const Glib::ustring& layout_name, const Glib::ustring& parent_table_name, const Glib::ustring& layout_platform = Glib::ustring()) const;
typedef std::list< sharedptr<TranslatableItem> > type_list_translatables;
- type_list_translatables get_translatable_layout_items(const Glib::ustring& table_name);
- type_list_translatables get_translatable_report_items(const Glib::ustring& table_name, const Glib::ustring& report_title);
+ type_list_translatables get_translatable_items();
static void fill_translatable_custom_choices(FieldFormatting& formatting, type_list_translatables& the_list);
@@ -523,6 +522,9 @@ private:
void fill_sort_field_details(const Glib::ustring& parent_table_name, FieldFormatting::type_list_sort_fields& sort_fields) const;
+ type_list_translatables get_translatable_layout_items(const Glib::ustring& table_name);
+ type_list_translatables get_translatable_report_items(const Glib::ustring& table_name, const Glib::ustring& report_title);
+
/// If the attribute is not there, then the default will be returned.
static bool get_node_attribute_value_as_bool(const xmlpp::Element* node, const Glib::ustring& strAttributeName, bool value_default = false);
diff --git a/glom/libglom/filelist.am b/glom/libglom/filelist.am
index 59e3dac..3ecc651 100644
--- a/glom/libglom/filelist.am
+++ b/glom/libglom/filelist.am
@@ -25,7 +25,8 @@ libglom_toplevel_headers = \
glom/libglom/standard_table_prefs_fields.h \
glom/libglom/utils.h \
glom/libglom/db_utils.h \
- glom/libglom/report_builder.h
+ glom/libglom/report_builder.h \
+ glom/libglom/translations_po.h
libglom_data_structure_headers = \
glom/libglom/data_structure/choicevalue.h \
@@ -112,6 +113,8 @@ libglom_sources = \
glom/libglom/report_builder.h \
glom/libglom/spawn_with_feedback.cc \
glom/libglom/spawn_with_feedback.h \
+ glom/libglom/translations_po.cc \
+ glom/libglom/translations_po.h \
glom/libglom/utils.cc \
glom/libglom/utils.h \
glom/libglom/xsl_utils.cc \
diff --git a/glom/libglom/translations_po.cc b/glom/libglom/translations_po.cc
new file mode 100644
index 0000000..6faa83f
--- /dev/null
+++ b/glom/libglom/translations_po.cc
@@ -0,0 +1,263 @@
+/* Glom
+ *
+ * Copyright (C) 2001-2012 Murray Cumming
+ *
+ * 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 <libglom/translations_po.h>
+
+// To read the .po files
+#include <gettext-po.h>
+#include "config.h" //For HAVE_GETTEXTPO_XERROR
+
+#include <glibmm/convert.h>
+#include <glibmm/i18n.h>
+
+#include <iostream>
+
+/* For really ugly hacks! */
+#include <setjmp.h>
+
+namespace Glom
+{
+
+static jmp_buf jump;
+
+static void show_gettext_error(int severity, const char* filename, const gchar* message)
+{
+ std::ostringstream msg_stream;
+ if(filename)
+ msg_stream << filename << ": ";
+
+ if(message)
+ msg_stream << message;
+
+ switch(severity)
+ {
+ #ifdef PO_SEVERITY_WARNING //This was introduced in libgettext-po some time after gettext version 0.14.5
+ case PO_SEVERITY_WARNING:
+ {
+ // Show only debug output
+ std::cout << _("Gettext-Warning: ") << msg_stream.str() << std::endl;
+ break;
+ }
+ #endif //PO_SEVERITY_WARNING
+
+
+ #ifdef PO_SEVERITY_ERROR //This was introduced in libgettext-po some time after gettext version 0.14.5
+ case PO_SEVERITY_ERROR:
+ #endif //PO_SEVERITY_ERROR
+
+ #ifdef PO_SEVERITY_FATAL_ERROR //This was introduced in libgettext-po some time after gettext version 0.14.5
+ case PO_SEVERITY_FATAL_ERROR:
+ #endif //PO_SEVERITY_FATAL_ERROR
+
+ default:
+ {
+ //TODO: const Glib::ustring msg = Glib::ustring(_("Gettext-Error: ")) + ' ' + msg_stream.str();
+ //Gtk::MessageDialog dlg(msg, false, Gtk::MESSAGE_ERROR);
+ //dlg.run();
+ break;
+ }
+ }
+}
+
+/*
+ * The exception handling of libgettext-po is very ugly! The following methods are called
+ * if an exception occurs and may not return in case of a fatal exception. We use setjmp
+ * and longjmp to bypass this and return to the caller
+ */
+#ifdef HAVE_GETTEXTPO_XERROR
+static void on_gettextpo_xerror (int severity, po_message_t /* message */, const char *filename, size_t /* lineno */, size_t /* column */,
+ int /* multiline_p */, const char *message_text)
+{
+ show_gettext_error(severity, filename, message_text);
+
+ #ifdef PO_SEVERITY_FATAL_ERROR //This was introduced in libgettext-po some time after gettext version 0.14.5
+ if(severity == PO_SEVERITY_FATAL_ERROR)
+ longjmp(jump, 1);
+ #endif //PO_SEVERITY_FATAL_ERROR
+}
+
+static void on_gettextpo_xerror2 (int severity, po_message_t /* message1 */, const char * filename1, size_t /* lineno1 */, size_t /* column1 */,
+ int /* multiline_p1 */, const char *message_text1,
+ po_message_t /* message2 */, const char * /*filename2 */, size_t /* lineno2 */, size_t /* column2 */,
+ int /* multiline_p2 */, const char * /* message_text2 */)
+{
+ show_gettext_error(severity, filename1, message_text1);
+
+ #ifdef PO_SEVERITY_FATAL_ERROR //This was introduced in libgettext-po some time after gettext version 0.14.5
+ if(severity == PO_SEVERITY_FATAL_ERROR)
+ longjmp(jump, 1);
+ #endif //PO_SEVERITY_FATAL_ERROR
+}
+#else //HAVE_GETTEXTPO_XERROR
+static void on_gettextpo_error(int status, int errnum, const char * /* format */, ...)
+{
+ std::cerr << "gettext error (old libgettext-po API): status=" << status << ", errnum=" << errnum << std::endl;
+}
+#endif //HAVE_GETTEXTPO_XERROR
+
+static Glib::ustring get_po_context_for_item(const sharedptr<TranslatableItem>& item)
+{
+ // Note that this context string should use English rather than the translated strings,
+ // or the context would change depending on the locale of the user doing the export:
+ return TranslatableItem::get_translatable_type_name_nontranslated(item->get_translatable_item_type()) + " (" + item->get_name() + ')';
+}
+
+bool write_translations_to_po_file(Document* document, const Glib::ustring& po_file_uri, const Glib::ustring& translation_locale)
+{
+ std::string filename;
+
+ try
+ {
+ filename = Glib::filename_from_uri(po_file_uri);
+ }
+ catch(const Glib::Error& ex)
+ {
+ std::cerr << G_STRFUNC << "Exception when converting URI to filepath: " << ex.what() << std::endl;
+ return false;
+ }
+
+ if(setjmp(jump) != 0)
+ return false;
+
+ po_file_t po_file = po_file_create();
+ po_message_iterator_t msg_iter = po_message_iterator(po_file, 0);
+
+ Document::type_list_translatables list_layout_items = document->get_translatable_items();
+ for(Document::type_list_translatables::iterator iter = list_layout_items.begin(); iter != list_layout_items.end(); ++iter)
+ {
+ sharedptr<TranslatableItem> item = *iter;
+ if(!item)
+ continue;
+
+ if(item->get_title_original().empty())
+ continue;
+
+ po_message_t msg = po_message_create();
+ po_message_set_msgid(msg, item->get_title_original().c_str());
+ po_message_set_msgstr(msg, item->get_title_translation(translation_locale, false).c_str());
+
+ // Add "context" comments, to uniquely identify similar strings, used in different places,
+ // and to provide a hint for translators.
+ po_message_set_msgctxt(msg, get_po_context_for_item(item).c_str());
+
+ po_message_insert(msg_iter, msg);
+ }
+
+ po_message_iterator_free(msg_iter);
+
+ #ifdef HAVE_GETTEXTPO_XERROR
+ po_xerror_handler error_handler;
+ memset(&error_handler, 0, sizeof(error_handler));
+ error_handler.xerror = &on_gettextpo_xerror;
+ error_handler.xerror2 = &on_gettextpo_xerror2;
+ #else
+ po_error_handler error_handler;
+ memset(&error_handler, 0, sizeof(error_handler));
+ error_handler.error = &on_gettextpo_error;
+ #endif //HAVE_GETTEXTPO_XERROR
+
+ if(po_file_write(po_file, filename.c_str(), &error_handler))
+ {
+ po_file_free(po_file);
+ }
+
+ return true;
+}
+
+bool import_translations_from_po_file(Document* document, const Glib::ustring& po_file_uri, const Glib::ustring& translation_locale)
+{
+ std::string filename;
+
+ try
+ {
+ filename = Glib::filename_from_uri(po_file_uri);
+ }
+ catch(const Glib::Error& ex)
+ {
+ std::cerr << G_STRFUNC << "Exception when converting URI to filepath: " << ex.what() << std::endl;
+ return false;
+ }
+
+ Document::type_list_translatables list_layout_items = document->get_translatable_items();
+ if(list_layout_items.empty())
+ return false;
+
+ if(setjmp(jump) != 0)
+ return false;
+
+ #ifdef HAVE_GETTEXTPO_XERROR
+ po_xerror_handler error_handler;
+ memset(&error_handler, 0, sizeof(error_handler));
+ error_handler.xerror = &on_gettextpo_xerror;
+ error_handler.xerror2 = &on_gettextpo_xerror2;
+ #else
+ po_error_handler error_handler;
+ memset(&error_handler, 0, sizeof(error_handler));
+ error_handler.error = &on_gettextpo_error;
+ #endif //HAVE_GETTEXTPO_XERROR
+
+ po_file_t po_file = po_file_read(filename.c_str(), &error_handler);
+ if(!po_file)
+ {
+ // error message is already given by error_handle.
+ return false;
+ }
+
+ //Look at each domain (could there be more than one?):
+ const char* const* domains = po_file_domains(po_file);
+ for (int i = 0; domains[i] != 0; ++i)
+ {
+ //Look at each message:
+ po_message_iterator_t iter = po_message_iterator(po_file, domains[i]);
+ po_message_t msg;
+ while ((msg = po_next_message(iter)))
+ {
+ //This message:
+ //TODO: Just use const char* instead of copying it in to a Glib::ustring,
+ //if we have performance problems here:
+ const Glib::ustring msgid = po_message_msgid(msg);
+ const Glib::ustring msgstr = po_message_msgstr(msg);
+ const Glib::ustring msgcontext = po_message_msgctxt(msg);
+
+ //Find the matching item in the list:
+ for(Document::type_list_translatables::iterator iter = list_layout_items.begin(); iter != list_layout_items.end(); ++iter)
+ {
+ sharedptr<TranslatableItem> item = *iter;
+ if(!item)
+ continue;
+
+ if( (item->get_title_original() == msgid) &&
+ (get_po_context_for_item(item) == msgcontext) ) // This is not efficient, but it should be reliable.
+ {
+ item->set_title_translation(translation_locale, msgstr);
+ // Keep examining items, in case there are duplicates. break;
+ }
+ }
+ }
+
+ po_message_iterator_free(iter);
+ }
+
+ po_file_free(po_file);
+
+ return true;
+}
+
+} //namespace Glom
diff --git a/glom/libglom/translations_po.h b/glom/libglom/translations_po.h
new file mode 100644
index 0000000..1207e88
--- /dev/null
+++ b/glom/libglom/translations_po.h
@@ -0,0 +1,35 @@
+/* Glom
+ *
+ * Copyright (C) 2001-2012 Murray Cumming
+ *
+ * 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 GLOM_TRANSLATIONS_PO
+#define GLOM_TRANSLATIONS_PO
+
+#include <libglom/document/document.h>
+
+namespace Glom
+{
+
+bool write_translations_to_po_file(Document* document, const Glib::ustring& po_file_uri, const Glib::ustring& translation_locale);
+
+bool import_translations_from_po_file(Document* document, const Glib::ustring& po_file_uri, const Glib::ustring& translation_locale);
+
+} //namespace Glom
+
+#endif //GLOM_TRANSLATIONS_PO
diff --git a/glom/mode_design/translation/window_translations.cc b/glom/mode_design/translation/window_translations.cc
index f3975c5..aea3fa0 100644
--- a/glom/mode_design/translation/window_translations.cc
+++ b/glom/mode_design/translation/window_translations.cc
@@ -24,6 +24,7 @@
#include "dialog_copy_translation.h"
#include <glom/utils_ui.h> //For bold_message()).
#include <libglom/utils.h>
+#include <libglom/translations_po.h>
#include <glom/glade_utils.h>
#include <gtkmm/filefilter.h>
#include <gtkmm/stock.h>
@@ -32,16 +33,8 @@
#include <glibmm/i18n.h>
#include <string.h> // for memset
-// To read the .po files
-#include <gettext-po.h>
-#include "config.h" //For HAVE_GETTEXTPO_XERROR
-
#include <sstream>
-/* For really ugly hacks! */
-#include <setjmp.h>
-
-
namespace Glom
{
@@ -220,132 +213,23 @@ void Window_Translations::load_from_document()
original_locale_name = _("Unknown");
m_label_source_locale->set_text(original_locale_name);
- //Add tables:
- Document::type_listTableInfo tables = document->get_tables();
- for(Document::type_listTableInfo::const_iterator iter = tables.begin(); iter != tables.end(); ++iter)
+ Document::type_list_translatables list_layout_items = document->get_translatable_items();
+ for(Document::type_list_translatables::iterator iter = list_layout_items.begin(); iter != list_layout_items.end(); ++iter)
{
- sharedptr<TableInfo> tableinfo = *iter;
- const Glib::ustring table_name = tableinfo->get_name();
-
- //Table title:
- Gtk::TreeModel::iterator iterTree = m_model->append();
- Gtk::TreeModel::Row row = *iterTree;
- row[m_columns.m_col_item] = tableinfo;
- row[m_columns.m_col_translation] = tableinfo->get_title_translation(m_translation_locale, false);
- row[m_columns.m_col_parent_table] = Glib::ustring(); //Not used for tables.
-
- //The table's field titles:
- Document::type_vec_fields fields = document->get_table_fields(table_name);
- for(Document::type_vec_fields::iterator iter = fields.begin(); iter != fields.end(); ++iter)
+ sharedptr<TranslatableItem> item = *iter;
+ if(item)
{
- sharedptr<Field> field = *iter;
- if(!field)
+ if(item->get_title_original().empty())
continue;
-
+
Gtk::TreeModel::iterator iterTree = m_model->append();
Gtk::TreeModel::Row row = *iterTree;
- row[m_columns.m_col_item] = field;
- row[m_columns.m_col_translation] = field->get_title_translation(m_translation_locale, false);
- row[m_columns.m_col_parent_table] = table_name;
-
- //Custom Choices, if any:
- if(field->get_glom_type() == Field::TYPE_TEXT) //Choices for other field types could not be translated.
- {
- Document::type_list_translatables list_choice_items;
- Document::fill_translatable_custom_choices(field->m_default_formatting, list_choice_items);
- for(Document::type_list_translatables::iterator iter = list_choice_items.begin(); iter != list_choice_items.end(); ++iter)
- {
- sharedptr<TranslatableItem> item = *iter;
- if(!item)
- continue;
-
- if(item->get_title_original().empty())
- continue;
-
- Gtk::TreeModel::iterator iterTree = m_model->append();
- Gtk::TreeModel::Row row = *iterTree;
-
- row[m_columns.m_col_item] = item;
- row[m_columns.m_col_translation] = item->get_title_translation(m_translation_locale, false);
- row[m_columns.m_col_parent_table] = table_name;
- }
- }
- }
-
- //The table's relationships:
- Document::type_vec_relationships relationships = document->get_relationships(table_name);
- for(Document::type_vec_relationships::iterator iter = relationships.begin(); iter != relationships.end(); ++iter)
- {
- sharedptr<Relationship> relationship = *iter;
- if(relationship)
- {
- Gtk::TreeModel::iterator iterTree = m_model->append();
- Gtk::TreeModel::Row row = *iterTree;
-
- row[m_columns.m_col_item] = relationship;
- row[m_columns.m_col_translation] = relationship->get_title_translation(m_translation_locale, false);
- row[m_columns.m_col_parent_table] = table_name;
- }
- }
-
- //The table's report titles:
- Document::type_listReports listReports = document->get_report_names(table_name);
- for(Document::type_listReports::iterator iter = listReports.begin(); iter != listReports.end(); ++iter)
- {
- const Glib::ustring report_name = *iter;
- sharedptr<Report> report = document->get_report(table_name, report_name);
- if(report)
- {
- //Translatable report title:
- Gtk::TreeModel::iterator iterTree = m_model->append();
- Gtk::TreeModel::Row row = *iterTree;
-
- row[m_columns.m_col_item] = report;
- row[m_columns.m_col_translation] = report->get_title_translation(m_translation_locale, false);
- row[m_columns.m_col_parent_table] = table_name;
-
- //Translatable report items:
- Document::type_list_translatables list_layout_items = document->get_translatable_report_items(table_name, report_name);
- for(Document::type_list_translatables::iterator iter = list_layout_items.begin(); iter != list_layout_items.end(); ++iter)
- {
- sharedptr<TranslatableItem> item = *iter;
- if(item)
- {
- if(!(item->get_title_original().empty()))
- {
- Gtk::TreeModel::iterator iterTree = m_model->append();
- Gtk::TreeModel::Row row = *iterTree;
-
- row[m_columns.m_col_item] = item;
- row[m_columns.m_col_translation] = item->get_title_translation(m_translation_locale, false);
- row[m_columns.m_col_parent_table] = table_name;
- }
- }
- }
- }
- }
-
- //The table's translatable layout items:
- Document::type_list_translatables list_layout_items = document->get_translatable_layout_items(table_name);
- for(Document::type_list_translatables::iterator iter = list_layout_items.begin(); iter != list_layout_items.end(); ++iter)
- {
- sharedptr<TranslatableItem> item = *iter;
- if(item)
- {
- if(!(item->get_title_original().empty()))
- {
- Gtk::TreeModel::iterator iterTree = m_model->append();
- Gtk::TreeModel::Row row = *iterTree;
-
- row[m_columns.m_col_item] = item;
- row[m_columns.m_col_translation] = item->get_title_translation(m_translation_locale, false);
- row[m_columns.m_col_parent_table] = table_name;
- }
- }
+ row[m_columns.m_col_item] = item;
+ row[m_columns.m_col_translation] = item->get_title_translation(m_translation_locale, false);
+ //row[m_columns.m_col_parent_table] = table_name;
}
-
- } //for
+ }
m_treeview_modified = false;
}
@@ -438,95 +322,8 @@ void Window_Translations::on_treeview_edited(const Glib::ustring& /* path */, co
m_treeview_modified = true;
}
-static jmp_buf jump;
-
-static void show_gettext_error(int severity, const char* filename, const gchar* message)
-{
- std::ostringstream msg_stream;
- if(filename)
- msg_stream << filename << ": ";
-
- if(message)
- msg_stream << message;
-
- switch(severity)
- {
- #ifdef PO_SEVERITY_WARNING //This was introduced in libgettext-po some time after gettext version 0.14.5
- case PO_SEVERITY_WARNING:
- {
- // Show only debug output
- std::cout << _("Gettext-Warning: ") << msg_stream.str() << std::endl;
- break;
- }
- #endif //PO_SEVERITY_WARNING
-
-
- #ifdef PO_SEVERITY_ERROR //This was introduced in libgettext-po some time after gettext version 0.14.5
- case PO_SEVERITY_ERROR:
- #endif //PO_SEVERITY_ERROR
-
- #ifdef PO_SEVERITY_FATAL_ERROR //This was introduced in libgettext-po some time after gettext version 0.14.5
- case PO_SEVERITY_FATAL_ERROR:
- #endif //PO_SEVERITY_FATAL_ERROR
-
- default:
- {
- Glib::ustring msg = Glib::ustring(_("Gettext-Error: ")) + ' ' + msg_stream.str();
- Gtk::MessageDialog dlg(msg, false, Gtk::MESSAGE_ERROR);
- dlg.run();
- break;
- }
- }
-}
-
-/*
- * The exception handling of libgettext-po is very ugly! The following methods are called
- * if an exception occurs and may not return in case of a fatal exception. We use setjmp
- * and longjmp to bypass this and return to the caller
- */
-#ifdef HAVE_GETTEXTPO_XERROR
-static void on_gettextpo_xerror (int severity, po_message_t /* message */, const char *filename, size_t /* lineno */, size_t /* column */,
- int /* multiline_p */, const char *message_text)
-{
- show_gettext_error(severity, filename, message_text);
-
- #ifdef PO_SEVERITY_FATAL_ERROR //This was introduced in libgettext-po some time after gettext version 0.14.5
- if(severity == PO_SEVERITY_FATAL_ERROR)
- longjmp(jump, 1);
- #endif //PO_SEVERITY_FATAL_ERROR
-}
-
-static void on_gettextpo_xerror2 (int severity, po_message_t /* message1 */, const char * filename1, size_t /* lineno1 */, size_t /* column1 */,
- int /* multiline_p1 */, const char *message_text1,
- po_message_t /* message2 */, const char * /*filename2 */, size_t /* lineno2 */, size_t /* column2 */,
- int /* multiline_p2 */, const char * /* message_text2 */)
-{
- show_gettext_error(severity, filename1, message_text1);
-
- #ifdef PO_SEVERITY_FATAL_ERROR //This was introduced in libgettext-po some time after gettext version 0.14.5
- if(severity == PO_SEVERITY_FATAL_ERROR)
- longjmp(jump, 1);
- #endif //PO_SEVERITY_FATAL_ERROR
-}
-#else //HAVE_GETTEXTPO_XERROR
-static void on_gettextpo_error(int status, int errnum, const char * /* format */, ...)
-{
- std::cerr << "gettext error (old libgettext-po API): status=" << status << ", errnum=" << errnum << std::endl;
-}
-#endif //HAVE_GETTEXTPO_XERROR
-
-Glib::ustring Window_Translations::get_po_context_for_item(const sharedptr<TranslatableItem>& item)
-{
- // Note that this context string should use English rather than the translated strings,
- // or the context would change depending on the locale of the user doing the export:
- return TranslatableItem::get_translatable_type_name_nontranslated(item->get_translatable_item_type()) + " (" + item->get_name() + ')';
-}
-
void Window_Translations::on_button_export()
-{
- if(setjmp(jump) != 0)
- return;
-
+{
//Show the file-chooser dialog, to select an output .po file:
Gtk::FileChooserDialog file_dlg(_("Choose .po File Name"), Gtk::FILE_CHOOSER_ACTION_SAVE);
file_dlg.set_transient_for(*this);
@@ -539,74 +336,34 @@ void Window_Translations::on_button_export()
file_dlg.add_filter(filter);
file_dlg.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
- file_dlg.add_button(_("Export"), Gtk::RESPONSE_OK);
+ file_dlg.add_button(_("Export"), Gtk::RESPONSE_OK);
const int result = file_dlg.run();
- if(result == Gtk::RESPONSE_OK)
- {
- std::string filename = file_dlg.get_filename();
- if(filename.empty())
- return;
-
- //Enforce the file extension:
- const std::string extension = ".po";
- bool add_extension = false;
- if(filename.size() <= extension.size())
- add_extension = true;
- else if(filename.substr(filename.size() - extension.size()) != extension)
- add_extension = true;
-
- if(add_extension)
- filename += extension;
-
-
- po_file_t po_file = po_file_create();
- po_message_iterator_t msg_iter = po_message_iterator(po_file, 0);
-
- for(Gtk::TreeModel::iterator iter = m_model->children().begin(); iter != m_model->children().end(); ++iter)
- {
- Gtk::TreeModel::Row row = *iter;
-
- sharedptr<TranslatableItem> item = row[m_columns.m_col_item];
- if(item)
- {
- po_message_t msg = po_message_create();
- po_message_set_msgid(msg, item->get_title_original().c_str());
- po_message_set_msgstr(msg, item->get_title_translation(m_translation_locale, false).c_str());
-
- // Add "context" comments, to uniquely identify similar strings, used in different places,
- // and to provide a hint for translators.
- po_message_set_msgctxt(msg, get_po_context_for_item(item).c_str());
-
- po_message_insert(msg_iter, msg);
- }
- }
-
- po_message_iterator_free(msg_iter);
+ if(result != Gtk::RESPONSE_OK)
+ return;
- #ifdef HAVE_GETTEXTPO_XERROR
- po_xerror_handler error_handler;
- memset(&error_handler, 0, sizeof(error_handler));
- error_handler.xerror = &on_gettextpo_xerror;
- error_handler.xerror2 = &on_gettextpo_xerror2;
- #else
- po_error_handler error_handler;
- memset(&error_handler, 0, sizeof(error_handler));
- error_handler.error = &on_gettextpo_error;
- #endif //HAVE_GETTEXTPO_XERROR
+ Glib::ustring uri = file_dlg.get_uri();
+ if(uri.empty())
+ return;
- if(po_file_write(po_file, filename.c_str(), &error_handler))
- {
- po_file_free(po_file);
- }
- }
+ save_to_document();
+
+ //Enforce the file extension:
+ const Glib::ustring extension = ".po";
+ bool add_extension = false;
+ if(uri.size() <= extension.size())
+ add_extension = true;
+ else if(uri.substr(uri.size() - extension.size()) != extension)
+ add_extension = true;
+
+ if(add_extension)
+ uri += extension;
+
+ Glom::write_translations_to_po_file(get_document(), uri, m_translation_locale);
}
void Window_Translations::on_button_import()
{
- if(setjmp(jump) != 0)
- return;
-
Gtk::FileChooserDialog file_dlg(_("Choose .po File Name"), Gtk::FILE_CHOOSER_ACTION_OPEN);
file_dlg.set_transient_for(*this);
@@ -621,72 +378,18 @@ void Window_Translations::on_button_import()
//Note to translators: "Import" here is an action verb - it's a button.
file_dlg.add_button(_("Import"), Gtk::RESPONSE_OK);
- int result = file_dlg.run();
- if(result == Gtk::RESPONSE_OK)
- {
- // We cannot use an uri here:
- const std::string filename = file_dlg.get_filename();
- if(filename.empty())
- return;
-
- #ifdef HAVE_GETTEXTPO_XERROR
- po_xerror_handler error_handler;
- memset(&error_handler, 0, sizeof(error_handler));
- error_handler.xerror = &on_gettextpo_xerror;
- error_handler.xerror2 = &on_gettextpo_xerror2;
- #else
- po_error_handler error_handler;
- memset(&error_handler, 0, sizeof(error_handler));
- error_handler.error = &on_gettextpo_error;
- #endif //HAVE_GETTEXTPO_XERROR
-
- po_file_t po_file = po_file_read(filename.c_str(), &error_handler);
- if(!po_file)
- {
- // error message is already given by error_handle.
- return;
- }
-
- //Look at each domain (could there be more than one?):
- const char* const* domains = po_file_domains(po_file);
- for (int i = 0; domains[i] != 0; ++i)
- {
- //Look at each message:
- po_message_iterator_t iter = po_message_iterator(po_file, domains[i]);
- po_message_t msg;
- while ((msg = po_next_message(iter)))
- {
- //This message:
- //TODO: Just use const char* instead of copying it in to a Glib::ustring,
- //if we have performance problems here:
- const Glib::ustring msgid = po_message_msgid(msg);
- const Glib::ustring msgstr = po_message_msgstr(msg);
- const Glib::ustring msgcontext = po_message_msgctxt(msg);
-
- //Find the matching entry in the TreeModel:
- for(Gtk::TreeModel::iterator iter = m_model->children().begin(); iter != m_model->children().end(); ++iter)
- {
- Gtk::TreeModel::Row row = *iter;
-
- sharedptr<TranslatableItem> item = row[m_columns.m_col_item];
- if(item)
- {
- if( (item->get_title_original() == msgid) &&
- (get_po_context_for_item(item) == msgcontext) ) // This is not efficient, but it should be reliable.
- {
- item->set_title_translation(m_translation_locale, msgstr);
- // Keep examining items, in case there are duplicates. break;
- }
- }
- }
- }
- po_message_iterator_free(iter);
- }
+ const int result = file_dlg.run();
+ if(result != Gtk::RESPONSE_OK)
+ return;
- po_file_free(po_file);
+ const std::string uri = file_dlg.get_uri();
+ if(uri.empty())
+ return;
- save_to_document();
- }
+ Glom::import_translations_from_po_file(get_document(), uri, m_translation_locale);
+
+ //Show the changed document in the UI:
+ load_from_document();
}
} //namespace Glom
diff --git a/glom/mode_design/translation/window_translations.h b/glom/mode_design/translation/window_translations.h
index ccf6994..bfbbcbd 100644
--- a/glom/mode_design/translation/window_translations.h
+++ b/glom/mode_design/translation/window_translations.h
@@ -76,11 +76,11 @@ private:
public:
ModelColumns()
- { add(m_col_item); add(m_col_translation); add(m_col_parent_table); }
+ { add(m_col_item); add(m_col_translation); }
Gtk::TreeModelColumn< sharedptr<TranslatableItem> > m_col_item; //The table name, field name, etc.
Gtk::TreeModelColumn<Glib::ustring> m_col_translation;
- Gtk::TreeModelColumn<Glib::ustring> m_col_parent_table; //Not shown.
+ //Gtk::TreeModelColumn<Glib::ustring> m_col_parent_table; //Not shown.
};
ModelColumns m_columns;
diff --git a/po/POTFILES.in b/po/POTFILES.in
index a4209ba..6cea3c2 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -52,11 +52,13 @@ glom/libglom/document/bakery/view/view.cc
glom/libglom/document/bakery/view/view_composite.cc
glom/libglom/gst-package.c
glom/libglom/spawn_with_feedback.cc
+glom/libglom/translations_po.cc
glom/libglom/utils.cc
glom/libglom/db_utils.cc
glom/libglom/report_builder.cc
glom/libglom/xsl_utils.cc
glom/glom_create_from_example.cc
+glom/glom_export_po.cc
glom/glom_test_connection.cc
glom/main.cc
glom/mode_data/box_data_calendar_related.cc
diff --git a/tests/test_document_load_translations.cc b/tests/test_document_load_translations.cc
index e6b44a1..a3e7d35 100644
--- a/tests/test_document_load_translations.cc
+++ b/tests/test_document_load_translations.cc
@@ -70,6 +70,39 @@ private:
Glib::ustring m_title;
};
+/** A predicate for use with std::find_if() to find a LayoutItem of a particular type.
+ */
+template<class T_Element, class T_TypeToFind>
+class predicate_ItemHasType
+{
+public:
+ predicate_ItemHasType()
+ {
+ }
+
+ virtual ~predicate_ItemHasType()
+ {
+ }
+
+ bool operator() (const Glom::sharedptr<T_Element>& element)
+ {
+ Glom::sharedptr<T_TypeToFind> derived = Glom::sharedptr<T_TypeToFind>::cast_dynamic(element);
+ if(derived)
+ return true;
+ else
+ return false;
+ }
+
+ bool operator() (const Glom::sharedptr<const T_Element>& element)
+ {
+ Glom::sharedptr<const T_TypeToFind> derived = Glom::sharedptr<const T_TypeToFind>::cast_dynamic(element);
+ if(derived)
+ return true;
+ else
+ return false;
+ }
+};
+
template<typename T_Container>
typename T_Container::value_type get_titled(const T_Container& container, const Glib::ustring& title)
@@ -87,6 +120,22 @@ typename T_Container::value_type get_titled(const T_Container& container, const
return result;
}
+template<typename T_Container, typename T_TypeToFind>
+bool contains_item_type(const T_Container& container)
+{
+ typedef typename T_Container::value_type type_sharedptr;
+ type_sharedptr result;
+
+ typedef typename T_Container::value_type::object_type type_item;
+ typename T_Container::const_iterator iter =
+ std::find_if(container.begin(), container.end(),
+ predicate_ItemHasType<type_item, T_TypeToFind>());
+ if(iter != container.end())
+ result = *iter;
+
+ return result;
+}
+
static Glom::sharedptr<const Glom::LayoutItem_Field> get_field_on_layout(const Glom::Document& document, const Glib::ustring& layout_table_name, const Glib::ustring& table_name, const Glib::ustring& field_name)
{
const Glom::Document::type_list_layout_groups groups =
@@ -260,6 +309,35 @@ int main()
g_assert(print_layout);
check_title(print_layout, "Contact Details", "Kontakt Details" );
+ //Check the whole list of translatable items:
+ Glom::Document::type_list_translatables list_layout_items = document.get_translatable_items();
+ g_assert(!list_layout_items.empty());
+ const bool contains_tableinfo =
+ contains_item_type<Glom::Document::type_list_translatables, Glom::TableInfo>(list_layout_items);
+ g_assert( contains_tableinfo );
+ const bool contains_layoutitem =
+ contains_item_type<Glom::Document::type_list_translatables, Glom::LayoutItem>(list_layout_items);
+ g_assert( contains_layoutitem );
+ /*
+ const bool contains_layoutitemfield =
+ contains_item_type<Glom::Document::type_list_translatables, Glom::LayoutItem_Field>(list_layout_items);
+ g_assert( contains_layoutitemfield );
+ */
+ const bool contains_relationship =
+ contains_item_type<Glom::Document::type_list_translatables, Glom::Relationship>(list_layout_items);
+ g_assert( contains_relationship );
+ const bool contains_field =
+ contains_item_type<Glom::Document::type_list_translatables, Glom::Field>(list_layout_items);
+ g_assert( contains_field );
+ const bool contains_choicevalue =
+ contains_item_type<Glom::Document::type_list_translatables, Glom::ChoiceValue>(list_layout_items);
+ g_assert( contains_choicevalue );
+ const bool contains_customtitle =
+ contains_item_type<Glom::Document::type_list_translatables, Glom::CustomTitle>(list_layout_items);
+ g_assert( contains_customtitle );
+ const bool contains_report =
+ contains_item_type<Glom::Document::type_list_translatables, Glom::Report>(list_layout_items);
+ g_assert( contains_report );
Glom::libglom_deinit();
diff --git a/tests/translations_po/data/test.po b/tests/translations_po/data/test.po
new file mode 100644
index 0000000..c063e65
--- /dev/null
+++ b/tests/translations_po/data/test.po
@@ -0,0 +1,1163 @@
+msgctxt "Table (accommodation)"
+msgid "Accommodation"
+msgstr "Unterkunft"
+
+msgctxt "Field (accommodation_id)"
+msgid "Accommodation ID"
+msgstr "Unterkunft ID"
+
+msgctxt "Field (description)"
+msgid "Description"
+msgstr "Beschreibung"
+
+msgctxt "Field (comments)"
+msgid "Comments"
+msgstr "Kommentare"
+
+msgctxt "Field (address_street)"
+msgid "Street"
+msgstr "Strasse"
+
+msgctxt "Field (address_town)"
+msgid "Town"
+msgstr "Ort"
+
+msgctxt "Field (address_county)"
+msgid "County"
+msgstr "Bundesland/Kanton"
+
+msgctxt "Field (address_country)"
+msgid "Country"
+msgstr "Land"
+
+msgctxt "Field (address_postcode)"
+msgid "Postcode"
+msgstr "Postleitzahl"
+
+msgctxt "Field (contact_id)"
+msgid "Contact ID"
+msgstr "Kontakt ID"
+
+msgctxt "Field (name)"
+msgid "Name"
+msgstr ""
+
+msgctxt "Relationship (contacts)"
+msgid "Contacts"
+msgstr "Kontakte"
+
+msgctxt "Layout Group (overview)"
+msgid "Overview"
+msgstr ""
+
+msgctxt "Layout Group (address)"
+msgid "Address"
+msgstr "Addresse"
+
+msgctxt "Layout Group (contact)"
+msgid "Contact"
+msgstr "Kontakt"
+
+msgctxt "Table (cars)"
+msgid "Cars"
+msgstr "Autos"
+
+msgctxt "Field (car_id)"
+msgid "Car ID"
+msgstr "Auto ID"
+
+msgctxt "Field (manufacturer)"
+msgid "Manufacturer"
+msgstr "Hersteller"
+
+msgctxt "Field (model)"
+msgid "Model"
+msgstr "Model"
+
+msgctxt "Field (registration)"
+msgid "Registration"
+msgstr "Kennzeichnung"
+
+msgctxt "Field (description)"
+msgid "Description"
+msgstr "Beschreibung"
+
+msgctxt "Field (comment)"
+msgid "Comment"
+msgstr "Kommentar"
+
+msgctxt "Layout Group (overview)"
+msgid "Overview"
+msgstr "bersicht"
+
+msgctxt "Layout Group (details)"
+msgid "Details"
+msgstr "Details"
+
+msgctxt "Table (characters)"
+msgid "Characters"
+msgstr "Besetzung"
+
+msgctxt "Field (character_id)"
+msgid "Cast ID"
+msgstr "Besetzung ID"
+
+msgctxt "Field (character)"
+msgid "Character"
+msgstr "Charakter"
+
+msgctxt "Field (comments)"
+msgid "Comments"
+msgstr "Kommentar"
+
+msgctxt "Field (contact_id)"
+msgid "Contact ID"
+msgstr "Kontakt ID"
+
+msgctxt "Field (mainpart)"
+msgid "Main Part"
+msgstr "Hauptrolle"
+
+msgctxt "Relationship (contacts_actor)"
+msgid "Actor"
+msgstr "Schauspieler"
+
+msgctxt "Relationship (scenes)"
+msgid "Scenes"
+msgstr ""
+
+msgctxt "Report (cast_list)"
+msgid "Cast List"
+msgstr "Besetzungsliste"
+
+msgctxt "Custom Title ()"
+msgid "Actor"
+msgstr "Schauspieler"
+
+msgctxt "Custom Title ()"
+msgid "Agent"
+msgstr ""
+
+msgctxt "Layout Group (overview)"
+msgid "Overview"
+msgstr "bersicht"
+
+msgctxt "Layout Group (details)"
+msgid "Details"
+msgstr "Details"
+
+msgctxt "Layout Group (actor)"
+msgid "Actor"
+msgstr "Schauspieler"
+
+msgctxt "Custom Title ()"
+msgid "Actor's Contact ID"
+msgstr "Schauspieler Kontakt ID"
+
+msgctxt "Custom Title ()"
+msgid "Actor's Name"
+msgstr "Schauspieler Name"
+
+msgctxt "Layout Group (overview)"
+msgid "Overview"
+msgstr ""
+
+msgctxt "Layout Group (details)"
+msgid "Details"
+msgstr ""
+
+msgctxt "Layout Group (actor)"
+msgid "Actor"
+msgstr ""
+
+msgctxt "Custom Title ()"
+msgid "Actor's Name"
+msgstr "Schauspieler Name"
+
+msgctxt "Custom Title ()"
+msgid "Actor"
+msgstr ""
+
+msgctxt "Table (companies)"
+msgid "Companies"
+msgstr "Firmen"
+
+msgctxt "Field (company_id)"
+msgid "Company ID"
+msgstr "Firma ID"
+
+msgctxt "Field (name)"
+msgid "Name"
+msgstr ""
+
+msgctxt "Field (comments)"
+msgid "Comments"
+msgstr "Kommentar"
+
+msgctxt "Field (description)"
+msgid "Description"
+msgstr "Beschreibung"
+
+msgctxt "Field (logo)"
+msgid "Logo"
+msgstr ""
+
+msgctxt "Field (website)"
+msgid "Web Site"
+msgstr "Website"
+
+msgctxt "Relationship (staff)"
+msgid "Staff"
+msgstr "Angestellte"
+
+msgctxt "Layout Group (overview)"
+msgid "Overview"
+msgstr "bersicht"
+
+msgctxt "Layout Group (details)"
+msgid "Details"
+msgstr "Details"
+
+msgctxt "Table (contacts)"
+msgid "Contacts"
+msgstr "Kontakte"
+
+msgctxt "Field (contact_id)"
+msgid "Contact ID"
+msgstr "Kontakt ID"
+
+msgctxt "Field (name_first)"
+msgid "First Name"
+msgstr "Vorname"
+
+msgctxt "Field (name_middle)"
+msgid "Second Name"
+msgstr "Zweiter Name"
+
+msgctxt "Field (name_last)"
+msgid "Last Name"
+msgstr "Familiename"
+
+msgctxt "Field (name_title)"
+msgid "Title"
+msgstr "Titel"
+
+msgctxt "Field Choice ()"
+msgid "Mr"
+msgstr ""
+
+msgctxt "Field Choice ()"
+msgid "Ms"
+msgstr ""
+
+msgctxt "Field Choice ()"
+msgid "Mrs"
+msgstr ""
+
+msgctxt "Field Choice ()"
+msgid "Miss"
+msgstr ""
+
+msgctxt "Field Choice ()"
+msgid "Dr"
+msgstr ""
+
+msgctxt "Field Choice ()"
+msgid "Prof"
+msgstr ""
+
+msgctxt "Field (address_street2)"
+msgid "Street (line 2)"
+msgstr "Strasse (2)"
+
+msgctxt "Field (address_town)"
+msgid "Town"
+msgstr "Ort"
+
+msgctxt "Field (address_state)"
+msgid "State"
+msgstr "Bundesland/Kanton"
+
+msgctxt "Field (address_country)"
+msgid "Country"
+msgstr "Land"
+
+msgctxt "Field Choice ()"
+msgid "Germany"
+msgstr ""
+
+msgctxt "Field Choice ()"
+msgid "United Kingdom"
+msgstr ""
+
+msgctxt "Field Choice ()"
+msgid "USA"
+msgstr ""
+
+msgctxt "Field Choice ()"
+msgid "France"
+msgstr ""
+
+msgctxt "Field Choice ()"
+msgid "Spain"
+msgstr ""
+
+msgctxt "Field (address_postcode)"
+msgid "Postcode"
+msgstr "Postleitzahl"
+
+msgctxt "Field (date_of_birth)"
+msgid "Date Of Birth"
+msgstr "Geburtsdatum"
+
+msgctxt "Field (comments)"
+msgid "Comments"
+msgstr "Kommentare"
+
+msgctxt "Field (name_full)"
+msgid "Full Name"
+msgstr "Vollstndiger Name"
+
+msgctxt "Field (company_id)"
+msgid "Company ID"
+msgstr "Firma ID"
+
+msgctxt "Field (picture)"
+msgid "Picture"
+msgstr "Bild"
+
+msgctxt "Field (tel_home)"
+msgid "Home Telephone"
+msgstr "Telefon (Privat)"
+
+msgctxt "Field (tel_mobile)"
+msgid "Mobile Telephone"
+msgstr "Telefon (Handy)"
+
+msgctxt "Field (tel_fax)"
+msgid "Fax"
+msgstr ""
+
+msgctxt "Field (tel_work)"
+msgid "Work Telephone"
+msgstr "Telefon (Buro)"
+
+msgctxt "Field (email)"
+msgid "Email"
+msgstr "E-Mail"
+
+msgctxt "Field (address_street1)"
+msgid "Street (line 1)"
+msgstr "Strasse (1)"
+
+msgctxt "Field (website)"
+msgid "Web Site"
+msgstr "Website"
+
+msgctxt "Field (agent_id)"
+msgid "Agent ID"
+msgstr ""
+
+msgctxt "Field (stagename)"
+msgid "Stagename"
+msgstr "Knstlername"
+
+msgctxt "Relationship (company)"
+msgid "Company"
+msgstr "Firma"
+
+msgctxt "Relationship (agent)"
+msgid "Agent"
+msgstr ""
+
+msgctxt "Relationship (crew)"
+msgid "Crew"
+msgstr ""
+
+msgctxt "Relationship (cast)"
+msgid "Cast"
+msgstr ""
+
+msgctxt "Report (by_country)"
+msgid "Contacts By Country"
+msgstr ""
+
+msgctxt "Report (by_country_by_town)"
+msgid "By Country, By Town"
+msgstr ""
+
+msgctxt "Layout Group (overview)"
+msgid "Overview"
+msgstr "bersicht"
+
+msgctxt "Layout Group (details)"
+msgid "Details"
+msgstr "Details"
+
+msgctxt "Layout Group (name)"
+msgid "Name"
+msgstr "Name"
+
+msgctxt "Layout Group (company)"
+msgid "Company"
+msgstr "Firma"
+
+msgctxt "Layout Group (address)"
+msgid "Address"
+msgstr "Addresse"
+
+msgctxt "Layout Group (telephone)"
+msgid "Telephone"
+msgstr "Telefon"
+
+msgctxt "Layout Group (agent)"
+msgid "Agent"
+msgstr "Agent"
+
+msgctxt "Custom Title ()"
+msgid "Company Name"
+msgstr ""
+
+msgctxt "Table (costume)"
+msgid "Costume"
+msgstr ""
+
+msgctxt "Field (costume_id)"
+msgid "Costume ID"
+msgstr ""
+
+msgctxt "Field (description)"
+msgid "Description"
+msgstr ""
+
+msgctxt "Field (comments)"
+msgid "Comments"
+msgstr ""
+
+msgctxt "Field (name)"
+msgid "Name"
+msgstr ""
+
+msgctxt "Layout Group (overview)"
+msgid "Overview"
+msgstr ""
+
+msgctxt "Layout Group (details)"
+msgid "Details"
+msgstr ""
+
+msgctxt "Table (crew)"
+msgid "Crew"
+msgstr ""
+
+msgctxt "Field (crew_id)"
+msgid "Crew ID"
+msgstr ""
+
+msgctxt "Field (description)"
+msgid "Description"
+msgstr "Beschreibung"
+
+msgctxt "Field (comments)"
+msgid "Comments"
+msgstr "Kommentar"
+
+msgctxt "Field (dept_id)"
+msgid "Department ID"
+msgstr "Abteilung ID"
+
+msgctxt "Field (contact_id)"
+msgid "Contact ID"
+msgstr "Kontakt ID"
+
+msgctxt "Relationship (contacts)"
+msgid "Contacts"
+msgstr "Kontakten"
+
+msgctxt "Relationship (departments)"
+msgid "Departments"
+msgstr "Abteilungen"
+
+msgctxt "Relationship (scenes)"
+msgid "Scenes"
+msgstr "Szenen"
+
+msgctxt "Report (crew_list)"
+msgid "Crew List"
+msgstr "TestResult2"
+
+msgctxt "Custom Title ()"
+msgid "Department Name"
+msgstr "Abteilungsname"
+
+msgctxt "Layout Group (overview)"
+msgid "Overview"
+msgstr "bersicht"
+
+msgctxt "Layout Group (department)"
+msgid "Department"
+msgstr "Abteilung"
+
+msgctxt "Layout Group (contact)"
+msgid "Contact"
+msgstr "Kontakt"
+
+msgctxt "Layout Group (address)"
+msgid "Address"
+msgstr "Addresse"
+
+msgctxt "Layout Group (agent)"
+msgid "Agent"
+msgstr "Agent"
+
+msgctxt "Custom Title ()"
+msgid "Department Name"
+msgstr "Abteilungsname"
+
+msgctxt "Table (deliveries)"
+msgid "Deliveries"
+msgstr "Lieferungen"
+
+msgctxt "Field (delivery_id)"
+msgid "Delivery ID"
+msgstr "Lieferung ID"
+
+msgctxt "Field (arrival_date)"
+msgid "Arrival Date"
+msgstr "Lieferungsdatum"
+
+msgctxt "Field (departure_contact_id)"
+msgid "Contact ID"
+msgstr "Kontakt ID"
+
+msgctxt "Field (arrival_contact_id)"
+msgid "Contact ID"
+msgstr "Kontakt ID"
+
+msgctxt "Field (arrival_time)"
+msgid "Arrival Time"
+msgstr "Lieferungszeit"
+
+msgctxt "Field (arrival_place)"
+msgid "Arrival Place"
+msgstr "Lieferungsaddresse"
+
+msgctxt "Field (departure_time)"
+msgid "Departure Time"
+msgstr "Sendungszeit"
+
+msgctxt "Field (departure_date)"
+msgid "Departure Date"
+msgstr "Sendungsdatum"
+
+msgctxt "Field (departure_place)"
+msgid "Departure Place"
+msgstr "Sendungsaddresse"
+
+msgctxt "Field (comments)"
+msgid "Comments"
+msgstr "Kommentare"
+
+msgctxt "Field (description)"
+msgid "Description"
+msgstr "Beschreibung"
+
+msgctxt "Relationship (departure_contact)"
+msgid "Departure Contact"
+msgstr "Sendungskontakt"
+
+msgctxt "Relationship (arrival_contact)"
+msgid "Arrival Contact"
+msgstr "Empfaengerkontakt"
+
+msgctxt "Custom Title ()"
+msgid "Departure Name"
+msgstr "Sendername"
+
+msgctxt "Custom Title ()"
+msgid "Arrival Name"
+msgstr "Empfngerkontakt"
+
+msgctxt "Layout Group (overview)"
+msgid "Overview"
+msgstr ""
+
+msgctxt "Layout Group (departure)"
+msgid "Departure"
+msgstr "Departure"
+
+msgctxt "Layout Group (arrival)"
+msgid "Arrival"
+msgstr "Arrival"
+
+msgctxt "Table (departments)"
+msgid "Departments"
+msgstr "Abteilungen"
+
+msgctxt "Field (departments_id)"
+msgid "Department ID"
+msgstr "Abteilung ID"
+
+msgctxt "Field (name)"
+msgid "Name"
+msgstr ""
+
+msgctxt "Field (comments)"
+msgid "Comments"
+msgstr "Kommentar"
+
+msgctxt "Relationship (department_crew)"
+msgid "Department Crew"
+msgstr "Abteilung Crew"
+
+msgctxt "Layout Group (overview)"
+msgid "Overview"
+msgstr "bersicht"
+
+msgctxt "Table (equipment)"
+msgid "Equipment"
+msgstr ""
+
+msgctxt "Field (equipment_id)"
+msgid "Equipment ID"
+msgstr ""
+
+msgctxt "Field (description)"
+msgid "Description"
+msgstr "Beschreibung"
+
+msgctxt "Field (comments)"
+msgid "Comments"
+msgstr "Kommentar"
+
+msgctxt "Relationship (scenes)"
+msgid "Scenes"
+msgstr "Szenen"
+
+msgctxt "Layout Group (overview)"
+msgid "Overview"
+msgstr "bersicht"
+
+msgctxt "Layout Group (details)"
+msgid "Details"
+msgstr "Details"
+
+msgctxt "Table (journeys)"
+msgid "Journeys"
+msgstr "Fahrten"
+
+msgctxt "Field (journey_id)"
+msgid "Journey ID"
+msgstr "Fahrt ID"
+
+msgctxt "Field (comment)"
+msgid "Comment"
+msgstr "Kommentar"
+
+msgctxt "Field (description)"
+msgid "Description"
+msgstr "Beschreibung"
+
+msgctxt "Field (arrival_date)"
+msgid "Arrival Date"
+msgstr ""
+
+msgctxt "Field (arrival_time)"
+msgid "Arrival Time"
+msgstr ""
+
+msgctxt "Field (arrival_place)"
+msgid "Arrival Place"
+msgstr ""
+
+msgctxt "Field (departure_date)"
+msgid "Departure Date"
+msgstr ""
+
+msgctxt "Field (departure_time)"
+msgid "Departure Time"
+msgstr ""
+
+msgctxt "Field (departure_place)"
+msgid "Departure Place"
+msgstr ""
+
+msgctxt "Field (contact_id)"
+msgid "Contact ID"
+msgstr "Kontakt ID"
+
+msgctxt "Relationship (contacts)"
+msgid "Contacts"
+msgstr "Kontakte"
+
+msgctxt "Layout Group (overview)"
+msgid "Overview"
+msgstr ""
+
+msgctxt "Layout Group (person)"
+msgid "Person"
+msgstr "Person"
+
+msgctxt "Layout Group (departure)"
+msgid "Departure"
+msgstr "Departure"
+
+msgctxt "Layout Group (arrival)"
+msgid "Arrival"
+msgstr "Arrival"
+
+msgctxt "Table (locations)"
+msgid "Locations"
+msgstr ""
+
+msgctxt "Field (location_id)"
+msgid "Location ID"
+msgstr ""
+
+msgctxt "Field (name)"
+msgid "Name"
+msgstr ""
+
+msgctxt "Field (address_street)"
+msgid "Street"
+msgstr "Strasse"
+
+msgctxt "Field (address_town)"
+msgid "Town"
+msgstr "Stadt"
+
+msgctxt "Field (address_county)"
+msgid "County"
+msgstr "Land"
+
+msgctxt "Field (address_country)"
+msgid "Country"
+msgstr "Staat"
+
+msgctxt "Field (address_postcode)"
+msgid "Postcode"
+msgstr "Postleitzahl"
+
+msgctxt "Field (comments)"
+msgid "Comments"
+msgstr "Kommentar"
+
+msgctxt "Field (contact_id)"
+msgid "Contact ID"
+msgstr ""
+
+msgctxt "Field (rent)"
+msgid "Rent"
+msgstr ""
+
+msgctxt "Relationship (scenes)"
+msgid "Scenes"
+msgstr "Szenen"
+
+msgctxt "Relationship (contacts)"
+msgid "Contacts"
+msgstr ""
+
+msgctxt "Layout Group (overview)"
+msgid "Overview"
+msgstr ""
+
+msgctxt "Layout Group (address)"
+msgid "Address"
+msgstr "Addresse"
+
+msgctxt "Layout Group (contact_person)"
+msgid "Contact Person"
+msgstr "Contact Person"
+
+msgctxt "Table (props)"
+msgid "Props"
+msgstr ""
+
+msgctxt "Field (prop_id)"
+msgid "Prop ID"
+msgstr ""
+
+msgctxt "Field (description)"
+msgid "Description"
+msgstr ""
+
+msgctxt "Field (comments)"
+msgid "Comments"
+msgstr ""
+
+msgctxt "Field (name)"
+msgid "Name"
+msgstr ""
+
+msgctxt "Layout Group (overview)"
+msgid "Overview"
+msgstr ""
+
+msgctxt "Layout Group (details)"
+msgid "Details"
+msgstr ""
+
+msgctxt "Table (scene_cast)"
+msgid "Scene Cast"
+msgstr "Szene Besetzung"
+
+msgctxt "Field (scene_cast_id)"
+msgid "Scene Cast ID"
+msgstr "Szene Besetzung ID"
+
+msgctxt "Field (comments)"
+msgid "Comments"
+msgstr "Kommentar"
+
+msgctxt "Field (cast_id)"
+msgid "Cast ID"
+msgstr "Besetzung ID"
+
+msgctxt "Field (scene_id)"
+msgid "Scene ID"
+msgstr "Szene ID"
+
+msgctxt "Relationship (cast)"
+msgid "Cast"
+msgstr "Besetzung"
+
+msgctxt "Layout Group (overview)"
+msgid "Overview"
+msgstr ""
+
+msgctxt "Layout Group (details)"
+msgid "Details"
+msgstr ""
+
+msgctxt "Table (scene_costume)"
+msgid "Scene Costume"
+msgstr ""
+
+msgctxt "Field (scene_costume_id)"
+msgid "Scene Costume ID"
+msgstr ""
+
+msgctxt "Field (comments)"
+msgid "Comments"
+msgstr ""
+
+msgctxt "Field (scene_id)"
+msgid "Scene Id"
+msgstr ""
+
+msgctxt "Field (costume_id)"
+msgid "Costume ID"
+msgstr ""
+
+msgctxt "Relationship (costume)"
+msgid "Costume"
+msgstr ""
+
+msgctxt "Layout Group (overview)"
+msgid "Overview"
+msgstr ""
+
+msgctxt "Layout Group (details)"
+msgid "Details"
+msgstr ""
+
+msgctxt "Custom Title ()"
+msgid "Costume Name"
+msgstr ""
+
+msgctxt "Table (scene_crew)"
+msgid "Scene Crew"
+msgstr "Szene Crew"
+
+msgctxt "Field (scene_crew_id)"
+msgid "Scene Crew ID"
+msgstr "Szene Crew ID"
+
+msgctxt "Field (comments)"
+msgid "Comments"
+msgstr "Kommentar"
+
+msgctxt "Field (scene_id)"
+msgid "Scene ID"
+msgstr "Szene ID"
+
+msgctxt "Field (department_id)"
+msgid "Department ID"
+msgstr ""
+
+msgctxt "Relationship (department)"
+msgid "Department"
+msgstr ""
+
+msgctxt "Relationship (scenes)"
+msgid "Scenes"
+msgstr "Szenen"
+
+msgctxt "Layout Group (overview)"
+msgid "Overview"
+msgstr "bersicht"
+
+msgctxt "Layout Group (details)"
+msgid "Details"
+msgstr "Details"
+
+msgctxt "Field (scene_equipment_id)"
+msgid "Scene Equipment ID"
+msgstr ""
+
+msgctxt "Field (comments)"
+msgid "Comments"
+msgstr "Kommentar"
+
+msgctxt "Field (equipment_id)"
+msgid "Equipment ID"
+msgstr ""
+
+msgctxt "Field (scene_id)"
+msgid "Scene ID"
+msgstr ""
+
+msgctxt "Layout Group (overview)"
+msgid "Overview"
+msgstr ""
+
+msgctxt "Layout Group (details)"
+msgid "Details"
+msgstr ""
+
+msgctxt "Table (scene_extras)"
+msgid "Scene Extras"
+msgstr ""
+
+msgctxt "Field (scene_extras_id)"
+msgid "Scene Extras ID"
+msgstr ""
+
+msgctxt "Field (description)"
+msgid "Description"
+msgstr ""
+
+msgctxt "Field (comments)"
+msgid "Comments"
+msgstr ""
+
+msgctxt "Field (scene_id)"
+msgid "Scene ID"
+msgstr ""
+
+msgctxt "Field (contact_id)"
+msgid "Contact ID"
+msgstr ""
+
+msgctxt "Relationship (contact)"
+msgid "Contact"
+msgstr ""
+
+msgctxt "Layout Group (overview)"
+msgid "Overview"
+msgstr ""
+
+msgctxt "Layout Group (details)"
+msgid "Details"
+msgstr ""
+
+msgctxt "Table (scene_makeup)"
+msgid "Scene Makeup"
+msgstr ""
+
+msgctxt "Field (scene_makeup_id)"
+msgid "Scene Makeup ID"
+msgstr ""
+
+msgctxt "Field (description)"
+msgid "Description"
+msgstr ""
+
+msgctxt "Field (comments)"
+msgid "Comments"
+msgstr ""
+
+msgctxt "Field (scene_id)"
+msgid "Scene ID"
+msgstr ""
+
+msgctxt "Layout Group (overview)"
+msgid "Overview"
+msgstr ""
+
+msgctxt "Layout Group (details)"
+msgid "Details"
+msgstr ""
+
+msgctxt "Table (scene_props)"
+msgid "Scene Props"
+msgstr ""
+
+msgctxt "Field (scene_props_id)"
+msgid "Scene Prop ID"
+msgstr ""
+
+msgctxt "Field (comments)"
+msgid "Comments"
+msgstr ""
+
+msgctxt "Field (scene_id)"
+msgid "Scene ID"
+msgstr ""
+
+msgctxt "Field (prop_id)"
+msgid "Prop ID"
+msgstr ""
+
+msgctxt "Relationship (props)"
+msgid "Props"
+msgstr ""
+
+msgctxt "Layout Group (overview)"
+msgid "Overview"
+msgstr ""
+
+msgctxt "Layout Group (details)"
+msgid "Details"
+msgstr ""
+
+msgctxt "Table (scenes)"
+msgid "Scenes"
+msgstr "TestResult1"
+
+msgctxt "Field (scene_id)"
+msgid "Scene ID"
+msgstr "Szene ID"
+
+msgctxt "Field (comments)"
+msgid "Comments"
+msgstr "Kommentar"
+
+msgctxt "Field (description)"
+msgid "Description"
+msgstr "Beschreibung"
+
+msgctxt "Field (location_id)"
+msgid "Location ID"
+msgstr ""
+
+msgctxt "Field (date)"
+msgid "Date"
+msgstr "Termin"
+
+msgctxt "Field (time)"
+msgid "Time"
+msgstr "Zeit"
+
+msgctxt "Field (minutes)"
+msgid "Stop (minutes)"
+msgstr "Stunde"
+
+msgctxt "Field (day_or_night)"
+msgid "Day/Night"
+msgstr "Tag/Nacht"
+
+msgctxt "Field Choice ()"
+msgid "Day"
+msgstr "Tag"
+
+msgctxt "Field Choice ()"
+msgid "Night"
+msgstr "Nacht"
+
+msgctxt "Field Choice ()"
+msgid "Morning"
+msgstr ""
+
+msgctxt "Field Choice ()"
+msgid "Evening"
+msgstr ""
+
+msgctxt "Field Choice ()"
+msgid "Dawn"
+msgstr ""
+
+msgctxt "Field (interior_or_exterior)"
+msgid "Interior/Exterior"
+msgstr "Interior/Exterior"
+
+msgctxt "Field Choice ()"
+msgid "Interior"
+msgstr ""
+
+msgctxt "Field Choice ()"
+msgid "Exterior"
+msgstr ""
+
+msgctxt "Field (name)"
+msgid "Name"
+msgstr "Szene"
+
+msgctxt "Field (overview_name)"
+msgid "Scene"
+msgstr ""
+
+msgctxt "Field (pages)"
+msgid "Pages"
+msgstr ""
+
+msgctxt "Field (script_day)"
+msgid "Script Day"
+msgstr ""
+
+msgctxt "Relationship (location)"
+msgid "Locations"
+msgstr ""
+
+msgctxt "Relationship (scene_crew)"
+msgid "Additional Crew"
+msgstr "Szene Crew"
+
+msgctxt "Relationship (scene_cast)"
+msgid "Cast"
+msgstr "Szene Besetzung"
+
+msgctxt "Relationship (scene_equipment)"
+msgid "Additional Equipment"
+msgstr ""
+
+msgctxt "Relationship (scene_extras)"
+msgid "Extras"
+msgstr ""
+
+msgctxt "Relationship (scene_props)"
+msgid "Props"
+msgstr ""
+
+msgctxt "Relationship (scene_costume)"
+msgid "Costume"
+msgstr ""
+
+msgctxt "Relationship (scene_makeup)"
+msgid "Additional Makeup"
+msgstr ""
+
+msgctxt "Layout Group (overview)"
+msgid "Overview"
+msgstr "bersicht"
+
+msgctxt "Layout Group (details)"
+msgid "Details"
+msgstr "Details"
+
+msgctxt "Layout Group (scenario)"
+msgid "Scenario"
+msgstr "Stimmung"
+
+msgctxt "Layout Group (location)"
+msgid "Location"
+msgstr "Location"
+
+msgctxt "Custom Title ()"
+msgid "Contact Name"
+msgstr ""
+
+msgctxt "Custom Title ()"
+msgid "Actor's Name"
+msgstr ""
diff --git a/tests/translations_po/test_document_export_po.cc b/tests/translations_po/test_document_export_po.cc
new file mode 100644
index 0000000..fd60105
--- /dev/null
+++ b/tests/translations_po/test_document_export_po.cc
@@ -0,0 +1,120 @@
+/* Glom
+ *
+ * Copyright (C) 2012 Openismus GmbH
+ *
+ * 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
+71 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <libglom/document/document.h>
+#include <libglom/translations_po.h>
+#include <libglom/init.h>
+#include <libglom/utils.h>
+#include <giomm/file.h>
+#include <glibmm/convert.h>
+#include <glibmm/miscutils.h>
+#include <glibmm/fileutils.h>
+
+#include <iostream>
+
+
+int main()
+{
+ Glom::libglom_init();
+
+ // Get a URI for a test file:
+ Glib::ustring uri;
+
+ try
+ {
+ const std::string path =
+ Glib::build_filename(GLOM_DOCDIR_EXAMPLES_NOTINSTALLED,
+ "example_film_manager.glom");
+ uri = Glib::filename_to_uri(path);
+ }
+ catch(const Glib::ConvertError& ex)
+ {
+ std::cerr << G_STRFUNC << ": " << ex.what();
+ return EXIT_FAILURE;
+ }
+
+ //std::cout << "URI=" << uri << std::endl;
+
+
+ // Load the document:
+ Glom::Document document;
+ document.set_file_uri(uri);
+ int failure_code = 0;
+ const bool test = document.load(failure_code);
+ //std::cout << "Document load result=" << test << std::endl;
+
+ if(!test)
+ {
+ std::cerr << "Document::load() failed with failure_code=" << failure_code << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ const Glib::ustring po_file_uri = Glom::Utils::get_temp_file_uri("glom_export.po");
+ if(po_file_uri.empty())
+ {
+ std::cerr << "Could not generate a temporary file URI=" << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ //std::cout << "po file URI: " << po_file_uri << std::endl;
+
+ const Glib::ustring locale = "de_DE";
+ const bool success =
+ Glom::write_translations_to_po_file(&document, po_file_uri, locale);
+ if(!success)
+ {
+ std::cerr << "Glom::write_translations_to_po_file() failed." << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ //Get a filepath for the URI:
+ std::string po_file_path;
+ try
+ {
+ po_file_path = Glib::filename_from_uri(po_file_uri);
+ }
+ catch(const Glib::ConvertError& ex)
+ {
+ std::cerr << G_STRFUNC << ": " << ex.what();
+ return EXIT_FAILURE;
+ }
+
+ //Check that the exported po file contains an expected string:
+ std::string data;
+ try
+ {
+ data = Glib::file_get_contents(po_file_path);
+ }
+ catch(const Glib::Error& ex)
+ {
+ std::cerr << "Failed: file_get_contents() failed: " << ex.what() << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ const bool text_found =
+ (data.find("Stabliste") != std::string::npos);
+ g_assert(text_found);
+
+ //TODO: Remove po_file_uri
+
+ Glom::libglom_deinit();
+
+ return EXIT_SUCCESS;
+}
diff --git a/tests/translations_po/test_document_import_po.cc b/tests/translations_po/test_document_import_po.cc
new file mode 100644
index 0000000..0ae3125
--- /dev/null
+++ b/tests/translations_po/test_document_import_po.cc
@@ -0,0 +1,128 @@
+/* Glom
+ *
+ * Copyright (C) 2012 Openismus GmbH
+ *
+ * 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
+71 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <libglom/document/document.h>
+#include <libglom/translations_po.h>
+#include <libglom/init.h>
+#include <libglom/utils.h>
+#include <giomm/file.h>
+#include <glibmm/convert.h>
+#include <glibmm/miscutils.h>
+
+#include <iostream>
+
+
+int main()
+{
+ Glom::libglom_init();
+
+ // Get a URI for a test file:
+ Glib::ustring uri;
+
+ try
+ {
+ const std::string path =
+ Glib::build_filename(GLOM_DOCDIR_EXAMPLES_NOTINSTALLED,
+ "example_film_manager.glom");
+ uri = Glib::filename_to_uri(path);
+ }
+ catch(const Glib::ConvertError& ex)
+ {
+ std::cerr << G_STRFUNC << ": " << ex.what();
+ return EXIT_FAILURE;
+ }
+
+ //std::cout << "URI=" << uri << std::endl;
+
+
+ // Load the document:
+ Glom::Document document;
+ document.set_file_uri(uri);
+ int failure_code = 0;
+ const bool test = document.load(failure_code);
+ //std::cout << "Document load result=" << test << std::endl;
+
+ if(!test)
+ {
+ std::cerr << "Document::load() failed with failure_code=" << failure_code << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ document.set_allow_autosave(false); //Do not save changes back to the example file:
+
+ Glib::ustring po_file_uri;
+ try
+ {
+ const std::string path =
+ Glib::build_filename(GLOM_TESTS_TRANSLATIONS_PO_DATA_NOTINSTALLED,
+ "test.po");
+ po_file_uri = Glib::filename_to_uri(path);
+ }
+ catch(const Glib::ConvertError& ex)
+ {
+ std::cerr << G_STRFUNC << ": " << ex.what();
+ return EXIT_FAILURE;
+ }
+
+ if(po_file_uri.empty())
+ {
+ std::cerr << "po_file_uri was empty." << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ //std::cout << "po file URI: " << po_file_uri << std::endl;
+
+ const Glib::ustring locale = "de_DE";
+ const bool success =
+ Glom::import_translations_from_po_file(&document, po_file_uri, locale);
+ if(!success)
+ {
+ std::cerr << "Glom::import_translations_from_po_file() failed." << std::endl;
+ return EXIT_FAILURE;
+ }
+
+
+ //Check that some expected translated titles are now in the document:
+ Glom::sharedptr<const Glom::TableInfo> table = document.get_table("scenes");
+ g_assert(table);
+ g_assert( table->get_title() == "Scenes" ); //The original title should be unchanged:
+
+ //This should have a new translated title:
+ if(table->get_title_translation(locale) != "TestResult1")
+ {
+ std::cerr << "Failure: Unexpected translated report title." << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ const Glom::sharedptr<const Glom::Report> report = document.get_report("crew", "crew_list");
+ g_assert(report);
+ g_assert(report->get_title() == "Crew List"); //The original title should be unchanged:
+
+ //This should have a new translated title:
+ if(report->get_title_translation(locale) != "TestResult2")
+ {
+ std::cerr << "Failure: Unexpected translated report title." << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ Glom::libglom_deinit();
+
+ return EXIT_SUCCESS;
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]