Bug 1333184 - Introduce OSPreferences API. r=jfkthame

MozReview-Commit-ID: ALvLGtBmRgn

--HG--
extra : rebase_source : fb237beec41e7b93eeac862be285074acfc36a77
This commit is contained in:
Zibi Braniecki 2017-02-05 11:41:43 -08:00
parent 2db2a32d40
commit 1aa7bc8b32
11 changed files with 287 additions and 0 deletions

View File

@ -0,0 +1,65 @@
/* -*- 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;
}

View File

@ -0,0 +1,92 @@
/* -*- 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, relaying 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.
*
* This means that on platforms that do not support a mechanism to
* notify apps about changes, new OS-level settings may not be reflected
* in the app until it is relaunched.
*/
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__ */

View File

@ -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;
}

View File

@ -9,6 +9,9 @@ UNIFIED_SOURCES += [
'nsMacCharset.cpp',
]
if CONFIG['ENABLE_INTL_API']:
UNIFIED_SOURCES += ['OSPreferences_mac.cpp']
FINAL_LIBRARY = 'xul'
LOCAL_INCLUDES += [
'..',

View File

@ -6,6 +6,9 @@
XPCSHELL_TESTS_MANIFESTS += ['tests/unit/xpcshell.ini']
if CONFIG['ENABLE_INTL_API']:
SOURCES += ['OSPreferences.cpp']
toolkit = CONFIG['MOZ_WIDGET_TOOLKIT']
if toolkit == 'windows':

View File

@ -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;
ASSERT_TRUE(OSPreferences::GetInstance()->GetSystemLocales(systemLocales));
ASSERT_FALSE(systemLocales.IsEmpty());
}

View File

@ -8,6 +8,9 @@ UNIFIED_SOURCES += [
'TestLocaleService.cpp',
]
if CONFIG['ENABLE_INTL_API']:
UNIFIED_SOURCES += ['TestOSPreferences.cpp']
LOCAL_INCLUDES += [
'/intl/locale',
]

View File

@ -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;
}

View File

@ -9,6 +9,9 @@ SOURCES += [
'nsPosixLocale.cpp',
]
if CONFIG['ENABLE_INTL_API']:
SOURCES += ['OSPreferences_unix.cpp']
if CONFIG['OS_TARGET'] == 'Android':
SOURCES += [
'nsAndroidCharset.cpp',

View File

@ -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;
}

View File

@ -10,6 +10,9 @@ SOURCES += [
'nsWinCharset.cpp',
]
if CONFIG['ENABLE_INTL_API']:
SOURCES += ['OSPreferences_win.cpp']
FINAL_LIBRARY = 'xul'
GENERATED_FILES = [