Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add app.getSystemLocale() method #35697

Merged
merged 13 commits into from Sep 23, 2022
9 changes: 8 additions & 1 deletion docs/api/app.md
Expand Up @@ -715,14 +715,21 @@ To set the locale, you'll want to use a command line switch at app startup, whic
**Note:** When distributing your packaged app, you have to also ship the
`locales` folder.

**Note:** On Windows, you have to call it after the `ready` events gets emitted.
**Note:** On Windows, you have to call it after the `ready` event is emitted.

### `app.getLocaleCountryCode()`

Returns `string` - User operating system's locale two-letter [ISO 3166](https://www.iso.org/iso-3166-country-codes.html) country code. The value is taken from native OS APIs.

**Note:** When unable to detect locale country code, it returns empty string.

### `app.getSystemLocale()`

Returns `string` - The current system locale, fetched using Chromium's `l10n_util` library.
Possible return values are documented [here](https://source.chromium.org/chromium/chromium/src/+/main:ui/base/l10n/l10n_util.cc).
rzhao271 marked this conversation as resolved.
Show resolved Hide resolved

**Note:** This API must be called after the `ready` event is emitted.
rzhao271 marked this conversation as resolved.
Show resolved Hide resolved

### `app.addRecentDocument(path)` _macOS_ _Windows_

* `path` string
Expand Down
1 change: 1 addition & 0 deletions filenames.auto.gni
Expand Up @@ -140,6 +140,7 @@ auto_filenames = {
"lib/common/define-properties.ts",
"lib/common/ipc-messages.ts",
"lib/common/web-view-methods.ts",
"lib/common/webpack-globals-provider.ts",
rzhao271 marked this conversation as resolved.
Show resolved Hide resolved
"lib/renderer/api/context-bridge.ts",
"lib/renderer/api/crash-reporter.ts",
"lib/renderer/api/ipc-renderer.ts",
Expand Down
12 changes: 12 additions & 0 deletions shell/browser/api/electron_api_app.cc
Expand Up @@ -47,6 +47,7 @@
#include "shell/browser/api/electron_api_session.h"
#include "shell/browser/api/electron_api_web_contents.h"
#include "shell/browser/api/gpuinfo_manager.h"
#include "shell/browser/browser_process_impl.h"
#include "shell/browser/electron_browser_context.h"
#include "shell/browser/electron_browser_main_parts.h"
#include "shell/browser/javascript_environment.h"
Expand Down Expand Up @@ -1039,6 +1040,16 @@ std::string App::GetLocale() {
return g_browser_process->GetApplicationLocale();
}

std::string App::GetSystemLocale(gin_helper::ErrorThrower thrower) const {
if (!Browser::Get()->is_ready()) {
thrower.ThrowError(
"app.getSystemLocale() can only be called "
"after app is ready");
return std::string();
}
return static_cast<BrowserProcessImpl*>(g_browser_process)->GetSystemLocale();
}

std::string App::GetLocaleCountryCode() {
std::string region;
#if BUILDFLAG(IS_WIN)
Expand Down Expand Up @@ -1785,6 +1796,7 @@ gin::ObjectTemplateBuilder App::GetObjectTemplateBuilder(v8::Isolate* isolate) {
.SetMethod("setAppLogsPath", &App::SetAppLogsPath)
.SetMethod("setDesktopName", &App::SetDesktopName)
.SetMethod("getLocale", &App::GetLocale)
.SetMethod("getSystemLocale", &App::GetSystemLocale)
.SetMethod("getLocaleCountryCode", &App::GetLocaleCountryCode)
#if BUILDFLAG(USE_NSS_CERTS)
.SetMethod("importCertificate", &App::ImportCertificate)
Expand Down
1 change: 1 addition & 0 deletions shell/browser/api/electron_api_app.h
Expand Up @@ -191,6 +191,7 @@ class App : public ElectronBrowserClient::Delegate,
void SetDesktopName(const std::string& desktop_name);
std::string GetLocale();
std::string GetLocaleCountryCode();
std::string GetSystemLocale(gin_helper::ErrorThrower thrower) const;
void OnSecondInstance(const base::CommandLine& cmd,
const base::FilePath& cwd,
const std::vector<const uint8_t> additional_data);
Expand Down
8 changes: 8 additions & 0 deletions shell/browser/browser_process_impl.cc
Expand Up @@ -293,6 +293,14 @@ HidPolicyAllowedDevices* BrowserProcessImpl::hid_policy_allowed_devices() {
return nullptr;
}

void BrowserProcessImpl::SetSystemLocale(const std::string& locale) {
system_locale_ = locale;
}

const std::string& BrowserProcessImpl::GetSystemLocale() const {
return system_locale_;
}

void BrowserProcessImpl::SetApplicationLocale(const std::string& locale) {
locale_ = locale;
}
Expand Down
4 changes: 4 additions & 0 deletions shell/browser/browser_process_impl.h
Expand Up @@ -49,6 +49,9 @@ class BrowserProcessImpl : public BrowserProcess {
void PostDestroyThreads() {}
void PostMainMessageLoopRun();

void SetSystemLocale(const std::string& locale);
const std::string& GetSystemLocale() const;

void EndSession() override {}
void FlushLocalStateAndReply(base::OnceClosure reply) override {}
bool IsShuttingDown() override;
Expand Down Expand Up @@ -110,6 +113,7 @@ class BrowserProcessImpl : public BrowserProcess {
#endif
std::unique_ptr<PrefService> local_state_;
std::string locale_;
std::string system_locale_;
};

#endif // ELECTRON_SHELL_BROWSER_BROWSER_PROCESS_IMPL_H_
10 changes: 9 additions & 1 deletion shell/browser/electron_browser_main_parts.cc
Expand Up @@ -11,6 +11,7 @@
#include "base/base_switches.h"
#include "base/command_line.h"
#include "base/feature_list.h"
#include "base/i18n/rtl.h"
#include "base/metrics/field_trial.h"
#include "base/path_service.h"
#include "base/run_loop.h"
Expand Down Expand Up @@ -285,6 +286,13 @@ int ElectronBrowserMainParts::PreCreateThreads() {
if (!views::LayoutProvider::Get())
layout_provider_ = std::make_unique<views::LayoutProvider>();

// Fetch the system locale for Electron.
rzhao271 marked this conversation as resolved.
Show resolved Hide resolved
#if BUILDFLAG(IS_MAC)
fake_browser_process_->SetSystemLocale(GetCurrentSystemLocale());
#else
fake_browser_process_->SetSystemLocale(base::i18n::GetConfiguredLocale());
#endif

auto* command_line = base::CommandLine::ForCurrentProcess();
std::string locale = command_line->GetSwitchValueASCII(::switches::kLang);

Expand Down Expand Up @@ -320,7 +328,7 @@ int ElectronBrowserMainParts::PreCreateThreads() {
}
#endif

// Initialize the app locale.
// Initialize the app locale for Electron and Chromium.
std::string app_locale = l10n_util::GetApplicationLocale(loaded_locale);
ElectronBrowserClient::SetApplicationLocale(app_locale);
fake_browser_process_->SetApplicationLocale(app_locale);
Expand Down
1 change: 1 addition & 0 deletions shell/browser/electron_browser_main_parts.h
Expand Up @@ -130,6 +130,7 @@ class ElectronBrowserMainParts : public content::BrowserMainParts {
void FreeAppDelegate();
void RegisterURLHandler();
void InitializeMainNib();
std::string GetCurrentSystemLocale();
ckerr marked this conversation as resolved.
Show resolved Hide resolved
#endif

#if BUILDFLAG(IS_MAC)
Expand Down
21 changes: 21 additions & 0 deletions shell/browser/electron_browser_main_parts_mac.mm
Expand Up @@ -4,6 +4,8 @@

#include "shell/browser/electron_browser_main_parts.h"

#include <string>

#include "base/mac/bundle_locations.h"
#include "base/mac/foundation_util.h"
#include "base/path_service.h"
Expand Down Expand Up @@ -74,4 +76,23 @@
[mainNib release];
}

std::string ElectronBrowserMainParts::GetCurrentSystemLocale() {
NSString* systemLocaleIdentifier =
[[NSLocale currentLocale] localeIdentifier];

// Mac OS X uses "_" instead of "-", so swap to get a real locale value.
std::string locale_value = [[systemLocaleIdentifier
stringByReplacingOccurrencesOfString:@"_"
withString:@"-"] UTF8String];

// On disk the "en-US" resources are just "en" (http://crbug.com/25578), so
// the reverse mapping is done here to continue to feed Chrome the same values
// in all cases on all platforms. (l10n_util maps en to en-US if it gets
// passed this on the command line)
if (locale_value == "en")
locale_value = "en-US";
rzhao271 marked this conversation as resolved.
Show resolved Hide resolved

return locale_value;
}

} // namespace electron
6 changes: 6 additions & 0 deletions spec/api-app-spec.ts
Expand Up @@ -118,6 +118,12 @@ describe('app module', () => {
});
});

describe('app.getSystemLocale()', () => {
it('should not be empty', () => {
expect(app.getSystemLocale()).to.not.equal('');
});
});

describe('app.getLocaleCountryCode()', () => {
it('should be empty or have length of two', () => {
const localeCountryCode = app.getLocaleCountryCode();
Expand Down
6 changes: 4 additions & 2 deletions spec/chromium-spec.ts
Expand Up @@ -374,6 +374,7 @@ describe('command line switches', () => {
});
describe('--lang switch', () => {
const currentLocale = app.getLocale();
const currentSystemLocale = app.getSystemLocale();
const testLocale = async (locale: string, result: string, printEnv: boolean = false) => {
const appPath = path.join(fixturesPath, 'api', 'locale-check');
const args = [appPath, `--set-lang=${locale}`];
Expand All @@ -396,8 +397,9 @@ describe('command line switches', () => {
expect(output).to.equal(result);
};

it('should set the locale', async () => testLocale('fr', 'fr'));
it('should not set an invalid locale', async () => testLocale('asdfkl', currentLocale));
it('should set the locale', async () => testLocale('fr', `fr|${currentSystemLocale}`));
it('should set the locale with country code', async () => testLocale('zh-CN', `zh-CN|${currentSystemLocale}`));
it('should not set an invalid locale', async () => testLocale('asdfkl', `${currentLocale}|${currentSystemLocale}`));

const lcAll = String(process.env.LC_ALL);
ifit(process.platform === 'linux')('current process has a valid LC_ALL env', async () => {
Expand Down
2 changes: 1 addition & 1 deletion spec/fixtures/api/locale-check/main.js
Expand Up @@ -9,7 +9,7 @@ app.whenReady().then(() => {
if (process.argv[3] === '--print-env') {
process.stdout.write(String(process.env.LC_ALL));
} else {
process.stdout.write(app.getLocale());
process.stdout.write(`${app.getLocale()}|${app.getSystemLocale()}`);
}
process.stdout.end();

Expand Down