From c620887fb301b169bacdcdd552d10508682d3a08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20Gro=C3=9F?= Date: Sun, 16 Aug 2026 15:46:19 +0200 Subject: [PATCH] Add initial Urdu localization rules and tests - Set up localized speech rules for Urdu, including basic arithmetic, fractions, roots, powers, and comparisons. - Include shared rules for calculus, geometry, and linear algebra. - Add Urdu-specific test cases to validate rule functionality. - Update `languages.rs` to register Urdu rules. --- Rules/Languages/ur/ClearSpeak_Rules.yaml | 43 +++++ Rules/Languages/ur/SharedRules/calculus.yaml | 2 + Rules/Languages/ur/SharedRules/default.yaml | 44 +++++ Rules/Languages/ur/SharedRules/general.yaml | 2 + Rules/Languages/ur/SharedRules/geometry.yaml | 2 + .../ur/SharedRules/linear-algebra.yaml | 2 + Rules/Languages/ur/SimpleSpeak_Rules.yaml | 43 +++++ Rules/Languages/ur/definitions.yaml | 2 + Rules/Languages/ur/navigate.yaml | 2 + Rules/Languages/ur/overview.yaml | 2 + Rules/Languages/ur/unicode-full.yaml | 2 + Rules/Languages/ur/unicode.yaml | 19 +++ tests/Languages/ur.rs | 155 ++++++++++++++++++ tests/languages.rs | 1 + 14 files changed, 321 insertions(+) create mode 100644 Rules/Languages/ur/ClearSpeak_Rules.yaml create mode 100644 Rules/Languages/ur/SharedRules/calculus.yaml create mode 100644 Rules/Languages/ur/SharedRules/default.yaml create mode 100644 Rules/Languages/ur/SharedRules/general.yaml create mode 100644 Rules/Languages/ur/SharedRules/geometry.yaml create mode 100644 Rules/Languages/ur/SharedRules/linear-algebra.yaml create mode 100644 Rules/Languages/ur/SimpleSpeak_Rules.yaml create mode 100644 Rules/Languages/ur/definitions.yaml create mode 100644 Rules/Languages/ur/navigate.yaml create mode 100644 Rules/Languages/ur/overview.yaml create mode 100644 Rules/Languages/ur/unicode-full.yaml create mode 100644 Rules/Languages/ur/unicode.yaml create mode 100644 tests/Languages/ur.rs diff --git a/Rules/Languages/ur/ClearSpeak_Rules.yaml b/Rules/Languages/ur/ClearSpeak_Rules.yaml new file mode 100644 index 000000000..8a20bed45 --- /dev/null +++ b/Rules/Languages/ur/ClearSpeak_Rules.yaml @@ -0,0 +1,43 @@ +--- +- name: fraction + tag: fraction + match: "." + replace: [x: "*[1]", t: "بٹا", x: "*[2]", pause: short] + +- name: square-root + tag: square-root + match: "." + replace: [x: "*[1]", t: "کا جذر المربع", pause: short] + +- name: cube-root + tag: root + match: "*[2][self::m:mn][.='3']" + replace: [x: "*[1]", t: "کا جذر المکعب", pause: short] + +- name: root + tag: root + match: "." + replace: [x: "*[1]", t: "کا", x: "*[2]", t: "درجے کا جذر", pause: short] + +- name: square + tag: power + match: "*[2][self::m:mn][.='2']" + replace: [x: "*[1]", bookmark: "*[2]/@id", t: "کا مربع"] + +- name: cube + tag: power + match: "*[2][self::m:mn][.='3']" + replace: [x: "*[1]", bookmark: "*[2]/@id", t: "کا مکعب"] + +- name: power + tag: power + match: "." + replace: [x: "*[1]", t: "کی قوت", x: "*[2]", pause: short] + +- include: "SharedRules/calculus.yaml" +- include: "SharedRules/geometry.yaml" +- include: "SharedRules/linear-algebra.yaml" +- include: "SharedRules/general.yaml" +- include: "SharedRules/default.yaml" + +- include: "../en/ClearSpeak_Rules.yaml" diff --git a/Rules/Languages/ur/SharedRules/calculus.yaml b/Rules/Languages/ur/SharedRules/calculus.yaml new file mode 100644 index 000000000..fe9259443 --- /dev/null +++ b/Rules/Languages/ur/SharedRules/calculus.yaml @@ -0,0 +1,2 @@ +--- +[] diff --git a/Rules/Languages/ur/SharedRules/default.yaml b/Rules/Languages/ur/SharedRules/default.yaml new file mode 100644 index 000000000..a98f7a2f5 --- /dev/null +++ b/Rules/Languages/ur/SharedRules/default.yaml @@ -0,0 +1,44 @@ +--- +- name: positive + tag: plus + match: "count(*)=1" + replace: [t: "مثبت", x: "*[1]"] + +- name: plus + tag: plus + match: "." + replace: [x: "*[1]", t: "جمع", x: "*[2]"] + +- name: negative + tag: minus + match: "count(*)=1" + replace: [t: "منفی", x: "*[1]"] + +- name: minus + tag: minus + match: "." + replace: [x: "*[1]", t: "منفی", x: "*[2]"] + +- name: times + tag: times + match: "." + replace: [x: "*[1]", t: "ضرب", x: "*[2]"] + +- name: divided-by + tag: divided-by + match: "." + replace: [x: "*[1]", t: "تقسیم", x: "*[2]"] + +- name: equals + tag: equals + match: "." + replace: [x: "*[1]", t: "برابر", x: "*[2]"] + +- name: indexed-by + tag: indexed-by + match: "." + replace: + - x: "*[1]" + - t: "زیر نوشت" + - x: "*[2]" + - pause: short diff --git a/Rules/Languages/ur/SharedRules/general.yaml b/Rules/Languages/ur/SharedRules/general.yaml new file mode 100644 index 000000000..fe9259443 --- /dev/null +++ b/Rules/Languages/ur/SharedRules/general.yaml @@ -0,0 +1,2 @@ +--- +[] diff --git a/Rules/Languages/ur/SharedRules/geometry.yaml b/Rules/Languages/ur/SharedRules/geometry.yaml new file mode 100644 index 000000000..fe9259443 --- /dev/null +++ b/Rules/Languages/ur/SharedRules/geometry.yaml @@ -0,0 +1,2 @@ +--- +[] diff --git a/Rules/Languages/ur/SharedRules/linear-algebra.yaml b/Rules/Languages/ur/SharedRules/linear-algebra.yaml new file mode 100644 index 000000000..fe9259443 --- /dev/null +++ b/Rules/Languages/ur/SharedRules/linear-algebra.yaml @@ -0,0 +1,2 @@ +--- +[] diff --git a/Rules/Languages/ur/SimpleSpeak_Rules.yaml b/Rules/Languages/ur/SimpleSpeak_Rules.yaml new file mode 100644 index 000000000..50eec4e3c --- /dev/null +++ b/Rules/Languages/ur/SimpleSpeak_Rules.yaml @@ -0,0 +1,43 @@ +--- +- name: fraction + tag: fraction + match: "." + replace: [x: "*[1]", t: "بٹا", x: "*[2]", pause: short] + +- name: square-root + tag: square-root + match: "." + replace: [x: "*[1]", t: "کا جذر المربع", pause: short] + +- name: cube-root + tag: root + match: "*[2][self::m:mn][.='3']" + replace: [x: "*[1]", t: "کا جذر المکعب", pause: short] + +- name: root + tag: root + match: "." + replace: [x: "*[1]", t: "کا", x: "*[2]", t: "درجے کا جذر", pause: short] + +- name: square + tag: power + match: "*[2][self::m:mn][.='2']" + replace: [x: "*[1]", bookmark: "*[2]/@id", t: "کا مربع"] + +- name: cube + tag: power + match: "*[2][self::m:mn][.='3']" + replace: [x: "*[1]", bookmark: "*[2]/@id", t: "کا مکعب"] + +- name: power + tag: power + match: "." + replace: [x: "*[1]", t: "کی قوت", x: "*[2]", pause: short] + +- include: "SharedRules/calculus.yaml" +- include: "SharedRules/geometry.yaml" +- include: "SharedRules/linear-algebra.yaml" +- include: "SharedRules/general.yaml" +- include: "SharedRules/default.yaml" + +- include: "../en/SimpleSpeak_Rules.yaml" diff --git a/Rules/Languages/ur/definitions.yaml b/Rules/Languages/ur/definitions.yaml new file mode 100644 index 000000000..8a6187b43 --- /dev/null +++ b/Rules/Languages/ur/definitions.yaml @@ -0,0 +1,2 @@ +--- +- include: "../en/definitions.yaml" diff --git a/Rules/Languages/ur/navigate.yaml b/Rules/Languages/ur/navigate.yaml new file mode 100644 index 000000000..f6ef25698 --- /dev/null +++ b/Rules/Languages/ur/navigate.yaml @@ -0,0 +1,2 @@ +--- +- include: "../en/navigate.yaml" diff --git a/Rules/Languages/ur/overview.yaml b/Rules/Languages/ur/overview.yaml new file mode 100644 index 000000000..49b0a4e44 --- /dev/null +++ b/Rules/Languages/ur/overview.yaml @@ -0,0 +1,2 @@ +--- +- include: "../en/overview.yaml" diff --git a/Rules/Languages/ur/unicode-full.yaml b/Rules/Languages/ur/unicode-full.yaml new file mode 100644 index 000000000..bd4570c7f --- /dev/null +++ b/Rules/Languages/ur/unicode-full.yaml @@ -0,0 +1,2 @@ +--- +- include: "../en/unicode-full.yaml" diff --git a/Rules/Languages/ur/unicode.yaml b/Rules/Languages/ur/unicode.yaml new file mode 100644 index 000000000..494c10c6b --- /dev/null +++ b/Rules/Languages/ur/unicode.yaml @@ -0,0 +1,19 @@ +--- +- include: "../en/unicode.yaml" + +- "a": [t: "اے"] +- "b": [t: "بی"] +- "n": [t: "این"] +- "x": [t: "ایکس"] +- "y": [t: "وائے"] +- "س": [t: "س"] +- "ص": [t: "ص"] + +- "+": [t: "جمع"] +- "-": [t: "منفی"] +- "−": [t: "منفی"] +- "×": [t: "ضرب"] +- "÷": [t: "تقسیم"] +- "=": [t: "برابر"] +- "<": [t: "سے کم"] +- ">": [t: "سے زیادہ"] diff --git a/tests/Languages/ur.rs b/tests/Languages/ur.rs new file mode 100644 index 000000000..ae19e9f6f --- /dev/null +++ b/tests/Languages/ur.rs @@ -0,0 +1,155 @@ +use crate::common::*; +use anyhow::Result; + +fn test_both(expr: &str, speech: &str) -> Result<()> { + test("ur", "ClearSpeak", expr, speech)?; + test("ur", "SimpleSpeak", expr, speech) +} + +// Verifies that numbers remain usable before Urdu number-to-word rules are added. +#[test] +fn numbers() -> Result<()> { + test_both("123", "123")?; + test_both("3.14", "3.14") +} + +// Verifies every Latin identifier currently defined in the Urdu Unicode table. +#[test] +fn latin_identifiers() -> Result<()> { + test_both("a", "اے")?; + test_both("b", "بی")?; + test_both("n", "این")?; + test_both("x", "ایکس")?; + test_both("y", "وائے") +} + +// Verifies every Urdu identifier currently defined in the Unicode table. +#[test] +fn urdu_identifiers() -> Result<()> { + test_both("س", "س")?; + test_both("ص", "ص") +} + +// Verifies binary addition and equality in both speech styles. +#[test] +fn addition_and_equality() -> Result<()> { + let expr = "x+2=y"; + test_both(expr, "ایکس جمع 2, برابر وائے") +} + +// Verifies both commonly encountered subtraction characters. +#[test] +fn subtraction_characters() -> Result<()> { + let hyphen = "x-1"; + let minus = "x1"; + test_both(hyphen, "ایکس منفی 1")?; + test_both(minus, "ایکس منفی 1") +} + +// Verifies that unary signs select the positive and negative rules. +#[test] +fn unary_signs() -> Result<()> { + let positive = "+x"; + let negative = "x"; + test_both(positive, "مثبت ایکس")?; + test_both(negative, "منفی ایکس") +} + +// Verifies explicit multiplication and division signs. +#[test] +fn multiplication_and_division() -> Result<()> { + let multiplication = "6×x"; + let division = "6÷2"; + test_both(multiplication, "6 ضرب ایکس")?; + test_both(division, "6 تقسیم 2") +} + +// Verifies both ordering relations defined by the Urdu Unicode table. +#[test] +fn comparisons() -> Result<()> { + let less_than = "1<x"; + let greater_than = "x>0"; + test_both(less_than, "1 سے کم ایکس")?; + test_both(greater_than, "ایکس سے زیادہ 0") +} + +// Verifies the Urdu reading of a fraction with leaf children. +#[test] +fn simple_fraction() -> Result<()> { + let expr = "x5"; + test_both(expr, "ایکس بٹا 5") +} + +// Verifies that operators inside a fraction remain localized. +#[test] +fn compound_fraction() -> Result<()> { + let expr = "x+1y1"; + test_both(expr, "ایکس جمع 1 بٹا وائے منفی 1") +} + +// Verifies square roots in both speech styles. +#[test] +fn square_root() -> Result<()> { + let expr = "x"; + test_both(expr, "ایکس کا جذر المربع") +} + +// Verifies that a compound radicand retains localized operators. +#[test] +fn compound_square_root() -> Result<()> { + let expr = "x2+1"; + test_both(expr, "ایکس کا مربع, جمع 1 کا جذر المربع") +} + +// Verifies the dedicated cube-root phrase in both speech styles. +#[test] +fn cube_root() -> Result<()> { + let expr = "83"; + test_both(expr, "8 کا جذر المکعب") +} + +// Verifies the generic indexed-root rule. +#[test] +fn generic_root() -> Result<()> { + let expr = "x4"; + test_both(expr, "ایکس کا 4 درجے کا جذر") +} + +// Verifies the dedicated square and cube power rules. +#[test] +fn square_and_cube() -> Result<()> { + let square = "x2"; + let cube = "y3"; + test_both(square, "ایکس کا مربع")?; + test_both(cube, "وائے کا مکعب") +} + +// Verifies the generic power rule with an identifier exponent. +#[test] +fn generic_power() -> Result<()> { + let expr = "xn"; + test_both(expr, "ایکس کی قوت این") +} + +// Verifies that a compound exponent retains localized operators. +#[test] +fn compound_power() -> Result<()> { + let expr = "xn+1"; + test_both(expr, "ایکس کی قوت این جمع 1") +} + +// Verifies numeric and compound subscripts. +#[test] +fn subscripts() -> Result<()> { + let numeric = "x1"; + let compound = "xn+1"; + test_both(numeric, "ایکس زیر نوشت 1")?; + test_both(compound, "ایکس زیر نوشت این جمع 1") +} + +// Verifies the localized rules working together in a small equation. +#[test] +fn quadratic_expression() -> Result<()> { + let expr = "b+x22=y"; + test_both(expr, "منفی بی جمع, ایکس کا مربع کا جذر المربع, بٹا 2; برابر وائے") +} diff --git a/tests/languages.rs b/tests/languages.rs index b0552b95b..79a707254 100644 --- a/tests/languages.rs +++ b/tests/languages.rs @@ -13,6 +13,7 @@ mod Languages { mod pl; mod sv; mod nb; + mod ur; mod de; mod fr; mod vi {