Bug 1333184 - Introduce OSPreferences API. r?jfkthame
MozReview-Commit-ID: pS3y9hNYbp
new file mode 100644
--- /dev/null
+++ b/intl/locale/OSPreferences.cpp
@@ -0,0 +1,64 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/**
+ * This is a shared part of the OSPreferences API implementation.
+ * It defines helper methods and public methods that are calling
+ * platform specific private methods.
+ */
+
+#include "OSPreferences.h"
+#include "mozilla/ClearOnShutdown.h"
+
+using namespace mozilla::intl;
+
+mozilla::StaticAutoPtr<OSPreferences> OSPreferences::sInstance;
+
+OSPreferences* OSPreferences::GetInstance()
+{
+ if (!sInstance) {
+ sInstance = new OSPreferences();
+ ClearOnShutdown(&sInstance);
+ }
+ return sInstance;
+}
+
+bool
+OSPreferences::GetSystemLocales(nsTArray<nsCString>& aRetVal)
+{
+ bool status = true;
+ if (mSystemLocales.IsEmpty()) {
+ status = ReadSystemLocales(mSystemLocales);
+ }
+ aRetVal = mSystemLocales;
+ return status;
+}
+
+/**
+ * This method should be called by every method of OSPreferences that
+ * retrieves a locale id from external source.
+ *
+ * It attempts to retrieve as much of the locale ID as possible, cutting
+ * out bits that are not understood (non-strict behavior of ICU).
+ *
+ * It returns true if the canonicalization was successful.
+ */
+bool
+OSPreferences::CanonicalizeLanguageTag(nsCString& aLoc)
+{
+ char langTag[512];
+
+ UErrorCode status = U_ZERO_ERROR;
+
+ int32_t langTagLen =
+ uloc_toLanguageTag(aLoc.get(), langTag, sizeof(langTag) - 1, false, &status);
+
+ if (U_FAILURE(status)) {
+ return false;
+ }
+
+ aLoc.Assign(langTag, langTagLen);
+ return true;
+}
new file mode 100644
--- /dev/null
+++ b/intl/locale/OSPreferences.h
@@ -0,0 +1,88 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_intl_IntlOSPreferences_h__
+#define mozilla_intl_IntlOSPreferences_h__
+
+#include "mozilla/StaticPtr.h"
+#include "nsString.h"
+#include "nsTArray.h"
+#include "unicode/uloc.h"
+
+namespace mozilla {
+namespace intl {
+
+/**
+ * OSPreferences API provides a set of methods for retrieving information from
+ * the host environment on topics such as:
+ * - Internationalization
+ * - Localization
+ * - Regional preferences
+ *
+ * The API is meant to remain as simple as possible, relying information from
+ * the host environment to the user without too much logic.
+ *
+ * Saying that, there are two exceptions to that paradigm.
+ *
+ * First one is normalization. We do intend to translate host environment
+ * concepts to unified Intl/L10n vocabulary used by Mozilla.
+ * That means that we will format locale IDs, timezone names, currencies etc.
+ * into a chosen format.
+ *
+ * Second is caching. This API does cache values and where possible will
+ * hook into the environment for some event-driven cache invalidation.
+ */
+class OSPreferences
+{
+
+public:
+ static OSPreferences* GetInstance();
+
+ /**
+ * Returns a list of locales used by the host environment.
+ *
+ * The result is a sorted list and we expect that the OS attempts to
+ * use the top locale from the list for which it has data.
+ *
+ * Each element of the list is a valid locale ID that can be passed to ICU
+ * and ECMA402 Intl APIs,
+ * At the same time each element is a valid BCP47 language tag that can be
+ * used for language negotiation.
+ *
+ * Example: ["en-US", "de", "pl", "sr-Cyrl", "zh-Hans-HK"]
+ *
+ * The return bool value indicates whether the function successfully
+ * resolved at least one locale.
+ *
+ * Usage:
+ * nsTArray<nsCString>& systemLocales;
+ * OSPreferences::GetInstance()->GetSystemLocales(systemLocales);
+ */
+ bool GetSystemLocales(nsTArray<nsCString>& aRetVal);
+
+protected:
+ nsTArray<nsCString> mSystemLocales;
+
+private:
+ static StaticAutoPtr<OSPreferences> sInstance;
+
+ static bool CanonicalizeLanguageTag(nsCString& aLoc);
+
+ /**
+ * This is a host environment specific method that will be implemented
+ * separately for each platform.
+ *
+ * It is only called when the cache is empty or invalidated.
+ *
+ * The return value indicates whether the function successfully
+ * resolved at least one locale.
+ */
+ bool ReadSystemLocales(nsTArray<nsCString>& aRetVal);
+};
+
+} // intl
+} // namespace mozilla
+
+#endif /* mozilla_intl_IntlOSPreferences_h__ */
new file mode 100644
--- /dev/null
+++ b/intl/locale/mac/OSPreferences_mac.cpp
@@ -0,0 +1,39 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "OSPreferences.h"
+#include <Carbon/Carbon.h>
+
+using namespace mozilla::intl;
+
+bool
+OSPreferences::ReadSystemLocales(nsTArray<nsCString>& aLocaleList)
+{
+ MOZ_ASSERT(aLocaleList.IsEmpty());
+
+ // Get string representation of user's current locale
+ CFLocaleRef userLocaleRef = ::CFLocaleCopyCurrent();
+ CFStringRef userLocaleStr = ::CFLocaleGetIdentifier(userLocaleRef);
+
+ AutoTArray<UniChar, 32> buffer;
+ int size = ::CFStringGetLength(userLocaleStr);
+
+ CFRange range = ::CFRangeMake(0, size);
+ ::CFStringGetCharacters(userLocaleStr, range, buffer.Elements());
+
+ // Convert the locale string to the format that Mozilla expects
+ NS_LossyConvertUTF16toASCII locale(
+ reinterpret_cast<const char16_t*>(buffer.Elements()), buffer.Length());
+
+ CFRelease(userLocaleRef);
+
+ if (CanonicalizeLanguageTag(locale)) {
+ aLocaleList.AppendElement(locale);
+ return true;
+ }
+
+ return false;
+}
--- a/intl/locale/mac/moz.build
+++ b/intl/locale/mac/moz.build
@@ -4,12 +4,15 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
UNIFIED_SOURCES += [
'nsCollationMacUC.cpp',
'nsMacCharset.cpp',
]
+if CONFIG['ENABLE_INTL_API']:
+ UNIFIED_SOURCES += ['OSPreferences_mac.cpp']
+
FINAL_LIBRARY = 'xul'
LOCAL_INCLUDES += [
'..',
]
--- a/intl/locale/moz.build
+++ b/intl/locale/moz.build
@@ -1,16 +1,20 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
XPCSHELL_TESTS_MANIFESTS += ['tests/unit/xpcshell.ini']
+if CONFIG['ENABLE_INTL_API']:
+ SOURCES += ['OSPreferences.cpp']
+
+
toolkit = CONFIG['MOZ_WIDGET_TOOLKIT']
if toolkit == 'windows':
DIRS += ['windows']
elif toolkit == 'cocoa':
DIRS += ['mac']
else:
DIRS += ['unix']
@@ -69,8 +73,11 @@ RESOURCE_FILES += [
]
GENERATED_FILES += [
'langGroups.properties.h',
]
langgroups = GENERATED_FILES['langGroups.properties.h']
langgroups.script = 'props2arrays.py'
langgroups.inputs = ['langGroups.properties']
+
+if CONFIG['ENABLE_TESTS']:
+ DIRS += ['tests/gtest']
new file mode 100644
--- /dev/null
+++ b/intl/locale/tests/gtest/TestOSPreferences.cpp
@@ -0,0 +1,24 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "gtest/gtest.h"
+#include "OSPreferences.h"
+
+using namespace mozilla::intl;
+
+/**
+ * We test that on all platforms we test against (irrelevant of the tier),
+ * we will be able to retrieve at least a single locale out of the system.
+ *
+ * In theory, that may not be true, but if we encounter such platform we should
+ * decide how to handle this and special case and this test should make
+ * it not happen without us noticing.
+ */
+TEST(Intl_Locale_OSPreferences, GetSystemLocales) {
+ nsTArray<nsCString> systemLocales;
+ OSPreferences::GetInstance()->GetSystemLocales(systemLocales);
+
+ ASSERT_FALSE(systemLocales.IsEmpty());
+}
new file mode 100644
--- /dev/null
+++ b/intl/locale/tests/gtest/moz.build
@@ -0,0 +1,14 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+if CONFIG['ENABLE_INTL_API']:
+ UNIFIED_SOURCES += ['TestOSPreferences.cpp']
+
+LOCAL_INCLUDES += [
+ '/intl/locale',
+]
+
+FINAL_LIBRARY = 'xul-gtest'
new file mode 100644
--- /dev/null
+++ b/intl/locale/unix/OSPreferences_unix.cpp
@@ -0,0 +1,23 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "OSPreferences.h"
+
+using namespace mozilla::intl;
+
+bool
+OSPreferences::ReadSystemLocales(nsTArray<nsCString>& aLocaleList)
+{
+ MOZ_ASSERT(aLocaleList.IsEmpty());
+
+ nsAutoCString defaultLang(uloc_getDefault());
+
+ if (CanonicalizeLanguageTag(defaultLang)) {
+ aLocaleList.AppendElement(defaultLang);
+ return true;
+ }
+ return false;
+}
--- a/intl/locale/unix/moz.build
+++ b/intl/locale/unix/moz.build
@@ -4,16 +4,19 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
SOURCES += [
'nsCollationUnix.cpp',
'nsPosixLocale.cpp',
]
+if CONFIG['ENABLE_INTL_API']:
+ SOURCES += ['OSPreferences_unix.cpp']
+
if CONFIG['OS_TARGET'] == 'Android':
SOURCES += [
'nsAndroidCharset.cpp',
]
else:
SOURCES += [
'nsUNIXCharset.cpp',
]
new file mode 100644
--- /dev/null
+++ b/intl/locale/windows/OSPreferences_win.cpp
@@ -0,0 +1,29 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "OSPreferences.h"
+#include "nsWin32Locale.h"
+
+using namespace mozilla::intl;
+
+bool
+OSPreferences::ReadSystemLocales(nsTArray<nsCString>& aLocaleList)
+{
+ MOZ_ASSERT(aLocaleList.IsEmpty());
+
+ nsAutoString locale;
+
+ LCID win_lcid = GetSystemDefaultLCID();
+ nsWin32Locale::GetXPLocale(win_lcid, locale);
+
+ NS_LossyConvertUTF16toASCII loc(locale);
+
+ if (CanonicalizeLanguageTag(loc)) {
+ aLocaleList.AppendElement(loc);
+ return true;
+ }
+ return false;
+}
--- a/intl/locale/windows/moz.build
+++ b/intl/locale/windows/moz.build
@@ -5,16 +5,19 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
SOURCES += [
'nsCollationWin.cpp',
'nsWin32Locale.cpp',
'nsWinCharset.cpp',
]
+if CONFIG['ENABLE_INTL_API']:
+ SOURCES += ['OSPreferences_win.cpp']
+
FINAL_LIBRARY = 'xul'
GENERATED_FILES = [
'wincharset.properties.h',
]
wincharset = GENERATED_FILES['wincharset.properties.h']
wincharset.script = '../props2arrays.py'
wincharset.inputs = ['wincharset.properties']