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..6e1c7926c442c 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 + // effects HTTP header, navigator.languages, and CJK fallback font selection. + // + // 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..76bc557741ba0 --- /dev/null +++ b/shell/common/language_util_linux.cc @@ -0,0 +1,17 @@ +// 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() { + // Return empty as there's no API to use. You may be able to use + // GetApplicationLocale() of a browser process. + return std::vector{}; +} + +} // namespace electron diff --git a/shell/common/language_util_mac.mm b/shell/common/language_util_mac.mm new file mode 100644 index 0000000000000..205d7087bf1f8 --- /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() { + __block 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); }); });