From 764640419607b4918515f42722bb0950ea23d90c Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Tue, 6 Mar 2012 14:23:33 +0000 Subject: [PATCH] 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", -- 2.7.4