Browse Source

fix: proper localization when using GtkFileChooserNative (#30888)

* fix: proper localization when using GtkFileChooserNative

* fix: iwyu
Shelley Vohr 3 years ago
parent
commit
38b810b2e3

+ 15 - 13
shell/browser/ui/file_dialog_gtk.cc

@@ -5,6 +5,7 @@
 #include <gmodule.h>
 
 #include <memory>
+#include <string>
 
 #include "base/callback.h"
 #include "base/files/file_util.h"
@@ -131,24 +132,25 @@ class FileChooserDialog {
       : parent_(
             static_cast<electron::NativeWindowViews*>(settings.parent_window)),
         filters_(settings.filters) {
-    const char* confirm_text = gtk_util::kOkLabel;
-
-    if (!settings.button_label.empty())
-      confirm_text = settings.button_label.c_str();
-    else if (action == GTK_FILE_CHOOSER_ACTION_SAVE)
-      confirm_text = gtk_util::kSaveLabel;
-    else if (action == GTK_FILE_CHOOSER_ACTION_OPEN)
-      confirm_text = gtk_util::kOpenLabel;
-
     InitGtkFileChooserNativeSupport();
 
+    auto label = settings.button_label;
+
     if (*supports_gtk_file_chooser_native) {
-      dialog_ = GTK_FILE_CHOOSER(
-          dl_gtk_file_chooser_native_new(settings.title.c_str(), NULL, action,
-                                         confirm_text, gtk_util::kCancelLabel));
+      dialog_ = GTK_FILE_CHOOSER(dl_gtk_file_chooser_native_new(
+          settings.title.c_str(), NULL, action,
+          label.empty() ? nullptr : label.c_str(), nullptr));
     } else {
+      const char* confirm_text = gtk_util::GetOkLabel();
+      if (!label.empty())
+        confirm_text = label.c_str();
+      else if (action == GTK_FILE_CHOOSER_ACTION_SAVE)
+        confirm_text = gtk_util::GetSaveLabel();
+      else if (action == GTK_FILE_CHOOSER_ACTION_OPEN)
+        confirm_text = gtk_util::GetOpenLabel();
+
       dialog_ = GTK_FILE_CHOOSER(gtk_file_chooser_dialog_new(
-          settings.title.c_str(), NULL, action, gtk_util::kCancelLabel,
+          settings.title.c_str(), NULL, action, gtk_util::GetCancelLabel(),
           GTK_RESPONSE_CANCEL, confirm_text, GTK_RESPONSE_ACCEPT, NULL));
     }
 

+ 59 - 24
shell/browser/ui/gtk_util.cc

@@ -8,36 +8,71 @@
 #include <gtk/gtk.h>
 #include <stdint.h>
 
+#include <string>
+
+#include "base/no_destructor.h"
+#include "base/strings/string_number_conversions.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "third_party/skia/include/core/SkUnPreMultiply.h"
+#include "ui/gtk/gtk_compat.h"  // nogncheck
 
 namespace gtk_util {
 
-// Copied from L40-L55 in
-// https://cs.chromium.org/chromium/src/chrome/browser/ui/libgtkui/select_file_dialog_impl_gtk.cc
-#if GTK_CHECK_VERSION(3, 90, 0)
-// GTK stock items have been deprecated.  The docs say to switch to using the
-// strings "_Open", etc.  However this breaks i18n.  We could supply our own
-// internationalized strings, but the "_" in these strings is significant: it's
-// the keyboard shortcut to select these actions.  TODO: Provide
-// internationalized strings when GTK provides support for it.
-const char* const kCancelLabel = "_Cancel";
-const char* const kNoLabel = "_No";
-const char* const kOkLabel = "_OK";
-const char* const kOpenLabel = "_Open";
-const char* const kSaveLabel = "_Save";
-const char* const kYesLabel = "_Yes";
-#else
-G_GNUC_BEGIN_IGNORE_DEPRECATIONS
-const char* const kCancelLabel = GTK_STOCK_CANCEL;
-const char* const kNoLabel = GTK_STOCK_NO;
-const char* const kOkLabel = GTK_STOCK_OK;
-const char* const kOpenLabel = GTK_STOCK_OPEN;
-const char* const kSaveLabel = GTK_STOCK_SAVE;
-const char* const kYesLabel = GTK_STOCK_YES;
-G_GNUC_END_IGNORE_DEPRECATIONS
-#endif
+// The following utilities are pulled from
+// https://source.chromium.org/chromium/chromium/src/+/main:ui/gtk/select_file_dialog_impl_gtk.cc;l=43-74
+
+const char* GettextPackage() {
+  static base::NoDestructor<std::string> gettext_package(
+      "gtk" + base::NumberToString(gtk::GtkVersion().components()[0]) + "0");
+  return gettext_package->c_str();
+}
+
+const char* GtkGettext(const char* str) {
+  return g_dgettext(GettextPackage(), str);
+}
+
+const char* GetCancelLabel() {
+  if (!gtk::GtkCheckVersion(4))
+    return "gtk-cancel";  // In GTK3, this is GTK_STOCK_CANCEL.
+  static const char* cancel = GtkGettext("_Cancel");
+  return cancel;
+}
+
+const char* GetOpenLabel() {
+  if (!gtk::GtkCheckVersion(4))
+    return "gtk-open";  // In GTK3, this is GTK_STOCK_OPEN.
+  static const char* open = GtkGettext("_Open");
+  return open;
+}
+
+const char* GetSaveLabel() {
+  if (!gtk::GtkCheckVersion(4))
+    return "gtk-save";  // In GTK3, this is GTK_STOCK_SAVE.
+  static const char* save = GtkGettext("_Save");
+  return save;
+}
+
+const char* GetOkLabel() {
+  if (!gtk::GtkCheckVersion(4))
+    return "gtk-ok";  // In GTK3, this is GTK_STOCK_OK.
+  static const char* ok = GtkGettext("_Ok");
+  return ok;
+}
+
+const char* GetNoLabel() {
+  if (!gtk::GtkCheckVersion(4))
+    return "gtk-no";  // In GTK3, this is GTK_STOCK_NO.
+  static const char* no = GtkGettext("_No");
+  return no;
+}
+
+const char* GetYesLabel() {
+  if (!gtk::GtkCheckVersion(4))
+    return "gtk-yes";  // In GTK3, this is GTK_STOCK_YES.
+  static const char* yes = GtkGettext("_Yes");
+  return yes;
+}
 
 GdkPixbuf* GdkPixbufFromSkBitmap(const SkBitmap& bitmap) {
   if (bitmap.isNull())

+ 9 - 8
shell/browser/ui/gtk_util.h

@@ -11,14 +11,15 @@ class SkBitmap;
 
 namespace gtk_util {
 
-/* These are `const char*` rather than the project-preferred `const char[]`
-   because they must fit the type of an external dependency */
-extern const char* const kCancelLabel;
-extern const char* const kNoLabel;
-extern const char* const kOkLabel;
-extern const char* const kOpenLabel;
-extern const char* const kSaveLabel;
-extern const char* const kYesLabel;
+const char* GettextPackage();
+const char* GtkGettext(const char* str);
+
+const char* GetCancelLabel();
+const char* GetOpenLabel();
+const char* GetSaveLabel();
+const char* GetOkLabel();
+const char* GetNoLabel();
+const char* GetYesLabel();
 
 // Convert and copy a SkBitmap to a GdkPixbuf. NOTE: this uses BGRAToRGBA, so
 // it is an expensive operation.  The returned GdkPixbuf will have a refcount of

+ 4 - 4
shell/browser/ui/message_box_gtk.cc

@@ -145,13 +145,13 @@ class GtkMessageBox : public NativeWindowObserver {
   const char* TranslateToStock(int id, const std::string& text) {
     const std::string lower = base::ToLowerASCII(text);
     if (lower == "cancel")
-      return gtk_util::kCancelLabel;
+      return gtk_util::GetCancelLabel();
     if (lower == "no")
-      return gtk_util::kNoLabel;
+      return gtk_util::GetNoLabel();
     if (lower == "ok")
-      return gtk_util::kOkLabel;
+      return gtk_util::GetOkLabel();
     if (lower == "yes")
-      return gtk_util::kYesLabel;
+      return gtk_util::GetYesLabel();
     return text.c_str();
   }