[clutter] script: Support translatable strings for properties



commit 764640419607b4918515f42722bb0950ea23d90c
Author: Emmanuele Bassi <ebassi linux intel com>
Date:   Tue Mar 6 14:23:33 2012 +0000

    script: Support translatable strings for properties
    
    ClutterScript should be able to automatically call gettext() and friends
    on strings loaded from a UI definition, prior to passing the string to
    the object it is constructing.
    
    The basic implementation is trivial:
    
      - set a translation domain on the ClutterScript instance
      - mark the translatable strings inside the JSON data, like:
    
          "property" : {
            "translatable" : true,
            "string" : "a translatable string"
          }
    
    The hard part is now getting the tools we use to extract the
    translatable strings to understand the JSON format we use inside
    ClutterScript.

 clutter/clutter-script-parser.c  |   58 +++++++++++++++++++++++
 clutter/clutter-script-private.h |    3 +
 clutter/clutter-script.c         |   93 ++++++++++++++++++++++++++++++++++++++
 clutter/clutter-script.h         |    6 +++
 tests/data/test-script.json      |    4 +-
 5 files changed, 162 insertions(+), 2 deletions(-)
---
diff --git a/clutter/clutter-script-parser.c b/clutter/clutter-script-parser.c
index f2b281b..4dece6a 100644
--- a/clutter/clutter-script-parser.c
+++ b/clutter/clutter-script-parser.c
@@ -1089,6 +1089,54 @@ clutter_script_parser_parse_end (JsonParser *parser)
 }
 
 gboolean
+_clutter_script_parse_translatable_string (ClutterScript *script,
+                                           JsonNode      *node,
+                                           char         **str)
+{
+  JsonObject *obj;
+  const char *string, *domain;
+  const char *res;
+  gboolean translatable;
+
+  if (!JSON_NODE_HOLDS_OBJECT (node))
+    return FALSE;
+
+  obj = json_node_get_object (node);
+  if (!(json_object_has_member (obj, "translatable") &&
+        json_object_has_member (obj, "string")))
+    return FALSE;
+
+  translatable = json_object_get_boolean_member (obj, "translatable");
+
+  string = json_object_get_string_member (obj, "string");
+  if (string == NULL || *string == '\0')
+    return FALSE;
+
+  if (json_object_has_member (obj, "domain"))
+    domain = json_object_get_string_member (obj, "domain");
+  else
+    domain = NULL;
+
+  if (domain == NULL || *domain == '\0')
+    domain = clutter_script_get_translation_domain (script);
+
+  if (translatable)
+    {
+      if (domain != NULL && *domain != '\0')
+        res = g_dgettext (domain, string);
+      else
+        res = gettext (string);
+    }
+  else
+    res = string;
+
+  if (str != NULL)
+    *str = g_strdup (res);
+
+  return TRUE;
+}
+
+gboolean
 _clutter_script_parse_node (ClutterScript *script,
                             GValue        *value,
                             const gchar   *name,
@@ -1203,6 +1251,16 @@ _clutter_script_parse_node (ClutterScript *script,
                   return TRUE;
                 }
             }
+          else if (p_type == G_TYPE_STRING)
+            {
+              char *str = NULL;
+
+              if (_clutter_script_parse_translatable_string (script, node, &str))
+                {
+                  g_value_take_string (value, str);
+                  return TRUE;
+                }
+            }
          }
       return FALSE;
 
diff --git a/clutter/clutter-script-private.h b/clutter/clutter-script-private.h
index 5e7b5f5..7452952 100644
--- a/clutter/clutter-script-private.h
+++ b/clutter/clutter-script-private.h
@@ -130,6 +130,9 @@ gboolean _clutter_script_parse_color       (ClutterScript   *script,
                                             ClutterColor    *color);
 GObject *_clutter_script_parse_alpha       (ClutterScript   *script,
                                             JsonNode        *node);
+gboolean _clutter_script_parse_translatable_string (ClutterScript *script,
+                                                    JsonNode      *node,
+                                                    char         **str);
 
 void _clutter_script_construct_object (ClutterScript *script,
                                        ObjectInfo    *oinfo);
diff --git a/clutter/clutter-script.c b/clutter/clutter-script.c
index 566adc8..ec88c0b 100644
--- a/clutter/clutter-script.c
+++ b/clutter/clutter-script.c
@@ -256,6 +256,7 @@ enum
 
   PROP_FILENAME_SET,
   PROP_FILENAME,
+  PROP_TRANSLATION_DOMAIN,
 
   PROP_LAST
 };
@@ -278,6 +279,8 @@ struct _ClutterScriptPrivate
 
   gchar **search_paths;
 
+  gchar *translation_domain;
+
   gchar *filename;
   guint is_filename : 1;
 };
@@ -385,11 +388,32 @@ clutter_script_finalize (GObject *gobject)
   g_strfreev (priv->search_paths);
   g_free (priv->filename);
   g_hash_table_destroy (priv->states);
+  g_free (priv->translation_domain);
 
   G_OBJECT_CLASS (clutter_script_parent_class)->finalize (gobject);
 }
 
 static void
+clutter_script_set_property (GObject      *gobject,
+                             guint         prop_id,
+                             const GValue *value,
+                             GParamSpec   *pspec)
+{
+  ClutterScript *script = CLUTTER_SCRIPT (gobject);
+
+  switch (prop_id)
+    {
+    case PROP_TRANSLATION_DOMAIN:
+      clutter_script_set_translation_domain (script, g_value_get_string (value));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+      break;
+    }
+}
+
+static void
 clutter_script_get_property (GObject    *gobject,
                              guint       prop_id,
                              GValue     *value,
@@ -402,9 +426,15 @@ clutter_script_get_property (GObject    *gobject,
     case PROP_FILENAME_SET:
       g_value_set_boolean (value, script->priv->is_filename);
       break;
+
     case PROP_FILENAME:
       g_value_set_string (value, script->priv->filename);
       break;
+
+    case PROP_TRANSLATION_DOMAIN:
+      g_value_set_string (value, script->priv->translation_domain);
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
       break;
@@ -451,6 +481,25 @@ clutter_script_class_init (ClutterScriptClass *klass)
                          NULL,
                          CLUTTER_PARAM_READABLE);
 
+  /**
+   * ClutterScript:translation-domain:
+   *
+   * The translation domain, used to localize strings marked as translatable
+   * inside a UI definition.
+   *
+   * If #ClutterScript:translation-domain is set to %NULL, #ClutterScript
+   * will use gettext(), otherwise g_dgettext() will be used.
+   *
+   * Since: 1.10
+   */
+  obj_props[PROP_TRANSLATION_DOMAIN] =
+    g_param_spec_string ("translation-domain",
+                         P_("Translation Domain"),
+                         P_("The translation domain used to localize string"),
+                         NULL,
+                         CLUTTER_PARAM_READWRITE);
+
+  gobject_class->set_property = clutter_script_set_property;
   gobject_class->get_property = clutter_script_get_property;
   gobject_class->finalize = clutter_script_finalize;
 
@@ -1439,6 +1488,50 @@ clutter_script_get_states (ClutterScript *script,
   return g_hash_table_lookup (script->priv->states, name);
 }
 
+/**
+ * clutter_script_set_translation_domain:
+ * @script: a #ClutterScript
+ * @domain: (allow-none): the translation domain, or %NULL
+ *
+ * Sets the translation domain for @script.
+ *
+ * Since: 1.10
+ */
+void
+clutter_script_set_translation_domain (ClutterScript *script,
+                                       const gchar   *domain)
+{
+  g_return_if_fail (CLUTTER_IS_SCRIPT (script));
+
+  if (g_strcmp0 (domain, script->priv->translation_domain) == 0)
+    return;
+
+  g_free (script->priv->translation_domain);
+  script->priv->translation_domain = g_strdup (domain);
+
+  g_object_notify_by_pspec (G_OBJECT (script), obj_props[PROP_TRANSLATION_DOMAIN]);
+}
+
+/**
+ * clutter_script_get_translation_domain:
+ * @script: a #ClutterScript
+ *
+ * Retrieves the translation domain set using
+ * clutter_script_set_translation_domain().
+ *
+ * Return value: (transfer none): the translation domain, if any is set,
+ *   or %NULL
+ *
+ * Since: 1.10
+ */
+const gchar *
+clutter_script_get_translation_domain (ClutterScript *script)
+{
+  g_return_val_if_fail (CLUTTER_IS_SCRIPT (script), NULL);
+
+  return script->priv->translation_domain;
+}
+
 /*
  * _clutter_script_generate_fake_id:
  * @script: a #ClutterScript
diff --git a/clutter/clutter-script.h b/clutter/clutter-script.h
index d690dbc..43eb828 100644
--- a/clutter/clutter-script.h
+++ b/clutter/clutter-script.h
@@ -188,6 +188,12 @@ gchar *         clutter_script_lookup_filename          (ClutterScript
 GType           clutter_script_get_type_from_name       (ClutterScript             *script,
                                                          const gchar               *type_name);
 
+CLUTTER_AVAILABLE_IN_1_10
+void            clutter_script_set_translation_domain   (ClutterScript             *script,
+                                                         const gchar               *domain);
+CLUTTER_AVAILABLE_IN_1_10
+const gchar *   clutter_script_get_translation_domain   (ClutterScript             *script);
+
 const gchar *   clutter_get_script_id                   (GObject                   *gobject);
 
 G_END_DECLS
diff --git a/tests/data/test-script.json b/tests/data/test-script.json
index 3482d73..1d66b25 100644
--- a/tests/data/test-script.json
+++ b/tests/data/test-script.json
@@ -2,7 +2,7 @@
   "My Scene" : {
     "id" : "main-stage",
     "type" : "ClutterStage",
-    "title" : "ClutterScript test",
+    "title" : { "translatable" : true, "string" : "ClutterScript test" },
     "color" : "white",
     "signals" : [
       { "name" : "key-press-event", "handler" : "clutter_main_quit" },
@@ -62,7 +62,7 @@
         "type" : "ClutterText",
         "x" : 50,
         "y" : 200,
-        "text" : "Clutter\tScript",
+        "text" : { "translatable" : true, "string" : "Clutter Script" },
         "font-name" : "Sans 24px",
         "color" : "black",
         "line-alignment" : "center",



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]