Skip to main content

LangSl

Struct LangSl 

Source
pub struct LangSl { /* private fields */ }

Implementations§

Source§

impl LangSl

Source

pub fn new() -> Self

Trait Implementations§

Source§

impl Default for LangSl

Source§

fn default() -> Self

Returns the “default value” for a type. Read more
Source§

impl Lang for LangSl

Source§

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

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_float( &self, value: &FloatValue, _precision_override: Option<u32>, ) -> Result<String>

Port of Num2Word_SL.to_cardinal_float(self, value).

SL’s own one-arg override, NOT Num2Word_Base.to_cardinal_float (the default this trait method would otherwise route to). It diverges twice:

  1. Fraction as a single number. Where the base loops the padded fractional string digit by digit, SL emits it whole: self.to_cardinal(int(post_str)). So 12.34 is “dvanajst vejica štiriintrideset” (34), never “… tri štiri”; 12.345 is “dvanajst vejica tristo petinštirideset” (345).

  2. Always float-casts, even Decimal. Python does self.float2tuple(float(value)) unconditionally, so the exact-Decimal arm of base.float2tuple is never taken here. This reintroduces issue #603 that the Decimal arm exists to avoid: Decimal( "98746251323029.99") casts to the f64 98746251323029.98, so the fraction reads 98 (“osemindevetdeset”), not 99. Likewise Decimal("1.10") casts to 1.1 — precision 1, “ena”, not the precision-2 “deset” the exact arm would give. Reproduced by taking to_f64() on the Decimal variant and running the Float branch.

SL’s signature has no precision= parameter, so precision_override is dead: even when the dispatcher pre-sets self.precision, float2tuple immediately overwrites it from repr(float(value)). Verified live — num2words(0.5, lang='sl', precision=5) is still “nič vejica pet”. Ignored here to match.

Only non-integral values arrive: Num2Word_Base.to_cardinal sends integral floats (1.0, 0.0) down its integer branch, so precision is always >= 1 in practice and the fraction segment always fires.

Source§

fn ordinal_float_entry(&self, value: &FloatValue) -> Result<String>

to_ordinal(float/Decimal).

verify_ordinal(value) runs first: a non-integral value raises TypeError (errmsg_floatord), a negative one TypeError (errmsg_negord) — note -0.0 passes both (int(-0.0) == -0.0 and abs(-0.0) == -0.0 numerically). A surviving value is whole and non-negative; num = int(value) then walks the same table/ordflag machinery as the integer path, and to_cardinal(<whole float>) inside the ordflag arm takes Base’s integer branch (the assert int(value) == value passes), so the output is byte-identical to to_ordinal(int(value)): 5.0 -> “peti”, 0.0/-0.0 -> “niči”, 1e+16 -> “desetbilijardti”.

Source§

fn ordinal_num_float_entry( &self, value: &FloatValue, repr_str: &str, ) -> Result<String>

to_ordinal_num(float/Decimal) — verify_ordinal(value), then str(value) + "." with the original string form: 5.0 -> “5.0.”, -0.0 -> “-0.0.”, 1e+16 -> “1e+16.”, Decimal("5.00") -> “5.00.”. Non-integral or negative values raise TypeError exactly as above.

Source§

fn pluralize(&self, n: &BigInt, forms: &[String]) -> Result<String>

Port of Num2Word_SL.pluralize(n, forms).

Python’s % on int floors, so a negative n wraps up into a positive residue: (-99) % 100 == 1 selects forms[0]. Rust’s % truncates — -99 % 100 == -99, which matches nothing and falls to forms[3] — so mod_floor is required. The two agree on -1/-100 and disagree on -99/-98/-97, which is why the test pins -99.

Unreachable from to_currency (both operands are absolute values), but pluralize is a public hook and the residue rule is the whole point.

Source§

fn to_currency( &self, val: &CurrencyValue, currency: &str, _cents: bool, _separator: Option<&str>, _adjective: bool, ) -> Result<String>

Port of Num2Word_SL.to_currency.

Three of the five parameters are dead upstream and so are ignored here:

  • separator — SL declares separator=" in" and then never reads it, using the third CURRENCY_FORMS element instead. The generated default_separator() above still reports “ in“ because that is the live signature’s default; it simply has no effect. Passing separator=" XX" changes nothing in Python. Verified live.
  • cents — no _cents_terse call exists on this path.
  • adjective — no CURRENCY_ADJECTIVES lookup exists on this path.
§The int/float split

is_integer_input = isinstance(val, int) gates the cents segment: a true int never prints cents, a float always does — including 1.0, which is why currency:EUR of 1 is “ena evro” but of 1.0 is “ena evro nič centov”. has_decimal is therefore unused here: SL does not consult it, and the Int/Decimal variants already carry the only distinction SL makes.

§Known gap: fractional cents

When (Decimal(str(val)) * 100) % 1 != 0, parse_currency_parts keeps the subunit as a Decimal and Python renders it with Num2Word_SL.to_cardinal_float — SL’s own one-arg override, which emits the fractional digits as a single number (to_cardinal(int(post_str))). cardinal_from_decimal’s default routes to Num2Word_Base.to_cardinal_float, which emits them digit by digit. The two agree whenever the residue is a single digit and diverge beyond it:

to_currency(1.005,  "EUR")  "ena evro nič vejica pet centov"          both
to_currency(1.0025, "EUR")  "ena evro nič vejica petindvajset centov" Python
                            "ena evro nič vejica dve pet centov"      here

Measured, not assumed: diffed against the live interpreter over 1751 cases (17 currency codes x 51 ints incl. 10^100 and negatives x 50 floats, plus cheques). Exactly 8 diverge — 1.0025, 0.0001, 1e-07 and 3.14159 under EUR and USD — and all 8 are this one cause. No corpus row is among them; reaching the branch needs 4+ decimal places.

Closing it means porting SL’s to_cardinal_float, which needs repr(float) semantics that this crate deliberately keeps on the Python side (see currency.rs’s header): 1e-07 renders “nič vejica ena” precisely because Python’s repr goes exponential and SL then reads the zero-padded digits back as one number. That is the later float phase, not this one — and note currency::cardinal_from_bigdecimal calls default_to_cardinal_float directly rather than through lang.to_cardinal_float, so porting SL’s override alone will not reroute this hook.

Source§

fn to_cheque(&self, _val: &BigDecimal, currency: &str) -> Result<String>

Num2Word_Base.to_cheque — inherited, and it cannot succeed for SL.

try:
    cr1, _cr2 = self.CURRENCY_FORMS[currency]
except KeyError:
    raise NotImplementedError(...)

Every SL entry is a 3-tuple, so the unpack raises ValueError: too many values to unpack (expected 2) — from inside the try, where only KeyError is caught, so it propagates. An unknown code raises KeyError on the subscript first and converts to NotImplementedError as usual. So the implemented codes fail harder than the unimplemented ones:

cheque:EUR 1234.56  ValueError            cheque:GBP 1234.56  NotImplementedError
cheque:USD 1234.56  ValueError            cheque:JPY 1234.56  NotImplementedError

Both arms are corpus rows and both are reproduced. val is untouched because Python never gets far enough to look at it — the unpack is the first statement after the subscript.

Source§

fn cards(&self) -> &Cards

Source§

fn maxval(&self) -> &BigInt

Source§

fn negword(&self) -> &str

Source§

fn pointword(&self) -> &str

Source§

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.
Source§

fn to_cardinal(&self, value: &BigInt) -> Result<String>

Source§

fn to_ordinal(&self, value: &BigInt) -> Result<String>

Source§

fn to_ordinal_num(&self, value: &BigInt) -> Result<String>

Source§

fn to_year(&self, value: &BigInt) -> Result<String>

Source§

fn lang_name(&self) -> &str

Class name, for the 'X' not implemented for 'Num2Word_Y' message.
Source§

fn currency_forms(&self, code: &str) -> Option<&CurrencyForms>

CURRENCY_FORMS[code]. None -> NotImplementedError, as in Python.
Source§

fn is_title(&self) -> bool

Source§

fn exclude_title(&self) -> &[String]

Source§

fn title(&self, value: &str) -> String

Source§

fn currency_adjective(&self, _code: &str) -> Option<&str>

CURRENCY_ADJECTIVES[code].
Source§

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 money_verbose(&self, number: &BigInt, _currency: &str) -> Result<String>

Source§

fn cents_verbose(&self, number: &BigInt, _currency: &str) -> Result<String>

Source§

fn cents_terse(&self, number: &BigInt, currency: &str) -> Result<String>

Source§

fn cardinal_from_decimal(&self, value: &BigDecimal) -> Result<String>

Render a non-integral value, for the fractional-cents branch. Python reaches this as 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

This language’s own to_currency(adjective=...) default. Base’s is False; only Mongolian defaults to True.
Source§

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_float_entry( &self, value: &FloatValue, precision_override: Option<u32>, ) -> Result<String>

to_cardinal(float/Decimal) — the full entry, whole values included.
Source§

fn year_float_entry(&self, value: &FloatValue) -> Result<String>

to_year(float/Decimal). Base’s to_year is to_cardinal.
Source§

fn str_to_number(&self, s: &str) -> Result<ParsedNumber>

converter.str_to_number. Base is Decimal(value); ES (“1ro” -> ordinal handshake), PT_BR (“1.50” -> ‘ponto’), DV (TypeError instead of InvalidOperation), BN (abs()) and ID override.
Source§

fn cardinal_with_pointword( &self, _value: &FloatValue, _pointword: &str, _precision_override: Option<u32>, ) -> Result<String>

The pt_BR ‘ponto’ rendering: to_cardinal(value) with the pointword swapped for this one call. Only reachable through ParsedNumber::DecPoint, so only PT_BR implements it.
Source§

fn to_cardinal_kw(&self, value: &BigInt, kw: &Kwargs) -> Result<String>

Source§

fn to_ordinal_kw(&self, value: &BigInt, kw: &Kwargs) -> Result<String>

Source§

fn to_ordinal_num_kw(&self, value: &BigInt, kw: &Kwargs) -> Result<String>

Source§

fn to_year_kw(&self, value: &BigInt, kw: &Kwargs) -> Result<String>

Source§

fn to_currency_kw( &self, val: &CurrencyValue, currency: &str, cents: bool, separator: Option<&str>, adjective: bool, kw: &Kwargs, ) -> Result<String>

Source§

fn to_cardinal_float_kw( &self, value: &FloatValue, precision_override: Option<u32>, kw: &Kwargs, ) -> Result<String>

Source§

fn es_currency_ordinal_fires(&self) -> bool

Spanish “1ro” currency: does the stashed ordinal fire? 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>>

Render 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>

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>

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>

Python’s 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”.

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.