Browse Source

feat: Add app.getLocaleCountryCode() method for region detection (#15035)

* Add method to get system´s user region

* Fix linter

* Remove auto types

* Improved detection for POSIX

* Change name, add specs, minor fixes

* Remove left overs

* Fix locale test

* Fix Linux test

* Coding style fixes

* Fix docs

* Add test excaption for Linux

* fix spelling

* Polishing
Ondřej Záruba 6 years ago
parent
commit
de05ff894b
4 changed files with 58 additions and 0 deletions
  1. 41 0
      atom/browser/api/atom_api_app.cc
  2. 1 0
      atom/browser/api/atom_api_app.h
  3. 5 0
      docs/api/app.md
  4. 11 0
      spec/api-app-spec.js

+ 41 - 0
atom/browser/api/atom_api_app.cc

@@ -65,6 +65,7 @@
 #endif
 
 #if defined(OS_MACOSX)
+#include <CoreFoundation/CoreFoundation.h>
 #include "atom/browser/ui/cocoa/atom_bundle_mover.h"
 #endif
 
@@ -882,6 +883,45 @@ std::string App::GetLocale() {
   return g_browser_process->GetApplicationLocale();
 }
 
+std::string App::GetLocaleCountryCode() {
+  std::string region;
+#if defined(OS_WIN)
+  WCHAR locale_name[LOCALE_NAME_MAX_LENGTH] = {0};
+
+  if (GetLocaleInfoEx(LOCALE_NAME_USER_DEFAULT, LOCALE_SISO3166CTRYNAME,
+                      (LPWSTR)&locale_name,
+                      sizeof(locale_name) / sizeof(WCHAR)) ||
+      GetLocaleInfoEx(LOCALE_NAME_SYSTEM_DEFAULT, LOCALE_SISO3166CTRYNAME,
+                      (LPWSTR)&locale_name,
+                      sizeof(locale_name) / sizeof(WCHAR))) {
+    base::WideToUTF8(locale_name, wcslen(locale_name), &region);
+  }
+#elif defined(OS_MACOSX)
+  CFLocaleRef locale = CFLocaleCopyCurrent();
+  CFStringRef value = CFStringRef(
+      static_cast<CFTypeRef>(CFLocaleGetValue(locale, kCFLocaleCountryCode)));
+  const CFIndex kCStringSize = 128;
+  char temporaryCString[kCStringSize] = {0};
+  CFStringGetCString(value, temporaryCString, kCStringSize,
+                     kCFStringEncodingUTF8);
+  region = temporaryCString;
+#else
+  const char* locale_ptr = setlocale(LC_TIME, NULL);
+  if (!locale_ptr)
+    locale_ptr = setlocale(LC_NUMERIC, NULL);
+  if (locale_ptr) {
+    std::string locale = locale_ptr;
+    std::string::size_type rpos = locale.find('.');
+    if (rpos != std::string::npos)
+      locale = locale.substr(0, rpos);
+    rpos = locale.find('_');
+    if (rpos != std::string::npos && rpos + 1 < locale.size())
+      region = locale.substr(rpos + 1);
+  }
+#endif
+  return region.size() == 2 ? region : std::string();
+}
+
 void App::OnSecondInstance(const base::CommandLine::StringVector& cmd,
                            const base::FilePath& cwd) {
   Emit("second-instance", cmd, cwd);
@@ -1315,6 +1355,7 @@ void App::BuildPrototype(v8::Isolate* isolate,
       .SetMethod("getPath", &App::GetPath)
       .SetMethod("setDesktopName", &App::SetDesktopName)
       .SetMethod("getLocale", &App::GetLocale)
+      .SetMethod("getLocaleCountryCode", &App::GetLocaleCountryCode)
 #if defined(USE_NSS_CERTS)
       .SetMethod("importCertificate", &App::ImportCertificate)
 #endif

+ 1 - 0
atom/browser/api/atom_api_app.h

@@ -182,6 +182,7 @@ class App : public AtomBrowserClient::Delegate,
 
   void SetDesktopName(const std::string& desktop_name);
   std::string GetLocale();
+  std::string GetLocaleCountryCode();
   void OnSecondInstance(const base::CommandLine::StringVector& cmd,
                         const base::FilePath& cwd);
   bool HasSingleInstanceLock() const;

+ 5 - 0
docs/api/app.md

@@ -603,6 +603,11 @@ To set the locale, you'll want to use a command line switch at app startup, whic
 
 **Note:** On Windows you have to call it after the `ready` events gets 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.addRecentDocument(path)` _macOS_ _Windows_
 
 * `path` String

+ 11 - 0
spec/api-app-spec.js

@@ -122,6 +122,17 @@ describe('app module', () => {
     })
   })
 
+  describe('app.getLocaleCountryCode()', () => {
+    it('should be empty or have length of two', () => {
+      let expectedLength = 2
+      if (isCI && process.platform === 'linux') {
+        // Linux CI machines have no locale.
+        expectedLength = 0
+      }
+      expect(app.getLocaleCountryCode()).to.be.a('string').and.have.lengthOf(expectedLength)
+    })
+  })
+
   describe('app.isPackaged', () => {
     it('should be false durings tests', () => {
       expect(app.isPackaged).to.be.false()