From ca34978e73f9ab6378b40ded1a44b5cd9e3a5884 Mon Sep 17 00:00:00 2001 From: shelley vohr Date: Thu, 8 Feb 2018 09:26:37 -0500 Subject: [PATCH] add app.setLocale() (#11469) * infrastructure for setLocale via klang * add documentation for setLocale * add test for setLocale * fix spec * add spec and update docs * fix carriage feeds on windows * SetLocale() sets LC_ALL on Linux * in SetLocale() on Linux, use g_setenv() * fix tyop: '#ifdef OSX_POSIX' * make the linter happy * improvements from review --- atom/browser/atom_browser_main_parts.cc | 9 ++++-- brightray/browser/browser_main_parts.cc | 36 ++++++++++++++++++--- brightray/browser/browser_main_parts.h | 2 ++ brightray/common/main_delegate.cc | 19 +++++++---- brightray/common/main_delegate.h | 2 +- docs/api/app.md | 6 ++++ spec/api-app-spec.js | 19 +++++++++++ spec/fixtures/api/locale-check/main.js | 10 ++++++ spec/fixtures/api/locale-check/package.json | 5 +++ 9 files changed, 92 insertions(+), 16 deletions(-) create mode 100644 spec/fixtures/api/locale-check/main.js create mode 100644 spec/fixtures/api/locale-check/package.json diff --git a/atom/browser/atom_browser_main_parts.cc b/atom/browser/atom_browser_main_parts.cc index 07ddfca689bd..86d50d3c78bd 100644 --- a/atom/browser/atom_browser_main_parts.cc +++ b/atom/browser/atom_browser_main_parts.cc @@ -154,9 +154,12 @@ void AtomBrowserMainParts::PostEarlyInitialization() { } int AtomBrowserMainParts::PreCreateThreads() { - fake_browser_process_->SetApplicationLocale( - l10n_util::GetApplicationLocale("")); - return brightray::BrowserMainParts::PreCreateThreads(); + const int result = brightray::BrowserMainParts::PreCreateThreads(); + if (!result) { + fake_browser_process_->SetApplicationLocale( + brightray::BrowserClient::Get()->GetApplicationLocale()); + } + return result; } void AtomBrowserMainParts::PreMainMessageLoopRun() { diff --git a/brightray/browser/browser_main_parts.cc b/brightray/browser/browser_main_parts.cc index 0754c0c824fb..642734aa4db9 100644 --- a/brightray/browser/browser_main_parts.cc +++ b/brightray/browser/browser_main_parts.cc @@ -4,13 +4,17 @@ #include "brightray/browser/browser_main_parts.h" -#if defined(OSX_POSIX) +#if defined(OS_POSIX) #include #endif #include #include +#if defined(OS_LINUX) +#include // for g_setenv() +#endif + #include "base/command_line.h" #include "base/feature_list.h" #include "base/message_loop/message_loop.h" @@ -29,6 +33,8 @@ #include "net/proxy/proxy_resolver_v8.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/material_design/material_design_controller.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/base/ui_base_switches.h" #if defined(USE_AURA) #include "ui/display/display.h" @@ -220,10 +226,29 @@ void BrowserMainParts::ToolkitInitialized() { } void BrowserMainParts::PreMainMessageLoopStart() { -#if defined(OS_MACOSX) - l10n_util::OverrideLocaleWithCocoaLocale(); + // Initialize ui::ResourceBundle. + ui::ResourceBundle::InitSharedInstanceWithLocale( + "", nullptr, ui::ResourceBundle::DO_NOT_LOAD_COMMON_RESOURCES); + auto cmd_line = base::CommandLine::ForCurrentProcess(); + if (cmd_line->HasSwitch(switches::kLang)) { + const std::string locale = cmd_line->GetSwitchValueASCII(switches::kLang); + const base::FilePath locale_file_path = + ui::ResourceBundle::GetSharedInstance().GetLocaleFilePath(locale, true); + if (!locale_file_path.empty()) { + custom_locale_ = locale; +#if defined(OS_LINUX) + /* When built with USE_GLIB, libcc's GetApplicationLocaleInternal() uses + * glib's g_get_language_names(), which keys off of getenv("LC_ALL") */ + g_setenv("LC_ALL", custom_locale_.c_str(), TRUE); #endif - InitializeResourceBundle(""); + } + } + +#if defined(OS_MACOSX) + if (custom_locale_.empty()) + l10n_util::OverrideLocaleWithCocoaLocale(); +#endif + LoadResourceBundle(custom_locale_); #if defined(OS_MACOSX) InitializeMainNib(); #endif @@ -277,7 +302,8 @@ int BrowserMainParts::PreCreateThreads() { layout_provider_.reset(new views::LayoutProvider()); // Initialize the app locale. - BrowserClient::SetApplicationLocale(l10n_util::GetApplicationLocale("")); + BrowserClient::SetApplicationLocale( + l10n_util::GetApplicationLocale(custom_locale_)); // Manage global state of net and other IO thread related. io_thread_ = base::MakeUnique(); diff --git a/brightray/browser/browser_main_parts.h b/brightray/browser/browser_main_parts.h index 55474d442a3d..f69682ce5161 100644 --- a/brightray/browser/browser_main_parts.h +++ b/brightray/browser/browser_main_parts.h @@ -6,6 +6,7 @@ #define BRIGHTRAY_BROWSER_BROWSER_MAIN_PARTS_H_ #include +#include #include "base/compiler_specific.h" #include "base/macros.h" @@ -62,6 +63,7 @@ class BrowserMainParts : public content::BrowserMainParts { #endif std::unique_ptr layout_provider_; + std::string custom_locale_; DISALLOW_COPY_AND_ASSIGN(BrowserMainParts); }; diff --git a/brightray/common/main_delegate.cc b/brightray/common/main_delegate.cc index 423794d80279..fd4493655216 100644 --- a/brightray/common/main_delegate.cc +++ b/brightray/common/main_delegate.cc @@ -42,17 +42,22 @@ bool SubprocessNeedsResourceBundle(const std::string& process_type) { } // namespace -void InitializeResourceBundle(const std::string& locale) { - // Load locales. - ui::ResourceBundle::InitSharedInstanceWithLocale( - locale, nullptr, ui::ResourceBundle::DO_NOT_LOAD_COMMON_RESOURCES); +void LoadResourceBundle(const std::string& locale) { + const bool initialized = ui::ResourceBundle::HasSharedInstance(); + if (initialized) + ui::ResourceBundle::CleanupSharedInstance(); - // Load other resource files. + ui::ResourceBundle::InitSharedInstanceWithLocale( + locale, nullptr, ui::ResourceBundle::DO_NOT_LOAD_COMMON_RESOURCES); + + ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); + bundle.ReloadLocaleResources(locale); + +// Load other resource files. #if defined(OS_MACOSX) LoadCommonResources(); #else base::FilePath pak_dir; - ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); PathService::Get(base::DIR_MODULE, &pak_dir); bundle.AddDataPackFromPath( pak_dir.Append(FILE_PATH_LITERAL("content_shell.pak")), @@ -104,7 +109,7 @@ void MainDelegate::PreSandboxStartup() { // browser process as a command line flag. if (SubprocessNeedsResourceBundle(process_type)) { std::string locale = cmd.GetSwitchValueASCII(switches::kLang); - InitializeResourceBundle(locale); + LoadResourceBundle(locale); } } diff --git a/brightray/common/main_delegate.h b/brightray/common/main_delegate.h index 4139a20521b0..c5a294caab52 100644 --- a/brightray/common/main_delegate.h +++ b/brightray/common/main_delegate.h @@ -24,7 +24,7 @@ namespace brightray { class BrowserClient; class ContentClient; -void InitializeResourceBundle(const std::string& locale); +void LoadResourceBundle(const std::string& locale); void LoadCommonResources(); class MainDelegate : public content::ContentMainDelegate { diff --git a/docs/api/app.md b/docs/api/app.md index 04ba49b729d7..78f22127fd79 100644 --- a/docs/api/app.md +++ b/docs/api/app.md @@ -530,6 +530,12 @@ Returns `String` - The current application locale. Possible return values are do **Note:** On Windows you have to call it after the `ready` events gets emitted. +### `app.setLocale(locale)` + +* `locale` String + +Set the locale of the app (must be called before the `ready` event). + ### `app.addRecentDocument(path)` _macOS_ _Windows_ * `path` String diff --git a/spec/api-app-spec.js b/spec/api-app-spec.js index 0eda951b15d6..539cd661dca3 100644 --- a/spec/api-app-spec.js +++ b/spec/api-app-spec.js @@ -112,6 +112,25 @@ describe('app module', () => { }) }) + describe('app.setLocale()', () => { + const testLocale = (locale, result, done) => { + const appPath = path.join(__dirname, 'fixtures', 'api', 'locale-check') + const electronPath = remote.getGlobal('process').execPath + let output = '' + let appProcess = ChildProcess.spawn(electronPath, [appPath, `--lang=${locale}`]) + + appProcess.stdout.on('data', (data) => { output += data }) + appProcess.stdout.on('end', () => { + output = output.replace(/(\r\n|\n|\r)/gm, '') + assert.equal(output, result) + done() + }) + } + + it('should set the locale', (done) => testLocale('fr', 'fr', done)) + it('should not set an invalid locale', (done) => testLocale('asdfkl', 'en-US', done)) + }) + describe('app.isInApplicationsFolder()', () => { before(function () { if (process.platform !== 'darwin') { diff --git a/spec/fixtures/api/locale-check/main.js b/spec/fixtures/api/locale-check/main.js new file mode 100644 index 000000000000..be1807bb12e3 --- /dev/null +++ b/spec/fixtures/api/locale-check/main.js @@ -0,0 +1,10 @@ +const {app} = require('electron') + +app.on('ready', () => { + process.stdout.write(app.getLocale()) + process.stdout.end() + + setImmediate(() => { + app.quit() + }) +}) diff --git a/spec/fixtures/api/locale-check/package.json b/spec/fixtures/api/locale-check/package.json new file mode 100644 index 000000000000..a24f536930d2 --- /dev/null +++ b/spec/fixtures/api/locale-check/package.json @@ -0,0 +1,5 @@ +{ + "name": "locale-check", + "main": "main.js" +} +