Skip to content

Commit

Permalink
feat: respect language preferences on Win/macOS
Browse files Browse the repository at this point in the history
This commit partially fixes electron#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 electron#15532

Co-authored-by: Nitish Sakhawalkar <nitsakh@icloud.com>
Co-authored-by: Kasumi Hanazuki <kasumi@rollingapple.net>
  • Loading branch information
3 people committed Apr 28, 2020
1 parent 7377bb3 commit 78d7de6
Show file tree
Hide file tree
Showing 7 changed files with 167 additions and 3 deletions.
4 changes: 4 additions & 0 deletions filenames.gni
Expand Up @@ -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",
Expand Down
20 changes: 18 additions & 2 deletions shell/browser/api/electron_api_web_contents.cc
Expand Up @@ -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"
Expand All @@ -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"
Expand All @@ -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

Expand Down Expand Up @@ -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.
Expand Down
26 changes: 26 additions & 0 deletions 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 <string>
#include <vector>

#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<std::string> GetPreferredLanguages();

#if defined(OS_WIN)
bool GetPreferredLanguagesUsingGlobalization(
std::vector<base::string16>* languages);
#endif

} // namespace electron

#endif // SHELL_COMMON_LANGUAGE_UTIL_H_
16 changes: 16 additions & 0 deletions 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<std::string> GetPreferredLanguages() {
std::vector<std::string> languages = {l10n_util::GetApplicationLocale("")};
return languages;
}

} // namespace electron
25 changes: 25 additions & 0 deletions 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 <Cocoa/Cocoa.h>
#include <string>
#include <vector>

#include "base/strings/sys_string_conversions.h"

namespace electron {

std::vector<std::string> GetPreferredLanguages() {
std::vector<std::string> languages;
[[NSLocale preferredLanguages]
enumerateObjectsUsingBlock:^(NSString* language, NSUInteger i,
BOOL* stop) {
languages.push_back(base::SysNSStringToUTF8(language));
}];
return languages;
}

} // namespace electron
76 changes: 76 additions & 0 deletions 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 <roapi.h>
#include <windows.system.userprofile.h>
#include <wrl.h>

#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<std::string> GetPreferredLanguages() {
std::vector<base::string16> 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<std::string> languages;
for (const auto& language : languages16) {
languages.push_back(base::SysWideToUTF8(language));
}
return languages;
}

bool GetPreferredLanguagesUsingGlobalization(
std::vector<base::string16>* 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<HSTRING>* 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
3 changes: 2 additions & 1 deletion spec-main/chromium-spec.ts
Expand Up @@ -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);
});
});

Expand Down

0 comments on commit 78d7de6

Please sign in to comment.