2018-01-06 11:23:09 +03:00
|
|
|
/* -*- 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/. */
|
|
|
|
|
2018-01-26 01:50:32 +03:00
|
|
|
#ifndef mozilla_intl_MozLocale_h__
|
|
|
|
#define mozilla_intl_MozLocale_h__
|
2018-01-06 11:23:09 +03:00
|
|
|
|
|
|
|
#include "nsString.h"
|
2018-01-26 01:50:32 +03:00
|
|
|
#include "nsTArray.h"
|
2019-11-20 02:04:06 +03:00
|
|
|
#include "MozLocaleBindings.h"
|
2018-01-06 11:23:09 +03:00
|
|
|
|
|
|
|
namespace mozilla {
|
|
|
|
namespace intl {
|
|
|
|
|
|
|
|
/**
|
2018-01-26 01:50:32 +03:00
|
|
|
* Locale class is a core representation of a single locale.
|
|
|
|
*
|
|
|
|
* A locale is a data object representing a combination of language, script,
|
|
|
|
* region, variant and a set of regional extension preferences that may further
|
|
|
|
* specify particular user choices like calendar, numbering system, etc.
|
|
|
|
*
|
|
|
|
* A locale can be expressed as a language tag string, like a simple "fr" for
|
|
|
|
* French, or a more specific "sr-Cyrl-RS-u-hc-h12" for Serbian in Russia with a
|
|
|
|
* Cyrylic script, and hour cycle selected to be `h12`.
|
|
|
|
*
|
|
|
|
* The format of the language tag follows BCP47 standard and implements a subset
|
|
|
|
* of it. In the future we expect to extend this class to cover more subtags and
|
|
|
|
* extensions.
|
|
|
|
*
|
|
|
|
* BCP47: https://tools.ietf.org/html/bcp47
|
|
|
|
*
|
|
|
|
* The aim of this class it aid in validation, parsing and canonicalization of
|
|
|
|
* the string.
|
|
|
|
*
|
|
|
|
* It allows the user to input any well-formed BCP47 language tag and operate
|
|
|
|
* on its subtags in a canonicalized form.
|
|
|
|
*
|
|
|
|
* It should be used for all operations on language tags, and together with
|
|
|
|
* LocaleService::NegotiateLanguages for language negotiation.
|
|
|
|
*
|
|
|
|
* Example:
|
|
|
|
*
|
|
|
|
* Locale loc = Locale("de-at");
|
|
|
|
*
|
|
|
|
* ASSERT_TRUE(loc.GetLanguage().Equals("de"));
|
|
|
|
* ASSERT_TRUE(loc.GetScript().IsEmpty());
|
|
|
|
* ASSERT_TRUE(loc.GetRegion().Equals("AT")); // canonicalized to upper case
|
2018-01-06 11:23:09 +03:00
|
|
|
*
|
|
|
|
*
|
|
|
|
* Note: The file name is `MozLocale` to avoid compilation problems on
|
|
|
|
* case-insensitive Windows. The class name is `Locale`.
|
|
|
|
*/
|
|
|
|
class Locale {
|
|
|
|
public:
|
2018-04-27 00:18:08 +03:00
|
|
|
/**
|
|
|
|
* The constructor expects the input to be a well-formed BCP47-style locale
|
|
|
|
* string.
|
|
|
|
*
|
|
|
|
* Two operations are performed on the well-formed language tags:
|
|
|
|
*
|
|
|
|
* * Case normalization to conform with BCP47 (e.g. "eN-uS" -> "en-US")
|
|
|
|
* * Underscore delimiters replaced with dashed (e.g. "en_US" -> "en-US")
|
|
|
|
*
|
|
|
|
* If the input language tag string is not well-formed, the Locale will be
|
2018-08-23 21:21:38 +03:00
|
|
|
* created with its flag `mWellFormed` set to false which will make the Locale
|
|
|
|
* never match.
|
2018-04-27 00:18:08 +03:00
|
|
|
*/
|
2018-01-26 01:50:32 +03:00
|
|
|
explicit Locale(const nsACString& aLocale);
|
|
|
|
explicit Locale(const char* aLocale) : Locale(nsDependentCString(aLocale)){};
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2019-11-20 02:04:06 +03:00
|
|
|
const nsDependentCSubstring GetLanguage() const;
|
|
|
|
const nsDependentCSubstring GetScript() const;
|
|
|
|
const nsDependentCSubstring GetRegion() const;
|
|
|
|
void GetVariants(nsTArray<nsCString>& aRetVal) const;
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2018-04-27 00:18:08 +03:00
|
|
|
/**
|
|
|
|
* Returns a `true` if the locale is well-formed, such that the
|
|
|
|
* Locale object can validly be matched against others.
|
|
|
|
*/
|
2018-08-23 21:21:38 +03:00
|
|
|
bool IsWellFormed() const { return mIsWellFormed; }
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2018-04-27 00:18:08 +03:00
|
|
|
/**
|
|
|
|
* Returns a canonicalized language tag string of the locale.
|
|
|
|
*/
|
2018-01-31 23:28:51 +03:00
|
|
|
const nsCString AsString() const;
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2018-04-27 00:18:08 +03:00
|
|
|
/**
|
|
|
|
* Compares two locales optionally treating one or both of
|
|
|
|
* the locales as a range.
|
|
|
|
*
|
|
|
|
* In case one of the locales is treated as a range, its
|
|
|
|
* empty fields are considered to match all possible
|
|
|
|
* values of the same field on the other locale.
|
|
|
|
*
|
|
|
|
* Example:
|
|
|
|
*
|
|
|
|
* Locale("en").Matches(Locale("en-US"), false, false) // false
|
|
|
|
* Locale("en").Matches(Locale("en-US"), true, false) // true
|
|
|
|
*
|
|
|
|
* The latter returns true because the region field on the "en"
|
|
|
|
* locale is being treated as a range and matches any region field
|
|
|
|
* value including "US" of the other locale.
|
|
|
|
*/
|
2018-01-26 01:50:32 +03:00
|
|
|
bool Matches(const Locale& aOther, bool aThisRange, bool aOtherRange) const;
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2018-04-27 00:18:08 +03:00
|
|
|
/**
|
|
|
|
* This operation uses CLDR data to build a more specific version
|
|
|
|
* of a generic locale.
|
|
|
|
*
|
|
|
|
* Example:
|
|
|
|
*
|
2020-02-22 00:03:15 +03:00
|
|
|
* Locale("en").Maximize().AsString(); // "en-Latn-US"
|
2018-04-27 00:18:08 +03:00
|
|
|
*/
|
2020-02-22 00:03:15 +03:00
|
|
|
bool Maximize();
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2018-04-27 00:18:08 +03:00
|
|
|
/**
|
|
|
|
* Clears the variants field of the Locale object.
|
|
|
|
*/
|
2018-01-26 01:50:32 +03:00
|
|
|
void ClearVariants();
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2018-04-27 00:18:08 +03:00
|
|
|
/**
|
|
|
|
* Clears the region field of the Locale object.
|
|
|
|
*/
|
2018-01-26 01:50:32 +03:00
|
|
|
void ClearRegion();
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2018-04-27 00:18:08 +03:00
|
|
|
/**
|
|
|
|
* Marks the locale as invalid which in turns makes
|
|
|
|
* it to be skipped by most LocaleService operations.
|
|
|
|
*/
|
2018-08-23 21:21:38 +03:00
|
|
|
void Invalidate() { mIsWellFormed = false; }
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2018-04-27 00:18:08 +03:00
|
|
|
/**
|
|
|
|
* Compares two locales expecting all fields to match each other.
|
|
|
|
*/
|
2018-01-26 04:43:51 +03:00
|
|
|
bool operator==(const Locale& aOther) {
|
2018-08-23 21:21:38 +03:00
|
|
|
// Note: non-well-formed Locale objects are never
|
|
|
|
// treated as equal to anything
|
|
|
|
// (even other non-well-formed ones).
|
2019-11-20 02:04:06 +03:00
|
|
|
return Matches(aOther, false, false);
|
2018-01-06 11:23:09 +03:00
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2019-11-20 02:04:06 +03:00
|
|
|
Locale(Locale&& aOther)
|
|
|
|
: mIsWellFormed(aOther.mIsWellFormed), mRaw(std::move(aOther.mRaw)) {}
|
|
|
|
|
|
|
|
ffi::LanguageIdentifier* Raw() { return mRaw.get(); }
|
|
|
|
const ffi::LanguageIdentifier* Raw() const { return mRaw.get(); }
|
|
|
|
|
2018-01-06 11:23:09 +03:00
|
|
|
private:
|
2019-11-20 02:04:06 +03:00
|
|
|
bool mIsWellFormed;
|
|
|
|
|
|
|
|
// Notice. We had to remove `const` to allow for move constructor, but
|
|
|
|
// that makes it possible to nullptr `mRaw`. Just don't.
|
|
|
|
UniquePtr<ffi::LanguageIdentifier> mRaw;
|
2018-01-06 11:23:09 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace intl
|
|
|
|
} // namespace mozilla
|
|
|
|
|
2020-03-20 20:04:27 +03:00
|
|
|
MOZ_DECLARE_RELOCATE_USING_MOVE_CONSTRUCTOR(mozilla::intl::Locale)
|
2018-01-26 01:50:32 +03:00
|
|
|
|
|
|
|
#endif /* mozilla_intl_MozLocale_h__ */
|