diff --git a/Rules/Languages/pl/SharedRules/general.yaml b/Rules/Languages/pl/SharedRules/general.yaml
index f3d026f2..e6c94a36 100644
--- a/Rules/Languages/pl/SharedRules/general.yaml
+++ b/Rules/Languages/pl/SharedRules/general.yaml
@@ -293,6 +293,14 @@
# cannot be determined, which falls through to the genitive - the form
# Polish uses with unknown or large quantities.
- Coefficient: "IfThenElse($MRowForCoefficient, number($MRowForCoefficient/*[1][self::m:mn]), 0)"
+ # The 'per-fraction' rule speaks the denominator after the preposition "na",
+ # which governs the accusative: "na godzinę", not "na godzina". Only feminine
+ # nouns change form, so AccusativeCase holds just those; a missing entry
+ # means the accusative equals the nominative (as for "na litr", "na mol").
+ # The second test covers a denominator raised to a power, as in m/s^2, where
+ # the unit's parent is the 'power' element rather than the fraction itself.
+ - IsFractionDenominator: "(parent::m:fraction and preceding-sibling::*) or
+ (parent::m:power and parent::*[parent::m:fraction and preceding-sibling::*])"
- IsNominativePlural: "$Coefficient mod 10 >= 2 and $Coefficient mod 10 <= 4 and
not($Coefficient mod 100 >= 12 and $Coefficient mod 100 <= 14)"
- Prefix: "''"
@@ -339,7 +347,9 @@
if: "$Prefix = ''"
then:
- test:
- - if: "$IsSingular"
+ - if: "$IsSingular and $IsFractionDenominator and DefinitionValue($Word, 'Speech', 'AccusativeCase') != ''"
+ then: [x: "DefinitionValue($Word, 'Speech', 'AccusativeCase')"]
+ - else_if: "$IsSingular"
# HACK: '\uF8FE' is used internally for the concatenation char by 'ct' -- this gets the prefix concatenated to the base
then: [x: "$Word"]
- else_if: "$IsNominativePlural and DefinitionValue($Word, 'Speech', 'PluralForms') != ''"
@@ -353,7 +363,9 @@
- x: "$Prefix"
- ct: "-"
- test:
- - if: "$IsSingular"
+ - if: "$IsSingular and $IsFractionDenominator and DefinitionValue($Word, 'Speech', 'AccusativeCase') != ''"
+ then: [x: "concat('\uF8FE', DefinitionValue($Word, 'Speech', 'AccusativeCase'))"]
+ - else_if: "$IsSingular"
# HACK: '\uF8FE' is used internally for the concatenation char by 'ct' -- this gets the prefix concatenated to the base
then: [x: "concat('\uF8FE', $Word)"]
- else_if: "$IsNominativePlural and DefinitionValue($Word, 'Speech', 'PluralForms') != ''"
diff --git a/Rules/Languages/pl/definitions.yaml b/Rules/Languages/pl/definitions.yaml
index 18785562..0f212c4e 100644
--- a/Rules/Languages/pl/definitions.yaml
+++ b/Rules/Languages/pl/definitions.yaml
@@ -646,6 +646,48 @@
"łyżka stołowa": "łyżki stołowe"
}
+- AccusativeCase: {
+ # Accusative singular, used after the preposition "na" in the
+ # 'per-fraction' rule: "62 mile na godzinę", not "na godzina".
+ # Only feminine nouns differ from the nominative, so masculine and
+ # neuter names are deliberately absent - a missing entry means
+ # "the form does not change" (na litr, na mol, na metr).
+ # An adjective agrees with its noun (milę kwadratową), while a
+ # dependent noun keeps its own case (uncję płynu, minutę łuku).
+ "atmosfera": "atmosferę",
+ "baryłka": "baryłkę",
+ "drachma": "drachmę",
+ "drachma płynu": "drachmę płynu",
+ "dyna": "dynę",
+ "godzina": "godzinę",
+ "jednostka astronomiczna": "jednostkę astronomiczną",
+ "jednostka masy atomowej": "jednostkę masy atomowej",
+ "kaloria": "kalorię",
+ "kandela": "kandelę",
+ "kwarta": "kwartę",
+ "mila": "milę",
+ "mila kwadratowa": "milę kwadratową",
+ "mila na galon": "milę na galon",
+ "mila na godzinę": "milę na godzinę",
+ "minuta": "minutę",
+ "minuta łuku": "minutę łuku",
+ "pinta": "pintę",
+ "rupia": "rupię",
+ "sekunda": "sekundę",
+ "sekunda łuku": "sekundę łuku",
+ "stopa": "stopę",
+ "stopa deskowa": "stopę deskową",
+ "stopa kwadratowa": "stopę kwadratową",
+ "stopa sześcienna": "stopę sześcienną",
+ "tesla": "teslę",
+ "tona": "tonę",
+ "uncja": "uncję",
+ "uncja płynu": "uncję płynu",
+ "uncja trojańska": "uncję trojańską",
+ "łyżeczka": "łyżeczkę",
+ "łyżka stołowa": "łyżkę stołową"
+ }
+
- PluralGenitive: {
# Genitive plural - after 5 and above, and after 12-14, 112-114.
# Polish inflects the noun according to the numeral, so a single plural
diff --git a/tests/Languages/pl.rs b/tests/Languages/pl.rs
index c9423ea9..8e4c56f3 100644
--- a/tests/Languages/pl.rs
+++ b/tests/Languages/pl.rs
@@ -4,6 +4,7 @@
mod pl;
mod number_sets;
mod unit_plurals;
+mod preposition_case;
// Tests mirrored from the English suite, with expected speech localized to Polish.
mod ClearSpeak {
diff --git a/tests/Languages/pl/ClearSpeak/mfrac.rs b/tests/Languages/pl/ClearSpeak/mfrac.rs
index a53bba55..fff48569 100644
--- a/tests/Languages/pl/ClearSpeak/mfrac.rs
+++ b/tests/Languages/pl/ClearSpeak/mfrac.rs
@@ -86,7 +86,7 @@ fn frac_with_units() -> Result<()> {
";
- test("pl", "ClearSpeak", expr, "62 mile na godzina")?;
+ test("pl", "ClearSpeak", expr, "62 mile na godzinę")?;
return Ok(());
}
diff --git a/tests/Languages/pl/SimpleSpeak/mfrac.rs b/tests/Languages/pl/SimpleSpeak/mfrac.rs
index a07f0592..3b421b0f 100644
--- a/tests/Languages/pl/SimpleSpeak/mfrac.rs
+++ b/tests/Languages/pl/SimpleSpeak/mfrac.rs
@@ -164,7 +164,7 @@ fn frac_with_units() -> Result<()> {
";
- test("pl", "SimpleSpeak", expr, "62 mile na godzina")?;
+ test("pl", "SimpleSpeak", expr, "62 mile na godzinę")?;
return Ok(());
}
@@ -181,7 +181,7 @@ fn singular_frac_with_units() -> Result<()> {
";
- test("pl", "SimpleSpeak", expr, "1 galon na mila")?;
+ test("pl", "SimpleSpeak", expr, "1 galon na milę")?;
return Ok(());
}
@@ -198,7 +198,7 @@ fn number_in_numerator_with_units() -> Result<()> {
mi
";
- test("pl", "SimpleSpeak", expr, "3 galony na mila")?;
+ test("pl", "SimpleSpeak", expr, "3 galony na milę")?;
return Ok(());
}
@@ -212,7 +212,7 @@ fn units_with_powers() -> Result<()> {
s2
";
- test("pl", "SimpleSpeak", expr, "3 metry na sekunda do kwadratu")?;
+ test("pl", "SimpleSpeak", expr, "3 metry na sekundę do kwadratu")?;
return Ok(());
}
diff --git a/tests/Languages/pl/preposition_case.rs b/tests/Languages/pl/preposition_case.rs
new file mode 100644
index 00000000..92d1a452
--- /dev/null
+++ b/tests/Languages/pl/preposition_case.rs
@@ -0,0 +1,71 @@
+/// Polish prepositions govern case: the denominator of a unit fraction is spoken
+/// after "na", which requires the accusative - "na godzinę", not "na godzina".
+use crate::common::*;
+use anyhow::Result;
+
+/// Feminine denominators: these are the ones whose form actually changes.
+#[test]
+fn per_fraction_feminine_denominator() -> Result<()> {
+ let expr = r#""#;
+ test("pl", "SimpleSpeak", expr, "62 mile na godzinę, przecinek; 5 metrów na sekundę, przecinek; 2 kilo-metry na godzinę; przecinek; 7 radianów na minutę, przecinek; 3 dżule na tonę")?;
+ Ok(())
+}
+
+/// Masculine and neuter denominators must NOT change: their accusative already
+/// equals the nominative. This is the negative control for the change.
+#[test]
+fn per_fraction_masculine_denominator_unchanged() -> Result<()> {
+ let expr = r#""#;
+ test("pl", "SimpleSpeak", expr, "3 gramy na litr, przecinek; 1 dżul na mol, przecinek; 5 niutonów na metr, przecinek; 2 wolty na amper")?;
+ Ok(())
+}
+
+/// A unit standing on its own keeps the nominative - the accusative must not
+/// leak outside the fraction denominator.
+#[test]
+fn standalone_unit_stays_nominative() -> Result<()> {
+ let expr = r#""#;
+ test("pl", "SimpleSpeak", expr, "1 godzina, przecinek; 1 sekunda, przecinek; 1 tona, przecinek; 1 minuta")?;
+ Ok(())
+}
+
+/// Multi-word feminine units: the adjective agrees, a dependent noun does not.
+#[test]
+fn per_fraction_multiword_denominator() -> Result<()> {
+ let expr = r#""#;
+ test("pl", "SimpleSpeak", expr, "3 gramy na stopę kwadratową; przecinek; 2 metry na minutę łuku")?;
+ Ok(())
+}
+
+/// A denominator raised to a power, as in m/s^2: the unit's parent is the
+/// 'power' element, not the fraction, so this needs its own test.
+#[test]
+fn per_fraction_denominator_with_power() -> Result<()> {
+ let expr = r#""#;
+ test("pl", "SimpleSpeak", expr, "3 metry na sekundę do kwadratu")?;
+ Ok(())
+}