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 #35794

8 changes: 7 additions & 1 deletion docs/api/app.md
Expand Up @@ -715,14 +715,20 @@ 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:** This API must be called 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. On Windows and Linux, it is fetched using Chromium's `i18n` library. On macOS, the `NSLocale` object is used instead.

**Note:** This API must be called after the `ready` event is emitted.

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

* `path` string
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 @@ -1038,6 +1039,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 @@ -1779,6 +1790,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_
13 changes: 11 additions & 2 deletions 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 @@ -283,8 +284,16 @@ void ElectronBrowserMainParts::PostEarlyInitialization() {
}

int ElectronBrowserMainParts::PreCreateThreads() {
if (!views::LayoutProvider::Get())
if (!views::LayoutProvider::Get()) {
layout_provider_ = std::make_unique<views::LayoutProvider>();
}

// Fetch the system locale for Electron.
#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 @@ -321,7 +330,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();
static std::string GetCurrentSystemLocale();
#endif

#if BUILDFLAG(IS_MAC)
Expand Down
14 changes: 14 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,16 @@
[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];

return locale_value;
}

} // namespace electron
6 changes: 6 additions & 0 deletions spec-main/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-main/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