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.
This commit is contained in:
Emmanuele Bassi 2012-03-06 14:23:33 +00:00
parent 4a9414ff87
commit 7646404196
5 changed files with 162 additions and 2 deletions

View File

@ -1088,6 +1088,54 @@ clutter_script_parser_parse_end (JsonParser *parser)
clutter_script_ensure_objects (CLUTTER_SCRIPT_PARSER (parser)->script); clutter_script_ensure_objects (CLUTTER_SCRIPT_PARSER (parser)->script);
} }
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 gboolean
_clutter_script_parse_node (ClutterScript *script, _clutter_script_parse_node (ClutterScript *script,
GValue *value, GValue *value,
@ -1203,6 +1251,16 @@ _clutter_script_parse_node (ClutterScript *script,
return TRUE; 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; return FALSE;

View File

@ -130,6 +130,9 @@ gboolean _clutter_script_parse_color (ClutterScript *script,
ClutterColor *color); ClutterColor *color);
GObject *_clutter_script_parse_alpha (ClutterScript *script, GObject *_clutter_script_parse_alpha (ClutterScript *script,
JsonNode *node); JsonNode *node);
gboolean _clutter_script_parse_translatable_string (ClutterScript *script,
JsonNode *node,
char **str);
void _clutter_script_construct_object (ClutterScript *script, void _clutter_script_construct_object (ClutterScript *script,
ObjectInfo *oinfo); ObjectInfo *oinfo);

View File

@ -256,6 +256,7 @@ enum
PROP_FILENAME_SET, PROP_FILENAME_SET,
PROP_FILENAME, PROP_FILENAME,
PROP_TRANSLATION_DOMAIN,
PROP_LAST PROP_LAST
}; };
@ -278,6 +279,8 @@ struct _ClutterScriptPrivate
gchar **search_paths; gchar **search_paths;
gchar *translation_domain;
gchar *filename; gchar *filename;
guint is_filename : 1; guint is_filename : 1;
}; };
@ -385,10 +388,31 @@ clutter_script_finalize (GObject *gobject)
g_strfreev (priv->search_paths); g_strfreev (priv->search_paths);
g_free (priv->filename); g_free (priv->filename);
g_hash_table_destroy (priv->states); g_hash_table_destroy (priv->states);
g_free (priv->translation_domain);
G_OBJECT_CLASS (clutter_script_parent_class)->finalize (gobject); 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 static void
clutter_script_get_property (GObject *gobject, clutter_script_get_property (GObject *gobject,
guint prop_id, guint prop_id,
@ -402,9 +426,15 @@ clutter_script_get_property (GObject *gobject,
case PROP_FILENAME_SET: case PROP_FILENAME_SET:
g_value_set_boolean (value, script->priv->is_filename); g_value_set_boolean (value, script->priv->is_filename);
break; break;
case PROP_FILENAME: case PROP_FILENAME:
g_value_set_string (value, script->priv->filename); g_value_set_string (value, script->priv->filename);
break; break;
case PROP_TRANSLATION_DOMAIN:
g_value_set_string (value, script->priv->translation_domain);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break; break;
@ -451,6 +481,25 @@ clutter_script_class_init (ClutterScriptClass *klass)
NULL, NULL,
CLUTTER_PARAM_READABLE); 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->get_property = clutter_script_get_property;
gobject_class->finalize = clutter_script_finalize; 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); 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: * _clutter_script_generate_fake_id:
* @script: a #ClutterScript * @script: a #ClutterScript

View File

@ -188,6 +188,12 @@ gchar * clutter_script_lookup_filename (ClutterScript
GType clutter_script_get_type_from_name (ClutterScript *script, GType clutter_script_get_type_from_name (ClutterScript *script,
const gchar *type_name); 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); const gchar * clutter_get_script_id (GObject *gobject);
G_END_DECLS G_END_DECLS

View File

@ -2,7 +2,7 @@
"My Scene" : { "My Scene" : {
"id" : "main-stage", "id" : "main-stage",
"type" : "ClutterStage", "type" : "ClutterStage",
"title" : "ClutterScript test", "title" : { "translatable" : true, "string" : "ClutterScript test" },
"color" : "white", "color" : "white",
"signals" : [ "signals" : [
{ "name" : "key-press-event", "handler" : "clutter_main_quit" }, { "name" : "key-press-event", "handler" : "clutter_main_quit" },
@ -62,7 +62,7 @@
"type" : "ClutterText", "type" : "ClutterText",
"x" : 50, "x" : 50,
"y" : 200, "y" : 200,
"text" : "Clutter\tScript", "text" : { "translatable" : true, "string" : "Clutter Script" },
"font-name" : "Sans 24px", "font-name" : "Sans 24px",
"color" : "black", "color" : "black",
"line-alignment" : "center", "line-alignment" : "center",