/* 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 #include #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, 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 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 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, ICUError> Categories() const; ~PluralRules(); private: // The longest keyword is "other" static const size_t MAX_KEYWORD_LENGTH = 5; UPluralRules* mPluralRules = nullptr; UniquePtr mNumberFormat; UniquePtr mNumberRangeFormat; PluralRules(UPluralRules*&, UniquePtr&&, UniquePtr&&); /** * 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 aKeyword); /** * Returns the PluralRules::Keyword that matches the ASCII string. * Strings must be ["few", "many", "one", "other", "two", "zero"] */ static PluralRules::Keyword KeywordFromAscii(Span 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.mStripTrailingZero = mStripTrailingZero; options.mRoundingIncrement = mRoundingIncrement; options.mRoundingMode = NumberFormatOptions::RoundingMode(mRoundingMode); 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.mStripTrailingZero = mStripTrailingZero; options.mRoundingIncrement = mRoundingIncrement; options.mRoundingMode = NumberFormatOptions::RoundingMode(mRoundingMode); 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 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> 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> mSignificantDigits; /** * Set to true to strip trailing zeros after the decimal point for integer * values. */ bool mStripTrailingZero = false; /** * Set the rounding increment, which must be a non-zero number. */ uint32_t mRoundingIncrement = 1; /** * Set the rounding mode. */ using RoundingMode = NumberFormatOptions::RoundingMode; RoundingMode mRoundingMode = RoundingMode::HalfExpand; /** * Set the rounding priority. |mFractionDigits| and |mSignificantDigits| must * both be set if the rounding priority isn't equal to "auto". */ using RoundingPriority = NumberFormatOptions::RoundingPriority; RoundingPriority mRoundingPriority = RoundingPriority::Auto; }; } // namespace mozilla::intl #endif