Allow translation messages to be compiled in as GTK resources

This commit is contained in:
Vincent Sanders 2015-06-21 23:24:31 +01:00
parent 67ded2a02a
commit a94ae7a80a
6 changed files with 193 additions and 32 deletions

View File

@ -69,6 +69,17 @@ $(eval $(call pkg_config_find_and_add,gmodule-2.0,GModule2))
CFLAGS += $(GTKCFLAGS)
LDFLAGS += -lm
# ---------------------------------------------------------------------------
# Target setup
# ---------------------------------------------------------------------------
# The gtk binary target
EXETARGET := nsgtk
# The filter and target for split messages
MESSAGES_FILTER=gtk
MESSAGES_TARGET=gtk/res
# ---------------------------------------------------------------------------
# Windows flag setup
# ---------------------------------------------------------------------------
@ -84,6 +95,9 @@ endif
# builtin resource sources
S_RESOURCE :=
# Path to GTK resources
NSGTK_RESOURCES_DIR := gtk/res
# Glib prior to 2.32 does not have GResource handling.
#
# This uses pkg-config to check for the minimum required version for
@ -106,16 +120,24 @@ NETSURF_FEATURE_GRESOURCE_ENABLED := yes
GLIB_COMPILE_RESOURCES := glib-compile-resources
CFLAGS += -DWITH_GRESOURCE
S_RESOURCE += $(OBJROOT)/netsurf_gresource.c
NETSURF_GRESOURCE_XML := $(NSGTK_RESOURCES_DIR)/netsurf.gresource.xml
MESSAGES_GRESOURCE_XML := $(NSGTK_RESOURCES_DIR)/messages.gresource.xml
NSGTK_RESOURCES_DIR := gtk/res
GRESOURCE_XML := $(NSGTK_RESOURCES_DIR)/netsurf.gresource.xml
# generate the gresource source file
$(OBJROOT)/netsurf_gresource.c: $(GRESOURCE_XML) $(shell $(GLIB_COMPILE_RESOURCES) --sourcedir $(NSGTK_RESOURCES_DIR) --generate-dependencies $(GRESOURCE_XML))
# generate the netsurf gresource source files
$(OBJROOT)/netsurf_gresource.c: $(NETSURF_GRESOURCE_XML) $(shell $(GLIB_COMPILE_RESOURCES) --sourcedir $(NSGTK_RESOURCES_DIR) --generate-dependencies $(NETSURF_GRESOURCE_XML))
$(VQ)echo "GRESORCE: $<"
$(Q)$(GLIB_COMPILE_RESOURCES) --generate-source --sourcedir $(NSGTK_RESOURCES_DIR) --target=$@ $<
S_RESOURCE += $(OBJROOT)/netsurf_gresource.c
# generate the messages gresource source file
$(OBJROOT)/messages_gresource.c: $(MESSAGES_GRESOURCE_XML) $(addsuffix /Messages,$(addprefix $(MESSAGES_TARGET)/,$(MESSAGES_LANGUAGES)))
$(VQ)echo "GRESORCE: $<"
$(Q)$(GLIB_COMPILE_RESOURCES) --generate-source --sourcedir $(NSGTK_RESOURCES_DIR) --target=$@ $<
S_RESOURCE += $(OBJROOT)/messages_gresource.c
endif
endif
@ -125,7 +147,9 @@ ifneq ($(NETSURF_FEATURE_GRESOURCE_ENABLED),yes)
CFLAGS += -DWITH_BUILTIN_PIXBUF
GTK_IMAGE_menu_cursor := gtk/res/menu_cursor.png
GTK_IMAGE_favicon := favicon.png
GTK_IMAGE_netsurf := netsurf.xpm
GTK_IMAGE_menu_cursor := menu_cursor.png
# 1: input file
# 2: output file
@ -143,7 +167,7 @@ $(2): $(1)
endef
$(eval $(foreach V,$(filter GTK_IMAGE_%,$(.VARIABLES)),$(call convert_image,$($(V)),$(OBJROOT)/$(patsubst GTK_IMAGE_%,%,$(V)).c,$(patsubst GTK_IMAGE_%,%,$(V))_pixdata)))
$(eval $(foreach V,$(filter GTK_IMAGE_%,$(.VARIABLES)),$(call convert_image,$(addprefix $(NSGTK_RESOURCES_DIR)/,$($(V))),$(OBJROOT)/$(patsubst GTK_IMAGE_%,%,$(V)).c,$(patsubst GTK_IMAGE_%,%,$(V))_pixdata)))
endif
endif
@ -167,13 +191,6 @@ S_GTK := $(addprefix gtk/,$(S_GTK)) $(addprefix utils/,container.c)
# are not yet available
SOURCES = $(S_COMMON) $(S_IMAGE) $(S_BROWSER) $(S_RESOURCE) $(S_GTK)
# The gtk binary target
EXETARGET := nsgtk
# The filter and target for split messages
MESSAGES_FILTER=gtk
MESSAGES_TARGET=gtk/res
# ----------------------------------------------------------------------------
# Install target
# ----------------------------------------------------------------------------

View File

@ -1047,13 +1047,22 @@ static struct gui_browser_table nsgtk_browser_table = {
static nserror nsgtk_messages_init(char **respaths)
{
char *messages;
nserror ret = NSERROR_NOT_FOUND;
nserror ret;
const uint8_t *data;
size_t data_size;
/* Obtain path to messages */
messages = filepath_find(respaths, "Messages");
if (messages != NULL) {
ret = messages_add_from_file(messages);
free(messages);
ret = nsgtk_data_from_resname("Messages", &data, &data_size);
if (ret == NSERROR_OK) {
ret = messages_add_from_inline(data, data_size);
} else {
/* Obtain path to messages */
messages = filepath_find(respaths, "Messages");
if (messages != NULL) {
ret = messages_add_from_file(messages);
free(messages);
} else {
ret = NSERROR_NOT_FOUND;
}
}
return ret;
}

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/org/netsurf">
<file>Messages</file>
<file>nl/Messages</file>
<file>de/Messages</file>
<file>fr/Messages</file>
<file>it/Messages</file>
</gresource>
</gresources>

View File

@ -45,8 +45,12 @@
#ifdef WITH_BUILTIN_PIXBUF
#ifdef __GNUC__
extern const guint8 menu_cursor_pixdata[] __attribute__ ((__aligned__ (4)));
const guint8 favicon_pixdata[] __attribute__ ((__aligned__ (4)));
const guint8 netsurf_pixdata[] __attribute__ ((__aligned__ (4)));
#else
extern const guint8 menu_cursor_pixdata[];
const guint8 favicon_pixdata[];
const guint8 netsurf_pixdata[];
#endif
#endif
@ -119,6 +123,7 @@ static struct nsgtk_resource_s direct_resource[] = {
RES_ENTRY("icons/hotlist-add.png"),
RES_ENTRY("icons/hotlist-rmv.png"),
RES_ENTRY("icons/search.png"),
RES_ENTRY("Messages"),
{ NULL, 0, NSGTK_RESOURCE_FILE, NULL },
};
@ -129,9 +134,8 @@ GdkCursor *nsgtk_create_menu_cursor(void)
GdkCursor *cursor = NULL;
GdkPixbuf *pixbuf;
nserror res;
const char *resname = "menu_cursor.png";
res = nsgdk_pixbuf_new_from_resname(resname, &pixbuf);
res = nsgdk_pixbuf_new_from_resname("menu_cursor.png", &pixbuf);
if (res == NSERROR_OK) {
cursor = gdk_cursor_new_from_pixbuf(gdk_display_get_default(),
pixbuf, 0, 3);
@ -284,6 +288,20 @@ init_pixbuf_resource(char **respath, struct nsgtk_resource_s *resource)
LOG("Found builtin for %s", resource->name);
return NSERROR_OK;
}
if (strncmp(resource->name, "netsurf.xpm", resource->len) == 0) {
resource->path = (char *)&netsurf_pixdata[0];
resource->type = NSGTK_RESOURCE_INLINE;
LOG("Found builtin for %s", resource->name);
return NSERROR_OK;
}
if (strncmp(resource->name, "favicon.png", resource->len) == 0) {
resource->path = (char *)&favicon_pixdata[0];
resource->type = NSGTK_RESOURCE_INLINE;
LOG("Found builtin for %s", resource->name);
return NSERROR_OK;
}
#endif
return init_resource(respath, resource);
}

View File

@ -44,6 +44,41 @@
/** The hash table used to store the standard Messages file for the old API */
static struct hash_table *messages_hash = NULL;
/**
* process a line of input.
*/
static nserror
message_process_line(struct hash_table *hash, uint8_t *ln, int lnlen)
{
uint8_t *value;
uint8_t *colon;
/* empty or comment lines */
if (ln[0] == 0 || ln[0] == '#') {
return NSERROR_OK;
}
/* find first colon as key/value separator */
for (colon = ln; colon < (ln + lnlen); colon++) {
if (*colon == ':') {
break;
}
}
if (colon == (ln + lnlen)) {
/* no colon found */
return NSERROR_INVALID;
}
*colon = 0; /* terminate key */
value = colon + 1;
if (hash_add(hash, (char *)ln, (char *)value) == false) {
LOG("Unable to add %s:%s to hash table", ln, value);
return NSERROR_INVALID;
}
return NSERROR_OK;
}
/**
* Read keys and values from messages file.
*
@ -147,19 +182,89 @@ nserror messages_add_from_file(const char *path)
nserror err;
if (path == NULL) {
err = NSERROR_BAD_PARAMETER;
} else {
LOG("Loading Messages from '%s'", path);
err = messages_load_ctx(path, &messages_hash);
return NSERROR_BAD_PARAMETER;
}
LOG("Loading Messages from '%s'", path);
err = messages_load_ctx(path, &messages_hash);
return err;
}
/* exported interface documented in messages.h */
nserror messages_add_from_inline(const char *data)
nserror messages_add_from_inline(const uint8_t *data, size_t data_size)
{
z_stream strm;
int ret;
uint8_t s[512]; /* line buffer */
size_t used = 0; /* number of bytes in buffer in use */
uint8_t *nl;
/* ensure the hash table is initialised */
if (messages_hash == NULL) {
messages_hash = hash_create(HASH_SIZE);
}
if (messages_hash == NULL) {
LOG("Unable to create hash table");
return NSERROR_NOMEM;
}
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
strm.next_in = (uint8_t *)data;
strm.avail_in = data_size;
ret = inflateInit2(&strm, 32 + MAX_WBITS);
if (ret != Z_OK) {
LOG("inflateInit returned %d", ret);
return NSERROR_INVALID;
}
do {
strm.next_out = s + used;
strm.avail_out = sizeof(s) - used;
ret = inflate(&strm, Z_NO_FLUSH);
if ((ret != Z_OK) && (ret != Z_STREAM_END)) {
break;
}
used = sizeof(s) - strm.avail_out;
while (used > 0) {
/* find nl */
for (nl = &s[0]; nl < &s[used]; nl++) {
if (*nl == '\n') {
break;
}
}
if (nl == &s[used]) {
/* no nl found */
break;
}
/* found newline */
*nl = 0; /* null terminate line */
message_process_line(messages_hash, &s[0], nl - &s[0]);
memmove(&s[0], nl + 1, used - ((nl + 1) - &s[0]) );
used -= ((nl +1) - &s[0]);
}
if (used == sizeof(s)) {
/* entire buffer used and no newline */
LOG("Overlength line");
used = 0;
}
} while (ret != Z_STREAM_END);
inflateEnd(&strm);
if (ret != Z_STREAM_END) {
LOG("inflate returned %d", ret);
return NSERROR_INVALID;
}
return NSERROR_OK;
}
@ -181,7 +286,7 @@ char *messages_get_buff(const char *key, ...)
if (buff == NULL) {
LOG("malloc failed");
warn_user("NoMemory", 0);
warn_user("NoMemory", 0);
} else {
va_start(ap, key);
vsnprintf(buff, buff_len + 1, msg_fmt, ap);
@ -268,7 +373,7 @@ const char *messages_get_errorcode(nserror code)
return messages_get_ctx("ParsingFail", messages_hash);
case NSERROR_CSS:
/* CSS call returned error */
/* CSS call returned error */
return messages_get_ctx("CSSGeneric", messages_hash);
case NSERROR_CSS_BASE:

View File

@ -33,6 +33,8 @@
#ifndef _NETSURF_UTILS_MESSAGES_H_
#define _NETSURF_UTILS_MESSAGES_H_
#include <stdint.h>
#include "utils/errors.h"
/**
@ -57,7 +59,7 @@ nserror messages_add_from_file(const char *path);
* \param data The inline message data.
* \return NSERROR_OK on success or error code on faliure.
*/
nserror messages_add_from_inline(const char *data);
nserror messages_add_from_inline(const uint8_t *data, size_t data_size);
/**
* Fast lookup of a message by key from the standard Messages hash.