From 78d7de6c42b9c33fd077939f7139a3574c4fd529 Mon Sep 17 00:00:00 2001 From: Sorah Fukumori Date: Thu, 23 Apr 2020 07:57:14 +0900 Subject: [PATCH] feat: respect language preferences on Win/macOS This commit partially fixes https://github.com/electron/electron/issues/18829 Chromium uses navigator.languages (Accept-Language) to determine fallback fonts on Windows, especially kanji/han characters in CJK. Previously the full preferences set to OS was not given to Chromium. For instance, when user sets 'en-US, ja-JP' to Accept-Language, while Chromium chooses Japanese font for kanji text, but Electron chooses Chinese font. This is because only the first language is given to Accept-Language on Electron. This patch is based on https://github.com/electron/electron/pull/15532 Co-authored-by: Nitish Sakhawalkar Co-authored-by: Kasumi Hanazuki --- filenames.gni | 4 + .../browser/api/electron_api_web_contents.cc | 20 ++++- shell/common/language_util.h | 26 +++++++ shell/common/language_util_linux.cc | 16 ++++ shell/common/language_util_mac.mm | 25 ++++++ shell/common/language_util_win.cc | 76 +++++++++++++++++++ spec-main/chromium-spec.ts | 3 +- 7 files changed, 167 insertions(+), 3 deletions(-) create mode 100644 shell/common/language_util.h create mode 100644 shell/common/language_util_linux.cc create mode 100644 shell/common/language_util_mac.mm create mode 100644 shell/common/language_util_win.cc diff --git a/filenames.gni b/filenames.gni index ca3db4b5cddf7..01c32bd9a2533 100644 --- a/filenames.gni +++ b/filenames.gni @@ -545,6 +545,10 @@ filenames = { "shell/common/key_weak_map.h", "shell/common/keyboard_util.cc", "shell/common/keyboard_util.h", + "shell/common/language_util.h", + "shell/common/language_util_linux.cc", + "shell/common/language_util_mac.mm", + "shell/common/language_util_win.cc", "shell/common/mac/main_application_bundle.h", "shell/common/mac/main_application_bundle.mm", "shell/common/mouse_util.cc", diff --git a/shell/browser/api/electron_api_web_contents.cc b/shell/browser/api/electron_api_web_contents.cc index b65096d368ad3..40d5d5bb68d61 100644 --- a/shell/browser/api/electron_api_web_contents.cc +++ b/shell/browser/api/electron_api_web_contents.cc @@ -89,6 +89,7 @@ #include "shell/common/gin_converters/value_converter.h" #include "shell/common/gin_helper/dictionary.h" #include "shell/common/gin_helper/object_template_builder.h" +#include "shell/common/language_util.h" #include "shell/common/mouse_util.h" #include "shell/common/node_includes.h" #include "shell/common/options_switches.h" @@ -100,6 +101,7 @@ #include "third_party/blink/public/mojom/frame/find_in_page.mojom.h" #include "third_party/blink/public/mojom/frame/fullscreen.mojom.h" #include "third_party/blink/public/mojom/messaging/transferable_message.mojom.h" +#include "third_party/blink/public/mojom/renderer_preferences.mojom.h" #include "ui/base/cursor/cursor.h" #include "ui/base/mojom/cursor_type.mojom-shared.h" #include "ui/display/screen.h" @@ -121,7 +123,6 @@ #endif #if defined(OS_LINUX) || defined(OS_WIN) -#include "third_party/blink/public/mojom/renderer_preferences.mojom.h" #include "ui/gfx/font_render_params.h" #endif @@ -535,7 +536,22 @@ void WebContents::InitWithSessionAndOptions( managed_web_contents()->GetView()->SetDelegate(this); auto* prefs = web_contents()->GetMutableRendererPrefs(); - prefs->accept_languages = g_browser_process->GetApplicationLocale(); + + // Collect preferred languages from OS and browser process. accept_languages + // affects HTTP header, navigator.languages, and CJK fallback font seleciton. + // + // Note that an application locale set to the browser process might be + // different with the one set to the preference list. + // (e.g. overridden with --lang) + std::string accept_languages = + g_browser_process->GetApplicationLocale() + ","; + for (auto const& language : electron::GetPreferredLanguages()) { + if (language == g_browser_process->GetApplicationLocale()) + continue; + accept_languages += language + ","; + } + accept_languages.pop_back(); + prefs->accept_languages = accept_languages; #if defined(OS_LINUX) || defined(OS_WIN) // Update font settings. diff --git a/shell/common/language_util.h b/shell/common/language_util.h new file mode 100644 index 0000000000000..3e35073c142cc --- /dev/null +++ b/shell/common/language_util.h @@ -0,0 +1,26 @@ +// Copyright (c) 2020 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#ifndef SHELL_COMMON_LANGUAGE_UTIL_H_ +#define SHELL_COMMON_LANGUAGE_UTIL_H_ + +#include +#include + +#include "base/strings/string16.h" + +namespace electron { + +// Return a list of user preferred languages from OS. The list doesn't include +// overrides from command line arguments. +std::vector GetPreferredLanguages(); + +#if defined(OS_WIN) +bool GetPreferredLanguagesUsingGlobalization( + std::vector* languages); +#endif + +} // namespace electron + +#endif // SHELL_COMMON_LANGUAGE_UTIL_H_ diff --git a/shell/common/language_util_linux.cc b/shell/common/language_util_linux.cc new file mode 100644 index 0000000000000..ce61a80598b14 --- /dev/null +++ b/shell/common/language_util_linux.cc @@ -0,0 +1,16 @@ +// Copyright (c) 2020 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#include "shell/common/language_util.h" + +#include "ui/base/l10n/l10n_util.h" + +namespace electron { + +std::vector GetPreferredLanguages() { + std::vector languages = {l10n_util::GetApplicationLocale("")}; + return languages; +} + +} // namespace electron diff --git a/shell/common/language_util_mac.mm b/shell/common/language_util_mac.mm new file mode 100644 index 0000000000000..ce52f75c1ac1f --- /dev/null +++ b/shell/common/language_util_mac.mm @@ -0,0 +1,25 @@ +// Copyright (c) 2020 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#include "shell/common/language_util.h" + +#import +#include +#include + +#include "base/strings/sys_string_conversions.h" + +namespace electron { + +std::vector GetPreferredLanguages() { + std::vector languages; + [[NSLocale preferredLanguages] + enumerateObjectsUsingBlock:^(NSString* language, NSUInteger i, + BOOL* stop) { + languages.push_back(base::SysNSStringToUTF8(language)); + }]; + return languages; +} + +} // namespace electron diff --git a/shell/common/language_util_win.cc b/shell/common/language_util_win.cc new file mode 100644 index 0000000000000..d6717b31aec21 --- /dev/null +++ b/shell/common/language_util_win.cc @@ -0,0 +1,76 @@ +// Copyright (c) 2020 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#include "shell/common/language_util.h" + +#include +#include +#include + +#include "base/strings/sys_string_conversions.h" +#include "base/win/core_winrt_util.h" +#include "base/win/i18n.h" +#include "base/win/win_util.h" +#include "base/win/windows_version.h" + +namespace electron { + +std::vector GetPreferredLanguages() { + std::vector languages16; + + // Attempt to use API available on Windows 10 or later, which + // returns the full list of language preferences. + if (!GetPreferredLanguagesUsingGlobalization(&languages16)) { + base::win::i18n::GetThreadPreferredUILanguageList(&languages16); + } + + std::vector languages; + for (const auto& language : languages16) { + languages.push_back(base::SysWideToUTF8(language)); + } + return languages; +} + +bool GetPreferredLanguagesUsingGlobalization( + std::vector* languages) { + if (base::win::GetVersion() < base::win::Version::WIN10) + return false; + if (!base::win::ResolveCoreWinRTDelayload() || + !base::win::ScopedHString::ResolveCoreWinRTStringDelayload()) + return false; + + base::win::ScopedHString guid = base::win::ScopedHString::Create( + RuntimeClass_Windows_System_UserProfile_GlobalizationPreferences); + Microsoft::WRL::ComPtr< + ABI::Windows::System::UserProfile::IGlobalizationPreferencesStatics> + prefs; + + HRESULT hr = + base::win::RoGetActivationFactory(guid.get(), IID_PPV_ARGS(&prefs)); + if (FAILED(hr)) + return false; + + ABI::Windows::Foundation::Collections::IVectorView* langs; + hr = prefs->get_Languages(&langs); + if (FAILED(hr)) + return false; + + unsigned size; + hr = langs->get_Size(&size); + if (FAILED(hr)) + return false; + + for (unsigned i = 0; i < size; ++i) { + HSTRING hstr; + hr = langs->GetAt(i, &hstr); + if (SUCCEEDED(hr)) { + base::WStringPiece str = base::win::ScopedHString(hstr).Get(); + languages->emplace_back(str.data(), str.size()); + } + } + + return true; +} + +} // namespace electron diff --git a/spec-main/chromium-spec.ts b/spec-main/chromium-spec.ts index 2a4320d393427..894f856baa6ce 100644 --- a/spec-main/chromium-spec.ts +++ b/spec-main/chromium-spec.ts @@ -319,7 +319,8 @@ describe('chromium features', () => { const w = new BrowserWindow({ show: false }); await w.loadURL('about:blank'); const languages = await w.webContents.executeJavaScript('navigator.languages'); - expect(languages).to.deep.equal([appLocale]); + expect(languages.length).to.be.greaterThan(0); + expect(languages).to.contain(appLocale); }); });