pub struct LangPs { /* private fields */ }Implementations§
Trait Implementations§
Source§impl Lang for LangPs
impl Lang for LangPs
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>
Python’s to_cardinal.
The original works on str(number): it strips a leading "-" off the
decimal text and sets ret = self.negword, then feeds the remainder
back through int(). Removing the sign character from a decimal
rendering is exactly abs(), so operating on the BigInt directly is
equivalent for integral input.
The "." in n branch (float/point path) cannot trigger: str() of an
integer never contains a dot. Out of scope regardless.
The trailing .strip() is preserved for fidelity even though it is a
no-op here — negword supplies a leading space only when followed by
a word, and _int_to_word never returns padded output.
Source§fn to_ordinal(&self, value: &BigInt) -> Result<String>
fn to_ordinal(&self, value: &BigInt) -> Result<String>
return cardinal + "-م". No sign, zero or range handling whatsoever, so
to_ordinal(0) == “zero-م” and to_ordinal(-1) == “minus یو-م”.
Source§fn to_ordinal_num(&self, value: &BigInt) -> Result<String>
fn to_ordinal_num(&self, value: &BigInt) -> Result<String>
return str(number) + "." — the numeral, untouched, plus a dot.
Source§fn to_year(&self, value: &BigInt) -> Result<String>
fn to_year(&self, value: &BigInt) -> Result<String>
def to_year(self, val, longval=True): return self.to_cardinal(val).
longval is ignored, so years get no century/“nineteen-eighty” split —
1999 is the plain cardinal “یو زره نهه سل نوي نهه”. Overridden
explicitly rather than leaning on the identical trait default, to keep
the correspondence with the Python method visible.
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>
The float/Decimal half of Num2Word_PS.to_cardinal.
n = str(number).strip()
if n.startswith("-"):
n = n[1:]
ret = self.negword # "minus "
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()PS overrides to_cardinal outright and handles non-integers inline on
str(number); it never delegates to Num2Word_Base.to_cardinal_float
and never reads self.precision. precision_override is therefore
dropped on the floor exactly as Python does (confirmed: precision=
leaves PS’s cardinal output unchanged). Every digit — integer part and
each fractional character alike — is named by the same _int_to_word
the integer path uses, so the “no teens” and >= 10**9 stringify bugs
(module bugs 1 and 4) leak into the float output too.
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) — the FULL entry. Python routes every
float/Decimal through the str(number) algorithm, so a whole value
keeps its visible point: 5.0 -> “پنځه point zero”, -0.0 ->
“minus zero point zero”, Decimal("5.00") -> “پنځه point zero zero”.
The base default’s whole-value integer shortcut must not fire here.
Source§fn ordinal_float_entry(&self, value: &FloatValue) -> Result<String>
fn ordinal_float_entry(&self, value: &FloatValue) -> Result<String>
to_ordinal(float/Decimal): self.to_cardinal(number) + "-م" — the
cardinal being the string algorithm above, suffix glued on raw.
Exponent forms raise ValueError before the suffix is appended.
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) + ".". repr_str is
the binding’s Python str(value), so exponent forms echo verbatim:
to_ordinal_num(1e16) == “1e+16.”.
Source§fn year_float_entry(&self, value: &FloatValue) -> Result<String>
fn year_float_entry(&self, value: &FloatValue) -> Result<String>
to_year(float/Decimal): PS’s to_year forwards to to_cardinal,
which for a float/Decimal is the string algorithm above.
Source§fn str_to_number(&self, s: &str) -> Result<ParsedNumber>
fn str_to_number(&self, s: &str) -> Result<ParsedNumber>
Base’s str_to_number parses “Infinity” successfully; PS’s
ValueError comes later, from int("Infinity") inside to_cardinal.
The parse is the plain default and the two specials are served natively
by the Lang::inf_result / Lang::nan_result hooks below.
Source§fn inf_result(&self, _negative: bool, _to: &str) -> Result<String>
fn inf_result(&self, _negative: bool, _to: &str) -> Result<String>
Decimal("Infinity") / -Infinity. PS’s to_cardinal does
int(str(number)), and str(Decimal("Infinity")) is “Infinity” —
int("Infinity") raises ValueError, not the base path’s
OverflowError. -Infinity strips its “-” textually first, so both signs
raise with the token “Infinity”. Every mode reaches the same int()
(to_ordinal/to_year forward to to_cardinal), so to is unread.
Source§fn nan_result(&self, _to: &str) -> Result<String>
fn nan_result(&self, _to: &str) -> Result<String>
Decimal("NaN"). str(Decimal("NaN")) is “NaN”; int("NaN") raises
ValueError — the same type the base default gives, made byte-exact.
Source§fn currency_forms(&self, code: &str) -> Option<&CurrencyForms>
fn currency_forms(&self, code: &str) -> Option<&CurrencyForms>
self.CURRENCY_FORMS[code] — the strict lookup.
This hook models Python’s subscript, which is what
Num2Word_Base.to_cheque uses (self.CURRENCY_FORMS[currency] inside
a try/except KeyError). Returning None for an unknown code is what
makes currency::default_to_cheque raise the exact
NotImplementedError the corpus pins for
cheque:GBP/JPY/KWD/BHD/INR/CNY/CHF — message verified byte for byte
against the interpreter: Currency code "GBP" not implemented for "Num2Word_PS".
LangPs::to_currency deliberately does not call this: PS’s own
override uses .get(code, <first value>) and must never raise (bug 9).
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_PS.to_currency.
def to_currency(self, val, currency="AFN", cents=True,
separator=" ", adjective=False):
is_negative = False
if val < 0:
is_negative = True
val = abs(val)
parts = str(val).split(".")
left = int(parts[0]) if parts[0] else 0
right = int(parts[1][:2].ljust(2, "0")) if len(parts) > 1 and parts[1] else 0
cr1, cr2 = self.CURRENCY_FORMS.get(
currency, list(self.CURRENCY_FORMS.values())[0]
)
left_str = self._int_to_word(left)
result = left_str + " " + (cr1[1] if left != 1 else cr1[0])
if cents and right:
cents_str = self._int_to_word(right)
result += separator + cents_str + " " + (cr2[1] if right != 1 else cr2[0])
if is_negative:
result = self.negword + result
return result.strip()Shares nothing with Num2Word_Base.to_currency, so
currency::default_to_currency is bypassed entirely — no divisor, no
isinstance(val, int) branch, no pluralize, no
parse_currency_parts. See bugs 6-10.
adjective is accepted and dropped on the floor exactly as Python does
— CURRENCY_ADJECTIVES is never read on this path, so adjective=True
changes nothing.
_int_to_word is called with the already-abs’d left, so its
negative arm stays unreachable here and “minus “ is prepended exactly
once, at the end.
fn negword(&self) -> &str
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 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”.