[epiphany/pgriffis/web-extension-fixes-2] WebExtensions: Fix translation support



commit 986a599027cb2f89f1e16d5585be03d798c71c97
Author: Patrick Griffis <pgriffis igalia com>
Date:   Wed May 18 13:30:18 2022 -0500

    WebExtensions: Fix translation support

 embed/ephy-embed-shell.c                           |  5 +-
 .../ephy-web-process-extension-main.c              |  3 +-
 .../ephy-web-process-extension.c                   | 60 ++++++++++++++++++----
 .../web-process-extension/ephy-webextension-api.c  | 52 ++++++++++++++-----
 .../ephy-webextension-common.c                     | 20 +++++++-
 .../ephy-webextension-common.h                     |  5 +-
 src/webextension/ephy-web-extension-manager.c      | 37 +++++++------
 src/webextension/ephy-web-extension.c              |  1 +
 8 files changed, 137 insertions(+), 46 deletions(-)
---
diff --git a/embed/ephy-embed-shell.c b/embed/ephy-embed-shell.c
index 97caf1f14..b4a904bff 100644
--- a/embed/ephy-embed-shell.c
+++ b/embed/ephy-embed-shell.c
@@ -783,12 +783,13 @@ initialize_web_process_extensions (WebKitWebContext *web_context,
 #endif
 
   private_profile = priv->mode == EPHY_EMBED_SHELL_MODE_PRIVATE || priv->mode == 
EPHY_EMBED_SHELL_MODE_INCOGNITO || priv->mode == EPHY_EMBED_SHELL_MODE_AUTOMATION;
-  user_data = g_variant_new ("(smsbbb)",
+  user_data = g_variant_new ("(smsbbbs)",
                              priv->guid,
                              ephy_profile_dir_is_default () ? NULL : ephy_profile_dir (),
                              g_settings_get_boolean (EPHY_SETTINGS_WEB, EPHY_PREFS_WEB_REMEMBER_PASSWORDS),
                              private_profile,
-                             FALSE);
+                             FALSE,
+                             "");
   webkit_web_context_set_web_extensions_initialization_user_data (web_context, g_steal_pointer (&user_data));
 }
 
diff --git a/embed/web-process-extension/ephy-web-process-extension-main.c 
b/embed/web-process-extension/ephy-web-process-extension-main.c
index 63fee6605..cfb2584ec 100644
--- a/embed/web-process-extension/ephy-web-process-extension-main.c
+++ b/embed/web-process-extension/ephy-web-process-extension-main.c
@@ -37,12 +37,13 @@ webkit_web_extension_initialize_with_user_data (WebKitWebExtension *webkit_exten
 {
   const char *guid;
   const char *profile_dir;
+  const char *webextension_translations;
   gboolean private_profile;
   gboolean should_remember_passwords;
   gboolean is_webextension;
   g_autoptr (GError) error = NULL;
 
-  g_variant_get (user_data, "(&sm&sbbb)", &guid, &profile_dir, &should_remember_passwords, &private_profile, 
&is_webextension);
+  g_variant_get (user_data, "(&sm&sbbb&s)", &guid, &profile_dir, &should_remember_passwords, 
&private_profile, &is_webextension, &webextension_translations);
 
   if (!ephy_file_helpers_init (profile_dir, 0, &error))
     g_warning ("Failed to initialize file helpers: %s", error->message);
diff --git a/embed/web-process-extension/ephy-web-process-extension.c 
b/embed/web-process-extension/ephy-web-process-extension.c
index fe216a589..f28c11cab 100644
--- a/embed/web-process-extension/ephy-web-process-extension.c
+++ b/embed/web-process-extension/ephy-web-process-extension.c
@@ -64,12 +64,6 @@ struct _EphyWebProcessExtension {
 
 G_DEFINE_TYPE (EphyWebProcessExtension, ephy_web_process_extension, G_TYPE_OBJECT)
 
-GHashTable *
-ephy_web_process_extension_get_translations (EphyWebProcessExtension *extension)
-{
-  return extension->translation_table;
-}
-
 static void
 web_page_will_submit_form (WebKitWebPage            *web_page,
                            WebKitDOMHTMLFormElement *dom_form,
@@ -233,10 +227,15 @@ content_script_window_object_cleared_cb (WebKitScriptWorld *world,
                                          WebKitFrame       *frame,
                                          gpointer           user_data)
 {
+  EphyWebProcessExtension *extension = user_data;
   g_autoptr (JSCContext) js_context = NULL;
+  JsonObject *translations;
+  const char *guid;
 
+  guid = webkit_script_world_get_name (world);
   js_context = webkit_frame_get_js_context_for_script_world (frame, world);
-  ephy_webextension_install_common_apis (js_context, webkit_script_world_get_name (world));
+  translations = g_hash_table_lookup (extension->translation_table, guid);
+  ephy_webextension_install_common_apis (js_context, guid, translations);
 }
 
 static void
@@ -250,7 +249,7 @@ create_content_script_world (EphyWebProcessExtension *extension,
   g_signal_connect (world,
                     "window-object-cleared",
                     G_CALLBACK (content_script_window_object_cleared_cb),
-                    NULL);
+                    extension);
 }
 
 static gboolean
@@ -299,6 +298,34 @@ ephy_web_process_extension_page_created_cb (EphyWebProcessExtension *extension,
                     extension);
 }
 
+static void
+ephy_web_process_extension_add_translations (GHashTable *translation_table,
+                                             const char *guid,
+                                             const char *data)
+{
+  g_autoptr (JsonParser) parser = NULL;
+  JsonNode *root;
+  JsonObject *root_object;
+  g_autoptr (GError) error = NULL;
+
+  g_hash_table_remove (translation_table, guid);
+
+  if (!data || !*data)
+    return;
+
+  parser = json_parser_new ();
+  if (json_parser_load_from_data (parser, data, -1, &error)) {
+    root = json_parser_get_root (parser);
+    g_assert (root);
+    root_object = json_node_get_object (root);
+    g_assert (root_object);
+
+    g_hash_table_insert (translation_table, g_strdup (guid), json_object_ref (root_object));
+  } else {
+    g_warning ("Could not read translation json data: %s. '%s'", error->message, data);
+  }
+}
+
 static void
 ephy_web_process_extension_user_message_received_cb (EphyWebProcessExtension *extension,
                                                      WebKitUserMessage       *message)
@@ -387,8 +414,18 @@ ephy_web_process_extension_user_message_received_cb (EphyWebProcessExtension *ex
       return;
 
     g_variant_get (parameters, "b", &extension->should_remember_passwords);
-  } else {
-    g_warning ("Unhandled user-message: %s", name);
+  } else if (g_strcmp0 (name, "WebExtension.UpdateTranslations") == 0) {
+    GVariant *parameters;
+    const char *guid;
+    const char *data;
+    guint64 length;
+
+    parameters = webkit_user_message_get_parameters (message);
+    if (!parameters)
+      return;
+
+    g_variant_get (parameters, "(&s&s)", &guid, &data);
+    ephy_web_process_extension_add_translations (extension->translation_table, guid, data);
   }
 }
 
@@ -867,7 +904,8 @@ ephy_web_process_extension_initialize (EphyWebProcessExtension *extension,
   extension->frames_map = g_hash_table_new_full (g_int64_hash, g_int64_equal,
                                                  g_free, NULL);
 
-  extension->translation_table = g_hash_table_new (g_str_hash, NULL);
+  extension->translation_table = g_hash_table_new_full (g_str_hash, g_str_equal,
+                                                        g_free, (GDestroyNotify)json_object_unref);
 
   extension->content_script_worlds = g_hash_table_new_full (g_str_hash, g_str_equal,
                                                             g_free, g_object_unref);
diff --git a/embed/web-process-extension/ephy-webextension-api.c 
b/embed/web-process-extension/ephy-webextension-api.c
index 9499899f6..02302abc6 100644
--- a/embed/web-process-extension/ephy-webextension-api.c
+++ b/embed/web-process-extension/ephy-webextension-api.c
@@ -35,7 +35,7 @@ struct _EphyWebExtensionExtension {
 
   WebKitScriptWorld *script_world;
 
-  GHashTable *translation_table;
+  JsonObject *translations;
   int counter;
 };
 
@@ -43,12 +43,6 @@ G_DEFINE_TYPE (EphyWebExtensionExtension, ephy_web_extension_extension, G_TYPE_O
 
 static EphyWebExtensionExtension *extension = NULL;
 
-static GHashTable *
-ephy_web_extension_extension_get_translations (EphyWebExtensionExtension *extension)
-{
-  return extension->translation_table;
-}
-
 static void
 ephy_web_extension_page_user_message_received_cb (WebKitWebPage     *page,
                                                   WebKitUserMessage *message)
@@ -114,7 +108,7 @@ ephy_web_extension_dispose (GObject *object)
   g_clear_object (&extension->extension);
   g_clear_pointer (&extension->guid, g_free);
 
-  g_clear_pointer (&extension->translation_table, g_hash_table_destroy);
+  g_clear_pointer (&extension->translations, json_object_unref);
 
   G_OBJECT_CLASS (ephy_web_extension_extension_parent_class)->dispose (object);
 }
@@ -163,7 +157,7 @@ window_object_cleared_cb (WebKitScriptWorld         *world,
 
   js_context = webkit_frame_get_js_context_for_script_world (frame, world);
 
-  ephy_webextension_install_common_apis (js_context, extension->guid);
+  ephy_webextension_install_common_apis (js_context, extension->guid, extension->translations);
 
   js_browser = jsc_context_get_value (js_context, "browser");
   g_assert (jsc_value_is_object (js_browser));
@@ -174,10 +168,38 @@ window_object_cleared_cb (WebKitScriptWorld         *world,
   g_clear_object (&result);
 }
 
+static void
+ephy_web_extension_extension_update_translations (EphyWebExtensionExtension *extension,
+                                                  const char                *data)
+{
+  g_autoptr (JsonParser) parser = NULL;
+  JsonNode *root;
+  JsonObject *root_object;
+  g_autoptr (GError) error = NULL;
+
+  g_clear_pointer (&extension->translations, json_object_unref);
+
+  if (!data || !*data)
+    return;
+
+  parser = json_parser_new ();
+  if (json_parser_load_from_data (parser, data, -1, &error)) {
+    root = json_parser_get_root (parser);
+    g_assert (root);
+    root_object = json_node_get_object (root);
+    g_assert (root_object);
+
+    extension->translations = json_object_ref (root_object);
+  } else {
+    g_warning ("Could not read translation json data: %s. '%s'", error->message, data);
+  }
+}
+
 void
 ephy_web_extension_extension_initialize (EphyWebExtensionExtension *extension,
                                          WebKitWebExtension        *wk_extension,
-                                         const char                *guid)
+                                         const char                *guid,
+                                         const char                *translations)
 {
   g_assert (EPHY_IS_WEB_EXTENSION_EXTENSION (extension));
 
@@ -197,11 +219,11 @@ ephy_web_extension_extension_initialize (EphyWebExtensionExtension *extension,
 
   extension->extension = g_object_ref (wk_extension);
 
+  ephy_web_extension_extension_update_translations (extension, translations);
+
   g_signal_connect_swapped (extension->extension, "page-created",
                             G_CALLBACK (ephy_web_extension_extension_page_created_cb),
                             extension);
-
-  extension->translation_table = g_hash_table_new (g_str_hash, NULL);
 }
 
 G_MODULE_EXPORT void
@@ -210,11 +232,12 @@ webkit_web_extension_initialize_with_user_data (WebKitWebExtension *webkit_exten
 {
   const char *guid;
   const char *profile_dir;
+  const char *webextension_translations;
   gboolean private_profile;
   gboolean should_remember_passwords;
   gboolean is_webextension;
 
-  g_variant_get (user_data, "(&sm&sbbb)", &guid, &profile_dir, &should_remember_passwords, &private_profile, 
&is_webextension);
+  g_variant_get (user_data, "(&sm&sbbb&s)", &guid, &profile_dir, &should_remember_passwords, 
&private_profile, &is_webextension, &webextension_translations);
 
   if (!is_webextension)
     return;
@@ -223,7 +246,8 @@ webkit_web_extension_initialize_with_user_data (WebKitWebExtension *webkit_exten
 
   ephy_web_extension_extension_initialize (extension,
                                            webkit_extension,
-                                           guid);
+                                           guid,
+                                           webextension_translations);
 }
 
 static void __attribute__((destructor))
diff --git a/embed/web-process-extension/ephy-webextension-common.c 
b/embed/web-process-extension/ephy-webextension-common.c
index 0854641bb..ce341c16e 100644
--- a/embed/web-process-extension/ephy-webextension-common.c
+++ b/embed/web-process-extension/ephy-webextension-common.c
@@ -26,6 +26,19 @@ static char *
 js_getmessage (const char *message,
                gpointer    user_data)
 {
+  JsonObject *translations = user_data;
+  g_autoptr (JsonObject) translation = NULL;
+
+  if (!translations)
+    return g_strdup (message);
+
+  translation = json_object_get_object_member (translations, message);
+  if (translation) {
+    /* FIXME: Implement placeholders: 
https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Internationalization */
+    const char *translated_message = json_object_get_string_member (translation, "message");
+    return g_strdup (translated_message);
+  }
+
   return g_strdup (message);
 }
 
@@ -71,7 +84,8 @@ js_exception_handler (JSCContext   *context,
 
 void
 ephy_webextension_install_common_apis (JSCContext *js_context,
-                                       const char *guid)
+                                       const char *guid,
+                                       JsonObject *translations)
 {
   g_autoptr (JSCValue) result = NULL;
   g_autoptr (JSCValue) js_browser = NULL;
@@ -103,7 +117,9 @@ ephy_webextension_install_common_apis (JSCContext *js_context,
 
   js_function = jsc_value_new_function (js_context,
                                         "getMessage",
-                                        G_CALLBACK (js_getmessage), NULL, NULL,
+                                        G_CALLBACK (js_getmessage),
+                                        translations ? json_object_ref (translations) : NULL,
+                                        translations ? (GDestroyNotify)json_object_unref : NULL,
                                         G_TYPE_STRING, 1,
                                         G_TYPE_STRING);
   jsc_value_object_set_property (js_i18n, "getMessage", js_function);
diff --git a/embed/web-process-extension/ephy-webextension-common.h 
b/embed/web-process-extension/ephy-webextension-common.h
index d16cebab6..a37d0605f 100644
--- a/embed/web-process-extension/ephy-webextension-common.h
+++ b/embed/web-process-extension/ephy-webextension-common.h
@@ -22,9 +22,12 @@
 
 #include <glib-object.h>
 #include <jsc/jsc.h>
+#include <json-glib/json-glib.h>
 
 G_BEGIN_DECLS
 
-void ephy_webextension_install_common_apis (JSCContext *js_context, const char *guid);
+void ephy_webextension_install_common_apis (JSCContext *js_context,
+                                            const char *guid,
+                                            JsonObject *translations);
 
 G_END_DECLS
diff --git a/src/webextension/ephy-web-extension-manager.c b/src/webextension/ephy-web-extension-manager.c
index 3c859b37f..b7c9156e9 100644
--- a/src/webextension/ephy-web-extension-manager.c
+++ b/src/webextension/ephy-web-extension-manager.c
@@ -509,21 +509,24 @@ remove_custom_css (EphyWebExtension *self,
     webkit_user_content_manager_remove_style_sheet (WEBKIT_USER_CONTENT_MANAGER (ucm), 
ephy_web_extension_custom_css_style (self, list->data));
 }
 
-static void
-update_translations (EphyWebExtension *web_extension)
+static char *
+get_translation_contents (EphyWebExtension *web_extension)
 {
-  /* TODO: Use current locale and fallback to default web_extension locale if necessary */
+  /* FIXME: Use current locale and fallback to default web_extension locale if necessary. */
   g_autofree char *path = g_strdup_printf ("_locales/%s/messages.json", "en");
-  g_autofree char *data = NULL;
-  gint length = 0;
+  g_autofree char *data = ephy_web_extension_get_resource_as_string (web_extension, path);
+
+  return data ? g_steal_pointer (&data) : g_strdup ("");
+}
 
-  data = ephy_web_extension_get_resource_as_string (web_extension, path);
-  if (data)
-    length = strlen (data);
+static void
+update_translations (EphyWebExtension *web_extension)
+{
+  g_autofree char *data = get_translation_contents (web_extension);
 
-  webkit_web_context_send_message_to_all_extensions (ephy_embed_shell_get_web_context 
(ephy_embed_shell_get_default ()),
-                                                     webkit_user_message_new ("WebExtension.Add",
-                                                                              g_variant_new ("(sst)", 
ephy_web_extension_get_name (web_extension), data ? (char *)data : "", length)));
+  webkit_web_context_send_message_to_all_extensions ( ephy_embed_shell_get_web_context 
(ephy_embed_shell_get_default ()),
+                                                     webkit_user_message_new 
("WebExtension.UpdateTranslations",
+                                                                              g_variant_new ("(ss)", 
ephy_web_extension_get_guid (web_extension), data)));
 }
 
 static void
@@ -589,6 +592,10 @@ web_extension_cb (WebKitURISchemeRequest *request,
 
   path = webkit_uri_scheme_request_get_path (request);
 
+  /* FIXME: This may be the place to handle predefined messages and localized CSS:
+   * 
https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Internationalization#predefined_messages
+   */
+
   data = ephy_web_extension_get_resource (web_extension, path + 1, &length);
   if (!data) {
     error = g_error_new (G_IO_ERROR, G_IO_ERROR_FAILED, "Resource not found: %s", path);
@@ -605,6 +612,7 @@ init_web_extension_api (WebKitWebContext *web_context,
                         EphyWebExtension *web_extension)
 {
   g_autoptr (GVariant) user_data = NULL;
+  g_autofree char *translations = get_translation_contents (web_extension);
 
 #if DEVELOPER_MODE
   webkit_web_context_set_web_extensions_directory (web_context, BUILD_ROOT "/embed/web-process-extension");
@@ -612,12 +620,13 @@ init_web_extension_api (WebKitWebContext *web_context,
   webkit_web_context_set_web_extensions_directory (web_context, EPHY_WEB_PROCESS_EXTENSIONS_DIR);
 #endif
 
-  user_data = g_variant_new ("(smsbbb)",
+  user_data = g_variant_new ("(smsbbbs)",
                              ephy_web_extension_get_guid (web_extension),
                              ephy_profile_dir_is_default () ? NULL : ephy_profile_dir (),
                              FALSE,
                              FALSE,
-                             TRUE);
+                             TRUE,
+                             translations);
   webkit_web_context_set_web_extensions_initialization_user_data (web_context, g_steal_pointer (&user_data));
 }
 
@@ -650,8 +659,6 @@ create_web_extensions_webview (EphyWebExtension *web_extension)
   settings = webkit_web_view_get_settings (WEBKIT_WEB_VIEW (web_view));
   webkit_settings_set_enable_write_console_messages_to_stdout (settings, TRUE);
 
-  update_translations (web_extension);
-
   return web_view;
 }
 
diff --git a/src/webextension/ephy-web-extension.c b/src/webextension/ephy-web-extension.c
index 878de29b9..1d9d75945 100644
--- a/src/webextension/ephy-web-extension.c
+++ b/src/webextension/ephy-web-extension.c
@@ -915,6 +915,7 @@ ephy_web_extension_load (GFile *target)
     return NULL;
   }
 
+  /* FIXME: Implement i18n: 
https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Internationalization#retrieving_localized_strings_in_manifests
 */
   self->manifest = g_strndup ((char *)manifest, length);
   self->base_location = parent ? g_file_get_path (parent) : g_file_get_path (target);
   self->description = ephy_web_extension_manifest_get_key (self, root_object, "description");


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