diff options
Diffstat (limited to 'intl/components/src/PluralRules.h')
-rw-r--r-- | intl/components/src/PluralRules.h | 221 |
1 files changed, 221 insertions, 0 deletions
diff --git a/intl/components/src/PluralRules.h b/intl/components/src/PluralRules.h new file mode 100644 index 0000000000..a413d54279 --- /dev/null +++ b/intl/components/src/PluralRules.h @@ -0,0 +1,221 @@ +/* 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 intl_components_PluralRules_h_ +#define intl_components_PluralRules_h_ + +#include <string_view> +#include <type_traits> +#include <utility> + +#include "mozilla/intl/ICUError.h" +#include "mozilla/intl/NumberFormat.h" +#include "mozilla/intl/NumberRangeFormat.h" +#include "mozilla/EnumSet.h" +#include "mozilla/Maybe.h" +#include "mozilla/Result.h" +#include "mozilla/Span.h" + +#include "unicode/utypes.h" + +namespace mozilla::intl { + +class PluralRules final { + public: + /** + * The set of keywords that a PluralRules object uses. + * + * https://tc39.es/ecma402/#sec-intl.pluralrules.prototype.resolvedoptions + */ + enum class Keyword : uint8_t { + Few, + Many, + One, + Other, + Two, + Zero, + }; + + /** + * The two different types of PluralRules objects that can be created. + * + * https://tc39.es/ecma402/#sec-properties-of-intl-pluralrules-instances + */ + enum class Type : uint8_t { + Cardinal, + Ordinal, + }; + + PluralRules(const PluralRules&) = delete; + PluralRules& operator=(const PluralRules&) = delete; + + /** + * Attempts to construct a PluralRules with the given locale and options. + */ + // TODO(1709880) use mozilla::Span instead of std::string_view. + static Result<UniquePtr<PluralRules>, ICUError> TryCreate( + std::string_view aLocale, const PluralRulesOptions& aOptions); + + /** + * Returns the PluralRules keyword that corresponds to the |aNumber|. + * + * https://tc39.es/ecma402/#sec-intl.pluralrules.prototype.select + */ + Result<PluralRules::Keyword, ICUError> Select(double aNumber) const; + + /** + * Returns the PluralRules keyword that corresponds to the range from |aStart| + * to |aEnd|. + * + * https://tc39.es/ecma402/#sec-intl.pluralrules.prototype.selectrange + */ + Result<PluralRules::Keyword, ICUError> SelectRange(double aStart, + double aEnd) const; + + /** + * Returns an EnumSet with the plural-rules categories that are supported by + * the locale that the PluralRules instance was created with. + */ + Result<EnumSet<PluralRules::Keyword>, ICUError> Categories() const; + + ~PluralRules(); + + private: + // The longest keyword is "other" + static const size_t MAX_KEYWORD_LENGTH = 5; + + UPluralRules* mPluralRules = nullptr; + UniquePtr<NumberFormat> mNumberFormat; + UniquePtr<NumberRangeFormat> mNumberRangeFormat; + + PluralRules(UPluralRules*&, UniquePtr<NumberFormat>&&, + UniquePtr<NumberRangeFormat>&&); + + /** + * Returns the PluralRules::Keyword that matches the UTF-16 string. + * Strings must be [u"few", u"many", u"one", u"other", u"two", u"zero"] + */ + static PluralRules::Keyword KeywordFromUtf16(Span<const char16_t> aKeyword); + + /** + * Returns the PluralRules::Keyword that matches the ASCII string. + * Strings must be ["few", "many", "one", "other", "two", "zero"] + */ + static PluralRules::Keyword KeywordFromAscii(Span<const char> aKeyword); +}; + +/** + * Options required for constructing a PluralRules object. + */ +struct MOZ_STACK_CLASS PluralRulesOptions { + /** + * Creates a NumberFormatOptions from the PluralRulesOptions. + */ + NumberFormatOptions ToNumberFormatOptions() const { + NumberFormatOptions options; + options.mRoundingMode = NumberFormatOptions::RoundingMode::HalfExpand; + + if (mFractionDigits.isSome()) { + options.mFractionDigits.emplace(mFractionDigits.ref()); + } + + if (mMinIntegerDigits.isSome()) { + options.mMinIntegerDigits.emplace(mMinIntegerDigits.ref()); + } + + if (mSignificantDigits.isSome()) { + options.mSignificantDigits.emplace(mSignificantDigits.ref()); + } + + options.mRoundingPriority = + NumberFormatOptions::RoundingPriority(mRoundingPriority); + + return options; + } + /** + * Creates a NumberFormatOptions from the PluralRulesOptions. + */ + NumberRangeFormatOptions ToNumberRangeFormatOptions() const { + NumberRangeFormatOptions options; + options.mRoundingMode = NumberRangeFormatOptions::RoundingMode::HalfExpand; + options.mRangeCollapse = NumberRangeFormatOptions::RangeCollapse::None; + options.mRangeIdentityFallback = + NumberRangeFormatOptions::RangeIdentityFallback::Range; + + if (mFractionDigits.isSome()) { + options.mFractionDigits.emplace(mFractionDigits.ref()); + } + + if (mMinIntegerDigits.isSome()) { + options.mMinIntegerDigits.emplace(mMinIntegerDigits.ref()); + } + + if (mSignificantDigits.isSome()) { + options.mSignificantDigits.emplace(mSignificantDigits.ref()); + } + + options.mRoundingPriority = + NumberFormatOptions::RoundingPriority(mRoundingPriority); + + return options; + } + + /** + * Set the plural type between cardinal and ordinal. + * + * https://tc39.es/ecma402/#sec-intl.pluralrules.prototype.resolvedoptions + */ + PluralRules::Type mPluralType = PluralRules::Type::Cardinal; + + /** + * Set the minimum number of integer digits. |min| must be a non-zero + * number. + * + * https://tc39.es/ecma402/#sec-intl.pluralrules.prototype.resolvedoptions + */ + Maybe<uint32_t> mMinIntegerDigits; + + /** + * Set the fraction digits settings. |min| can be zero, |max| must be + * larger-or-equal to |min|. + * + * https://tc39.es/ecma402/#sec-intl.pluralrules.prototype.resolvedoptions + */ + Maybe<std::pair<uint32_t, uint32_t>> mFractionDigits; + + /** + * Set the significant digits settings. |min| must be a non-zero number, |max| + * must be larger-or-equal to |min|. + * + * https://tc39.es/ecma402/#sec-intl.pluralrules.prototype.resolvedoptions + */ + Maybe<std::pair<uint32_t, uint32_t>> mSignificantDigits; + + /** + * Set the rounding priority. |mFractionDigits| and |mSignificantDigits| must + * both be set if the rounding priority isn't equal to "auto". + */ + enum class RoundingPriority { + Auto, + MorePrecision, + LessPrecision, + } mRoundingPriority = RoundingPriority::Auto; + + // Must be compatible with NumberFormatOptions::RoundingPriority. + static_assert(std::is_same_v< + std::underlying_type_t<RoundingPriority>, + std::underlying_type_t<NumberFormatOptions::RoundingPriority>>); + static_assert(RoundingPriority::Auto == + RoundingPriority(NumberFormatOptions::RoundingPriority::Auto)); + static_assert( + RoundingPriority::LessPrecision == + RoundingPriority(NumberFormatOptions::RoundingPriority::LessPrecision)); + static_assert( + RoundingPriority::MorePrecision == + RoundingPriority(NumberFormatOptions::RoundingPriority::MorePrecision)); +}; + +} // namespace mozilla::intl + +#endif |