pub struct LangSu { /* private fields */ }Implementations§
Trait Implementations§
Source§impl Lang for LangSu
impl Lang for LangSu
Source§fn default_currency(&self) -> &str
fn default_currency(&self) -> &str
This language’s own to_currency(currency=...) default,
read from the live Python signature. Only 44 of 156 use EUR.
Source§fn default_separator(&self) -> &str
fn default_separator(&self) -> &str
This language’s own to_currency(separator=...) default,
read from the live Python signature. Base’s is “,”, but only
36 of 149 languages actually use it — most default to “ “ or a
conjunction, so inheriting Base’s comma silently corrupts them.
Source§fn to_cardinal(&self, value: &BigInt) -> Result<String>
fn to_cardinal(&self, value: &BigInt) -> Result<String>
Port of Num2Word_SU.to_cardinal, integer path only.
Python does n = str(number).strip(), peels a leading “-” into
ret = self.negword, then branches on whether n contains “.”.
str(int) never does, so integers always take the else branch:
(ret + self._int_to_word(int(n))).strip(). Stripping the “-” from
the string and re-parsing is exactly abs(). The float branch
(pointword + per-digit decimals) is out of scope.
The trailing .strip() is what removes negword’s built-in trailing
space when _int_to_word returns “” — which it never does — and is
otherwise a no-op, since no _int_to_word branch pads its result.
Kept anyway to match the Python exactly.
Source§fn to_ordinal(&self, value: &BigInt) -> Result<String>
fn to_ordinal(&self, value: &BigInt) -> Result<String>
Port of Num2Word_SU.to_ordinal: cardinal + “-na”, sign and all
(bug 5). Never errors, because to_cardinal never does.
Source§fn to_ordinal_num(&self, value: &BigInt) -> Result<String>
fn to_ordinal_num(&self, value: &BigInt) -> Result<String>
Port of Num2Word_SU.to_ordinal_num: str(number) + "." (bug 4).
Note this overrides the base default (return value) and is the one
mode that keeps the digits and the minus sign: -1 → “-1.”.
Source§fn to_year(&self, value: &BigInt) -> Result<String>
fn to_year(&self, value: &BigInt) -> Result<String>
Port of Num2Word_SU.to_year. Python’s signature is
to_year(self, val, longval=True), but longval is accepted and
ignored — the body is just return self.to_cardinal(val), so years
get no century/teen treatment: 1999 → “hiji rebu salapan ratus
salapan puluh salapan”.
Source§fn cardinal_float_entry(
&self,
value: &FloatValue,
precision_override: Option<u32>,
) -> Result<String>
fn cardinal_float_entry( &self, value: &FloatValue, precision_override: Option<u32>, ) -> Result<String>
to_cardinal(float/Decimal) FULL routing.
Python’s to_cardinal is string-driven: "." in str(number) picks the
decimal grammar, and str(5.0) is "5.0", so whole floats keep
their “.0” tail (“lima point zero”) instead of taking Base’s
whole-value integer route. Without a visible point the sign-free string
lands in int(n):
Decimal("5")->"5"-> the integer path (“lima”);- repr-exponential floats (
str(1e16)=="1e+16") and exponential Decimals (str(Decimal("1E+2"))=="1E+2") ->int()raises ValueError, type and message reproduced by [py_int].
Source§fn ordinal_float_entry(&self, value: &FloatValue) -> Result<String>
fn ordinal_float_entry(&self, value: &FloatValue) -> Result<String>
to_ordinal(float/Decimal): Python’s to_ordinal is
self.to_cardinal(number) + "-na" with no type guard, so floats get
the full decimal phrase plus the suffix (“lima point zero-na”) and the
exponential-form ValueError propagates unchanged.
Source§fn ordinal_num_float_entry(
&self,
_value: &FloatValue,
repr_str: &str,
) -> Result<String>
fn ordinal_num_float_entry( &self, _value: &FloatValue, repr_str: &str, ) -> Result<String>
to_ordinal_num(float/Decimal): str(number) + ".", no int()
anywhere — so it succeeds where the other modes raise (“1e+16.”) and
“-0.0” keeps its textual minus (“-0.0.”). repr_str is the
Python-side str(number).
Source§fn year_float_entry(&self, value: &FloatValue) -> Result<String>
fn year_float_entry(&self, value: &FloatValue) -> Result<String>
to_year(float/Decimal): to_year is return self.to_cardinal(val),
so the full float routing above applies verbatim, ValueErrors included.
Source§fn str_to_number(&self, s: &str) -> Result<ParsedNumber>
fn str_to_number(&self, s: &str) -> Result<ParsedNumber>
converter.str_to_number — Base’s Decimal(value), which SU does not
override. The Inf interception reproduces what happens next on the
pinned path: to_cardinal(Decimal("Infinity")) reads str(number) ==
“Infinity” (the “-Infinity” case strips its sign textually first),
finds no “.”, and dies in int("Infinity") with ValueError. The
binding otherwise maps ParsedNumber::Inf to the base integer path’s
OverflowError before any SU code runs, so the ValueError must be
raised here. (NaN needs no interception: the binding’s ValueError
already matches int("NaN")’s type.)
Source§fn to_cardinal_float(
&self,
value: &FloatValue,
_precision_override: Option<u32>,
) -> Result<String>
fn to_cardinal_float( &self, value: &FloatValue, _precision_override: Option<u32>, ) -> Result<String>
Port of the float/Decimal branch of Num2Word_SU.to_cardinal.
SU overrides to_cardinal outright and handles non-integers inline
by doing string surgery on str(number). It never calls the base
to_cardinal_float, never builds float2tuple, and never reads
self.precision. So none of the float2tuple rounding artefacts
apply here — the fractional digits come straight off the repr string,
one _int_to_word per digit character:
n = str(number).strip()
if n.startswith("-"): n = n[1:]; ret = self.negword
else: ret = ""
if "." in n:
left, right = n.split(".", 1)
ret += self._int_to_word(int(left)) + " " + self.pointword + " "
for digit in right:
ret += self._int_to_word(int(digit)) + " "
return ret.strip()
else:
return (ret + self._int_to_word(int(n))).strip()precision_override is ignored: the dispatcher’s precision=
kwarg writes onto self.precision, which this code path never consults,
so it has no effect on SU’s float output (verified below).
Consequences reproduced:
1.005→ “hiji point zero zero lima” and2.675→ “dua point genep tujuh lima”: the repr digits are taken verbatim, so the f64 artefacts (674.9999…) never arise — there is noabs(value-pre)*10**phere.- Trailing repr zeros survive:
str(1.0)== “1.0” → “hiji point zero”, and the Decimal1.10→ “hiji point hiji zero”. - Bug 3 leaks in: a
left≥ 10^9 is emitted as bare digits, so the Decimal98746251323029.99→ “98746251323029 point salapan salapan”. - The sign is peeled off
str(number)exactly as Python does, sostr(-0.0)== “-0.0” would yield “minus zero point zero” (Rust’s fixed formatting preserves the negative-zero sign, matching repr).
Source§fn currency_forms(&self, code: &str) -> Option<&CurrencyForms>
fn currency_forms(&self, code: &str) -> Option<&CurrencyForms>
CURRENCY_FORMS[code] — a plain lookup with no IDR fallback.
This is the to_cheque view of the table (self.CURRENCY_FORMS[currency]
-> KeyError -> NotImplementedError). to_currency does not go through
here; it overrides the whole method and applies its own .get(..., IDR)
fallback. Returning None for an unknown code is what makes
cheque:GBP raise while currency:GBP answers in rupiah.
Source§fn to_currency(
&self,
val: &CurrencyValue,
currency: &str,
cents: bool,
separator: Option<&str>,
_adjective: bool,
) -> Result<String>
fn to_currency( &self, val: &CurrencyValue, currency: &str, cents: bool, separator: Option<&str>, _adjective: bool, ) -> Result<String>
Port of Num2Word_SU.to_currency.
Mirrors the Python line for line: sign check, str(val).split("."),
a two-character truncating slice of the fraction, then a hand-rolled
singular/plural pick per segment.
adjective is accepted and ignored, exactly as in Python — SU never
reads it and has no CURRENCY_ADJECTIVES, so adjective=True changes
nothing. pluralize / _money_verbose / _cents_verbose /
_cents_terse / CURRENCY_PRECISION are likewise all bypassed.
fn pointword(&self) -> &str
fn cards(&self) -> &Cards
fn maxval(&self) -> &BigInt
fn is_title(&self) -> bool
fn exclude_title(&self) -> &[String]
Source§fn merge(&self, _l: (&str, &BigInt), _r: (&str, &BigInt)) -> (String, BigInt)
fn merge(&self, _l: (&str, &BigInt), _r: (&str, &BigInt)) -> (String, BigInt)
merge is abstract in Python (raise NotImplementedError).
Languages that override to_cardinal never reach it.fn title(&self, value: &str) -> String
Source§fn currency_precision(&self, _code: &str) -> i64
fn currency_precision(&self, _code: &str) -> i64
CURRENCY_PRECISION.get(code, 100) — subunits per unit. 1000 for
3-decimal currencies (BHD/KWD/…), 1 for no-subunit currencies.Source§fn pluralize(&self, _n: &BigInt, _forms: &[String]) -> Result<String>
fn pluralize(&self, _n: &BigInt, _forms: &[String]) -> Result<String>
pluralize(n, forms). Abstract in Python (raise NotImplementedError),
so the default raises rather than guessing a plural rule.fn money_verbose(&self, number: &BigInt, _currency: &str) -> Result<String>
fn cents_verbose(&self, number: &BigInt, _currency: &str) -> Result<String>
fn cents_terse(&self, number: &BigInt, currency: &str) -> Result<String>
Source§fn cardinal_from_decimal(&self, value: &BigDecimal) -> Result<String>
fn cardinal_from_decimal(&self, value: &BigDecimal) -> Result<String>
self.to_cardinal(float(right)), i.e. through the
float path, so the default routes there rather than raising.Source§fn default_adjective(&self) -> bool
fn default_adjective(&self) -> bool
to_currency(adjective=...) default. Base’s is
False; only Mongolian defaults to True.fn to_cheque(&self, val: &BigDecimal, currency: &str) -> Result<String>
Source§fn to_fraction(
&self,
numerator: &BigInt,
denominator: &BigInt,
) -> Result<String>
fn to_fraction( &self, numerator: &BigInt, denominator: &BigInt, ) -> Result<String>
Num2Word_Base.to_fraction (issue #584). EN/DE/ES/FR/IT/PT and the
aero profiles override with idiomatic forms (half/quarter/Drittel).Source§fn cardinal_with_pointword(
&self,
_value: &FloatValue,
_pointword: &str,
_precision_override: Option<u32>,
) -> Result<String>
fn cardinal_with_pointword( &self, _value: &FloatValue, _pointword: &str, _precision_override: Option<u32>, ) -> Result<String>
to_cardinal(value) with the pointword
swapped for this one call. Only reachable through
ParsedNumber::DecPoint, so only PT_BR implements it.fn to_cardinal_kw(&self, value: &BigInt, kw: &Kwargs) -> Result<String>
fn to_ordinal_kw(&self, value: &BigInt, kw: &Kwargs) -> Result<String>
fn to_ordinal_num_kw(&self, value: &BigInt, kw: &Kwargs) -> Result<String>
fn to_year_kw(&self, value: &BigInt, kw: &Kwargs) -> Result<String>
fn to_currency_kw( &self, val: &CurrencyValue, currency: &str, cents: bool, separator: Option<&str>, adjective: bool, kw: &Kwargs, ) -> Result<String>
fn to_cardinal_float_kw( &self, value: &FloatValue, precision_override: Option<u32>, kw: &Kwargs, ) -> Result<String>
Source§fn es_currency_ordinal_fires(&self) -> bool
fn es_currency_ordinal_fires(&self) -> bool
Num2Word_ES
apocopates 1 → “un euro” in to_currency, bypassing to_cardinal, so
the stash never fires (false, the default). The regional es_XX
classes inherit Base.to_currency, whose _money_verbose calls
to_cardinal(1) → the stash fires → “primero córdoba” (true).Source§fn neg_zero_decimal(&self, _to: &str) -> Option<Result<String>>
fn neg_zero_decimal(&self, _to: &str) -> Option<Result<String>>
Decimal('-0.0') for mode to, which BigDecimal cannot
represent (it has no signed zero). None — the default — means the
value coincides with float -0.0, so the binding’s Float{-0.0}
demotion is exact. The ~10 languages that render the Decimal form
differently (ce/cy “dim”/“ноль” via the integer path, pl its float
grammar with the negword, rm a TypeError) override this to serve it
natively instead of leaning on a Python fallback.Source§fn inf_result(&self, _negative: bool, _to: &str) -> Result<String>
fn inf_result(&self, _negative: bool, _to: &str) -> Result<String>
str_to_number produced Decimal('Infinity') / -Infinity. Base’s
integer path does int(Decimal('Infinity')) → OverflowError. The many
self-contained converters that feed the raw token to int("Infinity")
get ValueError instead and override this. to is the requested mode.Source§fn nan_result(&self, _to: &str) -> Result<String>
fn nan_result(&self, _to: &str) -> Result<String>
str_to_number produced Decimal('NaN'). Base’s int(NaN) raises
ValueError (caught into the float path, which raises ValueError again).
Languages whose parse raises decimal.InvalidOperation first override.Source§fn python_maxval(&self) -> Option<BigInt>
fn python_maxval(&self) -> Option<BigInt>
getattr(converter, "MAXVAL", None) — the maxval() API.
Engine languages get it from their card table (Base sets
MAXVAL = 1000 * top_card); self-contained ones mostly lack the
attribute (None). The zero sentinel in maxval() means “unset”.