Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 2 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ but add common mistakes of AI agents here instead.
- `ClearSpeak_Rules.yaml`, `SimpleSpeak_Rules.yaml`
- `SharedRules/`, `unicode.yaml`, `unicode-full.yaml`, `definitions.yaml`, `navigate.yaml`
- `build.rs` can bundle rules into `rules.zip` when `include-zip` is enabled (always the minimized tree). Shared zipper: `src/rules_archive.rs`, invoked as `cargo run --bin package-rules -- Rules <output> [--minimize]`.
- CI packages `Rules.zip` (verbatim) and `Rules-minimized.zip` (flow-style rewrite of all YAML: comments dropped). Each language/braille subdir is stored as `<name>/<name>.zip`; top-level and `Intent/` YAML stay loose. Inner language zips use BZIP2; the outer downloadable archive uses DEFLATE so `unzip` works. Both omit `Languages/zz`; the `test-rules-package` job restores `zz` from git after unzip so unit tests still run against release-like archives.
- CI packages `Rules.zip` (verbatim) and `Rules-minimized.zip` (comments stripped from `Languages/**/unicode.yaml` and `unicode-full.yaml` only). Each language/braille subdir is stored as `<name>/<name>.zip`; top-level and `Intent/` YAML stay loose. Inner language zips use BZIP2; the outer downloadable archive uses DEFLATE so `unzip` works. Both omit `Languages/zz`; the `test-rules-package` job restores `zz` from git after unzip so unit tests still run against release-like archives.

## Translation Conventions
- `t:` means untranslated or unverified.
Expand All @@ -33,6 +33,7 @@ but add common mistakes of AI agents here instead.
- Do not mirror README content here; keep guidance agent-specific.
- Avoid broad formatting sweeps; do not run `cargo fmt` in this repo.
- Keep code/rule changes focused and validate with targeted tests first: `cargo test <relevant-tests>`
- Do **not** change test goldens (expected braille/speech/nav strings) unless the user explicitly says to. Prefer fixing code/rules to match existing goldens; if a golden looks wrong vs the spec, ask before editing it.
- do not do any git commands unless explicitly asked for
- Rust coverage is in `target/coverage/`.
- When working with GitHub, e.g. looking at PRs and issues, check if the GitHub CLI is installed (`gh --version`).
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.7-alpha.1"
version = "0.7.6-rc.4"
authors = ["Neil Soiffer <soiffer@alum.mit.edu>"]
license = "MIT"
description = "MathCAT: Math Capable Assistive Technology ('Speech and braille from MathML')"
Expand Down
11 changes: 1 addition & 10 deletions PythonScripts/audit_translations/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,6 @@ uv run --project PythonScripts audit-translations --list
* Region variants are shown as `lang-region` (e.g., `zz-aa`) based on subdirectories under `Rules/Languages/<lang>`.
* `--source`: Sets the source/reference language. Defaults to `en`.
* `--file`: Audits a single specific file instead of the whole directory.
* `--exclude`: Exclude one or more files from the audit.
* `--rules-dir`: Override the Rules/Languages directory path.
* `--only`: Filter issue types (comma-separated): `missing`, `untranslated`, `extra`, `diffs`, `all`.
* `--verbose`: Show detailed output including source/target snippets for rule differences.
Expand All @@ -101,17 +100,9 @@ uv run audit-translations de
# Compare Norwegian Bokmal against Swedish instead of English
uv run audit-translations nb --source sv

# Audit only a specific file (note: --file is incompatible with --exclude)
uv run audit-translations es --file ClearSpeak_Rules.yaml
# Audit only a specific file
uv run audit-translations es --file SharedRules/default.yaml

# Exclude a list of files from the audit, note that if you use this option before specifying the
# target language you'll need to use the option terminator (--).
# (note: --exclude is incompatible with --file)
uv run audit-translations es --exclude unicode-full.yaml
uv run audit-translations es --exclude unicode-full.yaml unicode.yaml
uv run audit-translations --exclude unicode-full.yaml -- es

# Audit a regional variant (merges Rules/Languages/de and Rules/Languages/de/CH)
uv run audit-translations de-CH

Expand Down
34 changes: 13 additions & 21 deletions PythonScripts/audit_translations/auditor.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,31 +46,24 @@ def is_definitions_file(file_path: str | Path) -> bool:
return Path(file_path).name == "definitions.yaml"


def get_yaml_files(lang_dir: Path, region_dir: Path | None = None, excluded_files: list[str] | None = None) -> list[Path]:
def get_yaml_files(lang_dir: Path, region_dir: Path | None = None) -> list[Path]:
"""Get all YAML files to audit for a language, including region overrides."""
files: set[Path] = set()

def collect_from(directory: Path, root: Path, excluded: list[str] | None) -> None:
def collect_from(directory: Path, root: Path) -> None:
if not directory.exists():
return

excluded_paths = {Path(path) for path in excluded or []}

candidates = {f for f in directory.glob("*.yaml") if f.name != "prefs.yaml"}
candidates.update((directory / "SharedRules").glob("*.yaml"))

relative_candidates = {f.relative_to(directory): f for f in candidates}

for path in excluded_paths - relative_candidates.keys():
console.print(f"\n[yellow]⚠ Warning:[/] File to exclude {path} does not exist.")

files.update(
f.relative_to(root) for relative_path, f in relative_candidates.items() if relative_path not in excluded_paths
)

collect_from(lang_dir, lang_dir, excluded_files)
for f in directory.glob("*.yaml"):
if f.name != "prefs.yaml":
files.add(f.relative_to(root))
shared_dir = directory / "SharedRules"
if shared_dir.exists():
for f in shared_dir.glob("*.yaml"):
files.add(f.relative_to(root))

collect_from(lang_dir, lang_dir)
if region_dir:
collect_from(region_dir, region_dir, excluded_files)
collect_from(region_dir, region_dir)

return sorted(files)

Expand Down Expand Up @@ -222,7 +215,6 @@ def merge_definitions(
def audit_language(
language: str,
specific_file: str | None = None,
excluded_files: list[str] | None = None,
rules_dir: str | None = None,
issue_filter: set[str] | None = None,
verbose: bool = False,
Expand Down Expand Up @@ -256,7 +248,7 @@ def audit_language(
raise AuditError(f"Target region directory not found: {translated_region_dir}")

# Get list of files to audit
files = [specific_file] if specific_file else get_yaml_files(source_dir, source_region_dir, excluded_files)
files = [specific_file] if specific_file else get_yaml_files(source_dir, source_region_dir)

print_audit_header(language, len(files), source_language)

Expand Down
14 changes: 1 addition & 13 deletions PythonScripts/audit_translations/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,18 +30,7 @@ def main() -> None:

parser.add_argument("language", nargs="?", help="Language code to audit (e.g., 'es', 'de', 'fi')")
parser.add_argument("--source", default="en", help="Source/reference language code (default: 'en')")
file_group = parser.add_mutually_exclusive_group()
file_group.add_argument(
"--file",
dest="specific_file",
help="Audit only a specific file (e.g., 'SharedRules/default.yaml')",
)
file_group.add_argument(
"--exclude",
nargs="+",
dest="excluded_files",
help="Exclude a list of files from the audit.",
)
parser.add_argument("--file", dest="specific_file", help="Audit only a specific file (e.g., 'SharedRules/default.yaml')")
parser.add_argument("--list", action="store_true", help="List available languages")
parser.add_argument("--rules-dir", help="Override Rules/Languages directory path")
parser.add_argument(
Expand Down Expand Up @@ -78,7 +67,6 @@ def main() -> None:
audit_language(
args.language,
args.specific_file,
args.excluded_files,
args.rules_dir,
issue_filter,
args.verbose,
Expand Down
74 changes: 0 additions & 74 deletions PythonScripts/audit_translations/tests/test_cli_end_to_end.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,80 +127,6 @@ def test_cli_main_rich_only_filters_issue_groups(capsys, monkeypatch) -> None:
assert "Structure Differences" not in output


@pytest.mark.parametrize(
("excluded_file", "expected_file", "expected_rule", "unexpected_rule"),
[
(
"default.yaml",
"SharedRules/default.yaml",
"shared-only",
"root-only",
),
(
"SharedRules/default.yaml",
"default.yaml",
"root-only",
"shared-only",
),
],
ids=["exclude-root", "exclude-shared-rules"],
)
def test_cli_main_exclude_uses_relative_paths(
tmp_path,
capsys,
monkeypatch,
excluded_file,
expected_file,
expected_rule,
unexpected_rule,
) -> None:
"""Ensure --exclude distinguishes root files from SharedRules files."""
rules_dir = tmp_path / "Rules" / "Languages"
source_dir = rules_dir / "en"
target_dir = rules_dir / "de"

(source_dir / "SharedRules").mkdir(parents=True)
(target_dir / "SharedRules").mkdir(parents=True)

(source_dir / "default.yaml").write_text(
'- name: root-only\n tag: mo\n match: ".//m:mi"\n replace:\n - t: "root"\n',
encoding="utf-8",
)
(source_dir / "SharedRules" / "default.yaml").write_text(
'- name: shared-only\n tag: mo\n match: ".//m:mi"\n replace:\n - t: "shared"\n',
encoding="utf-8",
)

target_rule = '- name: target-only\n tag: mo\n match: ".//m:mi"\n replace:\n - t: "target"\n'
(target_dir / "default.yaml").write_text(
target_rule,
encoding="utf-8",
)
(target_dir / "SharedRules" / "default.yaml").write_text(
target_rule,
encoding="utf-8",
)

args = [
"de",
"--rules-dir",
str(rules_dir),
"--exclude",
excluded_file,
"--only",
"missing",
]
monkeypatch.setattr(sys, "argv", ["audit_translations", *args])

audit_cli.main()
output = strip_ansi(capsys.readouterr().out)

assert "Files to check: 1" in output
assert expected_file in output
assert expected_rule in output
assert unexpected_rule not in output


def test_cli_main_accepts_source_language(capsys, monkeypatch) -> None:
"""
Ensure --source changes the reference language without changing target semantics.
Expand Down
Loading