From cd81ae629cf62798f1488130054528c57dcdbeb2 Mon Sep 17 00:00:00 2001 From: mgros Date: Sat, 15 Aug 2026 02:46:09 +0200 Subject: [PATCH 1/2] Fix German grammar and update translations for math script descriptions --- Rules/Languages/de/SharedRules/default.yaml | 18 +++++++++--------- tests/Languages/de/shared.rs | 7 ++++--- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/Rules/Languages/de/SharedRules/default.yaml b/Rules/Languages/de/SharedRules/default.yaml index 837aa57f0..b9da351ae 100644 --- a/Rules/Languages/de/SharedRules/default.yaml +++ b/Rules/Languages/de/SharedRules/default.yaml @@ -286,15 +286,15 @@ then: - with: variables: - - PreSubscript: "IfThenElse($Verbosity='Verbose', 'pre subscript', 'pre sub')" - - PreSuperscript: "IfThenElse($Verbosity='Verbose', 'pre superscript', 'pre super')" + - PreSubscript: "IfThenElse($Verbosity='Verbose', 'vorangestellter Index', 'vorindex')" + - PreSuperscript: "IfThenElse($Verbosity='Verbose', 'vorangestellte Hochstellung', 'vorhochstellung')" replace: - test: # only bother announcing if there is more than one prescript if: "count($Prescripts) > 2" then: - - T: "durch" # phrase(substitute x 'with' y) + - T: "mit" # phrase(substitute x 'with' y) - x: "count($Prescripts) div 2" - - T: "präskripte" # phrase(in this equation certain 'prescripts' apply) + - T: "Präskripten" # phrase(in this equation certain 'prescripts' apply) - pause: short - test: if: "not($Prescripts[1][self::m:none])" @@ -337,8 +337,8 @@ then: - with: variables: - - PostSubscript: "IfThenElse($Verbosity='Verbose', 'subscript', 'sub')" - - PostSuperscript: "IfThenElse($Verbosity='Verbose', 'superscript', 'super')" + - PostSubscript: "IfThenElse($Verbosity='Verbose', 'Index', 'sub')" + - PostSuperscript: "IfThenElse($Verbosity='Verbose', 'Hochstellung', 'super')" replace: - test: # only bother announcing if there is more than one postscript if: "count($Postscripts) > 2" @@ -346,9 +346,9 @@ - test: if: "$Prescripts" then: [T: "und"] # phrase(10 is greater than 8 'and' less than 15) - - T: "durch" # phrase(substitute x 'with' y) + - T: "mit" # phrase(substitute x 'with' y) - x: "count($Postscripts) div 2" - - T: "postskripte" # phrase(this material includes several 'postscripts') + - T: "Postskripten" # phrase(this material includes several 'postscripts') - pause: short - test: if: "not($Postscripts[1][self::m:none])" @@ -434,7 +434,7 @@ - T: "und" # phrase(the table with 3 rows 'and' 4 columns) - x: "$NumColumns" - test: - if: "NumColumns=1" + if: "$NumColumns=1" then: [T: "spalte"] # phrase(the table with 3 rows and 1 'column') else: [T: "spalten"] # phrase(the table with 3 rows and 4 'columns') - pause: long diff --git a/tests/Languages/de/shared.rs b/tests/Languages/de/shared.rs index 2f3512bcd..34518d9e0 100644 --- a/tests/Languages/de/shared.rs +++ b/tests/Languages/de/shared.rs @@ -118,21 +118,22 @@ fn tensor_mmultiscripts() -> Result<()> { R i j k l "; test_prefs("de", "SimpleSpeak", vec![("Verbosity", "Verbose")], expr, - "groß r durch 4 postskripte, subscript i superscript j subscript k subscript l")?; + "groß r mit 4 Postskripten, Index i Hochstellung j Index k Index l")?; test_prefs("de", "SimpleSpeak", vec![("Verbosity", "Medium")], expr, - "groß r durch 4 postskripte, sub i super j sub k sub l")?; + "groß r mit 4 Postskripten, sub i super j sub k sub l")?; return Ok(()); } #[test] +// idk really about that one, as we have "None" in the expected speech. fn huge_num_mmultiscripts() -> Result<()> { let expr = " R i j k l m I J K L "; test_prefs("de", "SimpleSpeak", vec![("Verbosity", "Verbose")], expr, - "groß r durch 4 präskripte, pre subscript groß i, pre superscript groß j und abwechselnde präskripte groß k none groß l none ende der präskripte und durch 5 postskripte, subscript i superscript j subscript k subscript l und wechselnde skripte m none ende der skripte")?; + "groß r mit 4 Präskripten, vorangestellter Index groß i, vorangestellte Hochstellung groß j und abwechselnde präskripte groß k none groß l none ende der präskripte und mit 5 Postskripten, Index i Hochstellung j Index k Index l und wechselnde skripte m none ende der skripte")?; return Ok(()); } From f8a79caac774941c2b7b96e87d143b6e6affc0ac Mon Sep 17 00:00:00 2001 From: mgros Date: Sat, 15 Aug 2026 02:56:57 +0200 Subject: [PATCH 2/2] Improve German translations for unicode integral and logical symbols, add localization tests --- Rules/Languages/de/unicode-full.yaml | 30 +++++++++---------- .../de/ClearSpeak/symbols_and_adornments.rs | 13 ++++++++ 2 files changed, 28 insertions(+), 15 deletions(-) diff --git a/Rules/Languages/de/unicode-full.yaml b/Rules/Languages/de/unicode-full.yaml index 5e941c61e..03b3157a6 100644 --- a/Rules/Languages/de/unicode-full.yaml +++ b/Rules/Languages/de/unicode-full.yaml @@ -1861,7 +1861,7 @@ - "⨋": [T: "Summation mit Integral"] # 0x2a0b (en: 'summation with integral', google: 'summierung mit integral') - "⨌": [T: "Vierfach-Integral-Operator"] # 0x2a0c (SRE: 'Vierfach-Integral-Operator') - "⨍": [T: "endliches Teilintegral"] # 0x2a0d (en: 'finite part integral', MathPlayer: 'finite part integral', google: 'finite -teil -integral') - - "⨎": [T: "Integral mit Doppelhub"] # 0x2a0e (en: 'integral with double stroke', google: 'integral mit doppelter hub') + - "⨎": [T: "Integral mit doppeltem Strich"] # 0x2a0e (en: 'integral with double stroke') - "⨏": [T: "Integraler Durchschnitt mit Schrägstrich"] # 0x2a0f (en: 'integral average with slash', google: 'integraler durchschnitt mit schrägstrich') - "⨐": [T: "Zirkulationsfunktion"] # 0x2a10 (en: 'circulation function', MathPlayer: 'circulation function', google: 'zirkulationsfunktion') - "⨑": [T: "Integration gegen den Uhrzeigersinn"] # 0x2a11 (en: 'anticlockwise integration', MathPlayer: 'anticlockwise integration', google: 'integration gegen den uhrzeigersinn') @@ -1869,13 +1869,13 @@ - "⨓": [T: "Linienintegration mit halbkreisförmigem Pfad um den Pol"] # 0x2a13 (en: 'line integration with semicircular path around pole', MathPlayer: 'line integration with semicircular path around pole', google: 'linienintegration mit halbkreisförmigem pfad um pol') - "⨔": [T: "Leitungsintegration ohne Pole"] # 0x2a14 (en: 'line integration not including the pole', MathPlayer: 'line integration not including the pole', google: 'linienintegration ohne stange') - "⨕": [T: "Integral um einen Punktoperator"] # 0x2a15 (en: 'integral around a point operator', MathPlayer: 'integral around a point operator', google: 'integral um einen punktbetreiber') - - "⨖": [T: "quaternion Integral-Operator"] # 0x2a16 (SRE: 'Quaternion Integral Operator') + - "⨖": [T: "Quaternionen-Integraloperator"] # 0x2a16 (SRE: 'Quaternion Integral Operator') - "⨗": [T: "Integral mit Pfeil nach links mit Haken"] # 0x2a17 (en: 'integral with leftwards arrow with hook', MathPlayer: 'integral with leftwards arrow with hook', google: 'integraler mit linksem pfeil mit haken') - "⨘": [T: "Integral mit Kreuzproduktzeichen"] # 0x2a18 (en: 'integral with times sign', google: 'integral mit times sign') - "⨙": [T: "Integral mit Schnittmenge-Zeichen"] # 0x2a19 (en: 'integral with intersection', google: 'integral mit der kreuzung') - "⨚": [T: "Integral mit Vereinigungs-Zeichen"] # 0x2a1a (en: 'integral with union', google: 'integral mit union') - - "⨛": [T: "Integral mit Overbar"] # 0x2a1b (en: 'integral with overbar', google: 'integral mit overbar') - - "⨜": [T: "Integral mit Underbar"] # 0x2a1c (en: 'integral with underbar', google: 'integral mit underbar') + - "⨛": [T: "Integral mit Überstrich"] # 0x2a1b (en: 'integral with overbar') + - "⨜": [T: "Integral mit Unterstrich"] # 0x2a1c (en: 'integral with underbar') - "⨝": [T: "Beitreten"] # 0x2a1d (en: 'join', google: 'verbinden') - "⨞": [T: "Großes linkes Dreieckbediener"] # 0x2a1e (en: 'large left triangle operator', google: 'großer linker dreieck operator') - "⨟": [T: "Z-Notationsschema-Zusammensetzung"] # 0x2a1f (en: 'z notation schema composition', google: 'z notationschema -zusammensetzung') @@ -1913,8 +1913,8 @@ - "⨿": [T: "Verschmelzung oder Koprodukt"] # 0x2a3f (en: 'amalgamation or coproduct', MathPlayer: 'amalgamation or coproduct', google: 'verschmelzung oder koprodukt') - "⩀": [T: "Schnittpunkt mit Punkt"] # 0x2a40 (en: 'intersection with dot', MathPlayer: 'intersection with dot', google: 'kreuzung mit punkt') - "⩁": [T: "Union mit Minuszeichen"] # 0x2a41 (en: 'union with minus sign', google: 'gewerkschaft mit minus zeichen') - - "⩂": [T: "Union mit Overbar"] # 0x2a42 (en: 'union with overbar', MathPlayer: 'union with overbar', google: 'gewerkschaft mit overbar') - - "⩃": [T: "Kreuzung mit Overbar"] # 0x2a43 (en: 'intersection with overbar', MathPlayer: 'intersection with overbar', google: 'kreuzung mit überbär') + - "⩂": [T: "Vereinigung mit Überstrich"] # 0x2a42 (en: 'union with overbar') + - "⩃": [T: "Schnittmenge mit Überstrich"] # 0x2a43 (en: 'intersection with overbar') - "⩄": [T: "Überschneidung mit logischem und"] # 0x2a44 (en: 'intersection with logical and', MathPlayer: 'intersection with logical and', google: 'schnittpunkt mit logisch und') - "⩅": [T: "Vereinigung mit logischem Or"] # 0x2a45 (en: 'union with logical or', MathPlayer: 'union with logical or', google: 'vereinigung mit logisch oder') - "⩆": [T: "Vereinigung über dem Schnittpunkt"] # 0x2a46 (en: 'union above intersection', MathPlayer: 'union above intersection', google: 'union über der kreuzung') @@ -1926,8 +1926,8 @@ - "⩌": [T: "Geschlossene Vereinigung mit Serifen"] # 0x2a4c (en: 'closed union with serifs', MathPlayer: 'closed union with serifs', google: 'geschlossene vereinigung mit serifen') - "⩍": [T: "Geschlossener Schnittpunkt mit Serifen"] # 0x2a4d (en: 'closed intersection with serifs', MathPlayer: 'closed intersection with serifs', google: 'geschlossener kreuzung mit serifen') - "⩎": [T: "Doppelter Quadratschnitt"] # 0x2a4e (en: 'double square intersection', google: 'doppelquadratische kreuzung') - - "⩏": [T: "Double Square Union"] # 0x2a4f (en: 'double square union', google: 'doppelquadratische gewerkschaft') - - "⩐": [T: "Closed Union mit Serifen und Smash-Produkten"] # 0x2a50 (en: 'closed union with serifs and smash product', MathPlayer: 'closed union with serifs and smash product', google: 'geschlossene vereinigung mit serifen und smash -produkt') + - "⩏": [T: "doppelte quadratische Vereinigung"] # 0x2a4f (en: 'double square union') + - "⩐": [T: "geschlossene Vereinigung mit Serifen und Smash-Produkt"] # 0x2a50 (en: 'closed union with serifs and smash product') - "⩑": [T: "Logisch und mit Punkt oben"] # 0x2a51 (en: 'logical and with dot above', google: 'logisch und mit punkt oben') - "⩒": [T: "Logisch oder mit Punkt oben"] # 0x2a52 (en: 'logical or with dot above', google: 'logisch oder mit punkt oben') - "⩓": [T: "doppeltes logisches Und"] # 0x2a53 @@ -1937,15 +1937,15 @@ - "⩗": [T: "Abfallend großes oder"] # 0x2a57 (en: 'sloping large or', MathPlayer: 'sloping large or', google: 'groß oder') - "⩘": [T: "Abfallend großes und"] # 0x2a58 (en: 'sloping large and', MathPlayer: 'sloping large and', google: 'groß und') - "⩙": [T: "Logisch oder Überlappend Logisch Und"] # 0x2a59 (en: 'logical or overlapping logical and', google: 'logisch oder überlappend logisch und') - - "⩚": [T: "Logisch und mit Middle Stem"] # 0x2a5a (en: 'logical and with middle stem', MathPlayer: 'logical and with middle stem', google: 'logisch und mit mittlerem stiel') - - "⩛": [T: "Logisch oder mit Middle Stem"] # 0x2a5b (en: 'logical or with middle stem', MathPlayer: 'logical or with middle stem', google: 'logisch oder mit mittlerem stiel') + - "⩚": [T: "logisches Und mit Mittelsteg"] # 0x2a5a (en: 'logical and with middle stem') + - "⩛": [T: "logisches Oder mit Mittelsteg"] # 0x2a5b (en: 'logical or with middle stem') - "⩜": [T: "Logisch und mit Horizontalstrich"] # 0x2a5c (en: 'logical and with horizontal dash', MathPlayer: 'logical and with horizontal dash', google: 'logisch und mit horizontalem armaturenbrett') - "⩝": [T: "Logisch oder mit Horizontalstrich"] # 0x2a5d (en: 'logical or with horizontal dash', MathPlayer: 'logical or with horizontal dash', google: 'logisch oder mit horizontalem strich') - - "⩞": [T: "Logisch und mit Double Overbar"] # 0x2a5e (en: 'logical and with double overbar', google: 'logisch und mit doppelter überbärung') - - "⩟": [T: "Logisch und mit Underbar"] # 0x2a5f (en: 'logical and with underbar', MathPlayer: 'logical and with underbar', google: 'logisch und mit unterbar') - - "⩠": [T: "Logisch und mit Double Underbar"] # 0x2a60 (en: 'logical and with double underbar', google: 'logisch und mit doppelter unterbarung') - - "⩡": [T: "kleines Vee mit Underbar"] # 0x2a61 (en: 'small vee with underbar', google: 'kleiner vee mit unterbar') - - "⩢": [T: "Logisch oder mit Double Overbar"] # 0x2a62 (en: 'logical or with double overbar', google: 'logisch oder mit doppelter überbärung') + - "⩞": [T: "logisches Und mit doppeltem Überstrich"] # 0x2a5e (en: 'logical and with double overbar') + - "⩟": [T: "logisches Und mit Unterstrich"] # 0x2a5f (en: 'logical and with underbar') + - "⩠": [T: "logisches Und mit doppeltem Unterstrich"] # 0x2a60 (en: 'logical and with double underbar') + - "⩡": [T: "kleines V mit Unterstrich"] # 0x2a61 (en: 'small vee with underbar') + - "⩢": [T: "logisches Oder mit doppeltem Überstrich"] # 0x2a62 (en: 'logical or with double overbar') - "⩣": [T: "Logisch oder mit doppelter Unterleiste"] # 0x2a63 (en: 'logical or with double underbar', google: 'logisch oder mit doppelter unterbarung') - "⩤": [T: "Z-Notation Domain Antirestriction"] # 0x2a64 (en: 'z notation domain antirestriction', google: 'z notation domain antirestriktion') - "⩥": [T: "Z Notationsbereich Antirestriction"] # 0x2a65 (en: 'z notation range antirestriction', google: 'z notation range antirestriktion') diff --git a/tests/Languages/de/ClearSpeak/symbols_and_adornments.rs b/tests/Languages/de/ClearSpeak/symbols_and_adornments.rs index 330776c90..f0c5cb6b3 100644 --- a/tests/Languages/de/ClearSpeak/symbols_and_adornments.rs +++ b/tests/Languages/de/ClearSpeak/symbols_and_adornments.rs @@ -48,6 +48,19 @@ fn compound_relation_symbols_are_localized() -> Result<()> { Ok(()) } +/// Unicode integral and logical-relation names must not fall back to English. +#[test] +fn unicode_integral_and_logical_symbols_are_localized() -> Result<()> { + test("de", "ClearSpeak", "", "Integral mit doppeltem Strich")?; + test("de", "ClearSpeak", "", "Integral mit Überstrich")?; + test("de", "ClearSpeak", "", "doppelte quadratische Vereinigung")?; + test("de", "ClearSpeak", "", + "geschlossene Vereinigung mit Serifen und Smash-Produkt")?; + test("de", "ClearSpeak", "", + "logisches Und mit doppeltem Überstrich")?; + Ok(()) +} + /// A geometric ray uses the German term rather than the English fallback. #[test] fn geometric_ray_is_localized() -> Result<()> {