morph 0.1.0
Asynchronous bridge between GUI thread and business models
Loading...
Searching...
No Matches
message.hpp File Reference

The MessageFormat 2 subset ui/1 accepts for t(key, fallback, args), and the CLDR plural rules its .match on a :number selects by. More...

#include <algorithm>
#include <array>
#include <cctype>
#include <cstddef>
#include <cstdint>
#include <expected>
#include <iterator>
#include <optional>
#include <string>
#include <string_view>
#include <utility>
#include <vector>
#include "../render/locale_format.hpp"
#include "../util/rational.hpp"
#include "value.hpp"

Go to the source code of this file.

Classes

struct  morph::ui::detail::PluralOperands
 CLDR's plural operands of a number as it is shown. More...
struct  morph::ui::MessagePart
 One part of a pattern: literal text, or a placeholder of a variable. More...
struct  morph::ui::MessageVariant
 One variant of a .match: a key per selector (* is the catch-all) and its pattern. More...
struct  morph::ui::MessagePattern
 A parsed message in the ui/1 subset of MessageFormat 2. More...
class  morph::ui::detail::MessageReader
 A recursive-descent reader over one message's text. More...
struct  morph::ui::MessageLocale
 The locale a message is formatted for. More...
struct  morph::ui::FormattedMessage
 A formatted message, and the variables it could not format. More...

Typedefs

using morph::ui::detail::PluralRule = PluralCategory (*)(PluralOperands const&) noexcept
 A language's plural rule.

Enumerations

enum class  morph::ui::PluralCategory : std::uint8_t {
  Zero , One , Two , Few ,
  Many , Other
}
 A CLDR plural category. More...
enum class  morph::ui::MessageFunction : std::uint8_t { None , Number , String }
 The formatting function a placeholder or a declaration names. More...

Functions

constexpr std::string_view morph::ui::categoryName (PluralCategory category)
 The keyword of a plural category, as a .match key spells it.
std::string morph::ui::detail::decimalText (math::Rational const &value, std::uint32_t places)
 The decimal text of an exact value at a number of places: rounded half to even, then written with exactly that many fraction digits, through integer arithmetic only.
std::optional< std::pair< math::Rational, std::uint32_t > > morph::ui::detail::numberOf (Value const &value)
 The places a number is shown with: an int has none, a decimal or quantity its declared places.
std::optional< std::string > morph::ui::formatNumber (Value const &value, render::NumericLocale const &numeric)
 Formats a number for display in a locale: at its own places, rounded half to even.
constexpr bool morph::ui::detail::between (std::uint64_t operand, std::uint64_t low, std::uint64_t high) noexcept
 Whether an operand lies in a CLDR range low..high.
constexpr bool morph::ui::detail::wholeMillion (PluralOperands const &n) noexcept
 CLDR's many of the Romance languages: an integer that is a non-zero multiple of a million.
constexpr PluralCategory morph::ui::detail::germanicPlural (PluralOperands const &n) noexcept
 en, de, nl, sv: one is i = 1 and v = 0.
constexpr PluralCategory morph::ui::detail::italianPlural (PluralOperands const &n) noexcept
 it: as English, and many for a whole million.
constexpr PluralCategory morph::ui::detail::spanishPlural (PluralOperands const &n) noexcept
 es: one is n = 1, and many a whole million.
constexpr PluralCategory morph::ui::detail::frenchPlural (PluralOperands const &n) noexcept
 fr, pt: one is i = 0..1, and many a whole million.
constexpr PluralCategory morph::ui::detail::polishPlural (PluralOperands const &n) noexcept
 pl: one, few for 2..4 outside 12..14, many for other integers, other for fractions.
constexpr PluralCategory morph::ui::detail::eastSlavicPlural (PluralOperands const &n) noexcept
 ru, uk: one for 1 outside 11, few for 2..4 outside 12..14, many for other integers.
constexpr PluralCategory morph::ui::detail::czechPlural (PluralOperands const &n) noexcept
 cs: one, few for 2..4, many for fractions.
constexpr PluralCategory morph::ui::detail::arabicPlural (PluralOperands const &n) noexcept
 ar: zero, one, two, few for 3..10 and many for 11..99 (both modulo 100).
PluralCategory morph::ui::pluralCategory (std::string_view locale, math::Rational const &value, std::uint32_t places)
 The CLDR plural category of a number in a locale.
std::expected< MessagePattern, std::string > morph::ui::parseMessage (std::string_view text)
 Parses a message in the ui/1 subset of MessageFormat 2.
std::optional< math::Rational > morph::ui::detail::parseExactKey (std::string_view key)
 Reads an exact-number variant key: -?[0-9]+(\.[0-9]+)?, at most 18 digits.
std::optional< int > morph::ui::detail::matchKey (std::string_view key, Value const &value, MessageFunction function, MessageLocale const &locale)
 Whether a variant key matches a selector's value.
void morph::ui::detail::formatPattern (std::vector< MessagePart > const &pattern, ValueRecord const &args, std::vector< std::pair< std::string, MessageFunction > > const &functions, MessageLocale const &locale, FormattedMessage &out)
 Formats one pattern.
FormattedMessage morph::ui::formatMessage (MessagePattern const &message, ValueRecord const &args, MessageLocale const &locale)
 Formats a parsed message with named arguments.

Variables

constexpr std::array< std::pair< std::string_view, PluralRule >, 13 > morph::ui::detail::kPluralRules
 The languages whose rules are carried, by language subtag.

Detailed Description

The MessageFormat 2 subset ui/1 accepts for t(key, fallback, args), and the CLDR plural rules its .match on a :number selects by.

Specified in docs/spec/ui/expressions.md, "Messages".

Definition in file message.hpp.

Typedef Documentation

◆ PluralRule

using morph::ui::detail::PluralRule = PluralCategory (*)(PluralOperands const&) noexcept

A language's plural rule.

Definition at line 239 of file message.hpp.

Enumeration Type Documentation

◆ PluralCategory

enum class morph::ui::PluralCategory : std::uint8_t
strong

A CLDR plural category.

Enumerator
Zero 

zero

One 

one

Two 

two

Few 

few

Many 

many

Other 

other

Definition at line 30 of file message.hpp.

◆ MessageFunction

enum class morph::ui::MessageFunction : std::uint8_t
strong

The formatting function a placeholder or a declaration names.

Enumerator
None 

No annotation: a string as it is, a number as :number formats it.

Number 

:number: locale number formatting, and plural selection.

String 

:string: the text, and selection by exact match.

Definition at line 293 of file message.hpp.

Function Documentation

◆ categoryName()

std::string_view morph::ui::categoryName ( PluralCategory category)
nodiscardconstexpr

The keyword of a plural category, as a .match key spells it.

Parameters
categoryThe category.
Returns
zero, one, two, few, many or other.

Definition at line 42 of file message.hpp.

◆ decimalText()

std::string morph::ui::detail::decimalText ( math::Rational const & value,
std::uint32_t places )
inlinenodiscard

The decimal text of an exact value at a number of places: rounded half to even, then written with exactly that many fraction digits, through integer arithmetic only.

Parameters
valueThe exact value.
placesThe number of fraction digits, at most math::kMaxDecimalPlaces.
Returns
Canonical text -?[0-9]+(\.[0-9]+)?; no sign on a value that rounds to zero.

Definition at line 54 of file message.hpp.

◆ numberOf()

std::optional< std::pair< math::Rational, std::uint32_t > > morph::ui::detail::numberOf ( Value const & value)
inlinenodiscard

The places a number is shown with: an int has none, a decimal or quantity its declared places.

Parameters
valueThe number.
Returns
The places, or std::nullopt when value is not a number.

Definition at line 78 of file message.hpp.

◆ formatNumber()

std::optional< std::string > morph::ui::formatNumber ( Value const & value,
render::NumericLocale const & numeric )
inlinenodiscard

Formats a number for display in a locale: at its own places, rounded half to even.

Parameters
valueAn int, decimal or quantity (its magnitude).
numericThe locale's separators, sign and digits.
Returns
The display text, or std::nullopt when value is not a number.

Definition at line 97 of file message.hpp.

◆ between()

bool morph::ui::detail::between ( std::uint64_t operand,
std::uint64_t low,
std::uint64_t high )
nodiscardconstexprnoexcept

Whether an operand lies in a CLDR range low..high.

Parameters
operandThe operand.
lowThe range's start.
highThe range's end.
Returns
Whether low <= operand <= high.

Definition at line 123 of file message.hpp.

◆ wholeMillion()

bool morph::ui::detail::wholeMillion ( PluralOperands const & n)
nodiscardconstexprnoexcept

CLDR's many of the Romance languages: an integer that is a non-zero multiple of a million.

Parameters
nThe operands.
Returns
Whether the number is a whole million.

Definition at line 130 of file message.hpp.

◆ germanicPlural()

PluralCategory morph::ui::detail::germanicPlural ( PluralOperands const & n)
nodiscardconstexprnoexcept

en, de, nl, sv: one is i = 1 and v = 0.

Parameters
nThe operands.
Returns
The category.

Definition at line 137 of file message.hpp.

◆ italianPlural()

PluralCategory morph::ui::detail::italianPlural ( PluralOperands const & n)
nodiscardconstexprnoexcept

it: as English, and many for a whole million.

Parameters
nThe operands.
Returns
The category.

Definition at line 144 of file message.hpp.

◆ spanishPlural()

PluralCategory morph::ui::detail::spanishPlural ( PluralOperands const & n)
nodiscardconstexprnoexcept

es: one is n = 1, and many a whole million.

Parameters
nThe operands.
Returns
The category.

Definition at line 154 of file message.hpp.

◆ frenchPlural()

PluralCategory morph::ui::detail::frenchPlural ( PluralOperands const & n)
nodiscardconstexprnoexcept

fr, pt: one is i = 0..1, and many a whole million.

Parameters
nThe operands.
Returns
The category.

Definition at line 164 of file message.hpp.

◆ polishPlural()

PluralCategory morph::ui::detail::polishPlural ( PluralOperands const & n)
nodiscardconstexprnoexcept

pl: one, few for 2..4 outside 12..14, many for other integers, other for fractions.

Parameters
nThe operands.
Returns
The category.

Definition at line 174 of file message.hpp.

◆ eastSlavicPlural()

PluralCategory morph::ui::detail::eastSlavicPlural ( PluralOperands const & n)
nodiscardconstexprnoexcept

ru, uk: one for 1 outside 11, few for 2..4 outside 12..14, many for other integers.

Parameters
nThe operands.
Returns
The category.

Definition at line 190 of file message.hpp.

◆ czechPlural()

PluralCategory morph::ui::detail::czechPlural ( PluralOperands const & n)
nodiscardconstexprnoexcept

cs: one, few for 2..4, many for fractions.

Parameters
nThe operands.
Returns
The category.

Definition at line 206 of file message.hpp.

◆ arabicPlural()

PluralCategory morph::ui::detail::arabicPlural ( PluralOperands const & n)
nodiscardconstexprnoexcept

ar: zero, one, two, few for 3..10 and many for 11..99 (both modulo 100).

Parameters
nThe operands.
Returns
The category.

Definition at line 219 of file message.hpp.

◆ pluralCategory()

PluralCategory morph::ui::pluralCategory ( std::string_view locale,
math::Rational const & value,
std::uint32_t places )
inlinenodiscard

The CLDR plural category of a number in a locale.

The operands are CLDR's: n the absolute value, i its integer digits, v the count of visible fraction digits (the decimal's places; an int has none). Rules are carried for en, de, nl, sv, it, es, pt, fr, pl, ru, uk, cs and ar; ja, zh, ko and every other language select only other. The locale's language subtag decides, case-insensitively, so pl-PL uses the Polish rules.

Parameters
localeA BCP 47 locale, such as pl-PL.
valueThe exact number.
placesThe visible fraction digits.
Returns
The category.

Definition at line 270 of file message.hpp.

◆ parseMessage()

std::expected< MessagePattern, std::string > morph::ui::parseMessage ( std::string_view text)
inlinenodiscard

Parses a message in the ui/1 subset of MessageFormat 2.

The subset is: text with \\endiskip escapes; placeholders {$name}, {$name :number} and {$name :string}; .input declarations of the same form; and .match over declared :number or :string variables, with variant keys that are plural categories, exact numbers (0, =0), exact strings, or *, and a required catch-all. Literal placeholders, options, markup and .local are outside it.

Parameters
textThe message source.
Returns
The parsed message, or the reason it is refused.

Definition at line 631 of file message.hpp.

◆ parseExactKey()

std::optional< math::Rational > morph::ui::detail::parseExactKey ( std::string_view key)
inlinenodiscard

Reads an exact-number variant key: -?[0-9]+(\.[0-9]+)?, at most 18 digits.

Parameters
keyThe key, without a leading =.
Returns
The exact value, or std::nullopt when the key is not such a number.

Definition at line 656 of file message.hpp.

◆ matchKey()

std::optional< int > morph::ui::detail::matchKey ( std::string_view key,
Value const & value,
MessageFunction function,
MessageLocale const & locale )
inlinenodiscard

Whether a variant key matches a selector's value.

Parameters
keyThe key.
valueThe selector's value.
functionThe selector's function.
localeThe locale for plural rules.
Returns
0 for an exact match, 1 for a plural-category match, 2 for *, std::nullopt for no match.

Definition at line 691 of file message.hpp.

◆ formatPattern()

void morph::ui::detail::formatPattern ( std::vector< MessagePart > const & pattern,
ValueRecord const & args,
std::vector< std::pair< std::string, MessageFunction > > const & functions,
MessageLocale const & locale,
FormattedMessage & out )
inline

Formats one pattern.

Parameters
patternThe parts.
argsThe named arguments.
functionsThe .input declarations, which annotate a bare placeholder of their variable.
localeThe locale.
outThe message being built.

Definition at line 732 of file message.hpp.

◆ formatMessage()

FormattedMessage morph::ui::formatMessage ( MessagePattern const & message,
ValueRecord const & args,
MessageLocale const & locale )
inlinenodiscard

Formats a parsed message with named arguments.

A .match selects the variant whose keys match best, selector by selector: an exact key before a plural category before *.

Parameters
messageThe parsed message.
argsThe named arguments.
localeThe locale.
Returns
The text and the errors of the variables that could not be formatted.

Definition at line 775 of file message.hpp.

Variable Documentation

◆ kPluralRules

std::array<std::pair<std::string_view, PluralRule>, 13> morph::ui::detail::kPluralRules
inlineconstexpr
Initial value:
= {{
{"en", &germanicPlural},
{"de", &germanicPlural},
{"nl", &germanicPlural},
{"sv", &germanicPlural},
{"it", &italianPlural},
{"es", &spanishPlural},
{"fr", &frenchPlural},
{"pt", &frenchPlural},
{"pl", &polishPlural},
{"ru", &eastSlavicPlural},
{"uk", &eastSlavicPlural},
{"cs", &czechPlural},
{"ar", &arabicPlural},
}}
constexpr PluralCategory eastSlavicPlural(PluralOperands const &n) noexcept
ru, uk: one for 1 outside 11, few for 2..4 outside 12..14, many for other integers.
Definition message.hpp:190
constexpr PluralCategory polishPlural(PluralOperands const &n) noexcept
pl: one, few for 2..4 outside 12..14, many for other integers, other for fractions.
Definition message.hpp:174
constexpr PluralCategory arabicPlural(PluralOperands const &n) noexcept
ar: zero, one, two, few for 3..10 and many for 11..99 (both modulo 100).
Definition message.hpp:219
constexpr PluralCategory spanishPlural(PluralOperands const &n) noexcept
es: one is n = 1, and many a whole million.
Definition message.hpp:154
constexpr PluralCategory czechPlural(PluralOperands const &n) noexcept
cs: one, few for 2..4, many for fractions.
Definition message.hpp:206
constexpr PluralCategory germanicPlural(PluralOperands const &n) noexcept
en, de, nl, sv: one is i = 1 and v = 0.
Definition message.hpp:137
constexpr PluralCategory frenchPlural(PluralOperands const &n) noexcept
fr, pt: one is i = 0..1, and many a whole million.
Definition message.hpp:164

The languages whose rules are carried, by language subtag.

Definition at line 242 of file message.hpp.