[rkward-cvs] SF.net SVN: rkward-code:[4929] trunk/rkward

tfry at users.sf.net tfry at users.sf.net
Sat Oct 18 13:39:22 UTC 2014


Revision: 4929
          http://sourceforge.net/p/rkward/code/4929
Author:   tfry
Date:     2014-10-18 13:39:21 +0000 (Sat, 18 Oct 2014)
Log Message:
-----------
Ok, the first few strings from pluginmaps are actually translatable, now.

Modified Paths:
--------------
    trunk/rkward/ChangeLog
    trunk/rkward/rkward/main.cpp
    trunk/rkward/rkward/misc/rkmessagecatalog.cpp
    trunk/rkward/rkward/misc/rkmessagecatalog.h
    trunk/rkward/rkward/misc/xmlhelper.cpp
    trunk/rkward/rkward/misc/xmlhelper.h
    trunk/rkward/rkward/plugin/rkcomponentmap.cpp
    trunk/rkward/rkward/plugins/analysis.pluginmap

Modified: trunk/rkward/ChangeLog
===================================================================
--- trunk/rkward/ChangeLog	2014-10-18 11:20:39 UTC (rev 4928)
+++ trunk/rkward/ChangeLog	2014-10-18 13:39:21 UTC (rev 4929)
@@ -1,5 +1,9 @@
 - Fixed some erroneous plugin debug messages
 - IN PROGESS: Allow plugins to be translated
+  + Notes:
+    - Is it a problem to sync KDE_LANG and LANGUAGE? Should that also be set for the backend?
+    - Message extraction: Should we do this in R, using XiMpLe? That might allow us to give better context / comments
+    - Don't forget to write documentation
 
 --- Version 0.6.2 - Oct-20-2014
 - In data editor, indicate NAs, explicitly

Modified: trunk/rkward/rkward/main.cpp
===================================================================
--- trunk/rkward/rkward/main.cpp	2014-10-18 11:20:39 UTC (rev 4928)
+++ trunk/rkward/rkward/main.cpp	2014-10-18 13:39:21 UTC (rev 4929)
@@ -170,6 +170,9 @@
 	RKGlobals::startup_options["backend-debugger"] = decodeArgument (args->getOption ("backend-debugger"));
 
 	RKWardApplication app;
+	// No, I do not really understand the point of separating KDE_LANG from LANGUAGE. We do honor it in so far as not
+	// forcing LANGUAGE on the backend, though. Having language as LANGUAGE makes code in RKMessageCatalog much easier compared to KCatalog.
+	qputenv ("LANGUAGE", QFile::encodeName (KGlobal::locale ()->language ()));
 	// install message handler *after* the componentData has been initialized
 	RKSettingsModuleDebug::debug_file = new QTemporaryFile (QDir::tempPath () + "/rkward.frontend");
 	RKSettingsModuleDebug::debug_file->setAutoRemove (false);

Modified: trunk/rkward/rkward/misc/rkmessagecatalog.cpp
===================================================================
--- trunk/rkward/rkward/misc/rkmessagecatalog.cpp	2014-10-18 11:20:39 UTC (rev 4928)
+++ trunk/rkward/rkward/misc/rkmessagecatalog.cpp	2014-10-18 13:39:21 UTC (rev 4929)
@@ -2,7 +2,7 @@
                           rkmessagecatalog  -  description
                              -------------------
     begin                : Mon Jun 24 2013
-    copyright            : (C) 2013 by Thomas Friedrichsmeier
+    copyright            : (C) 2013, 2014 by Thomas Friedrichsmeier
     email                : tfry at users.sourceforge.net
  ***************************************************************************/
 
@@ -22,12 +22,18 @@
 
 #include "../debug.h"
 
+// statics
+QHash<QString, RKMessageCatalog*> RKMessageCatalog::catalogs;
+QMutex RKMessageCatalog::setup_mutex;
+RKMessageCatalog* RKMessageCatalog::null_catalog = 0;
+
 RKMessageCatalog::RKMessageCatalog (const QString &name, const QString& path) {
 	RK_TRACE (MISC);
 
-	bound = false;
-	catalog_path = path;
 	catalog_name = QFile::encodeName (name);
+	char *res = bindtextdomain (catalog_name, QFile::encodeName (path));
+	RK_DO (qDebug ("Opening catalog %s, expected at %s, found at %s", qPrintable (name), qPrintable (path), res), MISC, DL_WARNING);
+	bind_textdomain_codeset (catalog_name, "UTF-8");
 }
 
 RKMessageCatalog::~RKMessageCatalog () {
@@ -40,7 +46,6 @@
 
 QString RKMessageCatalog::translate (const QString &msgctxt, const QString &msgid) const {
 	RK_TRACE (MISC);
-	if (!bound) const_cast<RKMessageCatalog *> (this)->setup ();
 
 	QByteArray key = (msgctxt + GETTEXT_CONTEXT_GLUE + msgid).toUtf8 ();
 	const char *trans = dgettext (catalog_name, key);
@@ -50,19 +55,29 @@
 
 QString RKMessageCatalog::translate (const QString &msgid) const {
 	RK_TRACE (MISC);
-	if (!bound) const_cast<RKMessageCatalog *> (this)->setup ();
 
 	return QString::fromUtf8 (dgettext (catalog_name, msgid.toUtf8 ()));
 }
 
-void RKMessageCatalog::setup () {
+// static
+RKMessageCatalog* RKMessageCatalog::getCatalog (const QString& name, const QString& pathhint) {
 	RK_TRACE (MISC);
 
+	RKMessageCatalog *ret = catalogs.value (name, 0);
+	if (ret) return ret;
 	setup_mutex.lock ();
-	if (!bound) {
-		bindtextdomain (catalog_name, QFile::encodeName (catalog_path));
-		bind_textdomain_codeset (catalog_name, "UTF-8");
-		bound = true;
-	}
+		// try to look up again, in case initialized from another thread
+		ret = catalogs.value (name, 0);
+		if (!ret) {
+			ret = new RKMessageCatalog (name, pathhint);
+			catalogs.insert (name, ret);
+		}
 	setup_mutex.unlock ();
+	return ret;
 }
+
+RKMessageCatalog* RKMessageCatalog::nullCatalog () {
+	// ok, not thread-safe, here, but the worst that can happen is creating more than one dummy catalog.
+	if (!null_catalog) null_catalog = getCatalog  ("rkward_dummy", QString ());
+	return null_catalog;
+}

Modified: trunk/rkward/rkward/misc/rkmessagecatalog.h
===================================================================
--- trunk/rkward/rkward/misc/rkmessagecatalog.h	2014-10-18 11:20:39 UTC (rev 4928)
+++ trunk/rkward/rkward/misc/rkmessagecatalog.h	2014-10-18 13:39:21 UTC (rev 4929)
@@ -2,7 +2,7 @@
                           rkmessagecatalog  -  description
                              -------------------
     begin                : Mon Jun 24 2013
-    copyright            : (C) 2013 by Thomas Friedrichsmeier
+    copyright            : (C) 2013, 2014 by Thomas Friedrichsmeier
     email                : tfry at users.sourceforge.net
  ***************************************************************************/
 
@@ -20,25 +20,32 @@
 
 #include <QString>
 #include <QMutex>
+#include <QHash>
 
 /** This class - heavily inspired by KCatalog - wraps a gettext message catalog. Contrary to KCatalog, this does not currently support using a language other than
- * the system language, or switching languages at runtime. It allows (the base directory of) message catalogs to be at an arbitrary location.
+ * the system language, or switching languages at runtime. It allows (the base directory of) message catalogs to be at an arbitrary location, however, which is
+ * important for plugins (installed at runtime and outside of system path)
  * 
  * Also, msgids are passed as QStrings, since in our use cases, that's the source data format, anyway.
  */
 class RKMessageCatalog {
 public:
+	QString translate (const QString &msgctxt, const QString &msgid) const;
+	QString translate (const QString &msgid) const;
+
+/** Get the catalog identified by name. This could be an already open catalog, or a new one. In the latter case, the catalog is expected at pathhint. In the former case, pathhint is ignored. This function is guaranteed to return a non-null RKMessageCatalog, although that does not imply the catalog could actually be loaded. */
+	static RKMessageCatalog *getCatalog (const QString &name, const QString &pathhint);
+/** Returns a dummy null-catalog */
+	static RKMessageCatalog *nullCatalog ();
+private:
 	RKMessageCatalog (const QString &name, const QString &path);
 	~RKMessageCatalog ();
 
-	QString translate (const QString &msgctxt, const QString &msgid) const;
-	QString translate (const QString &msgid) const;
-private:
-	void setup ();
-	QString catalog_path;
 	QByteArray catalog_name;
-	bool bound;
-	QMutex setup_mutex;
+
+	static QHash<QString, RKMessageCatalog*> catalogs;
+	static QMutex setup_mutex;
+	static RKMessageCatalog *null_catalog;
 };
 
 #endif

Modified: trunk/rkward/rkward/misc/xmlhelper.cpp
===================================================================
--- trunk/rkward/rkward/misc/xmlhelper.cpp	2014-10-18 11:20:39 UTC (rev 4928)
+++ trunk/rkward/rkward/misc/xmlhelper.cpp	2014-10-18 13:39:21 UTC (rev 4929)
@@ -25,11 +25,15 @@
 #include <qdir.h>
 #include <QTextStream>
 
+#include <rkmessagecatalog.h>
+
 #include "../debug.h"
 
-XMLHelper::XMLHelper (const QString &filename) {
+XMLHelper::XMLHelper (const QString &filename, const RKMessageCatalog *default_catalog) {
 	RK_TRACE (XML);
 	XMLHelper::filename = filename;
+	if (!default_catalog) catalog = RKMessageCatalog::nullCatalog ();
+	else catalog = default_catalog;
 }
 
 XMLHelper::~XMLHelper () {
@@ -52,6 +56,10 @@
 	f.close();
 
 	QDomElement ret = doc.documentElement ();
+	if (ret.hasAttribute ("po_id")) {
+		QDir path = QFileInfo (filename).absoluteDir ();
+		catalog = RKMessageCatalog::getCatalog ("rkward__" + ret.attribute ("po_id"), path.absoluteFilePath (getStringAttribute (ret, "po_path", "po", DL_INFO)));
+	}
 	if (with_includes) {
 		XMLChildList includes = nodeListToChildList (doc.elementsByTagName ("include"));
 		for (XMLChildList::const_iterator it = includes.constBegin (); it != includes.constEnd (); ++it) {
@@ -232,6 +240,19 @@
 	return (element.attribute (name));
 }
 
+QString XMLHelper::i18nStringAttribute (const QDomElement& element, const QString& name, const QString& def, int debug_level) {
+	RK_TRACE (XML);
+	if (!element.hasAttribute (name)) {
+		const QString no18nname = "noi18n_" + name;
+		if (element.hasAttribute (no18nname)) return element.attribute (no18nname);
+		displayError (&element, i18n ("'%1'-attribute not given. Assuming '%2'", name, def), debug_level);
+		return def;
+	}
+	const QString context_element ("i18ncontext");
+	if (element.hasAttribute (context_element)) return (catalog->translate (context_element, element.attribute (name)));
+	return (catalog->translate (element.attribute (name)));
+}
+
 int XMLHelper::getMultiChoiceAttribute (const QDomElement &element, const QString &name, const QString &values, int def, int debug_level) {
 	RK_TRACE (XML);
 

Modified: trunk/rkward/rkward/misc/xmlhelper.h
===================================================================
--- trunk/rkward/rkward/misc/xmlhelper.h	2014-10-18 11:20:39 UTC (rev 4928)
+++ trunk/rkward/rkward/misc/xmlhelper.h	2014-10-18 13:39:21 UTC (rev 4929)
@@ -20,6 +20,8 @@
 
 #include <qdom.h>
 
+class RKMessageCatalog;
+
 /** a helper type used to pass a list of direct child elements of a node */
 typedef QList<QDomElement> XMLChildList;
 
@@ -33,11 +35,15 @@
 class XMLHelper {
 public:
 /** create an instance of XMLHelper.
- @param filename the name of the file to parse. The file is not yet opened on construction. Use openXMLFile() for that. */
-	XMLHelper (const QString &filename);
-/** destrcutor */
+ @param filename the name of the file to parse. The file is not yet opened on construction. Use openXMLFile() for that. 
+ @param default_catalog message catalog to use in case none is specified in the xml file itself. */
+	XMLHelper (const QString &filename, const RKMessageCatalog *default_catalog=0);
+/** destructor */
 	~XMLHelper ();
-	
+/** Return the a pointer to the message catalog in use. This may - or may not - be the same as specified as default catalog in the constructor.
+    Guaranteed to be non-null (but not guaranteed to be non-empty). */
+	const RKMessageCatalog *messageCatalog () const { return catalog; };
+
 /** Open the filename set in the constructor (read-only) and do basic parsing. Internally, the file will be closed right away, so there is no need to call an additional closeFile-equivalent. Once the returned element (and any copies you make of it) goes out of scope, the entire element-tree allocated will be freed,
 but you can re-open the file, if needed.
 @param debug_level level of debug message to generate if opening/parsing fails
@@ -88,6 +94,8 @@
 @param debug_level level of debug message to generate in case of failure (i.e. no such attribute was found)
 @returns the value of the given attribute or the given default */
 	QString getStringAttribute (const QDomElement &element, const QString &name, const QString &def, int debug_level);
+/** same as getStringAttribute(), but tries to translate the string, before returning it. Does not translate def! */
+	QString i18nStringAttribute (const QDomElement &element, const QString &name, const QString &def, int debug_level);
 
 /** checks whether the given attribute is one of the allowed string values and returns the number of the value in the list (or the default)
 @param element the element whose attributes to search
@@ -114,7 +122,6 @@
 @returns the value of the given attribute or the given default */
 	double getDoubleAttribute (const QDomElement &element, const QString &name, double def, int debug_level);
 
-
 /** returns the value of a boolean attribute ("true" or "false")
 @param element the element whose attributes to search
 @param name the name of the attribute to read
@@ -135,12 +142,12 @@
 @param debug_level the debug level to show the message at (highestError () will be adujsted if applicable)
 @param message_level sometime you may want to make sure your message is being shown even if it is not very important to your code. For instance, if there is a typo/illegal value in an optional setting, your code can continue using a reasonable default, but the user should still be notified of this error. If you omit this parameter or set it to something smaller that debug_level, debug_level will be used instead. */
 	void displayError (const QDomNode *in_node, const QString &message, int debug_level, int message_level=-1);
-	
 private:
 /** copy the node list into a child list. The main effect is that a child list is not updated according to document changes */
 	XMLChildList nodeListToChildList (const QDomNodeList &from);
 	void replaceWithChildren (QDomNode *replaced, const QDomElement &replacement_parent);
 	QString filename;
+	const RKMessageCatalog *catalog;
 };
 
 #endif

Modified: trunk/rkward/rkward/plugin/rkcomponentmap.cpp
===================================================================
--- trunk/rkward/rkward/plugin/rkcomponentmap.cpp	2014-10-18 11:20:39 UTC (rev 4928)
+++ trunk/rkward/rkward/plugin/rkcomponentmap.cpp	2014-10-18 13:39:21 UTC (rev 4929)
@@ -465,7 +465,7 @@
 
 		QString filename = xml.getStringAttribute((*it), "file", QString (), DL_WARNING);
 		int type = xml.getMultiChoiceAttribute ((*it), "type", "standard", 0, DL_WARNING);
-		QString label = xml.getStringAttribute ((*it), "label", i18n ("(no label)"), DL_WARNING);
+		QString label = xml.i18nStringAttribute ((*it), "label", i18n ("(no label)"), DL_WARNING);
 
 		if (components.contains (id)) {
 			ret.addAndPrintError (DL_WARNING, i18n ("RKComponentMap already contains a component with id \"%1\". Ignoring second entry.", id));

Modified: trunk/rkward/rkward/plugins/analysis.pluginmap
===================================================================
--- trunk/rkward/rkward/plugins/analysis.pluginmap	2014-10-18 11:20:39 UTC (rev 4928)
+++ trunk/rkward/rkward/plugins/analysis.pluginmap	2014-10-18 13:39:21 UTC (rev 4929)
@@ -1,6 +1,6 @@
 <!DOCTYPE rkpluginmap>
 
-<document base_prefix="" namespace="rkward" id="analysis">
+<document base_prefix="" namespace="rkward" id="analysis" po_id="analysis">
 	<include file="pluginmap_meta.inc"/>
 
 	<components>





More information about the rkward-tracker mailing list