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")?;
+ test_both("", "3.14")
+}
+
+// Verifies every Latin identifier currently defined in the Urdu Unicode table.
+#[test]
+fn latin_identifiers() -> Result<()> {
+ test_both("", "اے")?;
+ test_both("", "بی")?;
+ test_both("", "این")?;
+ test_both("", "ایکس")?;
+ test_both("", "وائے")
+}
+
+// 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 = "";
+ test_both(expr, "ایکس جمع 2, برابر وائے")
+}
+
+// Verifies both commonly encountered subtraction characters.
+#[test]
+fn subtraction_characters() -> Result<()> {
+ let hyphen = "";
+ let minus = "";
+ 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 = "";
+ let negative = "";
+ test_both(positive, "مثبت ایکس")?;
+ test_both(negative, "منفی ایکس")
+}
+
+// Verifies explicit multiplication and division signs.
+#[test]
+fn multiplication_and_division() -> Result<()> {
+ let multiplication = "";
+ let division = "";
+ 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 = "";
+ let greater_than = "";
+ 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 = "";
+ test_both(expr, "ایکس بٹا 5")
+}
+
+// Verifies that operators inside a fraction remain localized.
+#[test]
+fn compound_fraction() -> Result<()> {
+ let expr = "";
+ test_both(expr, "ایکس جمع 1 بٹا وائے منفی 1")
+}
+
+// Verifies square roots in both speech styles.
+#[test]
+fn square_root() -> Result<()> {
+ let expr = "";
+ test_both(expr, "ایکس کا جذر المربع")
+}
+
+// Verifies that a compound radicand retains localized operators.
+#[test]
+fn compound_square_root() -> Result<()> {
+ let expr = "";
+ test_both(expr, "ایکس کا مربع, جمع 1 کا جذر المربع")
+}
+
+// Verifies the dedicated cube-root phrase in both speech styles.
+#[test]
+fn cube_root() -> Result<()> {
+ let expr = "";
+ test_both(expr, "8 کا جذر المکعب")
+}
+
+// Verifies the generic indexed-root rule.
+#[test]
+fn generic_root() -> Result<()> {
+ let expr = "";
+ test_both(expr, "ایکس کا 4 درجے کا جذر")
+}
+
+// Verifies the dedicated square and cube power rules.
+#[test]
+fn square_and_cube() -> Result<()> {
+ let square = "";
+ let cube = "";
+ test_both(square, "ایکس کا مربع")?;
+ test_both(cube, "وائے کا مکعب")
+}
+
+// Verifies the generic power rule with an identifier exponent.
+#[test]
+fn generic_power() -> Result<()> {
+ let expr = "";
+ test_both(expr, "ایکس کی قوت این")
+}
+
+// Verifies that a compound exponent retains localized operators.
+#[test]
+fn compound_power() -> Result<()> {
+ let expr = "";
+ test_both(expr, "ایکس کی قوت این جمع 1")
+}
+
+// Verifies numeric and compound subscripts.
+#[test]
+fn subscripts() -> Result<()> {
+ let numeric = "";
+ let compound = "";
+ 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 = "";
+ 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 {