Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
68ff38d
initial seeded version of German language translation
NSoiffer Sep 18, 2023
caaba6a
fix up definitions.yaml file -- google translate had some issues...
NSoiffer Sep 19, 2023
5de2384
Translate some of the English phrases in SimpleSpeak that google didn…
NSoiffer Feb 28, 2024
0db4c4e
german translation (#259)
b-g-h Apr 4, 2024
b8875a9
Merge branch 'main' into de
NSoiffer Jul 25, 2025
62d4d58
Update the Rules files to match what is currently in main. Unfortunat…
NSoiffer Jul 25, 2025
78467fa
made it compile for the web-demo
polx Jul 30, 2025
48d6fb0
work-in-progress for the German
polx Jul 30, 2025
04b8e81
cleaned-up syntax.
polx Aug 7, 2025
738c6ce
German works in the demo now
polx Aug 7, 2025
bf869fe
First pass on the ported German
polx Aug 9, 2025
8a28771
one forgotten translation.
polx Aug 10, 2025
513373d
speak one-letter variables properly.
polx Aug 11, 2025
8af6621
a la => hoch
polx Aug 12, 2025
dbc8cc5
Update overview.yaml
robert-m-graf Aug 14, 2025
bff8a79
Merge pull request #1 from robert-m-graf/patch-1
polx Aug 14, 2025
d90a256
invitation to contribute
polx Aug 17, 2025
9e9366e
status
polx Aug 17, 2025
8fb6dc6
slightly more complete
polx Aug 17, 2025
a3b7c07
Verzierung soll weg
polx Aug 20, 2025
3d74e5d
A quick pass through the files in German translating anything I could…
polx Aug 21, 2025
96ec044
Performed various changes by comparing with the English default.yaml …
robert-m-graf Aug 22, 2025
2eca40d
Performed changes by comparing with the English general.yaml file
robert-m-graf Aug 22, 2025
fc32be4
Performed changes by comparing with the English geometry.yaml file
robert-m-graf Aug 22, 2025
bdf604c
Performed changes by comparing with the English linear-algebra.yaml file
robert-m-graf Aug 22, 2025
7559247
Performed changes by comparing with the English ClearSpeak_Rules.yaml…
robert-m-graf Aug 22, 2025
b28a66d
First port of the tests... a lot failing for German.
polx Aug 23, 2025
2cd1228
No more crashes by tests.
polx Aug 23, 2025
ae7c69f
German tests run invidiually
polx Aug 24, 2025
7978fca
Update default.yaml
nazliandjic Aug 27, 2025
3a652d2
Update general.yaml
nazliandjic Aug 28, 2025
24e1970
Update ClearSpeak_Rules.yaml
nazliandjic Aug 28, 2025
2bbd072
Update SimpleSpeak_Rules.yaml
nazliandjic Aug 28, 2025
34f5e83
Update navigate.yaml
nazliandjic Aug 28, 2025
1683dbd
Update overview.yaml
nazliandjic Aug 28, 2025
bf44a14
Update unicode-full.yaml
nazliandjic Aug 31, 2025
3a5a26e
Update unicode-full.yaml
nazliandjic Aug 31, 2025
b648bda
Update unicode-full.yaml
nazliandjic Sep 1, 2025
ca41a5c
Update unicode-full.yaml
nazliandjic Sep 3, 2025
afe5f2d
Update unicode-full.yaml
nazliandjic Sep 3, 2025
da9b23c
Update unicode-full.yaml
nazliandjic Sep 3, 2025
3cdcc25
Update unicode-full.yaml
nazliandjic Sep 6, 2025
65e8ba1
Update unicode-full.yaml
nazliandjic Sep 6, 2025
d08d9c4
Update unicode-full.yaml
nazliandjic Sep 6, 2025
187fc07
Update unicode-full.yaml
nazliandjic Sep 7, 2025
a83e303
Update unicode-full.yaml
nazliandjic Sep 7, 2025
6c92908
Update unicode-full.yaml
nazliandjic Sep 8, 2025
2a2157c
Update unicode-full.yaml
nazliandjic Sep 8, 2025
a681d7b
one extra example: supset.
polx Sep 11, 2025
f3a2912
fixed syntax
polx Sep 12, 2025
50693fa
ignores on macOS
polx Sep 12, 2025
d9a04a5
make de tests happy.
polx Sep 12, 2025
7af61a7
Gender
polx Sep 12, 2025
4db3624
Merge branch 'main' into de
polx Sep 13, 2025
6c6dd9b
Merge branch 'de'
polx Sep 13, 2025
a35331c
don't change README when pull-requesting
polx Sep 13, 2025
12db3e6
test cleanup
polx Sep 13, 2025
62b09c5
Our README
polx Sep 13, 2025
f2b067b
update acknowledgements
NSoiffer Sep 14, 2025
07bbd94
minor cleanup of 'use xxx'
NSoiffer Sep 17, 2025
1b3b9fc
added comment
NSoiffer Sep 17, 2025
311248f
Added searching in subdirs for a regional dialect version before fall…
NSoiffer Sep 17, 2025
65ebff2
bump version #
NSoiffer Sep 17, 2025
3af0ded
Redoing the way fake file system.
NSoiffer Sep 17, 2025
ca1717f
random changes for debugging
NSoiffer Sep 17, 2025
cf3ae6f
minor wording change
NSoiffer Sep 22, 2025
8b9043e
Removing unnecessary differences
polx Sep 25, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
.idea
.DS_Store
target
build.rs.orig
Python/libmathcat.pyd
Expand Down
4 changes: 3 additions & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"program": "${workspaceRoot}/target/debug/mathcat.exe",
"args": [],
"cwd": "${workspaceRoot}",
"env": {"RUST_LOG": "DEBUG"},
"preLaunchTask": "cargo build",
},
{
Expand All @@ -20,7 +21,8 @@
"program": "${workspaceRoot}/target/debug/mathcat.exe",
"args": [],
"cwd": "${workspaceFolder}",
"env": {"RUST_LOG": "DEBUG"},
"preLaunchTask": "cargo test build",
}
]
],
}
1 change: 0 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -517,5 +517,4 @@
"bzlib_private.h": "c",
"stdlib.h": "c"
},

}
4 changes: 2 additions & 2 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@
"type": "cargo",
"command": "build",
"args": [
"--features",
"include-zip" // Replace with your actual feature name
// "--features", "include-zip",
"--profile", "dev",
],
"group": {
"kind": "build",
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "mathcat"
version = "0.7.2-rc.1"
version = "0.7.2-rc.3"
authors = ["Neil Soiffer <soiffer@alum.mit.edu>"]
license = "MIT"
description = "MathCAT: Math Capable Assistive Technology ('Speech and braille from MathML')"
Expand Down
17 changes: 8 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
# MathCAT: Math Capable Assistive Technology
# MathCATde: German Translation for MathCAT: Math Capable Assistive Technology

<img src="logo.png" style="position: relative; top: 16px; z-index: -1;">
is a library that supports conversion of MathML to:


* Speech strings (in several languages) with embedded speech engine commands
* Braille (Nemeth, UEB Technical, CMU, and many others)
* (later: Braille (Nemeth, UEB Technical, CMU, and many others))
* Navigation of math (in multiple ways including overviews)

This is the fork of [MathCAT](https://github.com/NSoiffer/MathCAT) of Neil Soiffer focussed on the translations to the German speaking contexts.

There are four related projects that make use of MathCAT:
- [MathCATDemo](https://nsoiffer.github.io/MathCATDemo/) -- an online demonstration of some of what can be done with MathCAT
- [A python interface for MathCAT](https://github.com/NSoiffer/MathCATForPython) -- used by a [MathCAT NVDA add-on](https://addons.nvda-project.org/addons/MathCAT.en.html).
- [A C/C++ interface for MathCAT](https://github.com/NSoiffer/MathCATForC)
- [A Java interface for MathCAT](https://github.com/mwhapples/MathCAT4J) (thanks to Michael Whapples for working on that)
## Status
This translation project was launched in the summer 2025 it is quite new still.

MathCAT is used in many assistive technologies including NVDA and JAWS.
## How to contribute?
This project is untertaken by the team of IT&Tech at the [IU University of Applied Sciences](https://www.iu.org/) and welcomes test-reports in the form of issues and proposed changes in the form of pull-requests.

For more information, see the [full documentation](https://nsoiffer.github.io/MathCAT/).
For process questions, raising an issue is probably the best idea too.
1 change: 1 addition & 0 deletions Rules/Braille/UEB/unicode.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -453,6 +453,7 @@
- "γ": [t: "GL⠛"] # 0x3b3
- "δ": [t: "GL⠙"] # 0x3b4
- "ε": [t: "GL⠑"] # 0x3b5
- "ϵ": [t: "GL⠑"] # 0x3f5 \varepsilon
- "ζ": [t: "GL⠵"] # 0x3b6
- "η": [t: "GL⠱"] # 0x3b7
- "θ": [t: "GL⠹"] # 0x3b8
Expand Down
2 changes: 1 addition & 1 deletion Rules/Languages/de/unicode.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -467,7 +467,7 @@
- "⊃": # 0x2283
- test:
if: "$Verbosity!='Terse'"
then: [T: "ist ein"] # (en: 'is a', google translation)
then: [T: "ist eine"] # (en: 'is a', google translation)
- T: "obermenge von" # (en: 'superset of', MathPlayer: 'Obermenge von', google: 'superset von')
- "⊄": # 0x2284
- test:
Expand Down
4 changes: 2 additions & 2 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ Using open source math books, the initial load should cover at least 99.99% of t

The library is about ~3mb in size.

If you are working on an in-browser solution (i.e, you are using JavaScript or some other browser-based language), MathCAT is probably not the best tool for you (although I will probably factor the [MathCATDemo](https://github.com/NSoiffer/MathCATDemo/) into a Javascript interface which the demo is built on top of). Instead, take a look at [Speech rule engine](https://github.com/zorkow/speech-rule-engine) (SRE) by Volker Sorge. It is written in TypeScript and will likely meet your needs for an in-browser solution unless UEB braille is important.
If you are working on an in-browser solution (i.e, you are using JavaScript or some other browser-based language), MathCAT is probably not the best tool for you (although I will probably factor the [MathCATDemo](https://github.com/NSoiffer/MathCATDemo/) into a Javascript interface which the demo is built on top of). Instead, take a look at [Speech rule engine](https://github.com/zorkow/speech-rule-engine) (SRE) by Volker Sorge. It is written in TypeScript and will likely meet your needs for an in-browser solution unless braille is important; MathCAT supports multiple braille codes and at least for Nemeth Code, is higher quality.

# Acknowledgements
Several people helped out in various ways with the project. I am very grateful for all their help!
Expand All @@ -192,7 +192,7 @@ Translators:
* Finnish -- Sami Määttä, Accessibility Library Celia, and Essi Viippola, freelancer
* German --Nazli Andjic, Robert Graf and Paul Libbrecht (IU International University of Applied Sciences)
* 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
* Norwegian -- Marthe Gjelstad, National Library of Norway, Kvile
* Spanish -- Noelia Ruiz Martínez (also help with NVDA addon development) and María Allo Roldán
* Swedish -- Tim Arborealis Lötberg, Swedish Agency for Accessible Media (MTM) and Anders Eklund, SPSM
* Vietnamese -- Dang Hoai Phúc and Trang Pham
Expand Down
28 changes: 13 additions & 15 deletions docs/nav-commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -301,22 +301,20 @@ Note: while navigating an expression, "control+c" copies the math content of the

## Navigation Modes

<b>Enhanced mode</b>: &nbsp;navigation is by mathematically
meaningful pieces (operators, delimiters, and operands)
MathCAT supports three different navigation modes: enhanced, simple, and character. The first two modes of navigation follow the semantics of what was read for the entire expression except if LiteralSpeech is selected. For example $|x+y| > 0$ will not read the vertical lines that are used for the absolute value notation, but instead will say "absolute value". Zooming in will move directly saying "x plus y". In contrast, character mode will read this as "vertical line", "x", "plus", "y" "vertical line", "is greater than", "zero" as you move through the expression.


<b>Simple mode</b>: this moves by words except when you get to a
2D notation (fractions, roots, ...), then it speaks the entire notation.
Zooming in lets you explore the 2D notation in the same mode. Zooming out or
moving out of the 2D notation brings you back to the outer/higher level of
navigation.


<b>Character mode</b>: &nbsp;this is actually two useful modes --
word mode and character mode (zoom in to get &quot;real&quot; character mode).
&nbsp;Moves by words/characters. &nbsp;This differs for numbers of more than
one digit and function names such as &quot;sin&quot; that are multiple
characters. Otherwise, word and character navigation is the same.
* _Enhanced mode_: navigation is by mathematically meaningful pieces (operators, delimiters, and operands)
* _Simple mode_: this moves by words except when you get to a
2D notation (fractions, roots, ...), then it speaks the entire notation.
Zooming in lets you explore the 2D notation in the same mode. Zooming out or
moving out of the 2D notation brings you back to the outer/higher level of
navigation.
* _Character mode_: this is actually two useful modes --
word mode and character mode (zoom in to get &quot;real&quot; character mode).
&nbsp;Moves by words/characters. &nbsp;This differs for numbers of more than
one digit and function names such as &quot;sin&quot; that are multiple
characters. Otherwise, word and character navigation is the same. Both will
automatically zoom into fractions, etc.

## Typical Use

Expand Down
2 changes: 1 addition & 1 deletion src/canonicalize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3161,7 +3161,7 @@ impl CanonicalizeContext {
// FIX: MathType generates the wrong version of union and intersection ops (binary instead of unary)
} else if !is_base && (parent_name == "msup" || parent_name == "msubsup") {
mo_text = match mo_text {
"\u{00BA}"| "\u{2092}"| "\u{20D8}"| "\u{2218}" => "\u{00B0}", // circle-like objects -> degree
"\u{00BA}"| "\u{2092}"| "\u{20D8}"| "\u{2218}" | "\u{25E6}" => "\u{00B0}", // circle-like objects -> degree
_ => mo_text,
};
} else {
Expand Down
5 changes: 3 additions & 2 deletions src/definitions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,9 @@ use yaml_rust::yaml::Hash;
use yaml_rust::Yaml;
use crate::errors::*;
use crate::prefs::*;
use std::{cell::RefCell, cell::Ref, cell::RefMut, collections::HashSet, rc::Rc};
use std::{collections::HashMap, path::Path, path::PathBuf};
use std::{cell::RefCell, cell::Ref, cell::RefMut, rc::Rc};
use std::path::{Path, PathBuf};
use std::collections::{HashMap, HashSet};
use crate::shim_filesystem::read_to_string_shim;

/// An enum to paper over the different types of data access needed.
Expand Down
1 change: 1 addition & 0 deletions src/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -539,6 +539,7 @@ pub fn get_supported_languages() -> Vec<String> {
file_name.truncate(file_name.len() - "_Rules.yaml".len())
}
speech_styles.sort();
// remove duplicates -- shouldn't be any, but just in case
let mut i = 1;
while i < speech_styles.len() {
if speech_styles[i-1] == speech_styles[i] {
Expand Down
9 changes: 6 additions & 3 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ cfg_if::cfg_if! {
}
} else {
fn get_rules_dir() -> String {
// for testing with zipped rules dir
// let rules_path = std::env::current_exe().unwrap().parent().unwrap().join("../../../MathCATForPython/addon/globalPlugins/MathCAT/Rules");
let rules_path = std::env::current_exe().unwrap().parent().unwrap().join("../../Rules");
return rules_path.as_os_str().to_str().unwrap().to_string();
}
Expand Down Expand Up @@ -192,17 +194,18 @@ fn main() {
let expr = r#"
<math xmlns="http://www.w3.org/1998/Math/MathML"><mo>(</mo><mn>1</mn><mo>)</mo></math>
"#;
let instant = Instant::now();
// let instant = Instant::now();

// let rules_dir = "".to_string(); // Use MathCATRulesDir, potentially pointing to a zipped version
if let Err(e) = set_rules_dir(get_rules_dir()) {
panic!("Error: exiting -- {}", errors_to_string(&e));
}
debug!("Languages: {}", libmathcat::interface::get_supported_languages().join(", "));

#[cfg(feature = "include-zip")]
info!("***********include-zip is present**********");
info!("Version = '{}' using Rules dir {}", get_version(), get_rules_dir());
set_preference("Language".to_string(), "en-gb".to_string()).unwrap();
set_preference("Language".to_string(), "en".to_string()).unwrap();
set_preference("DecimalSeparator".to_string(), "Auto".to_string()).unwrap();
set_preference("BrailleCode".to_string(), "Nemeth".to_string()).unwrap();
set_preference("TTS".to_string(), "None".to_string()).unwrap();
Expand Down Expand Up @@ -291,7 +294,7 @@ fn main() {
debug!("...using BrailleCode: {:?}", get_preference("BrailleCode".to_string()).unwrap());
// let xpath_counts = libmathcat::speech::xpath_count();
// info!("#xpath = {}; duplicates = {}", xpath_counts.0, xpath_counts.1);
info!("Time taken (second time for speech + braille): {}ms", instant.elapsed().as_millis());
// info!("Time taken (second time for speech + braille): {}ms", instant.elapsed().as_millis());
// debug!("Hashmap sizes:\n{}", libmathcat::speech::SpeechRules::print_sizes());
timing_test(expr, 0);

Expand Down
32 changes: 30 additions & 2 deletions src/prefs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -398,7 +398,8 @@ impl PreferenceManager {
fn set_style_file(&mut self, language_dir: &Path, language: &str, style_file_name: &str) -> Result<()> {
let style_file_name = style_file_name.to_string() + "_Rules.yaml";
self.speech = PreferenceManager::find_file(language_dir, language, Some("en"), &style_file_name)?;

// debug!("set_style_file: language_dir: {}, language: {}, style_file_name: {}, self.speech: {}",
// language_dir.display(), language, style_file_name, self.speech.display());
return Ok( () );
}

Expand Down Expand Up @@ -477,6 +478,16 @@ impl PreferenceManager {
PreferenceManager::unzip_files(path, language, default_lang)
.chain_err(|| format!("Couldn't open zip file {zip_file_string} in parent {language}: {e}."))?
} else {
// maybe just regional dialects
let mut regional_dirs = Vec::new();
find_all_dirs_shim(&dir, &mut regional_dirs);
for dir in regional_dirs {
// debug!("unzip_files: trying again in subdir: {}", dir.display());
let language = format!("{}-{}", lang, dir.file_name().unwrap().to_str().unwrap());
if let Ok(result) =PreferenceManager::unzip_files(path, &language, default_lang) {
return Ok(result);
}
}
bail!("Couldn't open zip file {}: {}.", zip_file_string, e)
}
},
Expand Down Expand Up @@ -569,6 +580,7 @@ impl PreferenceManager {
};
if looking_for_style_file && alternative_style_file.is_none() {
if let Ok(alt_file_path) = find_any_style_file(os_path) {
// debug!("find_file: found alternative style file '{}'", alt_file_path.display());
alternative_style_file = Some(alt_file_path);
}
}
Expand All @@ -578,11 +590,26 @@ impl PreferenceManager {
}
}


if let Some(result) = alternative_style_file {
// debug!("find_file: found alternative_style_file '{}'", result.to_string_lossy());
return Ok(result); // found an alternative style file in the same lang dir
}

// try a subdir (regional dialect) of the language dir
let mut regional_dirs = Vec::new();
find_all_dirs_shim(&lang_dir, &mut regional_dirs);
for dir in regional_dirs {
// debug!("find_file: trying again in subdir: {}", dir.display());
// debug!(" ... files found = {:?}", find_files_in_dir_that_ends_with_shim(&dir, file_name));
if find_files_in_dir_that_ends_with_shim(&dir, ".yaml").contains(&file_name.to_string()) {
let path = dir.join(file_name);
if is_file_shim(&path) {
return Ok(path);
}
}
}

if let Some(default_lang) = default_lang {
// try again with the default language (we're likely in trouble)
return PreferenceManager::find_file(rules_dir, default_lang, None, file_name);
Expand All @@ -594,7 +621,8 @@ impl PreferenceManager {
Looking for file: {}",
rules_dir.to_str().unwrap(), lang, file_name);

// try to find a xxx_Rules.yaml file -- returns an error if none is found ()

/// try to find a xxx_Rules.yaml file -- returns an error if none is found ()
fn find_any_style_file(path: &Path) -> Result<PathBuf> {
// try to find a xxx_Rules.yaml file
// we find the first file because this is the deepest (most language specific) speech rule file
Expand Down
Loading
Loading