From f410e43a1460216330443a13aad60573f4c26ed6 Mon Sep 17 00:00:00 2001 From: "trop[bot]" <37223003+trop[bot]@users.noreply.github.com> Date: Thu, 23 Sep 2021 16:35:58 +0900 Subject: [PATCH] fix: proper localization when using GtkFileChooserNative (#31065) * fix: proper localization when using GtkFileChooserNative * fix: iwyu Co-authored-by: Shelley Vohr --- shell/browser/ui/file_dialog_gtk.cc | 28 +++++----- shell/browser/ui/gtk_util.cc | 83 ++++++++++++++++++++--------- shell/browser/ui/gtk_util.h | 17 +++--- shell/browser/ui/message_box_gtk.cc | 8 +-- 4 files changed, 87 insertions(+), 49 deletions(-) diff --git a/shell/browser/ui/file_dialog_gtk.cc b/shell/browser/ui/file_dialog_gtk.cc index 2456fcd7d1479..90b87db16c375 100644 --- a/shell/browser/ui/file_dialog_gtk.cc +++ b/shell/browser/ui/file_dialog_gtk.cc @@ -5,6 +5,7 @@ #include #include +#include #include "base/callback.h" #include "base/files/file_util.h" @@ -131,24 +132,25 @@ class FileChooserDialog { : parent_( static_cast(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)); } diff --git a/shell/browser/ui/gtk_util.cc b/shell/browser/ui/gtk_util.cc index 3bed1a8edafa8..ba6d6472a37bf 100644 --- a/shell/browser/ui/gtk_util.cc +++ b/shell/browser/ui/gtk_util.cc @@ -8,36 +8,71 @@ #include #include +#include + +#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 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()) diff --git a/shell/browser/ui/gtk_util.h b/shell/browser/ui/gtk_util.h index db9dc9cc36d1d..5d77ec668aab8 100644 --- a/shell/browser/ui/gtk_util.h +++ b/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 diff --git a/shell/browser/ui/message_box_gtk.cc b/shell/browser/ui/message_box_gtk.cc index b1290a6a5783f..2327262512c3e 100644 --- a/shell/browser/ui/message_box_gtk.cc +++ b/shell/browser/ui/message_box_gtk.cc @@ -132,13 +132,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(); }