mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-10-03 12:19:20 +02:00
Support Localized resources
This commit is contained in:
@@ -649,23 +649,29 @@ typedef enum {
|
|||||||
* GResourceFlags:
|
* GResourceFlags:
|
||||||
* @G_RESOURCE_FLAGS_NONE: No flags set.
|
* @G_RESOURCE_FLAGS_NONE: No flags set.
|
||||||
* @G_RESOURCE_FLAGS_COMPRESSED: The file is compressed.
|
* @G_RESOURCE_FLAGS_COMPRESSED: The file is compressed.
|
||||||
|
* @G_RESOURCE_FLAGS_LOCALIZED: The file has alternate versions based on locale.
|
||||||
*
|
*
|
||||||
* GResourceFlags give information about a particular file inside a resource
|
* GResourceFlags give information about a particular file inside a resource
|
||||||
* bundle.
|
* bundle.
|
||||||
**/
|
**/
|
||||||
typedef enum {
|
typedef enum {
|
||||||
G_RESOURCE_FLAGS_NONE = 0,
|
G_RESOURCE_FLAGS_NONE = 0,
|
||||||
G_RESOURCE_FLAGS_COMPRESSED = (1<<0)
|
G_RESOURCE_FLAGS_COMPRESSED = (1<<0),
|
||||||
|
G_RESOURCE_FLAGS_LOCALIZED = (1<<1)
|
||||||
} GResourceFlags;
|
} GResourceFlags;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GResourceLookupFlags:
|
* GResourceLookupFlags:
|
||||||
* @G_RESOURCE_LOOKUP_FLAGS_NONE: No flags set.
|
* @G_RESOURCE_LOOKUP_FLAGS_NONE: No flags set.
|
||||||
|
* @G_RESOURCE_LOOKUP_FLAGS_NO_ALTERNATIVE: If there is an alternative
|
||||||
|
* (for instance a locale-specific version of the file) return the original
|
||||||
|
* version, not the alternative.
|
||||||
*
|
*
|
||||||
* GResourceLookupFlags determine how resource path lookups are handled.
|
* GResourceLookupFlags determine how resource path lookups are handled.
|
||||||
**/
|
**/
|
||||||
typedef enum {
|
typedef enum {
|
||||||
G_RESOURCE_LOOKUP_FLAGS_NONE = 0,
|
G_RESOURCE_LOOKUP_FLAGS_NONE = 0,
|
||||||
|
G_RESOURCE_LOOKUP_FLAGS_NO_ALTERNATIVE = (1<<0),
|
||||||
} GResourceLookupFlags;
|
} GResourceLookupFlags;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -54,6 +54,7 @@ typedef struct
|
|||||||
|
|
||||||
/* per gresource */
|
/* per gresource */
|
||||||
char *prefix;
|
char *prefix;
|
||||||
|
char *lang;
|
||||||
|
|
||||||
/* per file */
|
/* per file */
|
||||||
char *alias;
|
char *alias;
|
||||||
@@ -106,7 +107,8 @@ start_element (GMarkupParseContext *context,
|
|||||||
if (strcmp (element_name, "gresource") == 0)
|
if (strcmp (element_name, "gresource") == 0)
|
||||||
{
|
{
|
||||||
COLLECT (OPTIONAL | STRDUP,
|
COLLECT (OPTIONAL | STRDUP,
|
||||||
"prefix", &state->prefix);
|
"prefix", &state->prefix,
|
||||||
|
OPTIONAL | STRDUP, "lang", &state->lang);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -172,12 +174,14 @@ end_element (GMarkupParseContext *context,
|
|||||||
{
|
{
|
||||||
g_free (state->prefix);
|
g_free (state->prefix);
|
||||||
state->prefix = NULL;
|
state->prefix = NULL;
|
||||||
|
g_free (state->lang);
|
||||||
|
state->lang = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (strcmp (element_name, "file") == 0)
|
else if (strcmp (element_name, "file") == 0)
|
||||||
{
|
{
|
||||||
gchar *file, *real_file;
|
gchar *file, *real_file;
|
||||||
gchar *key;
|
gchar *key, *old_key;
|
||||||
FileData *data;
|
FileData *data;
|
||||||
|
|
||||||
file = state->string->str;
|
file = state->string->str;
|
||||||
@@ -190,6 +194,23 @@ end_element (GMarkupParseContext *context,
|
|||||||
else
|
else
|
||||||
key = g_build_path ("/", "/", key, NULL);
|
key = g_build_path ("/", "/", key, NULL);
|
||||||
|
|
||||||
|
if (state->lang)
|
||||||
|
{
|
||||||
|
data = g_hash_table_lookup (state->table, key);
|
||||||
|
if (data == NULL)
|
||||||
|
{
|
||||||
|
g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
|
||||||
|
_("File %s is in lang=%s, but not without lang"),
|
||||||
|
key, state->lang);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
data->flags |= G_RESOURCE_FLAGS_LOCALIZED;
|
||||||
|
|
||||||
|
old_key = key;
|
||||||
|
key = g_build_path ("/", "/", state->lang, key, NULL);
|
||||||
|
g_free (old_key);
|
||||||
|
}
|
||||||
|
|
||||||
if (g_hash_table_lookup (state->table, key) != NULL)
|
if (g_hash_table_lookup (state->table, key) != NULL)
|
||||||
{
|
{
|
||||||
g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
|
g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
|
||||||
|
@@ -58,6 +58,9 @@ G_DEFINE_BOXED_TYPE (GResource, g_resource, g_resource_ref, g_resource_unref)
|
|||||||
* simple (no need to check for things like I/O errors or locate the files in the filesystem). It
|
* simple (no need to check for things like I/O errors or locate the files in the filesystem). It
|
||||||
* also makes it easier to create relocatable applications.
|
* also makes it easier to create relocatable applications.
|
||||||
*
|
*
|
||||||
|
* Resource files can have locale specific alternatives, so that the current locale causes resource
|
||||||
|
* lookups to automatically pick up an alternate file.
|
||||||
|
*
|
||||||
* Resource files can also be marked as compresses. Such files will be included in the resource bundle
|
* Resource files can also be marked as compresses. Such files will be included in the resource bundle
|
||||||
* in a compressed form, but will be automatically uncompressed when the resource is used. This
|
* in a compressed form, but will be automatically uncompressed when the resource is used. This
|
||||||
* is very useful e.g. for larger text files that are parsed once (or rarely) and then thrown away.
|
* is very useful e.g. for larger text files that are parsed once (or rarely) and then thrown away.
|
||||||
@@ -75,6 +78,9 @@ G_DEFINE_BOXED_TYPE (GResource, g_resource, g_resource_ref, g_resource_unref)
|
|||||||
* <file compressed="true">dialog.ui</file>
|
* <file compressed="true">dialog.ui</file>
|
||||||
* <file>menumarkup.xml</file>
|
* <file>menumarkup.xml</file>
|
||||||
* </gresource>
|
* </gresource>
|
||||||
|
* <gresource lang="sv" prefix="/org/gtk/Example">
|
||||||
|
* <file alias="menumarkup.xml">menumarkup_SV.xml</file>
|
||||||
|
* </gresource>
|
||||||
* </gresources>
|
* </gresources>
|
||||||
* ]]></programlisting></example>
|
* ]]></programlisting></example>
|
||||||
*
|
*
|
||||||
@@ -83,8 +89,12 @@ G_DEFINE_BOXED_TYPE (GResource, g_resource, g_resource_ref, g_resource_unref)
|
|||||||
* /org/gtk/Example/data/splashscreen.png
|
* /org/gtk/Example/data/splashscreen.png
|
||||||
* /org/gtk/Example/dialog.ui
|
* /org/gtk/Example/dialog.ui
|
||||||
* /org/gtk/Example/menumarkup.xml
|
* /org/gtk/Example/menumarkup.xml
|
||||||
|
* /sv/org/gtk/Example/menumarkup.xml
|
||||||
* ]]></programlisting>
|
* ]]></programlisting>
|
||||||
*
|
*
|
||||||
|
* Where the contents at "/org/gtk/Example/menumarkup.xml" automatically redirects
|
||||||
|
* to "/sv/org/gtk/Example/menumarkup.xml" when run in e.g. a sv_SE locale.
|
||||||
|
*
|
||||||
* Note that all resources in the process share the same namespace, so use java-style
|
* Note that all resources in the process share the same namespace, so use java-style
|
||||||
* path prefixes (like in the above example) to avoid conflicts.
|
* path prefixes (like in the above example) to avoid conflicts.
|
||||||
*
|
*
|
||||||
@@ -277,6 +287,29 @@ static gboolean do_lookup (GResource *resource,
|
|||||||
&_flags,
|
&_flags,
|
||||||
&array);
|
&array);
|
||||||
|
|
||||||
|
if (!(lookup_flags & G_RESOURCE_LOOKUP_FLAGS_NO_ALTERNATIVE) &&
|
||||||
|
(_flags & G_RESOURCE_FLAGS_LOCALIZED))
|
||||||
|
{
|
||||||
|
const gchar * const *langs = g_get_language_names ();
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; langs[i] != NULL; i++)
|
||||||
|
{
|
||||||
|
char *prefixed_path = g_strconcat ("/", langs[i], path, NULL);
|
||||||
|
res = do_lookup (resource, prefixed_path,
|
||||||
|
lookup_flags | G_RESOURCE_LOOKUP_FLAGS_NO_ALTERNATIVE,
|
||||||
|
size, flags, data, data_size, NULL);
|
||||||
|
g_free (prefixed_path);
|
||||||
|
if (res)
|
||||||
|
{
|
||||||
|
/* Mark the target as localized too if we followed the "link" */
|
||||||
|
if (flags)
|
||||||
|
*flags |= G_RESOURCE_FLAGS_LOCALIZED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!res)
|
if (!res)
|
||||||
{
|
{
|
||||||
if (size)
|
if (size)
|
||||||
|
@@ -48,7 +48,7 @@ test_resource (GResource *resource)
|
|||||||
g_assert (found);
|
g_assert (found);
|
||||||
g_assert_no_error (error);
|
g_assert_no_error (error);
|
||||||
g_assert (size == 6);
|
g_assert (size == 6);
|
||||||
g_assert (flags == (G_RESOURCE_FLAGS_COMPRESSED));
|
g_assert (flags == (G_RESOURCE_FLAGS_LOCALIZED | G_RESOURCE_FLAGS_COMPRESSED));
|
||||||
|
|
||||||
found = g_resource_get_info (resource,
|
found = g_resource_get_info (resource,
|
||||||
"/a_prefix/test2.txt",
|
"/a_prefix/test2.txt",
|
||||||
@@ -68,6 +68,15 @@ test_resource (GResource *resource)
|
|||||||
g_assert (size == 6);
|
g_assert (size == 6);
|
||||||
g_assert (flags == 0);
|
g_assert (flags == 0);
|
||||||
|
|
||||||
|
found = g_resource_get_info (resource,
|
||||||
|
"/sv/test1.txt",
|
||||||
|
G_RESOURCE_LOOKUP_FLAGS_NONE,
|
||||||
|
&size, &flags, &error);
|
||||||
|
g_assert (found);
|
||||||
|
g_assert_no_error (error);
|
||||||
|
g_assert (size == 6);
|
||||||
|
g_assert (flags == 0);
|
||||||
|
|
||||||
data = g_resource_lookup_data (resource,
|
data = g_resource_lookup_data (resource,
|
||||||
"/test1.txt",
|
"/test1.txt",
|
||||||
G_RESOURCE_LOOKUP_FLAGS_NONE,
|
G_RESOURCE_LOOKUP_FLAGS_NONE,
|
||||||
@@ -116,6 +125,16 @@ test_resource (GResource *resource)
|
|||||||
g_assert_cmpstr (g_bytes_get_data (data, NULL), ==, "test2\n");
|
g_assert_cmpstr (g_bytes_get_data (data, NULL), ==, "test2\n");
|
||||||
g_bytes_unref (data);
|
g_bytes_unref (data);
|
||||||
|
|
||||||
|
data = g_resource_lookup_data (resource,
|
||||||
|
"/sv/test1.txt",
|
||||||
|
G_RESOURCE_LOOKUP_FLAGS_NONE,
|
||||||
|
&error);
|
||||||
|
g_assert (data != NULL);
|
||||||
|
g_assert_no_error (error);
|
||||||
|
g_assert (size == 6);
|
||||||
|
g_assert_cmpstr (g_bytes_get_data (data, NULL), ==, "test3\n");
|
||||||
|
g_bytes_unref (data);
|
||||||
|
|
||||||
children = g_resource_enumerate_children (resource,
|
children = g_resource_enumerate_children (resource,
|
||||||
"/not/here",
|
"/not/here",
|
||||||
G_RESOURCE_LOOKUP_FLAGS_NONE,
|
G_RESOURCE_LOOKUP_FLAGS_NONE,
|
||||||
@@ -209,7 +228,7 @@ test_resource_registred (void)
|
|||||||
g_assert (found);
|
g_assert (found);
|
||||||
g_assert_no_error (error);
|
g_assert_no_error (error);
|
||||||
g_assert (size == 6);
|
g_assert (size == 6);
|
||||||
g_assert (flags == (G_RESOURCE_FLAGS_COMPRESSED));
|
g_assert (flags == (G_RESOURCE_FLAGS_LOCALIZED | G_RESOURCE_FLAGS_COMPRESSED));
|
||||||
|
|
||||||
found = g_resources_get_info ("/a_prefix/test2.txt",
|
found = g_resources_get_info ("/a_prefix/test2.txt",
|
||||||
G_RESOURCE_LOOKUP_FLAGS_NONE,
|
G_RESOURCE_LOOKUP_FLAGS_NONE,
|
||||||
@@ -227,6 +246,14 @@ test_resource_registred (void)
|
|||||||
g_assert (size == 6);
|
g_assert (size == 6);
|
||||||
g_assert (flags == 0);
|
g_assert (flags == 0);
|
||||||
|
|
||||||
|
found = g_resources_get_info ("/sv/test1.txt",
|
||||||
|
G_RESOURCE_LOOKUP_FLAGS_NONE,
|
||||||
|
&size, &flags, &error);
|
||||||
|
g_assert (found);
|
||||||
|
g_assert_no_error (error);
|
||||||
|
g_assert (size == 6);
|
||||||
|
g_assert (flags == 0);
|
||||||
|
|
||||||
data = g_resources_lookup_data ("/test1.txt",
|
data = g_resources_lookup_data ("/test1.txt",
|
||||||
G_RESOURCE_LOOKUP_FLAGS_NONE,
|
G_RESOURCE_LOOKUP_FLAGS_NONE,
|
||||||
&error);
|
&error);
|
||||||
@@ -272,6 +299,16 @@ test_resource_registred (void)
|
|||||||
g_assert_cmpstr (g_bytes_get_data (data, NULL), ==, "test2\n");
|
g_assert_cmpstr (g_bytes_get_data (data, NULL), ==, "test2\n");
|
||||||
g_bytes_unref (data);
|
g_bytes_unref (data);
|
||||||
|
|
||||||
|
data = g_resources_lookup_data ("/sv/test1.txt",
|
||||||
|
G_RESOURCE_LOOKUP_FLAGS_NONE,
|
||||||
|
&error);
|
||||||
|
g_assert (data != NULL);
|
||||||
|
g_assert_no_error (error);
|
||||||
|
size = g_bytes_get_size (data);
|
||||||
|
g_assert (size == 6);
|
||||||
|
g_assert_cmpstr (g_bytes_get_data (data, NULL), ==, "test3\n");
|
||||||
|
g_bytes_unref (data);
|
||||||
|
|
||||||
children = g_resources_enumerate_children ("/not/here",
|
children = g_resources_enumerate_children ("/not/here",
|
||||||
G_RESOURCE_LOOKUP_FLAGS_NONE,
|
G_RESOURCE_LOOKUP_FLAGS_NONE,
|
||||||
&error);
|
&error);
|
||||||
|
@@ -7,4 +7,7 @@
|
|||||||
<file alias="test2-alias.txt">test2.txt</file>
|
<file alias="test2-alias.txt">test2.txt</file>
|
||||||
<file>test2.txt</file>
|
<file>test2.txt</file>
|
||||||
</gresource>
|
</gresource>
|
||||||
|
<gresource lang="sv">
|
||||||
|
<file alias="test1.txt">test3.txt</file>
|
||||||
|
</gresource>
|
||||||
</gresources>
|
</gresources>
|
||||||
|
Reference in New Issue
Block a user