Skip to content

ja: the phrases that were carried over word for word - #779

Merged
moritz-gross merged 29 commits into
daisy:jafrom
yasumorishima:ja-word-order
Sep 21, 2026
Merged

moritz-gross merged 29 commits into
daisy:jafrom
yasumorishima:ja-word-order

Conversation

@yasumorishima

Copy link
Copy Markdown
Contributor

Each of these phrases was translated token by token, in English order, so the Japanese carries the words and not the work they were doing. Where a phrase is split across several t: entries the fix moves material between them — the same thing the merged navigation work (#752, #773) had to do — and the en phrase(...) comments are left alone.

was now
{x | x > 2} 集合 すべて x そのようなこと x は 大なり 2 集合 すべての x ただし x は 大なり 2
P(A | B) A 与えられた B A 条件は B
a labelled row 行 1 ラベルを使って 第1式 行 1 ラベルは 第1式
f|_a^b f 評価される b 同じ式が評価されるマイナス a f 次の点で評価 b マイナス 同じ式を次の点で評価 a
round() ラウンド値 丸めた値
fenced-group フェンスグループ 括弧のまとまり

Why each one:

  • そのようなこと is “such a thing”. It translates the words of “such that” and none of its work, which is to attach a condition to what was just named; ただし is the word Japanese mathematical prose uses for that.
  • 与えられた is the past participle “given”, and a Japanese past participle modifies the noun after it — so B was being described rather than named as the condition. 条件は names it.
  • ラベルを使って is “using a label”, which says the row does something with one. The label is simply what the row is called.
  • 評価される is the passive “is evaluated” with nothing to say where, and 同じ式が評価されるマイナス put the minus last, so the subtraction arrived after the thing being subtracted.
  • ラウンド値 is “round” in katakana with 値 stuck on the end, and フェンスグループ is an English term in katakana that carries no Japanese meaning.

One deliberate choice worth flagging: 集合 stays in front of the variable rather than moving to the head-noun position Japanese would normally give it. In a speech stream it tells the listener what they are about to hear, and the first argument can run long — {x ∈ ℤ : x > 5} is already in the test suite.

Each phrase is swept across every file that carries it, including the sibling branches the audit did not flag: unicode.yaml has two more givens, SharedRules/general.yaml a second evaluated at, and definitions.yaml the intent mappings for such-that, given and conditional-probability. The copy of such that in unicode-full.yaml is left alone, since that file is waiting on a MathPlayer seed.

Measurements

audit-translations ja, against this branch's merge base:

before after
untranslated text 3415 3400
rule differences 30 30
missing / extra rules 0 / 0 0 / 0
missing / mismatched / extra definitions 0 / 0 / 0 0 / 0 / 0

The drop is exactly the number of rule lines promoted. definitions.yaml entries carry no case marker, so they do not move that count.

Tests

Five new in ja.rs, plus one updated: set_builder_member_symbol had pinned the old reading. To check that the tests hold the readings rather than merely passing, I pushed a branch reverting every reading and nothing else — exactly those six went red.

This does not conflict with #778; I measured git merge-tree in both orders.

TimArborealis and others added 22 commits September 1, 2026 11:46
Co-authored-by: k4its1t <306379390+k4its1t@users.noreply.github.com>
* Create test

* Traducao das regras pt-BR: unicode, definitions, SimpleSpeak, SharedRules e testes

* Versão inicial em português do MathCAT

* Corrige bugs da auditoria e traduz unicode-full.yaml (acentos, setas, operadores, formas)

* Regras da rodada de testes: probability, ignore_period, unicode-full

* Corrige unidades sec/arcsec, remove dot-over espúria, ACHADOS.md

* pt: corrige 7 bugs de regra e reconcilia os testes (92/92)

cargo test Languages::pt saía de 33 falhas em 91 testes. Agora passa 92/92,
e a suíte inteira do repositório continua verde. Nada em src/ foi tocado.

Bugs de regra:

- SharedRules/general.yaml: a distinção Verbose/Medium tinha desabado na
  química. 14 pares de ramos diziam "subscrito"/"sobrescrito" nos dois
  níveis, onde o inglês tem subscript/sub. Um deles (ramo $Prescripts[4])
  dizia "subscrito" onde o inglês diz superscript.
- SharedRules/general.yaml: ligação dupla escrita "::" não era reconhecida.
  A regra testava .='::', mas o canonicalizador converte para ∷ (U+2237)
  antes de as regras rodarem, então H₂C::CH₂ saía "maiúsculo c, como
  maiúsculo c".
- unicode.yaml: a regra de "|" era uma simplificação da inglesa e perdia
  três casos — P(A|B) ("dado"), a|b entre números ("divide") e o intent
  literal. Portada a estrutura inglesa inteira.
- SharedRules/general.yaml: <none/> fora da química caía no default-text,
  que fala o nome da tag, e saía a palavra inglesa "none". Agora "nenhum".
- SharedRules/general.yaml: faltava o Log maiúsculo (valor principal), que
  saía "Log de x". Marcado t: — a tradução precisa de conferência.
- definitions.yaml: "segundo de arco" estava duplicado em PluralForms. O
  leitor de YAML do Rust aceita, mas audit-translations recusava o arquivo
  inteiro, ou seja, definitions.yaml não estava sendo auditado de verdade.
- definitions.yaml: plurais das formas prefixadas de "segundo de arco", que
  a regra genérica produzia como "yoctossegundo de arcos".

Testes desatualizados: pausas geradas pelo motor (ver ACHADOS.md seção 1),
o artigo em "o log de x", "1 meio" em vez de "um meio", "l n x" no modo
conciso, e a vírgula do grego (que o teste inglês também tem).

Decisão: menos unário fica "menos", não "negativo". Os testes estavam
divididos; a regra já dizia "menos" e os três discordantes foram alinhados.

Resolve duas pendências do ACHADOS.md: a contradição aparente entre
tensor_mmultiscripts e mhchem_so4_2mais (caminhos de código diferentes — só
o da química estava quebrado) e a divergência de inverse_trig entre
SimpleSpeak e ClearSpeak (as regras já estavam alinhadas; era o teste).

ACHADOS.md ganha a seção 6. Corrigidas duas afirmações das seções
anteriores: compute_auto_pause conta bytes, não letras; e as regras de
química não eram idênticas às inglesas (só as diretivas de pausa eram).
Registrado também que trocar bytes por caracteres foi testado e não
resolve — piora de 15 para 36 falhas.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* Terminologia: maiúscula, romanos por valor, expoente zero cardinal, testes

* pt: pertinência sem verbo finito dentro de conjunto; ∉ com In deixa de colidir com ⊄

Duas correções de fala, com varredura e não caso a caso (ACHADOS 7.8/7.9):

1. Dentro de um conjunto ({x ∈ ℤ : x > 5}) a expressão modifica "todos os x"
   e não pode ter verbo finito nem singular: o verbo grudava em "conjunto"
   ("o conjunto de todos os x pertence a inteiros"). Seis dos oito ramos
   estavam errados, não só o Belongs. Agora: em / membros de / elementos de /
   pertencentes a, e as negações nominais. "fora de" foi rejeitado por trocar
   pertinência por localização; "não em" por ser truncado. O ramo SimpleSpeak
   usava uma string só para dentro e fora e passou a bifurcar.

2. ∉ com ClearSpeak_SetMemberSymbol=In fora de conjunto falava "não está
   contido em", exatamente a fala do ⊄. Passa a "não está em", espelhando o ∈.

Também nesta rodada, já em varredura: termo único por família de estilo
(fraktur, caligráfico) e adjetivo posposto nos dois arquivos; ∈ ∊ com Auto
separado de Member como o ∉; ! volta a distinguir literal/fatorial; ≇ ≚ ≞ ⋕
com termo matemático em vez do nome Unicode; cópula dupla em ∦ ⊈ ⊉.

Novo: tests/Languages/pt/ClearSpeak/sets.rs (pt vai de 102 para 142 testes,
∈ e ∊ travados iguais nas cinco preferências e nos dois estilos),
PythonScripts/conferir_vocabulario.py (consistência de vocabulário entre
unicode.yaml e unicode-full.yaml: 8 -> 4 grupos, restantes benignos) e
Rules/Languages/pt/TERMINOLOGIA_PT_BR.md (registro único das leituras).

Suíte inteira: 7307 passed, 0 failed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0134dJm6wzqbquvZrNhPD3Ea

* pt: corrige o que o material real do ACESSÍLIA exige; recuo controlado; pacote de escuta

Diagnóstico antes de escolher (ACHADOS 9): o MathML do ACESSÍLIA vem do
latex2mathml nos dois caminhos (inclusive Docling) e nunca traz intent=, então
os 186 IntentMappings ausentes não são prioridade. O que importa é o que o
motor infere sozinho e o que sai cru para o sintetizador.

Correções, pelo dano ao estudante:
- caracteres crus no corpus real: negrito latino e grego (\mathbf, \boldsymbol),
  ⟨ ⟩, ¯ de \bar{x} (o motor canonicaliza U+0304/U+203E para U+00AF, então a
  entrada "com mácron" nunca era alcançada), setas longas, µ Ω ℧ Å soltos
- "1 terceiro" -> "1 terço": listas fracionárias paravam em "meio"
- "o integral" -> "a integral": artigo concorda com o operador grande
- "magnitude de x" -> "a norma de x": intent inferido sem mapping pt
- "cross product"/"dot product" literais -> "produto vetorial/escalar": o
  intent inferido vem sem filhos e nenhuma regra casava com count(*)=0
- recuo controlado só em regra (gerar_recuo_en.py): 2091 entradas do en para
  codepoints sem cobertura, estilo já definido traduzido, resto em t: minúsculo.
  Antes o caractere saía cru; agora sai em inglês, contado como pendente.

Pacote da sessão de escuta (gerar_pacote_escuta.py -> SESSAO_ESCUTA.md): 30
expressões em 6 áreas, fala real nos dois estilos e três verbosidades, roteiro
e tabela das decisões que dependem do ouvinte.

cargo test: 7307 passed, 0 failed (pt: 142). conferir_vocabulario.py: 4 grupos,
todos benignos, antes e depois.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0134dJm6wzqbquvZrNhPD3Ea

* pt: P(A ∣ B) fala "dado"; varredura de vazamento nas 593 expressões do en

O latex2mathml emite \mid como U+2223, não "|": P(A ∣ B) saía "A divide B".
A entrada "∣" ganha a mesma condição de contexto da regra do "|" (dentro de
P( · ∣ · ) é "dado"; fora continua "divide"). Em conjunto por compreensão
{x ∣ ...} o problema persiste e não é regra: o canonicalizador só trata "|"
como cerca (registrado como item de src/ em ACHADOS 9.6).

Varredura: as 593 expressões dos testes do inglês faladas em português, à
procura de palavras inglesas. Fora dos <mtext> em inglês dos próprios testes
e das letras decoradas, nenhum vazamento em material real. As decorações
(circulado, entre parênteses, com ponto, invertido) entraram no mapa de
estilo do recuo controlado.

cargo test: 7307 passed, 0 failed (pt: 142). conferir_vocabulario.py: 4.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0134dJm6wzqbquvZrNhPD3Ea

* pt: recuo marcado # RECUO-EN e separado da tradução pendente; regressão do recuo = 0

As entradas do recuo controlado usavam t: minúsculo, a mesma marca de
"traduzido mas não conferido" — 2 mil delas contra 20 pendências reais, que
sumiam no meio. Cada entrada do bloco leva agora # RECUO-EN na linha da chave
e o conferir_vocabulario.py ganhou a seção 5, que reporta os dois números em
separado: 2091 entradas de recuo (1980 strings em inglês) contra 20 strings
pendentes de conferência (fraktur x10, caligráfico x10).

Verificação de regressão: as 593 expressões dos testes do en faladas em pt
sem e com o bloco. 526 iguais; 67 mudaram, todas com caractere cru antes.
Nenhuma expressão 100% português mudou de fala.

cargo test: 7307 passed, 0 failed (pt: 142). conferir_vocabulario.py: 4.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0134dJm6wzqbquvZrNhPD3Ea

* Delete auditar_pt.sh

* Delete Rules/Languages/pt/ACHADOS.md

* Delete Rules/Languages/pt/SESSAO_ESCUTA.md

* Delete Rules/Languages/pt/TERMINOLOGIA_PT_BR.md

* Terminologia: maiúscula, romanos por valor, expoente zero cardinal, testes

* Restaura arquivos apagados por engano

* Delete venv directory

* Delete PythonScripts/venv directory

* Delete PythonScripts/gerar_recuo_en.py

* Delete PythonScripts/gerar_pacote_escuta.py

* Delete PythonScripts/conferir_vocabulario.py

* Remove translation correction comments from YAML

Removed comments regarding translation corrections and pluralization issues.

* Clean up comments in ClearSpeak_Rules.yaml

Removed comments regarding corrections in Portuguese grammar and terminology for mathematical expressions.

* Clean up comments in SimpleSpeak_Rules.yaml

Removed comments regarding corrections related to gendered ordinal numbers and unnecessary English suffixes.

* Clean up translation notes in definitions.yaml

Removed translation notes and comments from definitions.yaml.

* Fix tag for overview-default in overview.yaml

Corrected the tag for 'overview-default' to include 'fraction' for better intent matching.

* Clean up comments in escuta.rs

Removed comments and documentation from escuta.rs.

* Update expressions in escuta_expressoes.tsv

* Clean up comments in intent.rs

Removed cautionary comments regarding the Spanish equivalent tests and their historical inaccuracies.

* Remove venv from version control

* Restringe o PR a Rules/Languages/pt e tests/Languages/pt

Reverte o .gitignore à versão do upstream; arquivos locais (venv, saídas
de teste, scripts auxiliares e documentos .md) ficam fora do controle de
versão via .git/info/exclude.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VJN43HMwJHeagwCporXvF3

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
* Add UEB G1 BANA/GTM mode preference and expand Grade-2 contractions.
Adding the preference is a stall tactic while I wait for feedback from ICEB about whether BANA rules are obsolete.

Introduce UEB_G1_BANA_Style (default true) to choose BANA 2019 vs ICEB GTM
1.7.3/1.7.5 grade-1 indicator placement in ueb_cleanup. Implement GTM 1.7
per-symbols-sequence counting with gtm_1_7_mode, and add matching ICEB tests.

Extend handle_contractions for technical vocabulary: UEB 10.8 final-letter
groupsigns, dot-5 through/part, dis/con prefixes, cc/ea exception words, and
a ful-pattern fix. Add ueb_technical_word_contractions (311 words, goldens
cross-checked with brailletranslators.com). Wire the preference through
prefs, fuzz, and docs.

* updated to new BANA and ICEB spec updates. Five tests fail. Still working on them

* removed an option

* fix contractions involving 'be, con, dis' which can only be at the start of a 'word' (where 'word' has a specific UEB meaning)

* Updated to UEB to the latest guidance for grade 1 indicators. This adds new tests and changes a few tests.

Also added more contractions.

* update rc #

* fix new clippy warnings

* fix up Vietanmese tests

* fix str compile issue with no-unsafe feature
…anges (daisy#738)

* pl: speak up tack (U+22A5) as perpendicular, matching en

Follow-up to 45aefb2 for Polish. Editors commonly emit U+22A5 where
perpendicularity is meant, so both U+27C2 and U+22A5 now say
"jest prostopadle do". LiteralSpeak keeps reading U+22A5 literally
as "dol".

Previously Polish said "dol" for U+22A5, so the same formula was read
differently in Polish than in English.

Adds up_tack_330 to tests/Languages/pl/alphabets.rs, mirroring the
English test.

* pl: adopt the `|` argument-glue syntax from definitions.yaml

Follow-up to 4347d88 for Polish. That commit added the `|` syntax and
updated the Polish tests, but not the Polish rule files, so several
intents lost their function name in speech.

Fixed, with the spoken output before -> after:

  quotient        "podzielone przez z x przecinek, y"
               -> "czesc calkowita z x podzielone przez y"
  remainder       "podzielone przez z x przecinek, y"
               -> "reszta z x podzielone przez y"
  set-difference  "i z wielka a przecinek, wielka b"
               -> "roznica zbiorow z wielka a i wielka b"
  polar-coordinate "przecinek z x przecinek, y"
               -> "wspolrzedna biegunowa z x przecinek, y"

The `|` syntax needs the function-intent rule to call
IntentFunctionUseArityPath / IntentFunctionGlueBefore. Only en and hu
had it, so it is now ported to pl (with "of" -> "z").

Also here:
* SharedRules/geometry.yaml: the `coordinate` rule matched "." instead
  of "not(*[@arg])", so it swallowed coordinate($x,...) intents that
  should fall through to IntentMappings. Its name was also mistranslated
  as "przecinek" (comma) rather than "punkt" (point).
* transpose: fixity order now matches en (postfix first). The
  function form is tested explicitly via intent='transpose:function($x)',
  as en does.
* empty-set: added, it was missing.

NOT adopted: arity templates ("| po | od,do") for sum/product.
intent_function_glue_before in src/infer_intent.rs hardcodes the English
word "of" for the last argument, which yields "suma po i of x" in Polish.
This affects every non-English language; hu avoids it the same way. The
binary separator form works correctly and is what this commit uses.

* pl: fix navigation direction words, unreachable for any translation

Follow-up to ec36e05 and 080ca16 for Polish, but it also fixes a
long-standing Polish bug rather than only porting the new code.

navigate.yaml compared the suffix of $NavCommand (always English, e.g.
"ZoomIn") against a substring offset by the length of the SPOKEN $Prefix.
For English those are the same; for any translation they are not. With
"przybliz" (8 chars) vs "Zoom" (4), "ZoomIn" was cut to "" instead of
"In", so ALL 16 branches were dead:

  ZoomIn        -> ""            (want "In")
  ZoomOutAll    -> "ll"          (want "OutAll")
  MoveNext      -> "t"           (want "Next")
  DescribeNext  -> "ibeNext"     (want "Next")

Users heard "przejdz; do mianownika" with no direction, never
"przejdz w prawo". Using $CommandOffset, as ec36e05 introduced, fixes
all of them.

Two more things here:

* Polish needs two verbs where English reuses "zoom": "przybliz na
  zewnatrz" (zoom in outwards) is self-contradictory, so ZoomOut* now
  says "oddal". The direction word for plain In/Out is dropped, as the
  verb already carries it: "przybliz" / "oddal", and
  "przybliz maksymalnie" / "oddal maksymalnie".
* Ports into-or-out-of-prefix-or-silent-without-parts (080ca16) and the
  SpeakIntentName fallbacks in into-or-out-of-default, keeping our own
  Polish preposition logic (including "ze stopnia" euphony).

Adds zoom_speech_pl and move_char_speech_pl. Both fail on the old
formula, showing the missing direction word, so they do discriminate.

* pl: announce table column and row separators

Follow-up to fbc49bb (daisy#679) for Polish. The HasVisibleColumnLine /
HasVisibleRowLine rules were missing from pl/SharedRules/default.yaml,
so visible lines in a matrix were silent for Polish users, e.g. an
augmented matrix was read exactly like a plain one.

  before: "2 na 3 macierz rozszerzona; wiersz 1; 3, 1, 4; ..."
  after:  "2 na 3 macierz rozszerzona; wiersz 1; 3, 1, separator, 4; ..."

Two existing tests (augmented_matrix_2x3, augmented_matrix_3x4_end_matrix)
were pinning the pre-daisy#679 output; their English counterparts already
expect "separator", so they are updated rather than worked around.

Adds dashed_augmented_matrix_separator and matrix_row_separator,
ported from tests/Languages/en/mtable.rs. Removing either rule fails
all four tests, so they discriminate.

* pl: clear the remaining untranslated unicode entries

The audit tool reported 81 unicode entries whose text equals the English
source. Reviewing them one by one, only two were actually untranslated:

  U+2127  "mhos"  -> "mho"    (unit, as nb and sv have it)
  U+2644  "Saturn"           (Polish spelling is the same; key raised)

The other 75 are correct as-is and only needed the verified key:

  * 30 Roman numerals (U+2160..U+217F) spelled out letter by letter
  * 29 space, PUA and zero-width entries with no speech at all
  *  6 typographic ligatures (ff, fl, ffi, ffl, ft, st)
  * 10 proper names and symbols (spesmilos, paragraphos, hypodiastole,
       digamma, differential d, imaginary j, oV, pH)

Four more in unicode.yaml (digit separator, space, U+2062, U+2063)
likewise carry no translatable speech.

Raising the key on an entry whose text legitimately matches English is
what the convention is for; it is not the same as marking English text
as verified. Only the wording of "mhos" changed - the diff is otherwise
key case only, checked line by line.

Audit's "untranslated" for unicode files: 81 -> 0.
…"s" (daisy#744)

* pl: mark the unicode translations as verified (t -> T)

Mechanical change: 2435 text keys raised from t/ot/ct to T/OT/CT in the
two unicode files. No text is touched.

The Polish rules were written before the lowercase/uppercase convention
was in use, so entries that have been translated all along still carried
the "needs review" key. The audit tool therefore reported them as
untranslated, which made the real gaps impossible to see:

  audit-translations pl, untranslated text:  3162 -> 727

The remaining 727 are in the rule files, where the entries need reading
rather than a mechanical pass, so they are deliberately left alone.

Every raised entry was checked to differ from the English source, i.e.
it really is translated. Entries whose text legitimately equals English
(Roman numerals, ligatures, proper names, whitespace) were handled
separately in the previous PR; entries still holding English text are
NOT raised, since that would assert a translation that does not exist.

Verification:

  cargo test --test languages Languages::pl   609 passed, 0 failed
  diff: 2436 insertions, 2436 deletions, zero changes outside key case

The last point is checked by normalising the key case in the diff and
confirming no unpaired lines remain (without normalising, 4710 remain,
so the check does discriminate).

* pl: also mark the multi-line unicode entries as verified

The previous commit raised the key on entries written on a single line
(`- "±": [t: "..."]`), but not on entries whose body is a block:

    - "°":
       - test:
           if: "parent::*[name(.)='msup' ...]"
           then: [t: "stopni"]
           else: [t: "stopień"]

Those are exactly the entries carrying inflection or a TTS condition, so
312 of the most deliberate translations in the file were left looking
unreviewed. This raises them: 64 in unicode.yaml, 247 in unicode-full.yaml
and one single-line entry (U+23E6) missed earlier.

One entry is deliberately left with a lower-case key: `t: ""` for U+00A0,
the else-branch of the `@data-empty-in-2D` test. That is silence rather
than text, and an upper-case key means "a translator checked this
wording" - there is no wording to check. English keeps a lower-case key
there too.

No content changes; only key case. `cargo test --test languages
Languages::pl` gives 609 passed, 0 failed, which is the same result as
before this commit, as expected for a change the engine treats as
equivalent (src/speech.rs matches "t"|"T" in one match arm).

* pl: raise the remaining rule-file keys and test the number-set rules

Two loose ends in the Polish localization.

**Rule-file keys.** 248 entries in the rule files still used a lower-case
key while carrying translated Polish text. Content is untouched - every
one of the 248 changed lines differs from its predecessor only in the
case of the key name, verified line by line after normalizing the key.

17 entries are deliberately left lower-case: five are the letters C, N,
Q, R, Z in `dimension-number-sets` (the letter itself is the wording, as
in English); `ct: "s"`/`ct: "-"` in the unit rule are the plural suffix
and prefix separator; `navigate.yaml:176` is a Polish euphony variant
("ze" before "st-"); the remaining seven are XPath expressions rather
than speech.

**Tests for the number-set rules.** These rules had no Polish test at
all, in a file where two silent defects were already found. New
`tests/Languages/pl/number_sets.rs` covers the bare symbols, the
dimension form, both sign variants, and ClearSpeak agreeing with
SimpleSpeak.

The `number_set_with_variable_exponent` case is the negative control:
`dimension-number-sets` fires on `count(*)=2`, so a non-numeric exponent
must fall through to the full phrase ("liczby całkowite do potęgi n")
rather than being read as a dimension. Without it, a rule that swallowed
every superscript would still pass.

Polish keeps the letter with a dimension ("R 3"), matching en, de, fr,
nb, sv, fi and es; Hungarian is the only language that translates in that
position too. Measured with the SAPI voice NVDA actually uses: "R 3" is
byte-identical to a phonetic "er 3" and "N 4" to "en 4", so the letters
are pronounced as their Polish names.

    cargo test --test languages Languages::pl   614 passed, 0 failed

* pl: inflect unit names according to the numeral, not with an English "s"

The `unit` rule appended `ct: "s"` whenever a unit had no entry in
`PluralForms`, and the Polish `PluralForms` contained no SI base unit at
all. Measured output of the engine before this change:

    1 metr, 2 metrs, 5 metrs, 21 metrs, 2 grams, 2 sekundas,
    2 ampers, 2 mols, 2 kilo-metrs

So a Polish NVDA user heard an English plural ending on essentially every
quantity. Hungarian avoids this with `CT: ""` (it appends nothing);
French and German legitimately use "s"; Russian, whose plurals work like
Polish, does not rely on a suffix at all and fills in `PluralForms`
instead. Polish was in the wrong group.

Polish does not have one plural form. The noun follows the numeral:

    1 metr | 2, 3, 4 metry (nominative plural) | 5 metrów (genitive plural)

and the teens are the exception that breaks the naive rule: 12, 13, 14
metrów, likewise 112-114, while 22 and 102 take the nominative again.
One extra plural column is therefore not enough, so this adds a second
definition section, `PluralGenitive`, next to `PluralForms` (now the
nominative plural). No Rust change is needed: `build_values` accepts any
definition name as a hashmap.

The `unit` rule (both the bare and the prefixed branch) and the
`currency` rule now read the value of the numeral and pick the section
accordingly. When the numeral cannot be determined - a variable
coefficient, as in "x ms" - `$Coefficient` is 0 and the genitive is
used, which is also what Polish uses for unknown quantities ("x
mili-sekund").

Where no inflected form is known the singular is spoken rather than a
guessed ending: a wrong ending is worse for a screen reader user than a
missing one.

Both sections cover all 131 unit and currency names that the Polish
`SIUnits`, `UnitsWithoutPrefixes`, `EnglishUnits` and `CurrencySymbols`
can produce. The forms are written out because Polish inflection cannot
be derived from the ending: metr/metry but litr/litry, om/omy,
dzień/dni, tydzień/tygodnie, rok/lata. Multi-word units inflect the head
noun and keep the dependent word's case ("5 lat świetlnych", "5 minut
łuku"). They were checked against hunspell pl_PL; the only words it does
not know are the binary-prefix neologisms (kibibajt, gibibit, ...) whose
singular forms already existed in the file.

Three base forms were themselves wrong - plurals used as singulars, so
the engine said "1 herce" and "1 konie mechaniczne":

    Hz  herce             -> herc
    hp  konie mechaniczne -> koń mechaniczny
    ℧   M h o             -> mho

Every other language has a singular here (en hertz, ru герц, fi hertsi,
es hercio; hp: ru "лошадиная сила", hu "lóerő", nb "hestekraft"; ℧:
de/fr "mho").

Why this survived: the existing Polish expectations in
tests/Languages/pl/units.rs recorded the broken output, so 609 tests
passed while the speech was wrong ("2 dzieńs", "2 tydzieńs",
"kwetta-grams"). Expectations harvested from real engine output are a
good regression net but prove nothing about correctness unless they are
read as a user would hear them. 21 test expectations are updated here,
each difference reviewed word by word.

Verification:

    cargo test --test languages Languages::pl   615 passed, 0 failed
    reverting general.yaml alone            ->  6 of 6 new tests fail

The new tests in tests/Languages/pl/unit_plurals.rs cover one class of
phenomenon each: the three numeral classes including the teens
exception, SI base units, the prefixed branch of the rule, irregular
nouns, the corrected base forms, and multi-word units.
…aisy#745)

* pl: mark the unicode translations as verified (t -> T)

Mechanical change: 2435 text keys raised from t/ot/ct to T/OT/CT in the
two unicode files. No text is touched.

The Polish rules were written before the lowercase/uppercase convention
was in use, so entries that have been translated all along still carried
the "needs review" key. The audit tool therefore reported them as
untranslated, which made the real gaps impossible to see:

  audit-translations pl, untranslated text:  3162 -> 727

The remaining 727 are in the rule files, where the entries need reading
rather than a mechanical pass, so they are deliberately left alone.

Every raised entry was checked to differ from the English source, i.e.
it really is translated. Entries whose text legitimately equals English
(Roman numerals, ligatures, proper names, whitespace) were handled
separately in the previous PR; entries still holding English text are
NOT raised, since that would assert a translation that does not exist.

Verification:

  cargo test --test languages Languages::pl   609 passed, 0 failed
  diff: 2436 insertions, 2436 deletions, zero changes outside key case

The last point is checked by normalising the key case in the diff and
confirming no unpaired lines remain (without normalising, 4710 remain,
so the check does discriminate).

* pl: also mark the multi-line unicode entries as verified

The previous commit raised the key on entries written on a single line
(`- "±": [t: "..."]`), but not on entries whose body is a block:

    - "°":
       - test:
           if: "parent::*[name(.)='msup' ...]"
           then: [t: "stopni"]
           else: [t: "stopień"]

Those are exactly the entries carrying inflection or a TTS condition, so
312 of the most deliberate translations in the file were left looking
unreviewed. This raises them: 64 in unicode.yaml, 247 in unicode-full.yaml
and one single-line entry (U+23E6) missed earlier.

One entry is deliberately left with a lower-case key: `t: ""` for U+00A0,
the else-branch of the `@data-empty-in-2D` test. That is silence rather
than text, and an upper-case key means "a translator checked this
wording" - there is no wording to check. English keeps a lower-case key
there too.

No content changes; only key case. `cargo test --test languages
Languages::pl` gives 609 passed, 0 failed, which is the same result as
before this commit, as expected for a change the engine treats as
equivalent (src/speech.rs matches "t"|"T" in one match arm).

* pl: raise the remaining rule-file keys and test the number-set rules

Two loose ends in the Polish localization.

**Rule-file keys.** 248 entries in the rule files still used a lower-case
key while carrying translated Polish text. Content is untouched - every
one of the 248 changed lines differs from its predecessor only in the
case of the key name, verified line by line after normalizing the key.

17 entries are deliberately left lower-case: five are the letters C, N,
Q, R, Z in `dimension-number-sets` (the letter itself is the wording, as
in English); `ct: "s"`/`ct: "-"` in the unit rule are the plural suffix
and prefix separator; `navigate.yaml:176` is a Polish euphony variant
("ze" before "st-"); the remaining seven are XPath expressions rather
than speech.

**Tests for the number-set rules.** These rules had no Polish test at
all, in a file where two silent defects were already found. New
`tests/Languages/pl/number_sets.rs` covers the bare symbols, the
dimension form, both sign variants, and ClearSpeak agreeing with
SimpleSpeak.

The `number_set_with_variable_exponent` case is the negative control:
`dimension-number-sets` fires on `count(*)=2`, so a non-numeric exponent
must fall through to the full phrase ("liczby całkowite do potęgi n")
rather than being read as a dimension. Without it, a rule that swallowed
every superscript would still pass.

Polish keeps the letter with a dimension ("R 3"), matching en, de, fr,
nb, sv, fi and es; Hungarian is the only language that translates in that
position too. Measured with the SAPI voice NVDA actually uses: "R 3" is
byte-identical to a phonetic "er 3" and "N 4" to "en 4", so the letters
are pronounced as their Polish names.

    cargo test --test languages Languages::pl   614 passed, 0 failed

* pl: inflect unit names according to the numeral, not with an English "s"

The `unit` rule appended `ct: "s"` whenever a unit had no entry in
`PluralForms`, and the Polish `PluralForms` contained no SI base unit at
all. Measured output of the engine before this change:

    1 metr, 2 metrs, 5 metrs, 21 metrs, 2 grams, 2 sekundas,
    2 ampers, 2 mols, 2 kilo-metrs

So a Polish NVDA user heard an English plural ending on essentially every
quantity. Hungarian avoids this with `CT: ""` (it appends nothing);
French and German legitimately use "s"; Russian, whose plurals work like
Polish, does not rely on a suffix at all and fills in `PluralForms`
instead. Polish was in the wrong group.

Polish does not have one plural form. The noun follows the numeral:

    1 metr | 2, 3, 4 metry (nominative plural) | 5 metrów (genitive plural)

and the teens are the exception that breaks the naive rule: 12, 13, 14
metrów, likewise 112-114, while 22 and 102 take the nominative again.
One extra plural column is therefore not enough, so this adds a second
definition section, `PluralGenitive`, next to `PluralForms` (now the
nominative plural). No Rust change is needed: `build_values` accepts any
definition name as a hashmap.

The `unit` rule (both the bare and the prefixed branch) and the
`currency` rule now read the value of the numeral and pick the section
accordingly. When the numeral cannot be determined - a variable
coefficient, as in "x ms" - `$Coefficient` is 0 and the genitive is
used, which is also what Polish uses for unknown quantities ("x
mili-sekund").

Where no inflected form is known the singular is spoken rather than a
guessed ending: a wrong ending is worse for a screen reader user than a
missing one.

Both sections cover all 131 unit and currency names that the Polish
`SIUnits`, `UnitsWithoutPrefixes`, `EnglishUnits` and `CurrencySymbols`
can produce. The forms are written out because Polish inflection cannot
be derived from the ending: metr/metry but litr/litry, om/omy,
dzień/dni, tydzień/tygodnie, rok/lata. Multi-word units inflect the head
noun and keep the dependent word's case ("5 lat świetlnych", "5 minut
łuku"). They were checked against hunspell pl_PL; the only words it does
not know are the binary-prefix neologisms (kibibajt, gibibit, ...) whose
singular forms already existed in the file.

Three base forms were themselves wrong - plurals used as singulars, so
the engine said "1 herce" and "1 konie mechaniczne":

    Hz  herce             -> herc
    hp  konie mechaniczne -> koń mechaniczny
    ℧   M h o             -> mho

Every other language has a singular here (en hertz, ru герц, fi hertsi,
es hercio; hp: ru "лошадиная сила", hu "lóerő", nb "hestekraft"; ℧:
de/fr "mho").

Why this survived: the existing Polish expectations in
tests/Languages/pl/units.rs recorded the broken output, so 609 tests
passed while the speech was wrong ("2 dzieńs", "2 tydzieńs",
"kwetta-grams"). Expectations harvested from real engine output are a
good regression net but prove nothing about correctness unless they are
read as a user would hear them. 21 test expectations are updated here,
each difference reviewed word by word.

Verification:

    cargo test --test languages Languages::pl   615 passed, 0 failed
    reverting general.yaml alone            ->  6 of 6 new tests fail

The new tests in tests/Languages/pl/unit_plurals.rs cover one class of
phenomenon each: the three numeral classes including the teens
exception, SI base units, the prefixed branch of the rule, irregular
nouns, the corrected base forms, and multi-word units.

* pl: speak the unit after "na" in the accusative, not the nominative

The `per-fraction` rule speaks the denominator of a unit fraction after
the preposition "na", which in Polish governs the accusative case. The
unit was inserted in the nominative, so the engine said:

    62 mile na godzina        (should be "na godzinę")
    5 metrów na sekunda       (should be "na sekundę")
    3 galony na mila          (should be "na milę")
    3 metry na sekunda do kwadratu

Only feminine nouns change form here. For masculine inanimate and neuter
names the accusative already equals the nominative, so "3 gramy na litr"
and "1 dżul na mol" were correct and stay untouched. That narrows the
work to 32 of the 131 unit and currency names, which is why
`AccusativeCase` deliberately holds only those - a missing entry means
"the form does not change".

Why this lives in the `unit` rule rather than in `per-fraction`: Russian
has the same problem and solves it inside `per-fraction` by testing the
unit symbol and writing the inflected word inline (`милю`), which works
because only one word is affected. Polish would need 32 such cases in
the rule. Instead the `unit` rule asks whether it is being spoken as a
fraction denominator, so the choice is made once, in one place, for every
name.

The denominator can also be raised to a power, as in m/s², and then the
unit's parent is the `power` element rather than the fraction itself, so
`IsFractionDenominator` tests both shapes. That second case was found
only after the first fix: the existing expectation "3 metry na sekunda do
kwadratu" was still passing green, because the list of failing tests
shows only the cases whose output actually changed. Searching every
Polish expectation for a nominative after "na" is what surfaced it.

An adjective agrees with its noun ("na stopę kwadratową") while a
dependent noun keeps its own case ("na minutę łuku", "na uncję płynu"),
so the forms are written out rather than derived.

Verification:

    cargo test --test languages Languages::pl   620 passed, 0 failed

New tests in tests/Languages/pl/preposition_case.rs include two negative
controls: masculine and neuter denominators must NOT change, and a unit
standing on its own must stay in the nominative, so the accusative cannot
leak outside the fraction denominator.

---------

Co-authored-by: NSoiffer <NSoiffer@users.noreply.github.com>
…gitignore

Update: Add `Cargo.lock` file to track dependencies
Changed chemical arrow operator to read "reagerar och bildar" instead of "reaktion bildar", to make grammatical sense.
* pl: mark the unicode translations as verified (t -> T)

Mechanical change: 2435 text keys raised from t/ot/ct to T/OT/CT in the
two unicode files. No text is touched.

The Polish rules were written before the lowercase/uppercase convention
was in use, so entries that have been translated all along still carried
the "needs review" key. The audit tool therefore reported them as
untranslated, which made the real gaps impossible to see:

  audit-translations pl, untranslated text:  3162 -> 727

The remaining 727 are in the rule files, where the entries need reading
rather than a mechanical pass, so they are deliberately left alone.

Every raised entry was checked to differ from the English source, i.e.
it really is translated. Entries whose text legitimately equals English
(Roman numerals, ligatures, proper names, whitespace) were handled
separately in the previous PR; entries still holding English text are
NOT raised, since that would assert a translation that does not exist.

Verification:

  cargo test --test languages Languages::pl   609 passed, 0 failed
  diff: 2436 insertions, 2436 deletions, zero changes outside key case

The last point is checked by normalising the key case in the diff and
confirming no unpaired lines remain (without normalising, 4710 remain,
so the check does discriminate).

* pl: also mark the multi-line unicode entries as verified

The previous commit raised the key on entries written on a single line
(`- "±": [t: "..."]`), but not on entries whose body is a block:

    - "°":
       - test:
           if: "parent::*[name(.)='msup' ...]"
           then: [t: "stopni"]
           else: [t: "stopień"]

Those are exactly the entries carrying inflection or a TTS condition, so
312 of the most deliberate translations in the file were left looking
unreviewed. This raises them: 64 in unicode.yaml, 247 in unicode-full.yaml
and one single-line entry (U+23E6) missed earlier.

One entry is deliberately left with a lower-case key: `t: ""` for U+00A0,
the else-branch of the `@data-empty-in-2D` test. That is silence rather
than text, and an upper-case key means "a translator checked this
wording" - there is no wording to check. English keeps a lower-case key
there too.

No content changes; only key case. `cargo test --test languages
Languages::pl` gives 609 passed, 0 failed, which is the same result as
before this commit, as expected for a change the engine treats as
equivalent (src/speech.rs matches "t"|"T" in one match arm).

* pl: raise the remaining rule-file keys and test the number-set rules

Two loose ends in the Polish localization.

**Rule-file keys.** 248 entries in the rule files still used a lower-case
key while carrying translated Polish text. Content is untouched - every
one of the 248 changed lines differs from its predecessor only in the
case of the key name, verified line by line after normalizing the key.

17 entries are deliberately left lower-case: five are the letters C, N,
Q, R, Z in `dimension-number-sets` (the letter itself is the wording, as
in English); `ct: "s"`/`ct: "-"` in the unit rule are the plural suffix
and prefix separator; `navigate.yaml:176` is a Polish euphony variant
("ze" before "st-"); the remaining seven are XPath expressions rather
than speech.

**Tests for the number-set rules.** These rules had no Polish test at
all, in a file where two silent defects were already found. New
`tests/Languages/pl/number_sets.rs` covers the bare symbols, the
dimension form, both sign variants, and ClearSpeak agreeing with
SimpleSpeak.

The `number_set_with_variable_exponent` case is the negative control:
`dimension-number-sets` fires on `count(*)=2`, so a non-numeric exponent
must fall through to the full phrase ("liczby całkowite do potęgi n")
rather than being read as a dimension. Without it, a rule that swallowed
every superscript would still pass.

Polish keeps the letter with a dimension ("R 3"), matching en, de, fr,
nb, sv, fi and es; Hungarian is the only language that translates in that
position too. Measured with the SAPI voice NVDA actually uses: "R 3" is
byte-identical to a phonetic "er 3" and "N 4" to "en 4", so the letters
are pronounced as their Polish names.

    cargo test --test languages Languages::pl   614 passed, 0 failed

---------

Co-authored-by: NSoiffer <NSoiffer@users.noreply.github.com>
…fect the outcome. Also consolodate nav preference testing.
…aisy#762) (daisy#763)

* fix(speech): flatten nested TEMP_NAME wrappers so a matrix raised to a power is not read as "TEMP NAME of"

The mrow 'matrix' intent rule replaces with a bare `x: "*[2]"`, so its result is
wrapped in the internal TEMP_NAME transport element; the parent `power` rule's
`x: "*[1]"` wraps it again and lift_children only stripped one level. The
leftover wrapper reached the generic function-intent speech rule, which spoke
its name: "TEMP NAME of the 2 by 2 matrix; ...; squared" (daisy#762).

lift_children now flattens nested wrappers recursively. A leaf wrapper holding
text is still only unwrapped as a direct child, matching the previous behavior.
Two regression tests added to tests/Languages/en/mtable.rs; no goldens changed.

Fixes daisy#762

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01U86v5m1m8oaLSy5UsNbBpc

* Simplify condition in push_lifted function

Fixes clippy warning

* Fix indent and delete extra "}" I should have deleted on the last change

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Co-authored-by: NSoiffer <NSoiffer@users.noreply.github.com>
…finitions.yaml.

This also cleans up some really old code that tried to figure out if what was read was a vector or hashmap/hashset.

Fixes daisy#739.
Adjust the audit-translations parser so `# audit-ignore` markers immediately above a rule apply to that rule, while still supporting existing inline markers inside a rule block. This also clarifies the documented behavior and adds regression tests for leading, inline, and first-item ignore cases.
* Add in-memory virtual filesystem support to shim_filesystem

* Fix clippy warnings across codebase and tests
Each of these was translated token by token, in English order, so the Japanese
carries the words and not the meaning. Where a phrase is split across several
`t:` entries the fix moves material between them, which is what the merged
navigation work (daisy#752, daisy#773) already did; the en `phrase(...)` comments are left
alone.

  {x | x > 2}
    集合 すべて x そのようなこと x は 大なり 2
    -> 集合 すべての x ただし x は 大なり 2
    そのようなこと is "such a thing": it translates the words of "such that" and
    none of its work, which is to attach a condition to what was just named.
    ただし is what Japanese mathematical prose uses. 集合 stays in front of the
    variable rather than moving to the head-noun position Japanese would
    normally give it, because in a speech stream it tells the listener what
    they are about to hear, and the first argument can be long ({x ∈ ℤ : x > 5}).

  P(A | B)
    A 与えられた B -> A 条件は B
    与えられた is the past participle "given", which in Japanese modifies the
    noun after it, so B was being described rather than named as the condition.

  a labelled row
    行 1 ラベルを使って 第1式 -> 行 1 ラベルは 第1式
    ラベルを使って is "using a label", which says the row does something with
    one. The label is simply what the row is called.

  f|_a^b
    f 評価される b 同じ式が評価されるマイナス a
    -> f 次の点で評価 b マイナス 同じ式を次の点で評価 a
    評価される is the passive "is evaluated" with nothing to say where, and the
    minus came last, so the subtraction arrived after the thing subtracted.

  round()        ラウンド値 ("round" in katakana + 値) -> 丸めた値
  fenced-group   フェンスグループ, an English term in katakana -> 括弧のまとまり

Each phrase is swept across every file that carries it, including the sibling
branches: unicode.yaml has two more `given`s, general.yaml a second
`evaluated at`, and definitions.yaml the intent mappings for such-that, given
and conditional-probability. The copy of `such that` in unicode-full.yaml is
left alone, since that file is waiting on a MathPlayer seed.

audit-translations ja: untranslated 3415 -> 3400, which is exactly the number of
rule lines promoted; rule differences unchanged at 30; missing, extra and
definition counts unchanged at 0. definitions.yaml entries carry no case marker,
so they do not move that count.

Tests: five new in ja.rs and one updated, since set_builder_member_symbol had
pinned the old reading. Reverting the readings and nothing else turns exactly
those six red.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XzNYYoiVRzKGnDEWTJnuHh
michaldziwisz and others added 3 commits September 20, 2026 00:21
…ate.yaml (daisy#766)

Ports ec36e05 to the two remaining languages that still cut the direction
word out of $NavCommand with the length of the SPOKEN prefix.

$NavCommand is always English (ZoomIn, MoveNext), while $Prefix is the
translated word, so string-length($Prefix)+1 only lands on the right offset
while the prefix happens to match the English stem. In de and el the prefixes
are still the untranslated zoom/move/read/describe, so all 18 branches work
today by coincidence; localizing those strings -- the obvious thing for a
translator to do -- silently kills every direction word.

This is a no-op right now, which is exactly why it is a good time to do it:
substring($NavCommand, $CommandOffset) returns the same value as before for
every one of the 15 navigation commands with the current prefixes.

Verified on the engine, not only on paper: Languages::de is 209/209 both with
and without this change. Greek has no tests at all (tests/Languages/el exists
but is not declared in tests/languages.rs), so el rests on the structural
check: offsets and the list of 9 branches are now identical to en.

Refs daisy#740.
This change fixes how audit_translations YAML blocks are split when comments or blank lines appear around list items. It keeps introductory comments with the correct rule, preserves explicit audit-ignore markers inside a rule, and avoids incorrectly attaching comment-only lines to neighboring items.
@moritz-gross

Copy link
Copy Markdown
Collaborator

@yasumorishima Merging main fixed some of the CI issues for me. though I still don't understand what went wrong in the first place. maybe try merging main again here as well?

@moritz-gross

Copy link
Copy Markdown
Collaborator

hmmm, now we have 103 files changed in total, as the ja branch was outdated to main anyway. This should be fine right?
I mean, what's the plan on when to merge this back into main anyway? I feel like the progress on Japanese has been enough to ship it.

@yasumorishima

Copy link
Copy Markdown
Contributor Author

Merged main (374ea588) in — no conflicts, and nothing of mine moved: git diff between the pre-merge commit and the merge for Rules/Languages/ja and tests/Languages/ja is empty, and the branch's diff against main is still only the ja files plus the four-line registration in tests/languages.rs.

Test (no-unsafe, Rules.zip), the job that was failing, passes on the merged head in 6m28s. Rules-minimized.zip, both builds, both clippy runs, the Python tests and the rules zip are green as well; Build and fuzz is still running.

I do not know what the original failure was either. What I could measure at the time is in #781: the panic was RefCell already borrowed from speech.rs, the failing test was not fixed — en::alphabets::cap_cyrillic in one run and zh::tw::alphabets::cap_cyrillic in another on this same branch — and Rules-minimized.zip passed in the same runs. With one green run I cannot tell whether the merge removed the cause or only changed the timing, so I would not read this as a diagnosis.

@moritz-gross

Copy link
Copy Markdown
Collaborator

can you please make your messages easier to read? While I agree on the technical side, this heavily looks like it is written by Claude. I'm also using AI agents in my workflow, but I think that messages in discussions here on GitHub should remain human-authored (and potentially AI-translated).

so I think we can merge this. on the question regarding the integration into main: have you heard anything from Neil on what the plan is when that should happen, or what the conditions for that are?

@yasumorishima

Copy link
Copy Markdown
Contributor Author

On the 103: yes, but one part of it was not fine until a minute ago, so let me give the measurements on the head I just pushed (ce129706).

Against main this branch is 15 files, +11,136, −0 — the whole Rules/Languages/ja and tests/Languages/ja tree plus four lines in tests/languages.rs, since ja is not in main at all yet.

Against the base branch ja it is the 103 you see. 95 of those files come from main, and on every one of them this branch is byte-identical to current main: git diff main HEAD -- <those 95 paths> prints nothing. So merging reverts nothing of main's and introduces nothing of mine outside ja. The remaining 8 files are this PR's own work, +80 −22.

The part that was not fine: my branch predated your merge of #778, so until now the diff against ja also looked as though it took the verified navigation strings back out. I have merged ja in as well, and git diff ja HEAD -- Rules/Languages/ja/navigate.yaml now shows nothing at all — #778 is untouched. Thank you for asking about the file count; that is what surfaced it.

On when to merge ja into main — that is your call, and here is the state I can measure on this head with audit-translations ja:

  • Missing rules 0, extra rules 0, rule differences 30 — the same 30 as before, the ones I changed deliberately carry # audit-ignore.
  • Untranslated text 3,400, but that is a review-status count rather than English reaching a user: of the lowercase t:/ot:/ct: values, 3,271 are already Japanese and exactly 6 are pure ASCII, those six being - - -, 1, 2, 3, . and ..
  • 2,816 of the 3,400 sit in unicode-full.yaml, which I have deliberately left alone because NSoiffer said he would seed it from the MathPlayer Japanese data.
  • That file is also where the readings I would least like to ship still live: ∋ 会員を含む, ∌ 会員は含まない, ∍ 会員を含む — 会員 is a club member — and ∅ 空のセット, ∖ セットマイナス, ≺ プリセット (U+227A, which is "precedes", not a preset). None of those six characters is in unicode.yaml, so replace_single_char falls through to unicode-full.yaml and a user hears them today.
  • "Missing definitions 1" is FunctionApplicationWord; en is the only language in the repository that defines it, so ja is not behind the other translations there.
  • 104 tests under tests/Languages/ja.

So the rules files are in a state I would be happy to see shipped. The one thing I would want decided before or soon after a merge is those six unicode-full.yaml readings, since they reach users now and the seed has not arrived. If you would like, I can send a small PR that changes only those six and leaves the rest of the file for the seed — otherwise I will leave the file as it is.

@yasumorishima

Copy link
Copy Markdown
Contributor Author

Sorry, that was far too long. I'll keep these short.

No, I haven't heard anything from Neil about the timing or the conditions for merging ja into main. He has only said two related things to me. In #715 he mentioned he has Japanese data from MathPlayer that could seed the unicode files, and in #720 he said he will approve changes that stay inside the Japanese directories, since he can't review the language himself.

@moritz-gross
moritz-gross merged commit e0a219b into daisy:ja Sep 21, 2026
10 checks passed
@github-project-automation github-project-automation Bot moved this from Triage to Done in MathCAT Project Board Sep 21, 2026
@moritz-gross

Copy link
Copy Markdown
Collaborator

next time I talk to him, I'll ask. Thanks for all your work!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

10 participants