ja: the phrases that were carried over word for word - #779
Conversation
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
…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.
Fix audit-ignore rule scoping
|
@yasumorishima Merging |
|
hmmm, now we have 103 files changed in total, as the |
|
Merged
I do not know what the original failure was either. What I could measure at the time is in #781: the panic was |
|
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? |
|
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 ( Against Against the base branch The part that was not fine: my branch predated your merge of #778, so until now the diff against On when to merge ja into main — that is your call, and here is the state I can measure on this head with
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 |
|
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 |
|
next time I talk to him, I'll ask. Thanks for all your work! |
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 enphrase(...)comments are left alone.{x | x > 2}P(A | B)f|_a^bround()fenced-groupWhy each one:
Bwas being described rather than named as the condition. 条件は names it.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.yamlhas two moregivens,SharedRules/general.yamla secondevaluated at, anddefinitions.yamlthe intent mappings forsuch-that,givenandconditional-probability. The copy ofsuch thatinunicode-full.yamlis left alone, since that file is waiting on a MathPlayer seed.Measurements
audit-translations ja, against this branch's merge base:The drop is exactly the number of rule lines promoted.
definitions.yamlentries carry no case marker, so they do not move that count.Tests
Five new in
ja.rs, plus one updated:set_builder_member_symbolhad 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-treein both orders.