From e8921d4e9f11b9c914b80fb76bfdc35013b4f149 Mon Sep 17 00:00:00 2001 From: Christos <5067905+ChristosBouronikos@users.noreply.github.com> Date: Mon, 28 Sep 2026 20:27:11 +0300 Subject: [PATCH] Add native Greek Math Reader style and terminology --- PythonScripts/audit_translations/parsers.py | 4 +- .../tests/test_definitions.py | 17 +- Rules/Languages/el/ClearSpeak_Rules.yaml | 1 + Rules/Languages/el/GreekMathReader_Rules.yaml | 213 ++++++ Rules/Languages/el/SharedRules/default.yaml | 53 +- Rules/Languages/el/SharedRules/general.yaml | 19 +- .../el/SharedRules/reader-intents.yaml | 162 ++++ Rules/Languages/el/SimpleSpeak_Rules.yaml | 1 + Rules/Languages/el/definitions.yaml | 155 +++- Rules/Languages/el/navigate.yaml | 105 ++- Rules/Languages/el/unicode-full.yaml | 35 +- Rules/Languages/el/unicode.yaml | 115 ++- docs/greek-math-reader-examples.html | 111 +++ docs/greek-math-reader.md | 185 +++++ docs/index.md | 2 +- tests/Languages/el.rs | 7 + tests/Languages/el/navigation.rs | 97 +++ tests/Languages/el/reader.rs | 281 +++++++ tests/Languages/el/reader_documents.rs | 189 +++++ tests/Languages/el/reader_intents.rs | 712 ++++++++++++++++++ tests/Languages/el/reader_symbols.rs | 88 +++ tests/languages.rs | 1 + 22 files changed, 2474 insertions(+), 79 deletions(-) create mode 100644 Rules/Languages/el/GreekMathReader_Rules.yaml create mode 100644 Rules/Languages/el/SharedRules/reader-intents.yaml create mode 100644 docs/greek-math-reader-examples.html create mode 100644 docs/greek-math-reader.md create mode 100644 tests/Languages/el/navigation.rs create mode 100644 tests/Languages/el/reader.rs create mode 100644 tests/Languages/el/reader_documents.rs create mode 100644 tests/Languages/el/reader_intents.rs create mode 100644 tests/Languages/el/reader_symbols.rs diff --git a/PythonScripts/audit_translations/parsers.py b/PythonScripts/audit_translations/parsers.py index bcbdd0027..60b213674 100644 --- a/PythonScripts/audit_translations/parsers.py +++ b/PythonScripts/audit_translations/parsers.py @@ -123,7 +123,7 @@ def invalid(message: str) -> AuditError: if isinstance(value, dict): if not value: - raise invalid("empty mappings have no unambiguous definition kind") + return DefinitionKind.SET if not all(isinstance(key, str) for key in value): raise invalid("mapping keys must all be strings") @@ -136,7 +136,7 @@ def invalid(message: str) -> AuditError: raise invalid("mixed set/map values are not supported") raise invalid("mapping values must be all null (set) or all strings (map)") - raise invalid("value must be a non-empty sequence or mapping") + raise invalid("value must be a sequence or mapping") def format_tag(tag_value: Any) -> str | None: diff --git a/PythonScripts/audit_translations/tests/test_definitions.py b/PythonScripts/audit_translations/tests/test_definitions.py index a87fc51d2..68cead7ff 100644 --- a/PythonScripts/audit_translations/tests/test_definitions.py +++ b/PythonScripts/audit_translations/tests/test_definitions.py @@ -8,7 +8,7 @@ from ..auditor import compare_definition_files from ..errors import AuditError from ..models.definitions import DefinitionKind -from ..parsers import parse_definitions +from ..parsers import parse_definitions, parse_definitions_file def parse(content: str): @@ -66,19 +66,24 @@ def test_parse_definitions_rejects_empty_vector() -> None: assert_invalid("- Foo: []\n", "empty sequences") -def test_parse_definitions_rejects_empty_mapping() -> None: - """An empty mapping is rejected because it could be either a set or a map.""" - assert_invalid("- Foo: {}\n", "empty mappings") +def test_parse_empty_greek_known_words_as_set() -> None: + """Greek KnownWords uses an empty mapping, which MathCAT loads as an empty set.""" + repo_root = Path(__file__).resolve().parents[3] + definitions, _ = parse_definitions_file(repo_root / "Rules/Languages/el/definitions.yaml") + + known_words = definitions["KnownWords"] + assert known_words.kind is DefinitionKind.SET + assert known_words.data == {} def test_parse_definitions_rejects_string_scalar() -> None: """A string scalar cannot be used as a definition value.""" - assert_invalid("- Foo: bar\n", "non-empty sequence or mapping") + assert_invalid("- Foo: bar\n", "sequence or mapping") def test_parse_definitions_rejects_numeric_scalar() -> None: """A numeric scalar cannot be used as a definition value.""" - assert_invalid("- Foo: 123\n", "non-empty sequence or mapping") + assert_invalid("- Foo: 123\n", "sequence or mapping") def test_parse_definitions_rejects_nested_mapping_value() -> None: diff --git a/Rules/Languages/el/ClearSpeak_Rules.yaml b/Rules/Languages/el/ClearSpeak_Rules.yaml index 61782a6f1..8f5715a07 100644 --- a/Rules/Languages/el/ClearSpeak_Rules.yaml +++ b/Rules/Languages/el/ClearSpeak_Rules.yaml @@ -904,6 +904,7 @@ replace: - x: "*[2]" +- include: "SharedRules/reader-intents.yaml" - include: "SharedRules/geometry.yaml" - include: "SharedRules/linear-algebra.yaml" - include: "SharedRules/general.yaml" diff --git a/Rules/Languages/el/GreekMathReader_Rules.yaml b/Rules/Languages/el/GreekMathReader_Rules.yaml new file mode 100644 index 000000000..f2afca7ed --- /dev/null +++ b/Rules/Languages/el/GreekMathReader_Rules.yaml @@ -0,0 +1,213 @@ +--- +# Greek Math Reader mathematical reading conventions, implemented as native MathCAT rules. +# NVDA Greek Math (Greek Math Reader) by Bouronikos Christos (cbouronikos@uth.gr) +# New wording remains lowercase until Greek expert and screen-reader listening review. +# Native SimpleSpeak supplies structures not overridden here, including tables and units. + +- name: reader-silent-token + tag: [mi, mo, mn] + match: "contains(@data-intent-property, ':silent:')" + replace: [] + +- name: reader-equality + tag: mo + match: ".='='" + replace: [t: "ίσον"] + +- name: reader-plus-minus + tag: mo + match: ".='±'" + replace: [t: "συν πλην"] + +- name: reader-decimal + tag: mn + match: "contains(., $DecimalSeparators)" + replace: + - bookmark: "@id" + - x: "translate(substring-before(., $DecimalSeparators), $BlockSeparators, '')" + - t: "κόμμα" + - x: "substring-after(., $DecimalSeparators)" + +# Recognize conventional notation only within this speech style. Author-supplied +# literal intent and unrelated notation retain MathCAT's structural reading. +- name: reader-scalar-multiplication + tag: mo + match: ".='·' and not(ancestor-or-self::*[contains(@data-intent-property, ':literal:')])" + replace: [t: "επί"] + +- name: reader-first-derivative + tag: fraction + match: + - "count(*)=2 and *[1][self::m:mrow] and *[2][self::m:mrow] and" + - "*[1]/*[1][.='d' or .='∂'] and *[1]/*[1]=*[2]/*[1] and" + - "((count(*[1]/*)=3 and count(*[2]/*)=3 and *[1]/*[2]='⁢' and *[2]/*[2]='⁢') or" + - "(count(*[1]/*)=2 and count(*[2]/*)=2 and *[1]/*[1]='∂')) and" + - "*[2]/*[last()][self::m:mi] and not(ancestor-or-self::*[contains(@data-intent-property, ':literal:')])" + replace: + - test: + if: "*[1]/*[1][.='∂']" + then: [t: "μερική παράγωγος του"] + else: [t: "παράγωγος του"] + - x: "*[1]/*[last()]" + - t: "ως προς" + - x: "*[2]/*[last()]" + +- name: reader-integral-differential + tag: mrow + match: + - "count(*)>=5 and preceding-sibling::*[1][self::m:large-op and *[1][contains('∫∬∭∮∯∰', .)]] and" + - "*[last()-3][self::m:mo and .='⁢'] and *[last()-2][self::m:mi and .='d'] and" + - "*[last()-1][self::m:mo and .='⁢'] and *[last()][self::m:mi] and" + - "not(ancestor-or-self::*[contains(@data-intent-property, ':literal:')])" + replace: + - x: "*[position() k+1 args, + # spoken as name + glue1 + arg1 + ... + "of" + lastArg (e.g. "| over | from,to") + # * unmatched arity (or binary glue with ≠2 args): commas between all args tag: "*" match: "count(*)>0" replace: - x: "SpeakIntentName(name(.), $Verbosity, 'function')" - test: - if: "$Verbosity != 'Terse' and not(contains(@data-intent-property, ':literal:')) and - not(count(*)=2 and (IsInDefinition(*[1], 'TrigFunctionNames') or IsInDefinition(name(.), 'TerseFunctionNames')) and IsNode(*[2], 'simple'))" - then: [t: "του", pause: auto] # phrase(sine 'of' 5) - - - insert: - nodes: "*" - replace: - - test: - if: "not(contains(@data-intent-property, ':literal:'))" - then: [x: "','"] + - if: "IntentFunctionUseArityPath(name(.), 'function', count(*))" + then: + - x: "IntentFunctionGlueBefore(name(.), 'function', 1, count(*))" - pause: auto + - insert: + nodes: "*" + replace: + - x: "IntentFunctionGlueBefore(name(.), 'function', $InsertIndex, count(*))" + - pause: auto + else: + - test: + if: "$Verbosity != 'Terse' and not(contains(@data-intent-property, ':literal:')) and + not(count(*)=2 and (IsInDefinition(*[1], 'TrigFunctionNames') or IsInDefinition(name(.), 'TerseFunctionNames')) and IsNode(*[2], 'simple'))" + then: [t: "του", pause: auto] # phrase(sine 'of' 5) + - insert: + nodes: "*" + replace: + - test: + if: "not(contains(@data-intent-property, ':literal:'))" + then: [x: "IntentFunctionArgSeparator(name(.), 'function', count(*))"] + - pause: auto - test: # speak "end ..." if not bracketed or last child is not simple and not last node if: "$Impairment = 'Blindness' and not(*[last()][IsBracketed(., '', '') or IsNode(., 'simple')] )" diff --git a/Rules/Languages/el/SharedRules/general.yaml b/Rules/Languages/el/SharedRules/general.yaml index 41671f5b9..f1f6d9f79 100644 --- a/Rules/Languages/el/SharedRules/general.yaml +++ b/Rules/Languages/el/SharedRules/general.yaml @@ -814,6 +814,23 @@ then: [t: "ινφ"] else: [t: "ινφίμουμ"] ##################### +- name: currency + tag: mrow + match: "count(*)=3 and *[2][self::m:mo and .='⁢'] and *[3][self::m:mn] and DefinitionValue(*[1], 'Speech', 'CurrencySymbols') != ''" + variables: + # If the amount is singular, we don't add the plural ending. + - IsSingular: "*[3][self::m:mn and .=1] and *[2]='\u2062'" + - CurrencyWord: "DefinitionValue(*[1], 'Speech', 'CurrencySymbols')" + replace: + - bookmark: "*[3]/@id" + - x: "*[3]" + - test: + - if: "$IsSingular" + then: [x: "$CurrencyWord"] + - else_if: "DefinitionValue($CurrencyWord, 'Speech', 'PluralForms') != ''" + then: [x: "DefinitionValue($CurrencyWord, 'Speech', 'PluralForms')"] + else: [x: "DefinitionValue(*[1], 'Speech', 'CurrencySymbols')"] + - name: sin tag: mi match: ".='sin'" @@ -1439,7 +1456,7 @@ replace: - insert: nodes: "*" - replace: [t: "by", pause: auto] # phrase(3 'by' 5 matrix) + replace: [t: "επί", pause: auto] # phrase(3 'by' 5 matrix) - name: chemistry-msup tag: [chemical-formula] diff --git a/Rules/Languages/el/SharedRules/reader-intents.yaml b/Rules/Languages/el/SharedRules/reader-intents.yaml new file mode 100644 index 000000000..d65bd6c90 --- /dev/null +++ b/Rules/Languages/el/SharedRules/reader-intents.yaml @@ -0,0 +1,162 @@ +--- +# Greek grammar for the exported Greek Math Reader semantic concepts. +# Explicit arities keep malformed or extended intents on MathCAT's generic, +# operand-preserving fallback. No domain is guessed from an ambiguous letter. +# NVDA Greek Math (Greek Math Reader) by Bouronikos Christos (cbouronikos@uth.gr) +# Candidate terminology is documented in docs/greek-math-reader.md. + +- name: reader-conditional-expectation + tag: conditional-expectation + match: "count(*)=2 and contains(@data-intent-property, ':function:') and not(contains(@data-intent-property, ':literal:'))" + replace: + - t: "δεσμευμένη αναμενόμενη τιμή του" + - x: "*[1]" + - t: "δεδομένου του" + - x: "*[2]" + +- name: reader-covariance + tag: [covariance, commutator, anticommutator, classical-hamiltonian] + match: "count(*)=2 and contains(@data-intent-property, ':function:') and not(contains(@data-intent-property, ':literal:'))" + replace: + - x: "SpeakIntentName(name(.), $Verbosity, 'function')" + - t: "των" + - x: "*[1]" + - t: "και" + - x: "*[2]" + +- name: reader-coordinate + tag: coordinate + match: "count(*)>=2 and contains(@data-intent-property, ':function:') and not(contains(@data-intent-property, ':literal:'))" + replace: + - t: "σημείο με συντεταγμένες" + - insert: + nodes: "*" + replace: [t: "και"] + +- name: reader-point-definition + tag: point-definition + match: "count(*)>=3 and contains(@data-intent-property, ':function:') and not(contains(@data-intent-property, ':literal:'))" + replace: + - t: "το σημείο" + - x: "*[1]" + - t: "έχει συντεταγμένες" + - insert: + nodes: "*[position()>1]" + replace: [t: "και"] + +- name: reader-normal-distribution + tag: normal-distribution + match: "count(*)=3 and contains(@data-intent-property, ':function:') and not(contains(@data-intent-property, ':literal:'))" + replace: + - x: "*[1]" + - t: "ακολουθεί κανονική κατανομή με μέση τιμή" + - x: "*[2]" + - t: "και διακύμανση" + - x: "*[3]" + +- name: reader-modular-congruence + tag: modular-congruence + match: "count(*)=3 and contains(@data-intent-property, ':function:') and not(contains(@data-intent-property, ':literal:'))" + replace: + - x: "*[1]" + - t: "ισότιμο με" + - x: "*[2]" + - t: "μόντουλο" + - x: "*[3]" + +- name: reader-evaluation + tag: evaluation + match: "count(*)=3 and contains(@data-intent-property, ':function:') and not(contains(@data-intent-property, ':literal:'))" + replace: + - x: "*[1]" + - pause: short + - t: "υπολογισμένο από" + - x: "*[2]" + - t: "έως" + - x: "*[3]" + +- name: reader-identified-transform + tag: [fourier-transform, laplace-transform] + match: "count(*)=1 and contains(@data-intent-property, ':function:') and not(contains(@data-intent-property, ':literal:'))" + replace: + - x: "SpeakIntentName(name(.), $Verbosity, 'function')" + - test: + if: "self::m:fourier-transform" + then: [t: "της"] + else: [t: "του"] + - x: "*[1]" + +- name: reader-dirac-delta + tag: dirac-delta + match: "count(*)=1 and contains(@data-intent-property, ':function:') and not(contains(@data-intent-property, ':literal:'))" + replace: + - t: "δέλτα του Ντιράκ στο" + - x: "*[1]" + +- name: reader-condition + tag: [initial-condition, boundary-condition] + match: "count(*)=1 and contains(@data-intent-property, ':function:') and not(contains(@data-intent-property, ':literal:'))" + replace: + - x: "SpeakIntentName(name(.), $Verbosity, 'function')" + - pause: short + - x: "*[1]" + +- name: reader-braket + tag: braket + match: "count(*)=2 and contains(@data-intent-property, ':function:') and not(contains(@data-intent-property, ':literal:'))" + replace: + - t: "εσωτερικό γινόμενο" + - x: "*[1]" + - t: "με" + - x: "*[2]" + +- name: reader-matrix-element + tag: matrix-element + match: "count(*)=3 and contains(@data-intent-property, ':function:') and not(contains(@data-intent-property, ':literal:'))" + replace: + - t: "στοιχείο πίνακα με μπρα" + - x: "*[1]" + - x: "*[2]" + - t: "κετ" + - x: "*[3]" + +- name: reader-derivative + tag: [ordinary-derivative, partial-derivative] + match: "count(*)=2 and contains(@data-intent-property, ':function:') and not(contains(@data-intent-property, ':literal:'))" + replace: + - x: "SpeakIntentName(name(.), $Verbosity, 'function')" + - t: "του" + - x: "*[1]" + - t: "ως προς" + - x: "*[2]" + +- name: reader-directional-derivative + tag: directional-derivative + match: "count(*)=2 and contains(@data-intent-property, ':function:') and not(contains(@data-intent-property, ':literal:'))" + replace: + - t: "παράγωγος του" + - x: "*[1]" + - t: "κατά την κατεύθυνση" + - x: "*[2]" + +- name: reader-quotient-group + tag: quotient-group + match: "count(*)=2 and contains(@data-intent-property, ':function:') and not(contains(@data-intent-property, ':literal:'))" + replace: + - t: "ομάδα πηλίκο του" + - x: "*[1]" + - t: "ως προς" + - x: "*[2]" + +- name: reader-identity-matrix + tag: identity-matrix + match: "count(*)=1 and contains(@data-intent-property, ':function:') and not(contains(@data-intent-property, ':literal:'))" + replace: + - t: "μοναδιαίος πίνακας τάξης" + - x: "*[1]" + +- name: reader-zero-argument-intent + tag: "*" + match: "count(*)=0 and contains(@data-intent-property, ':function:') and DefinitionValue(name(.), 'Speech', 'IntentMappings') != ''" + replace: + - x: "SpeakIntentName(name(.), $Verbosity, 'function')" diff --git a/Rules/Languages/el/SimpleSpeak_Rules.yaml b/Rules/Languages/el/SimpleSpeak_Rules.yaml index 65994d1c3..5db5e684a 100644 --- a/Rules/Languages/el/SimpleSpeak_Rules.yaml +++ b/Rules/Languages/el/SimpleSpeak_Rules.yaml @@ -387,6 +387,7 @@ replace: - x: "*[2]" +- include: "SharedRules/reader-intents.yaml" - include: "SharedRules/geometry.yaml" - include: "SharedRules/linear-algebra.yaml" - include: "SharedRules/general.yaml" diff --git a/Rules/Languages/el/definitions.yaml b/Rules/Languages/el/definitions.yaml index d507f0719..090ae5de9 100644 --- a/Rules/Languages/el/definitions.yaml +++ b/Rules/Languages/el/definitions.yaml @@ -44,7 +44,7 @@ "kernel": "function= ; πυρήνας : πυρήνας: ο πυρήνας; τέλος πυρήνα", "vector": "function= ; διάνυσμα || prefix=διάνυσμα", "cross-product": "infix=διανυσματικό γινόμενο", # theodora. check το είχε έτσι "infix=cross: διανυσματικό γινόμενο: διανυσματικό γινόμενο", - "dot-product": "infix=τελεία: εσωτερικό γινόμενο: τελεία: εσωτερικό γινόμενο", #theodora. check. είναι ολα εσωτερικό γινόμενο ή πιάνει κι άλλα οπότε θέλει πιο γενικό όρο; + "dot-product": "infix=τελεία: εσωτερικό γινόμενο: εσωτερικό γινόμενο", #theodora. check. είναι ολα εσωτερικό γινόμενο ή πιάνει κι άλλα οπότε θέλει πιο γενικό όρο; "divergence": "function= ; απόκλιση: απόκλιση: απόκλιση; τέλος απόκλισης", "curl": "function= ; στροβιλισμός; τέλος στροβιλισμού", @@ -52,6 +52,102 @@ "laplacian": "function=λαπλασιανή", # speech engines don't do a good job with "laplacian" "chemistry-concentration": "function= ; συγκέντρωση: η συγκέντρωση του: η συγκέντρωση του; τέλος συγκέντρωσης", + + # NVDA Greek Math (Greek Math Reader) by Bouronikos Christos (cbouronikos@uth.gr) + # Exported registry 2026.08.2; supplied under MathCAT terms. + # Pending entries remain terminology candidates, not expert-verified translations. + "acceleration": "function=επιτάχυνση", # source-checked-pending-expert-review + "adjoint": "function=συζυγής ανάστροφος", # source-checked-pending-expert-review + "angular-momentum": "function=στροφορμή", # source-checked-pending-expert-review + "anticommutator": "function=αντιμεταθέτης", # source-checked-pending-expert-review + "asymptotic-equivalence": "infix=είναι ασυμπτωτικά ισοδύναμο με", # source-checked-pending-expert-review + "augmented-matrix": "function=επαυξημένος πίνακας", # source-checked-pending-expert-review + "block-matrix": "function=πίνακας κατά μπλοκ", # source-checked-pending-expert-review + "boundary-condition": "function=συνοριακή συνθήκη", # source-checked-pending-expert-review + "bounded-operator": "function=φραγμένος τελεστής", # source-checked-pending-expert-review + "bra": "function=μπρα", # source-checked-pending-expert-review + "braket": "function=εσωτερικό γινόμενο", # source-checked-pending-expert-review + "cardinality": "function=πληθάριθμος", # reviewed + "classical-hamiltonian": "function=χαμιλτονιανή συνάρτηση", # source-checked-pending-expert-review + "closed-interval": "function=κλειστό διάστημα", # reviewed + "closed-open-interval": "function=διάστημα κλειστό αριστερά ανοιχτό δεξιά", # reviewed + "commutator": "function=μεταθέτης", # source-checked-pending-expert-review + "conditional-expectation": "function=δεσμευμένη αναμενόμενη τιμή", # source-checked-pending-expert-review + "confidence-interval": "function=διάστημα εμπιστοσύνης", # source-checked-pending-expert-review + "contravariant-index": "function=ανταλλοίωτος δείκτης", # source-checked-pending-expert-review + "coordinate": "function=σημείο με συντεταγμένες", # reviewed + "covariance": "function=συνδιακύμανση", # source-checked-pending-expert-review + "covariant-index": "function=συναλλοίωτος δείκτης", # source-checked-pending-expert-review + "diagonal-matrix": "function=διαγώνιος πίνακας", # source-checked-pending-expert-review + "differential-form": "function=διαφορική μορφή", # source-checked-pending-expert-review + "dirac-delta": "function=δέλτα του Ντιράκ στο", # source-checked-pending-expert-review + "directional-derivative": "function=παράγωγος κατά την κατεύθυνση", # source-checked-pending-expert-review + "eigenvalue": "function=ιδιοτιμή", # source-checked-pending-expert-review + "eigenvector": "function=ιδιοδιάνυσμα", # source-checked-pending-expert-review + "electric-field": "function=ηλεκτρικό πεδίο", # source-checked-pending-expert-review + "entropy": "function=εντροπία", # source-checked-pending-expert-review + "estimator": "function=εκτιμητής", # source-checked-pending-expert-review + "evaluation": "function=υπολογισμένο", # source-checked-pending-expert-review + "expectation": "function=αναμενόμενη τιμή", # source-checked-pending-expert-review + "exterior-product": "infix=εξωτερικό γινόμενο", # source-checked-pending-expert-review + "field-structure": "function=σώμα", # source-checked-pending-expert-review + "four-momentum": "function=τετραορμή", # source-checked-pending-expert-review + "four-vector": "function=τετραδιάνυσμα", # source-checked-pending-expert-review + "fourier-transform": "function=μετασχηματισμός Φουριέ", # source-checked-pending-expert-review + "gamma-function": "function=συνάρτηση γάμα", # source-checked-pending-expert-review + "generalized-function": "function=γενικευμένη συνάρτηση", # source-checked-pending-expert-review + "group": "function=ομάδα", # source-checked-pending-expert-review + "hamiltonian": "function=χαμιλτονιανός τελεστής", # source-checked-pending-expert-review + "hessian": "function=εσσιανός πίνακας", # source-checked-pending-expert-review + "hypothesis-test": "function=έλεγχος υπόθεσης", # source-checked-pending-expert-review + "ideal": "function=ιδεώδες", # source-checked-pending-expert-review + "identity-matrix": "function=μοναδιαίος πίνακας τάξης", # source-checked-pending-expert-review + "independence": "infix=ανεξάρτητο από", # source-checked-pending-expert-review + "initial-condition": "function=αρχική συνθήκη", # source-checked-pending-expert-review + "interval": "function=διάστημα", # reviewed + "jacobian": "function=ιακωβιανός πίνακας", # source-checked-pending-expert-review + "ket": "function=κετ", # source-checked-pending-expert-review + "lagrangian": "function=λαγκρανζιανή συνάρτηση", # source-checked-pending-expert-review + "laplace-transform": "function=μετασχηματισμός Λαπλάς", # source-checked-pending-expert-review + "line-integral": "function=επικαμπύλιο ολοκλήρωμα", # source-checked-pending-expert-review + "magnetic-field": "function=μαγνητικό πεδίο", # source-checked-pending-expert-review + "manifold": "function=πολλαπλότητα", # source-checked-pending-expert-review + "material-derivative": "function=υλική παράγωγος", # source-checked-pending-expert-review + "matrix-element": "function=στοιχείο πίνακα", # source-checked-pending-expert-review + "measure": "function=μέτρο", # source-checked-pending-expert-review + "metric-tensor": "function=μετρικός τανυστής", # source-checked-pending-expert-review + "modular-congruence": "function=ισότιμο με", # source-checked-pending-expert-review + "momentum": "function=ορμή", # source-checked-pending-expert-review + "morphism": "function=μορφισμός", # source-checked-pending-expert-review + "multiple-integral": "function=πολλαπλό ολοκλήρωμα", # source-checked-pending-expert-review + "normal-distribution": "function=ακολουθεί κανονική κατανομή", # source-checked-pending-expert-review + "open-closed-interval": "function=διάστημα ανοιχτό αριστερά κλειστό δεξιά", # reviewed + "open-interval": "function=ανοιχτό διάστημα", # reviewed + "open-set": "function=ανοιχτό σύνολο", # source-checked-pending-expert-review + "ordinary-derivative": "function=παράγωγος", # source-checked-pending-expert-review + "partial-derivative": "function=μερική παράγωγος", # source-checked-pending-expert-review + "partition-function": "function=συνάρτηση επιμερισμού", # source-checked-pending-expert-review + "point-definition": "function=έχει συντεταγμένες", # source-checked-pending-expert-review + "position-vector": "function=διάνυσμα θέσης", # source-checked-pending-expert-review + "power": "function=δύναμη", # reviewed + "probability": "function=πιθανότητα", # reviewed + "proper-time": "function=ιδιοχρόνος", # source-checked-pending-expert-review + "quadratic-form": "function=τετραγωνική μορφή", # source-checked-pending-expert-review + "quantum-adjoint": "function=ερμιτιανός συζυγής", # source-checked-pending-expert-review + "quantum-operator": "function=κβαντικός τελεστής", # source-checked-pending-expert-review + "quotient-group": "function=ομάδα πηλίκο", # source-checked-pending-expert-review + "ring": "function=δακτύλιος", # source-checked-pending-expert-review + "semantic-entailment": "infix=συνεπάγεται σημασιολογικά", # source-checked-pending-expert-review + "standard-deviation": "function=τυπική απόκλιση", # reviewed + "stochastic-integral": "function=στοχαστικό ολοκλήρωμα", # source-checked-pending-expert-review + "stochastic-process": "function=στοχαστική διαδικασία", # source-checked-pending-expert-review + "surface-integral": "function=επιφανειακό ολοκλήρωμα", # source-checked-pending-expert-review + "tensor-product": "infix=τανυστικό γινόμενο", # reviewed + "topological-space": "function=τοπολογικός χώρος", # source-checked-pending-expert-review + "torque": "function=ροπή", # source-checked-pending-expert-review + "variance": "function=διακύμανση", # reviewed + "velocity": "function=ταχύτητα", # source-checked-pending-expert-review + "wavefunction": "function=κυματοσυνάρτηση", # source-checked-pending-expert-review } # Names of functions that in terse mode don't say "of" (or it's equivalent in other languages) @@ -61,6 +157,8 @@ - NavigationParts: { # These are the parts of a formula that can be navigated to "large-op": "βάση; κάτω όριο; άνω όριο", + "logarithm-with-base": "βάση", + "indexed-by": "βάση; δείκτης", "mfrac": "αριθμητής; παρονομαστής", "fraction": "αριθμητής; παρονομαστής", "msqrt": "ρίζα", @@ -80,8 +178,11 @@ # words for moving into and out of one of the parts (e.g., "move right 'out of' numerator, 'in' denominator") # it's a hack to put them here, but at least they are grouped with the other navigation parts - "in": "in", - "out": "out of", + "in": "μέσα σε", + "out": "έξω από", + "out of": "έξω από", + "end of": "τέλος", + "start of": "αρχή", } @@ -277,6 +378,10 @@ } - PluralForms: { + "δολάριο": "δολάρια", "σεντ": "σεντ", "ευρώ": "ευρώ", "λίρα": "λίρες", + "κολόν": "κολόν", "λιρέτα": "λιρέτες", "ρουπία": "ρουπίες", "γουόν": "γουόν", + "σέκελ": "σέκελ", "πέσο": "πέσο", "μπιτκόιν": "μπιτκόιν", + # FIX: this needs to be flushed out ### -------------- SIUnits -------------- ### vivi # base units @@ -284,7 +389,6 @@ "κιλό": "κιλά", "εκατοστό": "εκατοστά", "μέτρο": "μέτρα", # British spelling works for US also - "δευτερόλεπτο": "δευτερόλεπτα", "αμπέρ": "αμπέρ", "καντέλα": "καντέλα", "κέλβιν": "κέλβιν", # U+212A @@ -316,7 +420,6 @@ # accepted (plus a few variants) that take SI prefixes "λίτρο": "λίτρα", "τόνος": "τόνοι", # should only take positive powers - "ατομική μονάδα μάζας": "ατομικές μονάδες μάζας", # 'u' is correct: https://en.wikipedia.org/wiki/Dalton_(unit) "ακτίνιο": "ακτίνια", # should only take negative powers "στερακτίνιο": "στερακτίνια", # should only take negative powers "ντάλτον": "ντάλτον", @@ -325,7 +428,6 @@ # others that take a prefix - "δευτερόλεπτο τόξου": "δευτερόλεπτα τόξου", # see en.wikipedia.org/wiki/Minute_and_second_of_arc "άνουμ": "άνουμ", "μπιτ": "μπιτ", # should only take positive powers @@ -345,7 +447,6 @@ "έτος": "έτη", # angles - "βαθμός": "βαθμοί", "λεπτό τόξου": "λεπτά τόξου", "δευτερόλεπτο τόξου": "δευτερόλεπτα τόξου", @@ -408,7 +509,6 @@ "ουγγιά υγρών": "ουγγιές υγρών", "φλιτζάνι": "φλιτζάνια", - "πίντα": "πίντες", "γαλόνι": "γαλόνια", "πίντα": "πίντα", "κουάρτ": "κουάρτ", @@ -536,4 +636,41 @@ ] - NumbersOrdinalPluralLarge: [ "", "χιλιαστοί", "εκατομμυριοστοί", "δισεκατομμυριοστοί", "τρισεκατομμυριοστοί", "τετράκις εκατομμυριοστοί", "πεντάκις εκατομμυριοστοί", "εξάκις εκατομμυριοστοί", "επτάκις εκατομμυριοστοί", "οκτάκις εκατομμυριοστοί", "εννεάκις εκατομμυριοστοί", "δεκάκις εκατομμυριοστοί", "ενδεκάκις εκατομμυριοστοί", "δωδεκάκις εκατομμυριοστοί", "δεκατριάκις εκατομμυριοστοί", "δεκατετράκις εκατομμυριοστοί", "δεκαπεντάκις εκατομμυριοστοί", "δεκαεξάκις εκατομμυριοστοί", "δεκαεπτάκις εκατομμυριοστοί", "δεκαοκτάκις εκατομμυριοστοί", "δεκαεννεάκις εκατομμυριοστοί", "εικοσάκις εκατομμυριοστοί", "εικοσιάπαξ εκατομμυριοστοί", "εικοσιδίς εκατομμυριοστοί", "εικοσιτρίς εκατομμυριοστοί", "εικοσιτετράκις εκατομμυριοστοί", "εικοσιπεντάκις εκατομμυριοστοί", "εικοσιεξάκις εκατομμυριοστοί" - ] \ No newline at end of file + ] +# Letter names for the GreekMathReader style; existing styles keep their conventions. +- GreekMathReaderLetters: { + "a": "έι", + "b": "μπί", + "c": "σί", + "d": "ντί", + "e": "ί", + "f": "εφ", + "g": "τζί", + "h": "έιτς", + "i": "άι", + "j": "τζέι", + "k": "κάπα", + "l": "έλ", + "m": "μι", + "n": "νι", + "o": "όμικρον", + "p": "πι", + "q": "κιού", + "r": "άρ", + "s": "ες", + "t": "ταυ", + "u": "γιού", + "v": "βί", + "w": "ντάμπλιου", + "x": "χι", + "y": "γουάι", + "z": "ζήτα", + } + +- FunctionApplicationWord: ["του"] + +- CurrencySymbols: { + "$": "δολάριο", "¢": "σεντ", "€": "ευρώ", "£": "λίρα", "₡": "κολόν", + "₤": "λιρέτα", "₨": "ρουπία", "₩": "γουόν", "₪": "σέκελ", "₱": "πέσο", + "₹": "ρουπία", "₺": "λίρα", "₿": "μπιτκόιν" + } diff --git a/Rules/Languages/el/navigate.yaml b/Rules/Languages/el/navigate.yaml index 1cbfcc6f5..81b6eff85 100644 --- a/Rules/Languages/el/navigate.yaml +++ b/Rules/Languages/el/navigate.yaml @@ -48,34 +48,37 @@ - if: "$MatchCounter = 0 and $SayCommand = 'true'" then_test: - if: "self::m:math and starts-with($NavCommand, 'ZoomOut')" - then: [t: "πλήρης μεγέθυνση", pause: "medium"] + then: [t: "πλήρης σμίκρυνση", pause: "medium"] - else_if: "IsNode(., 'leaf') and starts-with($NavCommand, 'ZoomIn')" then: [t: "πλήρης μεγέθυνση", pause: "medium"] else: - test: - if: "starts-with($NavCommand, 'Zoom')" - then: [set_variables: [Prefix: "'zoom'", CommandOffset: "5"]] # phrase('zoom' in to see more details) + then: + - set_variables: [CommandOffset: "5"] + - test: + - if: "starts-with($NavCommand, 'ZoomOut')" + then: [set_variables: [Prefix: "'σμίκρυνση'"]] + else: [set_variables: [Prefix: "'μεγέθυνση'"]] - else_if: "starts-with($NavCommand, 'Move')" - then: [set_variables: [Prefix: "'move'", CommandOffset: "5"]] # phrase('move' to next entry in table) + then: [set_variables: [Prefix: "'μετακίνηση'", CommandOffset: "5"]] - else_if: "starts-with($NavCommand, 'Read')" - then: [set_variables: [Prefix: "'read'", CommandOffset: "5"]] # phrase('read' to next entry in table) + then: [set_variables: [Prefix: "'ανάγνωση'", CommandOffset: "5"]] - else_if: "starts-with($NavCommand, 'Describe')" - then: [set_variables: [Prefix: "'describe'", CommandOffset: "9"]] # phrase('describe' to next entry in table) + then: [set_variables: [Prefix: "'περιγραφή'", CommandOffset: "9"]] - test: if: "$Prefix != ''" then: - x: "$Prefix" - test: - if: "substring($NavCommand, $CommandOffset) = 'In'" - then: [t: "εντός"] # phrase(zoom 'in' to see more details) + then: [t: "προς τα μέσα"] # phrase(zoom 'in' to see more details) - else_if: "substring($NavCommand, $CommandOffset) = 'InAll'" - # HACK: '\uF8FE' is used internally for the concatenation char by 'ct' -- this gets "ed" concatenated to "zoom" - then: [t: "\uF8FEed πλήρως"] #theodora. check # phrase(zoom 'out all the way' to see more details) + then: [t: "μέχρι τέλους"] #theodora. check # phrase(zoom 'out all the way' to see more details) - else_if: "substring($NavCommand, $CommandOffset) = 'Out'" - then: [t: "εκτός"] # phrase(zoom 'out' to see more details) + then: [t: "προς τα έξω"] # phrase(zoom 'out' to see more details) - else_if: "substring($NavCommand, $CommandOffset) = 'OutAll'" - # HACK: '\uF8FE' is used internally for the concatenation char by 'ct' -- this gets "ed" concatenated to "zoom" - then: [t: "\uF8FEed πλήρως"] #theodora. check # phrase(zoom 'out all the way' to see more details) + then: [t: "μέχρι τέλους"] #theodora. check # phrase(zoom 'out all the way' to see more details) - else_if: "substring($NavCommand, $CommandOffset) = 'Next'" then: [t: "δεξιά"] # phrase(move to the 'right') - else_if: "substring($NavCommand, $CommandOffset) = 'Previous'" @@ -96,6 +99,14 @@ (name(.)='mrow' or name(.) = 'mtr' or name(.) = 'mlabeledtr' or @data-from-mathml = 'mtable')" replace: [] +# Prefix/silent intents with no NavigationParts entry should not announce "in"/"out". +- name: into-or-out-of-prefix-or-silent-without-parts + tag: "*" + match: "$Move2D != '' and + (contains(@data-intent-property, ':prefix:') or contains(@data-intent-property, ':silent:')) and + GetNavigationPartName(name(.), count($Child2D/preceding-sibling::*)) = ''" + replace: [] + - name: into-or-out-of-mtr tag: [mtr, mlabeledtr] match: "$Move2D = 'in'" @@ -115,7 +126,7 @@ variables: - NumPrecedingSiblings: "count($Child2D/preceding-sibling::*)" replace: - - x: "$Move2D" + - x: "GetNavigationPartName($Move2D, 0)" - test: - if: "$NumPrecedingSiblings=0" then: [t: "βάση"] # phrase(the 'base' of the power) @@ -144,14 +155,28 @@ - PartNumber: "count($Child2D/preceding-sibling::*)" - PartName: "GetNavigationPartName(name(.), $PartNumber)" replace: - - x: "$Move2D" + - x: "GetNavigationPartName($Move2D, 0)" - test: - if: "$PartName != ''" then: [x: "$PartName"] - else_if: "count(*) = 1" then_test: if: "$NavVerbosity = 'Verbose'" - then: [x: "translate(name(.), '-_', ' ')"] # e.g., "in absolute value" + then: # IntentMappings via SpeakIntentName; falls back to spaced intent name + - test: + - if: "contains(@data-intent-property, ':prefix:')" + then: [x: "SpeakIntentName(name(.), $Verbosity, 'prefix')"] + - else_if: "contains(@data-intent-property, ':postfix:')" + then: [x: "SpeakIntentName(name(.), $Verbosity, 'postfix')"] + - else_if: "contains(@data-intent-property, ':infix:')" + then: [x: "SpeakIntentName(name(.), $Verbosity, 'infix')"] + - else_if: "contains(@data-intent-property, ':function:')" + then: [x: "SpeakIntentName(name(.), $Verbosity, 'function')"] + - else_if: "contains(@data-intent-property, ':nofix:')" + then: [x: "SpeakIntentName(name(.), $Verbosity, 'nofix')"] + - else_if: "contains(@data-intent-property, ':silent:')" + then: [x: "SpeakIntentName(name(.), $Verbosity, 'silent')"] + - else: [x: "SpeakIntentName(name(.), $Verbosity, 'other')"] else: - t: "μέρος" # phrase(the 'part' of the expression) - x: "count($Child2D/preceding-sibling::*) + 1" @@ -261,7 +286,7 @@ if: "name(*[1]) != 'mrow'" then: - with: - variables: [Move2D: "'in'", Child2D: "IfThenElse(count(*)=0, $Move2D, $Move2D)"] # phrase('in' the denominator) + variables: [Move2D: "'in'", Child2D: "IfThenElse($NavCommand = 'MovePreviousZoom', (*[last()]), (*[1]))"] # phrase('in' the denominator) replace: [x: "IfThenElse($NavCommand = 'MovePreviousZoom', 1, $Child2D)"] - test: if: "$NavCommand = 'MovePreviousZoom'" @@ -1066,7 +1091,30 @@ # ======== Move/Read/Describe Next rules ================= +# Move between characters before moving between nodes. +- name: move-next-character + tag: [mn, mi, mtext] + match: + - "($NavCommand = 'MoveNext' or $NavCommand = 'ReadNext' or $NavCommand = 'DescribeNext' or $NavCommand = 'MoveNextZoom') and" + - "$NavNodeOffset > 0 and" + - "($NavNodeOffset < string-length(.) or name(EdgeNode(., 'right', 'math'))!='math')" # not at edge of math + replace: + - test: + if: "$NavNodeOffset < string-length(.)" + then: + - with: + variables: [SayCommand: "string($NavVerbosity = 'Verbose')"] + replace: [x: "."] + - set_variables: [NavNodeOffset: "$NavNodeOffset + 1"] + else: + - with: + variables: [SayCommand: "string($NavVerbosity = 'Verbose')"] + replace: [x: "."] + - set_variables: [NavNodeOffset: "0"] + - x: "." + # skip 'none' + - name: move-next-none tag: [none, mprescripts] match: @@ -1370,6 +1418,27 @@ - pause: long - set_variables: [SpeakExpression: "'false'"] +- name: move-prev-character + tag: [mn, mi, mtext] + match: + - "($NavCommand = 'MovePrevious' or $NavCommand = 'ReadPrevious' or $NavCommand = 'DescribePrevious' or $NavCommand = 'MovePreviousZoom') and" + - "$NavNodeOffset > 0 and" + - "($NavNodeOffset > 1 or name(EdgeNode(., 'left', 'math'))!='math')" # not at edge of math + replace: + - test: + if: "$NavNodeOffset > 1" + then: + - with: + variables: [SayCommand: "string($NavVerbosity = 'Verbose')"] + replace: [x: "."] + - set_variables: [NavNodeOffset: "$NavNodeOffset - 1"] + else: + - with: + variables: [SayCommand: "string($NavVerbosity = 'Verbose')"] + replace: [x: "."] + - set_variables: [NavNodeOffset: "0"] + - x: "." + - name: move-previous-auto-zoom-up-one-level # Last child or in auto-zoom'd in-- move up a level and try again # Note: we've already checked the for the case where we are at an edge and should not AutoZoomOut @@ -1592,7 +1661,7 @@ - if: "$NavCommand = 'ReadCurrent'" then: [t: "ανάγνωση"] # phrase('read' next entry in table) else: [t: "περιγραφή"] # phrase('describe' next entry in table) - - t: "current" # phrase('current' entry in table) + - t: "τρέχον" # phrase('current' entry in table) - pause: long - set_variables: [NavNode: "@id"] @@ -1616,7 +1685,7 @@ - else_if: "starts-with($NavCommand, 'MoveTo')" then: [t: "μετακίνηση"] # phrase('move to' the next entry in table) else: [t: "ορισμός"] # phrase('set' the value of the next entry in table) - - t: "κενής θέσης" # phrase('placeholder' for the value) + - t: "θέση κράτησης" # phrase('placeholder' for the value) - x: "$PlaceMarkerIndex" - pause: long - set_variables: [NavNode: "$PlaceMarker"] @@ -1628,7 +1697,7 @@ - test: if: "$NavVerbosity != 'Terse'" then: - - t: "ορισμός κενής θέσης" # phrase('set placeholder' to the value) + - t: "ορισμός θέσης κράτησης" # phrase('set placeholder' to the value) - x: "$PlaceMarkerIndex" - pause: long - set_variables: [NavNode: "@id"] diff --git a/Rules/Languages/el/unicode-full.yaml b/Rules/Languages/el/unicode-full.yaml index 9df9be30a..96d62cf6e 100644 --- a/Rules/Languages/el/unicode-full.yaml +++ b/Rules/Languages/el/unicode-full.yaml @@ -3700,4 +3700,37 @@ - "﹤": [t: "μικρό μικρότερο από"] # 0xfe64 - "﹥": [t: "μικρό μεγαλύτερο από"] # 0xfe65 - "﹦": [t: "μικρό ίσον"] # 0xfe66 - - "+": [t: "σύμβολο ίσον"] # 0xff0b \ No newline at end of file + - "+": [t: "συν"] # 0xff0b +# Symbols introduced in the current reference rules; terminology review pending. + - "͆": [t: "άνω γέφυρα"] + - "": [t: "κάτω μέρος αριστερής αγκύλης"] + - "<": [t: "μικρότερο από"] + - "=": [t: "ίσον"] + - ">": [t: "μεγαλύτερο από"] + - "\": [t: "ανάστροφη κάθετος"] + - "^": [t: "καπέλο"] + - "|": [t: "κάθετη γραμμή"] + - "~": [t: "περισπωμένη"] + - "¬": [t: "άρνηση"] + - "←": [t: "βέλος προς τα αριστερά"] + - "↑": [t: "βέλος προς τα πάνω"] + - "→": [t: "βέλος προς τα δεξιά"] + - "↓": [t: "βέλος προς τα κάτω"] + - "": [t: "άγνωστο ή ελλείπον αντικείμενο"] + - "�": [t: "ελλείπων χαρακτήρας"] + - "🣑": [t: "είναι σε ισορροπία με"] + - "🣒": [t: "είναι σε ισορροπία μετατοπισμένη προς τα δεξιά με"] + - "🣓": [t: "είναι σε ισορροπία μετατοπισμένη προς τα αριστερά με"] + - "": [t: "μερικός δεσμός"] + - "": [t: "διπλός μερικός δεσμός"] + - "": [t: "τριπλός μερικός δεσμός"] + - "\uE428": [spell: "'⟵'"] + - "\uE429": [spell: "'⟶'"] + - "\uE42A": [spell: "'⟷'"] + - "\uE408": [spell: "'🣑'"] + - "\uE409": [spell: "'🣒'"] + - "\uE40A": [spell: "'🣓'"] + - "\uE42B": [spell: "'⇄'"] + - "\uE42C": [spell: "'←'"] + - "\uE42D": [spell: "'→'"] + - "\uE42E": [spell: "'⇄'"] diff --git a/Rules/Languages/el/unicode.yaml b/Rules/Languages/el/unicode.yaml index 8cab33aac..27e706f40 100644 --- a/Rules/Languages/el/unicode.yaml +++ b/Rules/Languages/el/unicode.yaml @@ -4,14 +4,20 @@ # some languages say the word for "uppercase" after the letter. Make sure to change that where appropriate by moving some code around - "a": - test: - if: "$TTS='none'" - then: [t: "a"] # long "a" sound in all speech engines I tested (espeak, MS SAPI, eloquence, (en: 'eigh', google translation) - else: [spell: "'a'"] # AWS Polly, ReadSpeaker, NaturalReader, google cloud, nuance, ibm watson) + if: "$SpeechStyle = 'GreekMathReader'" + then: [x: "DefinitionValue('a', 'Speech', 'GreekMathReaderLetters')"] + else_test: + if: "$TTS='none'" + then: [t: "a"] # long "a" sound in all speech engines I tested (espeak, MS SAPI, eloquence, (en: 'eigh', google translation) + else: [spell: "'a'"] # AWS Polly, ReadSpeaker, NaturalReader, google cloud, nuance, ibm watson) - "b-z": - test: - if: "$TTS='none'" - then: [t: "."] # (en: '.', google translation) - else: [spell: "'.'"] + if: "$SpeechStyle = 'GreekMathReader'" + then: [x: "DefinitionValue('.', 'Speech', 'GreekMathReaderLetters')"] + else_test: + if: "$TTS='none'" + then: [t: "."] # (en: '.', google translation) + else: [spell: "'.'"] # Capital letters are a little tricky: users can pick their favorite word (something that was requested) and # screen readers have options to use pitch changes or beeps instead of or in addition to say "cap" @@ -36,9 +42,12 @@ value: "$CapitalLetters_Pitch" replace: - test: - if: "$TTS='none'" - then: [t: "A"] # (en: 'eigh', google translation) - else: [spell: "'a'"] + if: "$SpeechStyle = 'GreekMathReader'" + then: [x: "DefinitionValue('a', 'Speech', 'GreekMathReaderLetters')"] + else_test: + if: "$TTS='none'" + then: [t: "A"] # (en: 'eigh', google translation) + else: [spell: "'a'"] - "B-Z": - test: @@ -58,7 +67,11 @@ - pitch: value: "$CapitalLetters_Pitch" # note: processing of ranges converts '.' into the character, so it needs to be in quotes below - replace: [spell: "translate('.', 'BCDEFGHIJKLMNOPQRSTUVWXYZ', 'bcdefghijklmnopqrstuvwxyz')"] + replace: + - test: + if: "$SpeechStyle = 'GreekMathReader'" + then: [x: "DefinitionValue(translate('.', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'), 'Speech', 'GreekMathReaderLetters')"] + else: [spell: "translate('.', 'BCDEFGHIJKLMNOPQRSTUVWXYZ', 'bcdefghijklmnopqrstuvwxyz')"] - "0-9": [t: "."] # (en: '.', google: 'A') #theodora. is this replacing dots with commas in decimals for greek? @@ -72,12 +85,12 @@ else: [t: "θαυμαστικό"] # 0x21 (en: 'exclamation point', google: 'θαυμαστικό') else: [t: "παραγοντικό"] # 0x21 (en: 'factorial') - - \"": [t: "εισαγωγικά"] # 0x22 (en: 'quotation mark', google: 'εισαγωγικά') + - '"': [t: "εισαγωγικά"] # 0x22 (en: 'quotation mark', google: 'εισαγωγικά') - "#": [t: "σύμβολο αριθμού"] # 0x23 (en: 'number', google: 'αριθμός') - "$": [t: "δολάριο"] # 0x24 (en: 'dollars', google: 'δολάρια') - "%": [t: "τοις εκατό"] # 0x25 (en: 'percent') - "&": [t: "ampersand"] # 0x26 (en: 'ampersand', google: 'ampersand') - - \'": [t: "απόστροφος"] # 0x27 (en: 'apostrophe') + - "'": [t: "απόστροφος"] # 0x27 (en: 'apostrophe') - "(": # 0x28 - test: if: $SpeechStyle = 'ClearSpeak' or $SpeechStyle = 'SimpleSpeak' @@ -274,22 +287,66 @@ - "ζ": [t: "ζήτα"] # 0x3b6 (en: 'zeta', google: 'ζέτα') - "η": [t: "ήτα"] # 0x3b7 (en: 'eta', google: 'eta') - "θ": [t: "θήτα"] # 0x3b8 (en: 'theta', google: 'θήτα') - - "ι": [t: "ιότα"] # 0x3b9 (en: 'iota', google: 'ιώτα') - - "κ": [t: "καπα"] # 0x3ba (en: 'kappa', google: 'kappa') + - "ι": + - test: + if: "$SpeechStyle = 'GreekMathReader'" + then: [t: "γιώτα"] + else: [t: "ιότα"] + - "κ": + - test: + if: "$SpeechStyle = 'GreekMathReader'" + then: [t: "κάπα"] + else: [t: "καπα"] - "λ": [t: "λάμδα"] # 0x3bb (en: 'lambda', google: 'lambda') - - "μ": [t: "μί"] # 0x3bc (en: 'mu', google: 'mu') - - "ν": [t: "νί"] # 0x3bd (en: 'nu', google: 'nu') - - "ξ": [t: "ξ"] # 0x3be (en: 'zai', google: 'zai') + - "μ": + - test: + if: "$SpeechStyle = 'GreekMathReader'" + then: [t: "μι"] + else: [t: "μί"] + - "ν": + - test: + if: "$SpeechStyle = 'GreekMathReader'" + then: [t: "νι"] + else: [t: "νί"] + - "ξ": + - test: + if: "$SpeechStyle = 'GreekMathReader'" + then: [t: "ξι"] + else: [t: "ξ"] - "ο": [t: "όμικρον"] # 0x3bf (en: 'omicron', google: 'όμικρο') - - "π": [t: "π"] # 0x3c0 (en: 'pi', google: 'πι') - - "ρ": [t: "ρ"] # 0x3c1 (en: 'rho', google: 'rho') + - "π": + - test: + if: "$SpeechStyle = 'GreekMathReader'" + then: [t: "πι"] + else: [t: "π"] + - "ρ": + - test: + if: "$SpeechStyle = 'GreekMathReader'" + then: [t: "ρο"] + else: [t: "ρ"] - "ς": [t: "μικρό σίγμα"] # 0x3c2 (en: 'final sigma', google: 'τελική sigma') - "σ": [t: "σίγμα"] # 0x3c3 (en: 'sigma', google: 'sigma') - - "τ": [t: "τάαφ"] # 0x3c4 (en: 'tau', google: 'tau') + - "τ": + - test: + if: "$SpeechStyle = 'GreekMathReader'" + then: [t: "ταυ"] + else: [t: "τάαφ"] - "υ": [t: "ύψιλον"] # 0x3c5 (en: 'upsilon', google: 'ύψιλο') - - "φ": [t: "φ"] # 0x3c6 (en: 'phi', google: 'phi') - - "χ": [t: "χ"] # 0x3c7 (en: 'chi', google: 'τσι') - - "ψ": [t: "ψ"] # 0x3c8 (en: 'psi', google: 'psi') + - "φ": + - test: + if: "$SpeechStyle = 'GreekMathReader'" + then: [t: "φι"] + else: [t: "φ"] + - "χ": + - test: + if: "$SpeechStyle = 'GreekMathReader'" + then: [t: "χι"] + else: [t: "χ"] + - "ψ": + - test: + if: "$SpeechStyle = 'GreekMathReader'" + then: [t: "ψι"] + else: [t: "ψ"] - "ω": [t: "ωμέγα"] # 0x3c9 (en: 'omega', google: 'ωμέγα') - "ϕ": [t: "παραλλαγή του φ"] # 0x3d5 (en: 'phi', google: 'phi') - "ϖ": [t: "παραλλαγή του π"] # 0x3d6 (en: 'pi', google: 'πι') @@ -532,12 +589,11 @@ - "∷": [t: "σύμβολο αναλογίας"] # 0x2237 (en: 'as', google: 'όπως και') - "∼": [t: "κυματοειδής γραμμή"] # 0x223c (en: 'varies with', google: 'ποικίλλει με') - "∽": [t: "ανεστραμμένη κυματοειδής γραμμή"] # 0x223d (en: 'reversed tilde', google: 'αντιστράφηκε tilde') -# new -# - "∾": # 0x223e -# - test: -# if: "$Verbosity!='Terse'" -# then: [t: "είναι"] -# - t: "most positive" + - "∾": # 0x223e + - test: + if: "$Verbosity!='Terse'" + then: [t: "είναι"] + - t: "μέγιστο θετικό" - "∿": [t: "ημιτονοειδές κύμα"] # 0x223f (en: 'sine wave') - "≠": # 0x2260 - test: @@ -565,7 +621,6 @@ - "≻": [t: "έπεται του"] # 0x227b (en: 'succeeds', google: 'επιτυγχάνει') - "⊂": # 0x2282 - test: - if: "$Verbosity!='Terse'" if: "$Verbosity!='Terse'" then: [t: "είναι ένα"] # (en: 'is a', google translation) - t: "υποσύνολο του" # (en: 'subset of', google: 'υποσύνολο του') diff --git a/docs/greek-math-reader-examples.html b/docs/greek-math-reader-examples.html new file mode 100644 index 000000000..6a1c27f62 --- /dev/null +++ b/docs/greek-math-reader-examples.html @@ -0,0 +1,111 @@ + + + + + +Greek Math Reader — παραδείγματα για έλεγχο στο NVDA + + + +

Greek Math Reader: έλεγχος μαθηματικών εκφωνήσεων

+

Επιλέξτε γλώσσα Ελληνικά (el) και στυλ GreekMathReader +σε έκδοση του MathCAT που περιλαμβάνει τους νέους κανόνες. Τα παραδείγματα είναι προς έλεγχο από ειδικούς και χρήστες του NVDA.

+

Οι αναμενόμενες εκφωνήσεις χρησιμοποιούν μεσαία λεπτομέρεια και απενεργοποιημένη τη λέξη «κεφαλαίο». +Οι παύσεις μπορεί να ακούγονται διαφορετικά ανάλογα με τη φωνή. Τα παραδείγματα ελέγχουν MathML στον φυλλομετρητή· +ο έλεγχος των ίδιων τύπων μέσα στο Word και σε PDF παραμένει ξεχωριστός.

+

Implementation, provenance and review status

+
+

1. Διάστημα με δηλωμένη σημασία

+01 +
Αναμενόμενη εκφώνηση

διάστημα ανοιχτό αριστερά κλειστό δεξιά από 0 έως 1

+
+
+

2. Τύπος δευτεροβάθμιας εξίσωσης (MathJax)

+ + + + x= + + −b±b2−4ac + 2a + + + x=\frac{-b\pm\sqrt{b^2-4ac}}{2a} + + +
Αναμενόμενη εκφώνηση

χι ίσον; κλάσμα με αριθμητή μείον μπί, συν πλην; τετραγωνική ρίζα του μπί στο τετράγωνο, μείον, 4 έι σί, τέλος ρίζας, και παρονομαστή 2 έι, τέλος κλάσματος

+
+
+

3. Ορισμένο ολοκλήρωμα (MathType)

+ + + \int_0^1 x^2\,dx + + + ∫01 + x2dx + + + + +
Αναμενόμενη εκφώνηση

ολοκλήρωμα από 0 ως 1 του; χι στο τετράγωνο ως προς χι

+
+
+

4. Στοιχείο πίνακα στην κβαντική σημειογραφία

+ + ⟨ψ|H|φ⟩ + +
Αναμενόμενη εκφώνηση

στοιχείο πίνακα με μπρα ψι έιτς κετ φι

+
+
+

5. Δεσμευμένη αναμενόμενη τιμή

+ + E[X|Y] + +
Αναμενόμενη εκφώνηση

αναμενόμενη τιμή του χι δεδομένου του γουάι

+
+
+

6. Εξίσωση από επισημασμένο PDF

+ + + E=mc2 + + +
Αναμενόμενη εκφώνηση

ί ίσον, μι σί στο τετράγωνο

+
+
+

7. Τανυστικοί δείκτες

+ + Tji + +
Αναμενόμενη εκφώνηση

ταυ προτεταγμένος εκθέτης άι, δείκτης τζέι

+
+
+

8. Απόκλιση διανύσματος

+ + ∇·F=0 + +
Αναμενόμενη εκφώνηση

απόκλιση του έντονο εφ; ίσον 0

+
+
+

9. Άθροισμα με πρόθεμα χώρου ονομάτων (Word)

+ + + + ∑ + n=1 + ∞ + + 1n2 + + +
Αναμενόμενη εκφώνηση

άθροισμα από νι ίσον 1 ως άπειρο του; κλάσμα με αριθμητή 1, και παρονομαστή νι στο τετράγωνο, τέλος κλάσματος

+
+ + diff --git a/docs/greek-math-reader.md b/docs/greek-math-reader.md new file mode 100644 index 000000000..66526e0fa --- /dev/null +++ b/docs/greek-math-reader.md @@ -0,0 +1,185 @@ +# Greek Math Reader for MathCAT + +This contribution adds `GreekMathReader`, a native Greek speech style, and integrates the complete 101-concept terminology export from [NVDA Greek Math / Greek Math Reader](https://github.com/ChristosBouronikos/NVDA-Greek-Math). It is a draft language contribution for mathematical and listening review. The implementation uses MathCAT's YAML rules, intent processing, navigation, preferences, and braille engine. + +Select Greek (`el`) and the `GreekMathReader` speech style in a host that includes these rules. Library callers set `Language` to `el` and `SpeechStyle` to `GreekMathReader`. The style is discoverable through `get_supported_speech_styles("el")`. NVDA's [speech-style discovery](https://github.com/nvaccess/nvda/blob/master/source/mathPres/MathCAT/localization.py) enumerates the rule filenames, so a version containing this rules package can offer the style. This has been checked in source; Windows/NVDA interaction and listening remain to be tested. + +## Implementation + +| Capability | Native implementation | +| --- | --- | +| Greek pronunciation | Phonetic Latin letter names, selected Greek letter spellings, and the existing capital-word, pitch, beep, and typeface preferences. The established styles keep their letter conventions. | +| Arithmetic and algebra | Greek equality and scalar multiplication; decimal comma speech with configurable input separators; concise simple fractions; explicit compound-fraction, root, exponent, and subscript boundaries. | +| Calculus | First ordinary and partial derivative notation, differential tails in bounded integrals, and native MathCAT limits, sums, vector calculus, and general structural fallbacks. Higher-order or domain-specific concepts can use explicit intent. | +| Probability and statistics | Conventional `E`, `P`, `Var`, and `Cov` function notation, including binary conditional expectation/probability. An author can request `:literal` to retain structural notation. | +| Quantum notation | Paired angle brackets and bars for bra–ket products and matrix elements. Explicit absolute-value intent is preserved. A bare dagger retains its symbol reading; an author can specify `quantum-adjoint` explicitly. | +| Advanced terminology | All 101 exported semantic names: 92 new mappings and nine existing Greek mappings. Greek argument grammar covers coordinates, derivatives, transforms, evaluation, normal distributions, modular congruence, quotient groups, and other multi-argument concepts. | +| Native structures | Matrices, cases, multiscripts, units, chemistry, and other structures inherit the Greek SimpleSpeak/shared rules. Currency singulars/plurals and a missing matrix-dimension word are localized. The fullwidth plus sign is corrected to addition instead of equality. | +| Navigation | Greek command prefixes, directions and part names; next/previous character movement; corrected child selection when zooming into a structure. Regression tests check spoken output and cursor positions in fractions and matrices. | +| Braille | Uses MathCAT's existing braille codes. A regression checks that changing among the three Greek speech styles preserves UEB output. No Greek mathematical-braille code is introduced. | + +Custom semantic grammar checks arity and fixity. Unsupported argument counts retain the generic operand-preserving fallback. Explicit literal notation and silent concept names remain available. Statistical recognition is a convention of this speech style, not a claim that an isolated `E`, `P`, or other letter identifies a subject area. + +The style supplies the standard Greek Math Reader conventions within MathCAT. The add-on's separate school/university terminology profiles, domain selector, personal overrides, conversion engines, diagnostics UI, provider hooks, keyboard/clipboard commands, and voice manager are host/add-on features. They are not implemented by this MathCAT language PR. MathCAT's existing verbosity and presentation preferences remain available; they are not equivalent to those add-on profiles. + +## Inputs and document corpus + +MathCAT consumes Presentation MathML. Content MathML and input in LaTeX, UnicodeMath, images or document formats require conversion before calling it. A `semantics` presentation branch or `annotation-xml` with `MathML-Presentation` is supported; a TeX annotation alone is not a TeX parser. + +`tests/Languages/el/reader_documents.rs` includes all nine contributed document examples, plus nine notation/fallback regressions. Two source inputs are adapted: the Content MathML interval is expressed as Presentation MathML with `open-closed-interval` intent, and the Word-style `mml:` prefix receives its required namespace declaration. These cases test MathML payloads, not live Word, PDF, browser, or UI Automation extraction. + +The expected strings are native MathCAT expectations. They are not a claim of exact add-on output parity: MathCAT supplies its own pauses and boundaries, announces bold type when requested, and orders multiscript descriptions using its native convention. Latin `E` is pronounced `ί`, consistently with the letter table, rather than the older corpus's `έψιλον`. A complex denominator receives fraction boundaries. Both the integral bounds and differential variable remain audible. + +For ambiguous advanced notation, use explicit intent and named arguments: + +```xml + + + u×v + + +``` + +A [listening page](greek-math-reader-examples.html) provides the nine document examples with the expected native speech for expert and NVDA review. + +## Provenance and review status + +Greek Math Reader is by **Bouronikos Christos (cbouronikos@uth.gr)**. The source snapshot is [`af0641133e4865a82d3296d58703489816dc2102`](https://github.com/ChristosBouronikos/NVDA-Greek-Math/tree/af0641133e4865a82d3296d58703489816dc2102), registry `2026.08.2`. Its [`LICENSE.md`](https://github.com/ChristosBouronikos/NVDA-Greek-Math/blob/af0641133e4865a82d3296d58703489816dc2102/LICENSE.md) explicitly offers `mathcat-el/generated/` for inclusion under MathCAT's terms. The rules here are native MathCAT implementations; the add-on's Python engine is not embedded. Existing Greek contributors Theodora Antonakopoulou and Paraskevi Riga remain credited in [the project documentation](index.md). + +The registry contains **16 `reviewed` and 85 `source-checked-pending-expert-review`** entries. The table below preserves those original labels and source descriptions, including entries with citations pending. These are source-registry labels, not evidence of independent expert approval, MathCAT acceptance, or blind-user validation. New text remains lowercase `t:`; no existing verified `T:` entry is demoted. + +The translation audit now loads the Greek pack. It previously encountered malformed Unicode quote keys, a duplicate YAML condition, duplicate plural keys, and an empty `KnownWords` set. The duplicate plural keys are consolidated using the last value already used by MathCAT. The audit parser now accepts an empty mapping as a set, matching the Rust loader. Other language rules and the Rust runtime are unchanged. + +## Validation and remaining review + +The implementation is based on MathCAT `3bbbd4426725b1b20e6f501d2312e7d92f2ed6bf` (`0.7.6-rc.4`). Use a matching MathCAT build when testing the rules package. + +The active Greek suite contains **164 tests** across speech, the 101 exported concepts, real document payloads, symbol pronunciation, preferences, braille preservation, and navigation. The language is now registered in `tests/languages.rs`. The 1,449 pre-existing Greek test annotations remain in their previously disabled modules: they include untranslated/stale expectations and are not counted as passing coverage. Existing speech, braille and navigation goldens are unchanged. + +Run the targeted checks and upstream configurations: + +```sh +cargo test --locked --test languages Languages::el +uv run --project PythonScripts pytest PythonScripts/audit_translations/tests +uv run --project PythonScripts audit-translations el +RUSTFLAGS=-Dwarnings cargo test --locked +RUSTFLAGS=-Dwarnings cargo test --locked --features no-unsafe +RUSTFLAGS=-Dwarnings cargo clippy --locked +RUSTFLAGS=-Dwarnings cargo clippy --locked --features no-unsafe +cargo run --locked --bin package-rules -- Rules Rules.zip +cargo run --locked --bin package-rules -- Rules Rules-minimized.zip --minimize +``` + +The audit compares the 12 English-reference files, so additional style/shared files are covered by the Rust regressions and require direct linguistic review. The two reported missing Unicode keys are already covered by Greek's separate `Ⓐ-Ⓩ`/`ⓐ-ⓩ` ranges and separate `⟂`/`⊥` entries. There are no missing definitions or definition type mismatches. The audit reports 3,852 lowercase text entries and 277 rule differences across the reference files. Lowercase text and intentional structural differences remain reported; successful parsing is not translation approval. + +Before marking the contribution ready for merge, follow the [MathCAT translator guide](https://daisy.github.io/MathCAT/helpers.html): review terminology and grammar with a native-speaking mathematics expert, listen with Greek NVDA voices, obtain blind-user feedback, and review the pre-existing Greek translation issues. Exercise fractions, matrices, cases, statistics, quantum expressions, document extraction, navigation and braille on Windows. Record the NVDA and MathCAT versions, synthesizer, preferences, findings and reviewer approval. These human checks are pending. + +## Release path + +This is one MathCAT pull request. Maintainers decide its style and terminology acceptance, then release the rules. NVDA must subsequently include a MathCAT version/package containing the change. A MathCAT PR or merge does not guarantee inclusion in a particular NVDA release. See the [developer guide](https://daisy.github.io/MathCAT/developers.html) and [upstream CI workflow](https://github.com/daisy/MathCAT/blob/main/.github/workflows/rust.yml). + +## Generated terminology registry snapshot + +| Concept ID | Standard head (`forms.standard`) | Registry source | Registry review status | +| --- | --- | --- | --- | +| absolute_value | απόλυτη τιμή του | Greek school books | reviewed | +| acceleration | επιτάχυνση | Greek school books / Kallipos | source-checked-pending-expert-review | +| adjoint | συζυγής ανάστροφος του | Kallipos | source-checked-pending-expert-review | +| angular_momentum | στροφορμή | Kallipos | source-checked-pending-expert-review | +| anticommutator | αντιμεταθέτης των | Kallipos | source-checked-pending-expert-review | +| asymptotic_equivalence | είναι ασυμπτωτικά ισοδύναμο με | Kallipos | source-checked-pending-expert-review | +| augmented_matrix | επαυξημένος πίνακας | Kallipos | source-checked-pending-expert-review | +| block_matrix | πίνακας κατά μπλοκ | Greek academic usage; citation pending | source-checked-pending-expert-review | +| boundary_condition | συνοριακή συνθήκη | Kallipos | source-checked-pending-expert-review | +| bounded_operator | φραγμένος τελεστής | Greek academic usage; citation pending | source-checked-pending-expert-review | +| bra | μπρα | Kallipos | source-checked-pending-expert-review | +| braket | εσωτερικό γινόμενο | Kallipos | source-checked-pending-expert-review | +| cardinality | πληθάριθμος του | Greek school books / Kallipos | reviewed | +| classical_hamiltonian | χαμιλτονιανή συνάρτηση των | Maintainer wording approval 2026-09-08; expert review pending | source-checked-pending-expert-review | +| closed_interval | κλειστό διάστημα | Greek school books | reviewed | +| closed_open_interval | διάστημα κλειστό αριστερά ανοιχτό δεξιά | Greek school books | reviewed | +| commutator | μεταθέτης των | Kallipos | source-checked-pending-expert-review | +| conditional_expectation | δεσμευμένη αναμενόμενη τιμή του | Kallipos | source-checked-pending-expert-review | +| confidence_interval | διάστημα εμπιστοσύνης | Kallipos | source-checked-pending-expert-review | +| contravariant_index | ανταλλοίωτος δείκτης του | Kallipos | source-checked-pending-expert-review | +| coordinate | σημείο με συντεταγμένες | Greek school books | reviewed | +| covariance | συνδιακύμανση των | Kallipos | source-checked-pending-expert-review | +| covariant_index | συναλλοίωτος δείκτης του | Kallipos | source-checked-pending-expert-review | +| cross_product | διανυσματικό γινόμενο | Kallipos | source-checked-pending-expert-review | +| curl | στροβιλισμός του | Kallipos | source-checked-pending-expert-review | +| diagonal_matrix | διαγώνιος πίνακας του | Kallipos | source-checked-pending-expert-review | +| differential_form | διαφορική μορφή | Greek academic usage; citation pending | source-checked-pending-expert-review | +| dirac_delta | δέλτα του Ντιράκ στο | Maintainer wording approval 2026-09-08; expert review pending | source-checked-pending-expert-review | +| directional_derivative | παράγωγος κατά την κατεύθυνση | Kallipos | source-checked-pending-expert-review | +| divergence | απόκλιση του | Kallipos | source-checked-pending-expert-review | +| dot_product | εσωτερικό γινόμενο | Greek school books / Kallipos | reviewed | +| eigenvalue | ιδιοτιμή του | Kallipos | source-checked-pending-expert-review | +| eigenvector | ιδιοδιάνυσμα του | Kallipos | source-checked-pending-expert-review | +| electric_field | ηλεκτρικό πεδίο | Greek school books / Kallipos | source-checked-pending-expert-review | +| entropy | εντροπία | Kallipos | source-checked-pending-expert-review | +| estimator | εκτιμητής του | Kallipos | source-checked-pending-expert-review | +| evaluation | υπολογισμένο | Kallipos | source-checked-pending-expert-review | +| expectation | αναμενόμενη τιμή του | Greek school books / Kallipos | source-checked-pending-expert-review | +| exterior_product | εξωτερικό γινόμενο | Kallipos | source-checked-pending-expert-review | +| field_structure | σώμα | Greek academic usage; citation pending | source-checked-pending-expert-review | +| four_momentum | τετραορμή | Kallipos | source-checked-pending-expert-review | +| four_vector | τετραδιάνυσμα | Kallipos | source-checked-pending-expert-review | +| fourier_transform | μετασχηματισμός Φουριέ της | Kallipos | source-checked-pending-expert-review | +| gamma_function | συνάρτηση γάμα του | Maintainer wording approval 2026-09-08; expert review pending | source-checked-pending-expert-review | +| generalized_function | γενικευμένη συνάρτηση | Greek academic usage; citation pending | source-checked-pending-expert-review | +| gradient | ανάδελτα του | Kallipos | source-checked-pending-expert-review | +| group | ομάδα | Greek academic usage; citation pending | source-checked-pending-expert-review | +| hamiltonian | χαμιλτονιανός τελεστής | Kallipos | source-checked-pending-expert-review | +| hessian | εσσιανός πίνακας του | Kallipos | source-checked-pending-expert-review | +| hypothesis_test | έλεγχος υπόθεσης | Kallipos | source-checked-pending-expert-review | +| ideal | ιδεώδες | Greek academic usage; citation pending | source-checked-pending-expert-review | +| identity_matrix | μοναδιαίος πίνακας τάξης | Kallipos | source-checked-pending-expert-review | +| independence | ανεξάρτητο από | Kallipos | source-checked-pending-expert-review | +| initial_condition | αρχική συνθήκη | Kallipos | source-checked-pending-expert-review | +| interval | διάστημα | Greek school books | reviewed | +| jacobian | ιακωβιανός πίνακας του | Kallipos | source-checked-pending-expert-review | +| ket | κετ | Kallipos | source-checked-pending-expert-review | +| lagrangian | λαγκρανζιανή συνάρτηση | Kallipos | source-checked-pending-expert-review | +| laplace_transform | μετασχηματισμός Λαπλάς του | Kallipos | source-checked-pending-expert-review | +| laplacian | λαπλασιανή του | Kallipos | source-checked-pending-expert-review | +| line_integral | επικαμπύλιο ολοκλήρωμα του | Kallipos | source-checked-pending-expert-review | +| magnetic_field | μαγνητικό πεδίο | Greek school books / Kallipos | source-checked-pending-expert-review | +| manifold | πολλαπλότητα | Greek academic usage; citation pending | source-checked-pending-expert-review | +| material_derivative | υλική παράγωγος του | Kallipos | source-checked-pending-expert-review | +| matrix_element | στοιχείο πίνακα | Kallipos | source-checked-pending-expert-review | +| measure | μέτρο του | Greek academic usage; citation pending | source-checked-pending-expert-review | +| metric_tensor | μετρικός τανυστής | Kallipos | source-checked-pending-expert-review | +| modular_congruence | ισότιμο με | Maintainer wording approval 2026-09-08; expert review pending | source-checked-pending-expert-review | +| momentum | ορμή | Greek school books / Kallipos | source-checked-pending-expert-review | +| morphism | μορφισμός | Greek academic usage; citation pending | source-checked-pending-expert-review | +| multiple_integral | πολλαπλό ολοκλήρωμα του | Kallipos | source-checked-pending-expert-review | +| norm | νόρμα του | Kallipos | reviewed | +| normal_distribution | ακολουθεί κανονική κατανομή | Maintainer wording approval 2026-09-08; expert review pending | source-checked-pending-expert-review | +| open_closed_interval | διάστημα ανοιχτό αριστερά κλειστό δεξιά | Greek school books | reviewed | +| open_interval | ανοιχτό διάστημα | Greek school books | reviewed | +| open_set | ανοιχτό σύνολο | Greek academic usage; citation pending | source-checked-pending-expert-review | +| ordinary_derivative | παράγωγος του | Greek school books / Kallipos | source-checked-pending-expert-review | +| partial_derivative | μερική παράγωγος του | Kallipos | source-checked-pending-expert-review | +| partition_function | συνάρτηση επιμερισμού | Greek academic usage; citation pending | source-checked-pending-expert-review | +| point_definition | έχει συντεταγμένες | Maintainer wording approval 2026-09-08; expert review pending | source-checked-pending-expert-review | +| position_vector | διάνυσμα θέσης | Kallipos | source-checked-pending-expert-review | +| power | δύναμη | Greek school books | reviewed | +| probability | πιθανότητα του | Greek school books | reviewed | +| proper_time | ιδιοχρόνος | Kallipos | source-checked-pending-expert-review | +| quadratic_form | τετραγωνική μορφή του | Kallipos | source-checked-pending-expert-review | +| quantum_adjoint | ερμιτιανός συζυγής του | Kallipos | source-checked-pending-expert-review | +| quantum_operator | κβαντικός τελεστής | Kallipos | source-checked-pending-expert-review | +| quotient_group | ομάδα πηλίκο της | Maintainer wording approval; explicit quotient-group intent only | source-checked-pending-expert-review | +| ring | δακτύλιος | Greek academic usage; citation pending | source-checked-pending-expert-review | +| semantic_entailment | συνεπάγεται σημασιολογικά | Greek academic usage; citation pending | source-checked-pending-expert-review | +| standard_deviation | τυπική απόκλιση του | Greek school books / Kallipos | reviewed | +| stochastic_integral | στοχαστικό ολοκλήρωμα του | Greek academic usage; citation pending | source-checked-pending-expert-review | +| stochastic_process | στοχαστική διαδικασία | Kallipos | source-checked-pending-expert-review | +| surface_integral | επιφανειακό ολοκλήρωμα του | Kallipos | source-checked-pending-expert-review | +| tensor_product | τανυστικό γινόμενο | Kallipos | reviewed | +| topological_space | τοπολογικός χώρος | Greek academic usage; citation pending | source-checked-pending-expert-review | +| torque | ροπή | Greek school books / Kallipos | source-checked-pending-expert-review | +| transpose | ανάστροφος του | Greek school books / Kallipos | reviewed | +| variance | διακύμανση του | Greek school books / Kallipos | reviewed | +| velocity | ταχύτητα | Greek school books / Kallipos | source-checked-pending-expert-review | +| wavefunction | κυματοσυνάρτηση | Kallipos | source-checked-pending-expert-review | diff --git a/docs/index.md b/docs/index.md index 9a34a7b71..30d151d2d 100644 --- a/docs/index.md +++ b/docs/index.md @@ -173,7 +173,7 @@ Translators: * Finnish -- Sami Määttä (Accessibility Library Celia), and Essi Viippola (freelancer) * French -- Olivier Thiffault (Technologies Humanware) * German -- Nazli Andjic, Robert Graf and Paul Libbrecht (IU International University of Applied Sciences), and Moritz Groß (Math4VIP, Marburg University) -* Greek -- Theodora Antonakopoulou and Paraskevi Riga (National and Kapodistrian University of Athens) +* Greek -- Theodora Antonakopoulou and Paraskevi Riga (National and Kapodistrian University of Athens); [Greek Math Reader](greek-math-reader.md) speech style and terminology contribution by Bouronikos Christos * Hungarian -- Attila Hammer (IT Foundation for the Visually Impaired) * Indonesian -- Dr. Pinta Deniyanti Sampoerno, M.Si; Dr. Meiliasari, S.Pd., M.Sc; and Ari Hendarno, S.Pd., M.Kom. * Norwegian -- Marthe Gjelstad (National Library of Norway) and Kvile diff --git a/tests/Languages/el.rs b/tests/Languages/el.rs index 08d7d4e43..e08ea41de 100644 --- a/tests/Languages/el.rs +++ b/tests/Languages/el.rs @@ -38,3 +38,10 @@ //mod uoa_corpus_Clearspeak; //mod uoa_corpus_Simplespeak; + +// Active regression coverage for the Greek Math Reader contribution. +mod reader; +mod reader_intents; +mod reader_symbols; +mod navigation; +mod reader_documents; diff --git a/tests/Languages/el/navigation.rs b/tests/Languages/el/navigation.rs new file mode 100644 index 000000000..1620f3917 --- /dev/null +++ b/tests/Languages/el/navigation.rs @@ -0,0 +1,97 @@ +//! Greek navigation output for localized command phrases, NavigationParts, and character movement. +use crate::common::*; +use anyhow::Result; +use std::panic::{catch_unwind, AssertUnwindSafe}; + +fn assert_navigation(mathml: &str, command: &str, expected: &str) -> Result<()> { + init_panic_handler(); + let result = catch_unwind(AssertUnwindSafe(|| { + init_nav("el", mathml)?; + let speech = do_navigate_command(command)?; + let trimmed_speech = speech.trim_end_matches([' ', ',', ';']).to_string(); + assert_eq!(expected, trimmed_speech); + Ok(()) + })); + report_any_panic(result) +} + +#[test] +fn zoom_in_fraction_uses_greek_direction_and_part_names() -> Result<()> { + let expr = r#" + + + 1 + 2 + + + "#; + assert_navigation( + expr, + "ZoomIn", + "μεγέθυνση προς τα μέσα; μέσα σε αριθμητής; 1", + ) +} + +#[test] +fn move_next_reads_the_next_digit_in_a_number() -> Result<()> { + init_panic_handler(); + let result = catch_unwind(AssertUnwindSafe(|| { + let expr = r#"1234"#; + init_nav("el", expr)?; + set_navigation_node("digits", 1)?; + let speech = do_navigate_command("MoveNext")?; + let trimmed_speech = speech.trim_end_matches([' ', ',', ';']).to_string(); + assert_eq!("μετακίνηση δεξιά; 2", trimmed_speech); + Ok(()) + })); + report_any_panic(result) +} + +#[test] +fn fraction_navigation_preserves_position_and_localizes_zoom_out() -> Result<()> { + // Navigation must identify the actual operand as well as speaking Greek command names. + let expr = r#"12"#; + init_nav("el", expr)?; + set_preference("SpeechStyle", "GreekMathReader")?; + for (command, expected, id) in [ + ("ZoomIn", "μεγέθυνση προς τα μέσα; μέσα σε αριθμητής; 1", "num"), + ("MoveNext", "μετακίνηση δεξιά; μέσα σε παρονομαστής; 2", "den"), + ("MovePrevious", "μετακίνηση αριστερά; μέσα σε αριθμητής; 1", "num"), + ("ZoomOut", "σμίκρυνση προς τα έξω; έξω από αριθμητής; 1 διά 2", "fraction"), + ("ZoomInAll", "μεγέθυνση μέχρι τέλους; μέσα σε αριθμητής; 1", "num"), + ("ZoomOutAll", "σμίκρυνση μέχρι τέλους; έξω από αριθμητής; 1 διά 2", "fraction"), + ("ReadCurrent", "ανάγνωση τρέχον; 1 διά 2", "fraction"), + ] { + assert_eq!(expected, do_navigate_command(command)?, "{command}"); + assert_eq!((id.to_string(), 0), get_navigation_mathml_id()?, "{command}"); + } + Ok(()) +} + +#[test] +fn matrix_navigation_announces_rows_columns_and_reaches_each_cell() -> Result<()> { + // Test both horizontal and vertical moves; reading the right text alone is insufficient. + let expr = r#"(1234)"#; + init_nav("el", expr)?; + set_navigation_node("a", 0)?; + for (command, expected, id) in [ + ("MoveCellNext", "μετακίνηση δεξιά, στήλη 2; 2", "b"), + ("MoveCellDown", "μετακίνηση προς τα κάτω, γραμμή 2, στήλη 2; 4", "d"), + ("MoveCellPrevious", "μετακίνηση αριστερά, στήλη 1; 3", "c"), + ("MoveCellUp", "μετακίνηση επάνω, γραμμή 1, στήλη 1; 1", "a"), + ] { + assert_eq!(expected, do_navigate_command(command)?, "{command}"); + assert_eq!((id.to_string(), 0), get_navigation_mathml_id()?, "{command}"); + } + Ok(()) +} + +#[test] +fn moving_back_a_digit_updates_the_character_offset() -> Result<()> { + // The backward character rule must move the cursor, not just repeat the current digit. + init_nav("el", r#"1234"#)?; + set_navigation_node("digits", 3)?; + assert_eq!("μετακίνηση αριστερά; 2", do_navigate_command("MovePrevious")?); + assert_eq!(("digits".to_string(), 2), get_navigation_mathml_id()?); + Ok(()) +} diff --git a/tests/Languages/el/reader.rs b/tests/Languages/el/reader.rs new file mode 100644 index 000000000..9a463e6f8 --- /dev/null +++ b/tests/Languages/el/reader.rs @@ -0,0 +1,281 @@ +//! Native Greek Math Reader speech and structural regression tests. +use crate::common::*; +use anyhow::Result; + +#[test] +fn squared_expression() -> Result<()> { + // The add-on self-test expression must be Greek in the native speech style. + test("el", "GreekMathReader", "x2+1", "χι στο τετράγωνο, συν 1") +} + +#[test] +fn simple_fraction() -> Result<()> { + // Both operands remain audible in the concise fraction form. + test("el", "GreekMathReader", "23", "2 διά 3") +} + +#[test] +fn comma_decimal() -> Result<()> { + // Use the Greek decimal separator without spelling the comma as punctuation. + let expr = r#"3,14"#; + test_prefs("el", "GreekMathReader", vec![("CapitalLetters_UseWord", "false")], expr, + "3 κόμμα 14") +} + +#[test] +fn grouped_decimal() -> Result<()> { + // Remove grouping marks while preserving fractional trailing zeroes. + let expr = r#"1.234,50"#; + test_prefs("el", "GreekMathReader", vec![("CapitalLetters_UseWord", "false")], expr, + "1234 κόμμα 50") +} + +#[test] +fn cube_root() -> Result<()> { + // Read the root index after MathCAT intent conversion in the correct order. + let expr = r#"x3"#; + test_prefs("el", "GreekMathReader", vec![("CapitalLetters_UseWord", "false")], expr, + "κυβική ρίζα του χι") +} + +#[test] +fn fourth_root() -> Result<()> { + // Preserve a non-cubic root index. + let expr = r#"x4"#; + test_prefs("el", "GreekMathReader", vec![("CapitalLetters_UseWord", "false")], expr, + "ρίζα τάξης 4 του χι") +} + +#[test] +fn nested_fraction() -> Result<()> { + // Both nested fraction boundaries must be audible. + let expr = r#"123"#; + test_prefs("el", "GreekMathReader", vec![("CapitalLetters_UseWord", "false")], expr, + "κλάσμα με αριθμητή 1, και παρονομαστή κλάσμα με αριθμητή 2, και παρονομαστή 3, τέλος κλάσματος, τέλος κλάσματος") +} + +#[test] +fn variable_power() -> Result<()> { + // Terminate a compound exponent before returning to the surrounding expression. + let expr = r#"xn+1"#; + test_prefs("el", "GreekMathReader", vec![("CapitalLetters_UseWord", "false")], expr, + "χι στη δύναμη νι συν 1, τέλος εκθέτη") +} + +#[test] +fn index() -> Result<()> { + // Distinguish a subscript from an exponent. + let expr = r#"an"#; + test_prefs("el", "GreekMathReader", vec![("CapitalLetters_UseWord", "false")], expr, + "έι δείκτης νι") +} + +#[test] +fn partial_derivative() -> Result<()> { + // Recognize a partial differential when its operator does not insert invisible multiplication. + let expr = r#"∂f∂x"#; + test_prefs("el", "GreekMathReader", vec![("CapitalLetters_UseWord", "false")], expr, + "μερική παράγωγος του εφ ως προς χι") +} + +#[test] +fn literal_derivative() -> Result<()> { + // An explicit literal intent prevents differential interpretation. + let expr = r#"dfdx"#; + test_prefs("el", "GreekMathReader", vec![("CapitalLetters_UseWord", "false")], expr, + "αρχή, ντί εφ, προς, ντί χι, τέλος κλάσματος") +} + +#[test] +fn literal_expectation() -> Result<()> { + // An author can opt out of the conventional statistical reading. + let expr = r#"E[X|Y]"#; + test_prefs("el", "GreekMathReader", vec![("CapitalLetters_UseWord", "false")], expr, + "ί; αριστερή αγκύλη; χι κάθετη γραμμη, γουάι; δεξιά αγκύλη") +} + +#[test] +fn literal_bra_ket() -> Result<()> { + // Literal vertical bars must not be converted into an inner product. + let expr = r#"⟨ψ|φ⟩"#; + test_prefs("el", "GreekMathReader", vec![("CapitalLetters_UseWord", "false")], expr, + "αριστερή γωνιακή αγκύλη; ψι κάθετη γραμμη, φι; δεξιά γωνιακή αγκύλη") +} + +#[test] +fn literal_product() -> Result<()> { + // Literal dot notation retains the dot name. + let expr = r#"a·b"#; + test_prefs("el", "GreekMathReader", vec![("CapitalLetters_UseWord", "false")], expr, + "έι τελεία μπί") +} + +#[test] +fn standalone_differential() -> Result<()> { + // Do not identify ordinary d times x as a differential outside calculus notation. + let expr = r#"dx"#; + test_prefs("el", "GreekMathReader", vec![("CapitalLetters_UseWord", "false")], expr, + "ντί χι") +} + +#[test] +fn extended_expectation() -> Result<()> { + // Non-binary conditional notation retains all operands through structural speech. + let expr = r#"E[X|Y|Z]"#; + test_prefs("el", "GreekMathReader", vec![("CapitalLetters_UseWord", "false")], expr, + "αναμενόμενη τιμή του χι, η απόλυτη τιμή του γουάι; ζήτα") +} + +#[test] +fn extended_intent() -> Result<()> { + // Unsupported arity must preserve all four arguments rather than truncating them. + let expr = r#"2345"#; + test_prefs("el", "GreekMathReader", vec![("CapitalLetters_UseWord", "false")], expr, + "στοιχείο πίνακα του 2 κόμμα, 3 κόμμα, 4 κόμμα, 5") +} + +#[test] +fn empty_intent() -> Result<()> { + // A zero-argument named concept still has a Greek name. + let expr = r#"E"#; + test_prefs("el", "GreekMathReader", vec![("CapitalLetters_UseWord", "false")], expr, + "αναμενόμενη τιμή") +} + +#[test] +fn silent_tokens() -> Result<()> { + // Custom token rules must honor author-supplied silence, including numbers and equality. + let expr = r#"x=3,142"#; + test_prefs("el", "GreekMathReader", vec![("CapitalLetters_UseWord", "false")], expr, + "2") +} + +#[test] +fn currency_one() -> Result<()> { + // Use the Greek singular currency name. + let expr = r#"$1"#; + test_prefs("el", "GreekMathReader", vec![("CapitalLetters_UseWord", "false")], expr, + "1 δολάριο") +} + +#[test] +fn currency_two() -> Result<()> { + // Use a Greek plural, not an English s suffix. + let expr = r#"$2"#; + test_prefs("el", "GreekMathReader", vec![("CapitalLetters_UseWord", "false")], expr, + "2 δολάρια") +} + +#[test] +fn currency_plus() -> Result<()> { + // Do not consume a plus sign as if it were invisible multiplication. + let expr = r#"$+2"#; + test_prefs("el", "GreekMathReader", vec![("CapitalLetters_UseWord", "false")], expr, + "δολάριο συν 2") +} + +#[test] +fn units() -> Result<()> { + // Reuse native MathCAT unit intent and plural handling. + let expr = r#"3kg"#; + test_prefs("el", "GreekMathReader", vec![("CapitalLetters_UseWord", "false")], expr, + "3 κιλά") +} + +#[test] +fn matrix() -> Result<()> { + // Preserve dimensions, row positions, and all four matrix entries. + let expr = r#"(1234)"#; + test_prefs("el", "GreekMathReader", vec![("CapitalLetters_UseWord", "false")], expr, + "2 επί 2 πίνακας; γραμμή 1; στήλη 1; 1, στήλη 2; 2; γραμμή 2; στήλη 1; 3, στήλη 2; 4") +} + +#[test] +fn cases() -> Result<()> { + // Keep each branch and its condition audible. + let expr = r#"{xανx>00αλλιώς"#; + test_prefs("el", "GreekMathReader", vec![("CapitalLetters_UseWord", "false")], expr, + "2 περιπτώσεις; περίπτωση 1; χι, αν χι, είναι μεγαλύτερο από 0; περίπτωση 2; 0 αλλιώς") +} + +#[test] +fn limit() -> Result<()> { + // Reuse native limit and function application handling. + let expr = r#"limx→0f(x)"#; + test_prefs("el", "GreekMathReader", vec![("CapitalLetters_UseWord", "false")], expr, + "το όριο όταν χι προσεγγίζει 0; του εφ του χι") +} + +#[test] +fn chemistry() -> Result<()> { + // Preserve chemical subscripts and both element letters. + let expr = r#"H2O"#; + test_prefs("el", "GreekMathReader", vec![("CapitalLetters_UseWord", "false")], expr, + "έιτς, κάτω 2, όμικρον") +} + +#[test] +fn greek_capital_psi() -> Result<()> { + // Capital Greek letters use the same phonetic spelling through the native capital handler. + let expr = r#"Ψ"#; + test_prefs("el", "GreekMathReader", vec![("CapitalLetters_UseWord", "false")], expr, + "ψι") +} + +#[test] +fn authored_absolute_in_angle() -> Result<()> { + // Explicit absolute-value intent must not be replaced by a guessed matrix element. + let expr = r#"⟨ψHφ⟩"#; + test_prefs("el", "GreekMathReader", vec![("CapitalLetters_UseWord", "false")], expr, + "αριστερή γωνιακή αγκύλη; ψι, η απόλυτη τιμή του έιτς; φι; δεξιά γωνιακή αγκύλη") +} + +#[test] +fn dot_decimal_preference() -> Result<()> { + // Input using a decimal point remains readable when the user selects that convention. + test_prefs("el", "GreekMathReader", vec![("DecimalSeparator", ".")], + "3.14", "3 κόμμα 14") +} + +#[test] +fn style_is_discoverable_and_preserves_braille() -> Result<()> { + // Hosts discover the native style without a plugin, and its speech rules must not affect UEB. + test("el", "GreekMathReader", "2", "2")?; + assert!(get_supported_speech_styles("el")?.contains(&"GreekMathReader".to_string())); + set_preference("BrailleCode", "UEB")?; + set_preference("BrailleNavHighlight", "Off")?; + set_mathml("1x")?; + let reader_braille = get_braille("")?; + assert!(!reader_braille.is_empty()); + set_preference("SpeechStyle", "SimpleSpeak")?; + assert_eq!(reader_braille, get_braille("")?); + set_preference("SpeechStyle", "ClearSpeak")?; + assert_eq!(reader_braille, get_braille("")?); + Ok(()) +} + +#[test] +fn shared_semantics_work_in_existing_styles() -> Result<()> { + // The exported semantic vocabulary is available to both established Greek styles. + let expr = r#"23"#; + test("el", "SimpleSpeak", expr, "δεσμευμένη αναμενόμενη τιμή του 2 δεδομένου του 3")?; + test("el", "ClearSpeak", expr, "δεσμευμένη αναμενόμενη τιμή του 2 δεδομένου του 3") +} + +#[test] +fn authored_silent_intent_preserves_only_its_operands() -> Result<()> { + // Greek grammar must not override an author who explicitly silences the concept name. + test("el", "GreekMathReader", + r#"23"#, + "2 3") +} + +#[test] +fn terse_and_verbose_semantic_readings_remain_greek() -> Result<()> { + // Both verbosity extremes use the native vocabulary and preserve their arguments. + let expr = r#"23"#; + test_prefs("el", "GreekMathReader", vec![("Verbosity", "Terse")], expr, + "δεσμευμένη αναμενόμενη τιμή του 2 δεδομένου του 3")?; + test_prefs("el", "GreekMathReader", vec![("Verbosity", "Verbose")], expr, + "δεσμευμένη αναμενόμενη τιμή του 2 δεδομένου του 3") +} diff --git a/tests/Languages/el/reader_documents.rs b/tests/Languages/el/reader_documents.rs new file mode 100644 index 000000000..9ea7dc1e0 --- /dev/null +++ b/tests/Languages/el/reader_documents.rs @@ -0,0 +1,189 @@ +//! Presentation MathML document examples from Greek Math Reader, adapted to native MathCAT conventions. +use crate::common::*; +use anyhow::Result; + +#[test] +fn content_mathml_interval() -> Result<()> { + // Content MathML interval is converted to supported Presentation MathML with explicit intent. + let expr = r#"01"#; + test_prefs("el", "GreekMathReader", vec![("CapitalLetters_UseWord", "false")], expr, + "διάστημα ανοιχτό αριστερά κλειστό δεξιά από 0 έως 1") +} + +#[test] +fn mathjax_semantics() -> Result<()> { + // Read the presentation branch and ignore the TeX annotation, preserving nested boundaries. + let expr = r#" + + + x= + + −b±b2−4ac + 2a + + + x=\frac{-b\pm\sqrt{b^2-4ac}}{2a} + +"#; + test_prefs("el", "GreekMathReader", vec![("CapitalLetters_UseWord", "false")], expr, + "χι ίσον; κλάσμα με αριθμητή μείον μπί, συν πλην; τετραγωνική ρίζα του μπί στο τετράγωνο, μείον, 4 έι σί, τέλος ρίζας, και παρονομαστή 2 έι, τέλος κλάσματος") +} + +#[test] +fn mathtype_annotation_xml() -> Result<()> { + // Use the presentation annotation when it is the available MathML branch. + let expr = r#" + + \int_0^1 x^2\,dx + + + ∫01 + x2dx + + + +"#; + test_prefs("el", "GreekMathReader", vec![("CapitalLetters_UseWord", "false")], expr, + "ολοκλήρωμα από 0 ως 1 του; χι στο τετράγωνο ως προς χι") +} + +#[test] +fn quantum_matrix_element() -> Result<()> { + // Paired bars inside angle brackets identify all three matrix-element operands. + let expr = r#" + ⟨ψ|H|φ⟩ +"#; + test_prefs("el", "GreekMathReader", vec![("CapitalLetters_UseWord", "false")], expr, + "στοιχείο πίνακα με μπρα ψι έιτς κετ φι") +} + +#[test] +fn statistics_expectation() -> Result<()> { + // Keep both the random variable and conditioning event audible. + let expr = r#" + E[X|Y] +"#; + test_prefs("el", "GreekMathReader", vec![("CapitalLetters_UseWord", "false")], expr, + "αναμενόμενη τιμή του χι δεδομένου του γουάι") +} + +#[test] +fn tagged_pdf_formula() -> Result<()> { + // Latin E remains distinct from Greek epsilon, including outside statistical functions. + let expr = r#" + + E=mc2 + +"#; + test_prefs("el", "GreekMathReader", vec![("CapitalLetters_UseWord", "false")], expr, + "ί ίσον, μι σί στο τετράγωνο") +} + +#[test] +fn tensor_indices() -> Result<()> { + // Preserve left and right tensor indices through native multiscript handling. + let expr = r#" + Tji +"#; + test_prefs("el", "GreekMathReader", vec![("CapitalLetters_UseWord", "false")], expr, + "ταυ προτεταγμένος εκθέτης άι, δείκτης τζέι") +} + +#[test] +fn vector_calculus() -> Result<()> { + // Inherit vector-calculus intent and preserve the bold-typeface cue. + let expr = r#" + ∇·F=0 +"#; + test_prefs("el", "GreekMathReader", vec![("CapitalLetters_UseWord", "false")], expr, + "απόκλιση του έντονο εφ; ίσον 0") +} + +#[test] +fn word_uia_prefixed() -> Result<()> { + // Accept a correctly declared MathML prefix from a Word-style expression. + let expr = r#" + + + ∑ + n=1 + ∞ + + 1n2 + +"#; + test_prefs("el", "GreekMathReader", vec![("CapitalLetters_UseWord", "false")], expr, + "άθροισμα από νι ίσον 1 ως άπειρο του; κλάσμα με αριθμητή 1, και παρονομαστή νι στο τετράγωνο, τέλος κλάσματος") +} + +#[test] +fn ordinary_derivative() -> Result<()> { + // Recognize matching differentials in a first derivative. + let expr = r#"dfdx"#; + test_prefs("el", "GreekMathReader", vec![("CapitalLetters_UseWord", "false")], expr, + "παράγωγος του εφ ως προς χι") +} + +#[test] +fn conditional_probability() -> Result<()> { + // Recognize a conditional probability without discarding its event. + let expr = r#"P(A|B)"#; + test_prefs("el", "GreekMathReader", vec![("CapitalLetters_UseWord", "false")], expr, + "πιθανότητα του έι δεδομένου του μπί") +} + +#[test] +fn expectation_parens() -> Result<()> { + // Recognize the conventional expectation function with parentheses. + let expr = r#"E(X)"#; + test_prefs("el", "GreekMathReader", vec![("CapitalLetters_UseWord", "false")], expr, + "αναμενόμενη τιμή του χι") +} + +#[test] +fn variance_function() -> Result<()> { + // Use the Greek variance head for the named function. + let expr = r#"Var(X)"#; + test_prefs("el", "GreekMathReader", vec![("CapitalLetters_UseWord", "false")], expr, + "διακύμανση του χι") +} + +#[test] +fn bare_unknown() -> Result<()> { + // Unrecognized identifiers must remain audible through the native fallback. + let expr = r#"⧖fooBar"#; + test_prefs("el", "GreekMathReader", vec![("CapitalLetters_UseWord", "false")], expr, + "λευκή κλεψύδρα, fooBar") +} + +#[test] +fn scalar_product() -> Result<()> { + // Read scalar multiplication without falsely assigning a vector dot-product intent. + let expr = r#"a·b"#; + test_prefs("el", "GreekMathReader", vec![("CapitalLetters_UseWord", "false")], expr, + "έι επί μπί") +} + +#[test] +fn covariance() -> Result<()> { + // Join both covariance operands with Greek grammar. + let expr = r#"Cov(X,Y)"#; + test_prefs("el", "GreekMathReader", vec![("CapitalLetters_UseWord", "false")], expr, + "συνδιακύμανση των χι και γουάι") +} + +#[test] +fn bra_ket() -> Result<()> { + // Preserve both states in the inner product. + let expr = r#"⟨ψ|φ⟩"#; + test_prefs("el", "GreekMathReader", vec![("CapitalLetters_UseWord", "false")], expr, + "εσωτερικό γινόμενο ψι με φι") +} + +#[test] +fn quantum_dagger() -> Result<()> { + // A dagger alone is ambiguous; do not silently assert quantum adjoint semantics. + let expr = r#"A†"#; + test_prefs("el", "GreekMathReader", vec![("CapitalLetters_UseWord", "false")], expr, + "έι οβελίσκος") +} diff --git a/tests/Languages/el/reader_intents.rs b/tests/Languages/el/reader_intents.rs new file mode 100644 index 000000000..f0585de29 --- /dev/null +++ b/tests/Languages/el/reader_intents.rs @@ -0,0 +1,712 @@ +//! Regression fixtures from the Greek Math Reader 2026.08.2 exported registry. +//! The source offers these fixtures under MathCAT terms; linguistic review remains separate. +//! NVDA Greek Math (Greek Math Reader) by Bouronikos Christos (cbouronikos@uth.gr) +use crate::common::*; +use anyhow::Result; + +#[test] +fn absolute_value() -> Result<()> { + // Export status: reviewed; assert the name and every argument. + let expr = r#"2"#; + test("el", "GreekMathReader", expr, "η απόλυτη τιμή του 2") +} + +#[test] +fn acceleration() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"2"#; + test("el", "GreekMathReader", expr, "επιτάχυνση του 2") +} + +#[test] +fn adjoint() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"2"#; + test("el", "GreekMathReader", expr, "συζυγής ανάστροφος του 2") +} + +#[test] +fn angular_momentum() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"2"#; + test("el", "GreekMathReader", expr, "στροφορμή του 2") +} + +#[test] +fn anticommutator() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"23"#; + test("el", "GreekMathReader", expr, "αντιμεταθέτης των 2 και 3") +} + +#[test] +fn asymptotic_equivalence() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"23"#; + test("el", "GreekMathReader", expr, "2 είναι ασυμπτωτικά ισοδύναμο με 3") +} + +#[test] +fn augmented_matrix() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"2"#; + test("el", "GreekMathReader", expr, "επαυξημένος πίνακας του 2") +} + +#[test] +fn block_matrix() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"2"#; + test("el", "GreekMathReader", expr, "πίνακας κατά μπλοκ του 2") +} + +#[test] +fn boundary_condition() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"2"#; + test("el", "GreekMathReader", expr, "συνοριακή συνθήκη, 2") +} + +#[test] +fn bounded_operator() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"2"#; + test("el", "GreekMathReader", expr, "φραγμένος τελεστής του 2") +} + +#[test] +fn bra() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"2"#; + test("el", "GreekMathReader", expr, "μπρα του 2") +} + +#[test] +fn braket() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"23"#; + test("el", "GreekMathReader", expr, "εσωτερικό γινόμενο 2 με 3") +} + +#[test] +fn cardinality() -> Result<()> { + // Export status: reviewed; assert the name and every argument. + let expr = r#"2"#; + test("el", "GreekMathReader", expr, "πληθάριθμος του 2") +} + +#[test] +fn classical_hamiltonian() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"23"#; + test("el", "GreekMathReader", expr, "χαμιλτονιανή συνάρτηση των 2 και 3") +} + +#[test] +fn closed_interval() -> Result<()> { + // Export status: reviewed; assert the name and every argument. + let expr = r#"23"#; + test("el", "GreekMathReader", expr, "κλειστό διάστημα από 2 έως 3") +} + +#[test] +fn closed_open_interval() -> Result<()> { + // Export status: reviewed; assert the name and every argument. + let expr = r#"23"#; + test("el", "GreekMathReader", expr, "διάστημα κλειστό αριστερά ανοιχτό δεξιά από 2 έως 3") +} + +#[test] +fn commutator() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"23"#; + test("el", "GreekMathReader", expr, "μεταθέτης των 2 και 3") +} + +#[test] +fn conditional_expectation() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"23"#; + test("el", "GreekMathReader", expr, "δεσμευμένη αναμενόμενη τιμή του 2 δεδομένου του 3") +} + +#[test] +fn confidence_interval() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"2"#; + test("el", "GreekMathReader", expr, "διάστημα εμπιστοσύνης του 2") +} + +#[test] +fn contravariant_index() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"2"#; + test("el", "GreekMathReader", expr, "ανταλλοίωτος δείκτης του 2") +} + +#[test] +fn coordinate() -> Result<()> { + // Export status: reviewed; assert the name and every argument. + let expr = r#"23"#; + test("el", "GreekMathReader", expr, "σημείο με συντεταγμένες 2 και 3") +} + +#[test] +fn covariance() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"23"#; + test("el", "GreekMathReader", expr, "συνδιακύμανση των 2 και 3") +} + +#[test] +fn covariant_index() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"2"#; + test("el", "GreekMathReader", expr, "συναλλοίωτος δείκτης του 2") +} + +#[test] +fn cross_product() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"23"#; + test("el", "GreekMathReader", expr, "2 διανυσματικό γινόμενο 3") +} + +#[test] +fn curl() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"2"#; + test("el", "GreekMathReader", expr, "στροβιλισμός του 2") +} + +#[test] +fn diagonal_matrix() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"2"#; + test("el", "GreekMathReader", expr, "διαγώνιος πίνακας του 2") +} + +#[test] +fn differential_form() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"2"#; + test("el", "GreekMathReader", expr, "διαφορική μορφή του 2") +} + +#[test] +fn dirac_delta() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"2"#; + test("el", "GreekMathReader", expr, "δέλτα του Ντιράκ στο 2") +} + +#[test] +fn directional_derivative() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"23"#; + test("el", "GreekMathReader", expr, "παράγωγος του 2 κατά την κατεύθυνση 3") +} + +#[test] +fn divergence() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"2"#; + test("el", "GreekMathReader", expr, "απόκλιση του 2") +} + +#[test] +fn dot_product() -> Result<()> { + // Export status: reviewed; assert the name and every argument. + let expr = r#"23"#; + test("el", "GreekMathReader", expr, "2 εσωτερικό γινόμενο 3") +} + +#[test] +fn eigenvalue() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"2"#; + test("el", "GreekMathReader", expr, "ιδιοτιμή του 2") +} + +#[test] +fn eigenvector() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"2"#; + test("el", "GreekMathReader", expr, "ιδιοδιάνυσμα του 2") +} + +#[test] +fn electric_field() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"2"#; + test("el", "GreekMathReader", expr, "ηλεκτρικό πεδίο του 2") +} + +#[test] +fn entropy() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"2"#; + test("el", "GreekMathReader", expr, "εντροπία του 2") +} + +#[test] +fn estimator() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"2"#; + test("el", "GreekMathReader", expr, "εκτιμητής του 2") +} + +#[test] +fn evaluation() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"234"#; + test("el", "GreekMathReader", expr, "2, υπολογισμένο από 3 έως 4") +} + +#[test] +fn expectation() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"2"#; + test("el", "GreekMathReader", expr, "αναμενόμενη τιμή του 2") +} + +#[test] +fn exterior_product() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"23"#; + test("el", "GreekMathReader", expr, "2 εξωτερικό γινόμενο 3") +} + +#[test] +fn field_structure() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"2"#; + test("el", "GreekMathReader", expr, "σώμα του 2") +} + +#[test] +fn four_momentum() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"2"#; + test("el", "GreekMathReader", expr, "τετραορμή του 2") +} + +#[test] +fn four_vector() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"2"#; + test("el", "GreekMathReader", expr, "τετραδιάνυσμα του 2") +} + +#[test] +fn fourier_transform() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"2"#; + test("el", "GreekMathReader", expr, "μετασχηματισμός Φουριέ της 2") +} + +#[test] +fn gamma_function() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"2"#; + test("el", "GreekMathReader", expr, "συνάρτηση γάμα του 2") +} + +#[test] +fn generalized_function() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"2"#; + test("el", "GreekMathReader", expr, "γενικευμένη συνάρτηση του 2") +} + +#[test] +fn gradient() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"2"#; + test("el", "GreekMathReader", expr, "ανάδελτα του 2") +} + +#[test] +fn group() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"2"#; + test("el", "GreekMathReader", expr, "ομάδα του 2") +} + +#[test] +fn hamiltonian() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"2"#; + test("el", "GreekMathReader", expr, "χαμιλτονιανός τελεστής του 2") +} + +#[test] +fn hessian() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"2"#; + test("el", "GreekMathReader", expr, "εσσιανός πίνακας του 2") +} + +#[test] +fn hypothesis_test() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"2"#; + test("el", "GreekMathReader", expr, "έλεγχος υπόθεσης του 2") +} + +#[test] +fn ideal() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"2"#; + test("el", "GreekMathReader", expr, "ιδεώδες του 2") +} + +#[test] +fn identity_matrix() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"2"#; + test("el", "GreekMathReader", expr, "μοναδιαίος πίνακας τάξης 2") +} + +#[test] +fn independence() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"23"#; + test("el", "GreekMathReader", expr, "2 ανεξάρτητο από 3") +} + +#[test] +fn initial_condition() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"2"#; + test("el", "GreekMathReader", expr, "αρχική συνθήκη, 2") +} + +#[test] +fn interval() -> Result<()> { + // Export status: reviewed; assert the name and every argument. + let expr = r#"23"#; + test("el", "GreekMathReader", expr, "διάστημα από 2 έως 3") +} + +#[test] +fn jacobian() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"2"#; + test("el", "GreekMathReader", expr, "ιακωβιανός πίνακας του 2") +} + +#[test] +fn ket() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"2"#; + test("el", "GreekMathReader", expr, "κετ του 2") +} + +#[test] +fn lagrangian() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"2"#; + test("el", "GreekMathReader", expr, "λαγκρανζιανή συνάρτηση του 2") +} + +#[test] +fn laplace_transform() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"2"#; + test("el", "GreekMathReader", expr, "μετασχηματισμός Λαπλάς του 2") +} + +#[test] +fn laplacian() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"2"#; + test("el", "GreekMathReader", expr, "λαπλασιανή του 2") +} + +#[test] +fn line_integral() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"2"#; + test("el", "GreekMathReader", expr, "επικαμπύλιο ολοκλήρωμα του 2") +} + +#[test] +fn magnetic_field() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"2"#; + test("el", "GreekMathReader", expr, "μαγνητικό πεδίο του 2") +} + +#[test] +fn manifold() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"2"#; + test("el", "GreekMathReader", expr, "πολλαπλότητα του 2") +} + +#[test] +fn material_derivative() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"2"#; + test("el", "GreekMathReader", expr, "υλική παράγωγος του 2") +} + +#[test] +fn matrix_element() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"234"#; + test("el", "GreekMathReader", expr, "στοιχείο πίνακα με μπρα 2 3 κετ 4") +} + +#[test] +fn measure() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"2"#; + test("el", "GreekMathReader", expr, "μέτρο του 2") +} + +#[test] +fn metric_tensor() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"2"#; + test("el", "GreekMathReader", expr, "μετρικός τανυστής του 2") +} + +#[test] +fn modular_congruence() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"234"#; + test("el", "GreekMathReader", expr, "2 ισότιμο με 3 μόντουλο 4") +} + +#[test] +fn momentum() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"2"#; + test("el", "GreekMathReader", expr, "ορμή του 2") +} + +#[test] +fn morphism() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"2"#; + test("el", "GreekMathReader", expr, "μορφισμός του 2") +} + +#[test] +fn multiple_integral() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"2"#; + test("el", "GreekMathReader", expr, "πολλαπλό ολοκλήρωμα του 2") +} + +#[test] +fn norm() -> Result<()> { + // Export status: reviewed; assert the name and every argument. + let expr = r#"2"#; + test("el", "GreekMathReader", expr, "νόρμα του 2") +} + +#[test] +fn normal_distribution() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"234"#; + test("el", "GreekMathReader", expr, "2 ακολουθεί κανονική κατανομή με μέση τιμή 3 και διακύμανση 4") +} + +#[test] +fn open_closed_interval() -> Result<()> { + // Export status: reviewed; assert the name and every argument. + let expr = r#"23"#; + test("el", "GreekMathReader", expr, "διάστημα ανοιχτό αριστερά κλειστό δεξιά από 2 έως 3") +} + +#[test] +fn open_interval() -> Result<()> { + // Export status: reviewed; assert the name and every argument. + let expr = r#"23"#; + test("el", "GreekMathReader", expr, "ανοιχτό διάστημα από 2 έως 3") +} + +#[test] +fn open_set() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"2"#; + test("el", "GreekMathReader", expr, "ανοιχτό σύνολο του 2") +} + +#[test] +fn ordinary_derivative() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"23"#; + test("el", "GreekMathReader", expr, "παράγωγος του 2 ως προς 3") +} + +#[test] +fn partial_derivative() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"23"#; + test("el", "GreekMathReader", expr, "μερική παράγωγος του 2 ως προς 3") +} + +#[test] +fn partition_function() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"2"#; + test("el", "GreekMathReader", expr, "συνάρτηση επιμερισμού του 2") +} + +#[test] +fn point_definition() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"234"#; + test("el", "GreekMathReader", expr, "το σημείο 2 έχει συντεταγμένες 3 και 4") +} + +#[test] +fn position_vector() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"2"#; + test("el", "GreekMathReader", expr, "διάνυσμα θέσης του 2") +} + +#[test] +fn power() -> Result<()> { + // Export status: reviewed; assert the name and every argument. + let expr = r#"23"#; + test("el", "GreekMathReader", expr, "2 στον κύβο") +} + +#[test] +fn probability() -> Result<()> { + // Export status: reviewed; assert the name and every argument. + let expr = r#"2"#; + test("el", "GreekMathReader", expr, "πιθανότητα του 2") +} + +#[test] +fn proper_time() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"2"#; + test("el", "GreekMathReader", expr, "ιδιοχρόνος του 2") +} + +#[test] +fn quadratic_form() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"2"#; + test("el", "GreekMathReader", expr, "τετραγωνική μορφή του 2") +} + +#[test] +fn quantum_adjoint() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"2"#; + test("el", "GreekMathReader", expr, "ερμιτιανός συζυγής του 2") +} + +#[test] +fn quantum_operator() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"2"#; + test("el", "GreekMathReader", expr, "κβαντικός τελεστής του 2") +} + +#[test] +fn quotient_group() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"23"#; + test("el", "GreekMathReader", expr, "ομάδα πηλίκο του 2 ως προς 3") +} + +#[test] +fn ring() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"2"#; + test("el", "GreekMathReader", expr, "δακτύλιος του 2") +} + +#[test] +fn semantic_entailment() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"23"#; + test("el", "GreekMathReader", expr, "2 συνεπάγεται σημασιολογικά 3") +} + +#[test] +fn standard_deviation() -> Result<()> { + // Export status: reviewed; assert the name and every argument. + let expr = r#"2"#; + test("el", "GreekMathReader", expr, "τυπική απόκλιση του 2") +} + +#[test] +fn stochastic_integral() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"2"#; + test("el", "GreekMathReader", expr, "στοχαστικό ολοκλήρωμα του 2") +} + +#[test] +fn stochastic_process() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"2"#; + test("el", "GreekMathReader", expr, "στοχαστική διαδικασία του 2") +} + +#[test] +fn surface_integral() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"2"#; + test("el", "GreekMathReader", expr, "επιφανειακό ολοκλήρωμα του 2") +} + +#[test] +fn tensor_product() -> Result<()> { + // Export status: reviewed; assert the name and every argument. + let expr = r#"23"#; + test("el", "GreekMathReader", expr, "2 τανυστικό γινόμενο 3") +} + +#[test] +fn topological_space() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"2"#; + test("el", "GreekMathReader", expr, "τοπολογικός χώρος του 2") +} + +#[test] +fn torque() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"2"#; + test("el", "GreekMathReader", expr, "ροπή του 2") +} + +#[test] +fn transpose() -> Result<()> { + // Export status: reviewed; assert the name and every argument. + let expr = r#"2"#; + test("el", "GreekMathReader", expr, "ανάστροφος του 2") +} + +#[test] +fn variance() -> Result<()> { + // Export status: reviewed; assert the name and every argument. + let expr = r#"2"#; + test("el", "GreekMathReader", expr, "διακύμανση του 2") +} + +#[test] +fn velocity() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"2"#; + test("el", "GreekMathReader", expr, "ταχύτητα του 2") +} + +#[test] +fn wavefunction() -> Result<()> { + // Export status: source-checked-pending-expert-review; assert the name and every argument. + let expr = r#"2"#; + test("el", "GreekMathReader", expr, "κυματοσυνάρτηση του 2") +} diff --git a/tests/Languages/el/reader_symbols.rs b/tests/Languages/el/reader_symbols.rs new file mode 100644 index 000000000..34ab475bb --- /dev/null +++ b/tests/Languages/el/reader_symbols.rs @@ -0,0 +1,88 @@ +//! Latin letters use Greek names only in GreekMathReader; other styles retain their conventions. +use crate::common::*; +use anyhow::Result; + +#[test] +fn greek_math_reader_speaks_all_latin_letters_phonetically() -> Result<()> { + let letters = [ + ("a", "έι"), ("b", "μπί"), ("c", "σί"), ("d", "ντί"), ("e", "ί"), + ("f", "εφ"), ("g", "τζί"), ("h", "έιτς"), ("i", "άι"), ("j", "τζέι"), + ("k", "κάπα"), ("l", "έλ"), ("m", "μι"), ("n", "νι"), ("o", "όμικρον"), + ("p", "πι"), ("q", "κιού"), ("r", "άρ"), ("s", "ες"), ("t", "ταυ"), + ("u", "γιού"), ("v", "βί"), ("w", "ντάμπλιου"), ("x", "χι"), + ("y", "γουάι"), ("z", "ζήτα"), + ]; + for (letter, name) in letters { + let expr = format!("{letter}"); + test("el", "GreekMathReader", &expr, name)?; + } + Ok(()) +} + +#[test] +fn greek_math_reader_capitals_keep_capital_word_preferences() -> Result<()> { + let letters = [ + ("A", "έι"), ("B", "μπί"), ("C", "σί"), ("D", "ντί"), ("E", "ί"), + ("F", "εφ"), ("G", "τζί"), ("H", "έιτς"), ("I", "άι"), ("J", "τζέι"), + ("K", "κάπα"), ("L", "έλ"), ("M", "μι"), ("N", "νι"), ("O", "όμικρον"), + ("P", "πι"), ("Q", "κιού"), ("R", "άρ"), ("S", "ες"), ("T", "ταυ"), + ("U", "γιού"), ("V", "βί"), ("W", "ντάμπλιου"), ("X", "χι"), + ("Y", "γουάι"), ("Z", "ζήτα"), + ]; + for (letter, name) in letters { + let expr = format!("{letter}"); + test("el", "GreekMathReader", &expr, &format!("κεφαλαίο {name}"))?; + } + test_prefs( + "el", + "GreekMathReader", + vec![("CapitalLetters_UseWord", "false"), ("CapitalLetters_Pitch", "20")], + "A", + "έι", + )?; + Ok(()) +} + +#[test] +fn greek_math_reader_latin_vowels_remain_distinct_from_greek_letters() -> Result<()> { + let expr = "aeiαει"; + test( + "el", + "GreekMathReader", + expr, + "έι ί άι άλφα έψιλον γιώτα", + )?; + Ok(()) +} + +#[test] +fn existing_speech_styles_keep_latin_letter_behavior() -> Result<()> { + // Test separate tokens: adjacent mi elements may be canonicalized into a word. + for (letter, expected) in [("a", "a"), ("b", "b"), ("A", "κεφαλαίο A"), ("B", "κεφαλαίο b")] { + let expr = format!("{letter}"); + test("el", "SimpleSpeak", &expr, expected)?; + test("el", "ClearSpeak", &expr, expected)?; + } + Ok(()) +} + +#[test] +fn quote_punctuation_rules_remain_loadable() -> Result<()> { + test("el", "GreekMathReader", r#"""#, "εισαγωγικά")?; + test("el", "GreekMathReader", "'", "τόνος")?; + Ok(()) +} + +#[test] +fn extended_unicode_and_split_ranges_remain_greek() -> Result<()> { + // Fullwidth operators retain their mathematical operation; audit range aliases have real coverage. + for (symbol, expected) in [ + ("+", "συν"), ("<", "μικρότερο από"), ("=", "ίσον"), + (">", "μεγαλύτερο από"), ("→", "βέλος προς τα δεξιά"), + ("Ⓐ", "κυκλωμένο κεφαλαίο έι"), ("ⓩ", "κυκλωμένο ζήτα"), + ("⟂", "είναι κάθετο στο"), ("⊥", "είναι κάθετο"), + ] { + test("el", "GreekMathReader", &format!("{symbol}"), expected)?; + } + Ok(()) +} diff --git a/tests/languages.rs b/tests/languages.rs index 287b53652..001f104cc 100644 --- a/tests/languages.rs +++ b/tests/languages.rs @@ -7,6 +7,7 @@ mod Languages { mod intent; mod zh; mod en; + mod el; mod hu; mod ru; mod fi;