Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 46 additions & 33 deletions Rules/Languages/ja/navigate.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
- name: say-command
tag: "!*"
match: "$SayCommand != ''" # value should be '', 'true', or 'false'
variables: [Prefix: "''"]
variables: [Prefix: "''", Particle: "''"]
replace:
- test:
- if: "$MatchCounter = 0 and $SayCommand = 'true'"
Expand All @@ -63,38 +63,51 @@
# CommandOffset is 1 + length of the English NavCommand stem (Zoom/Move/Read/Describe),
# not the spoken Prefix length — so translations can use a different Prefix word.
- if: "starts-with($NavCommand, 'Zoom')"
then: [set_variables: [Prefix: "'zoom'", CommandOffset: "5"]] # phrase('zoom' in to see more details)
then: [set_variables: [Prefix: "'ズーム'", CommandOffset: "5"]] # phrase('zoom' in to see more details)
- else_if: "starts-with($NavCommand, 'Move')"
then: [set_variables: [Prefix: "'move'", CommandOffset: "5"]] # phrase('move' to next entry in table)
then: [set_variables: [Prefix: "'移動'", Particle: "'に'", CommandOffset: "5"]] # phrase('move' to next entry in table)
- else_if: "starts-with($NavCommand, 'Read')"
then: [set_variables: [Prefix: "'read'", CommandOffset: "5"]] # phrase('read' to next entry in table)
then: [set_variables: [Prefix: "'読み上げ'", Particle: "'を'", CommandOffset: "5"]] # phrase('read' to next entry in table)
- else_if: "starts-with($NavCommand, 'Describe')"
then: [set_variables: [Prefix: "'describe'", CommandOffset: "9"]] # phrase('describe' to next entry in table)
then: [set_variables: [Prefix: "'説明'", Particle: "'を'", CommandOffset: "9"]] # phrase('describe' to next entry in table)
- test:
if: "$Prefix != ''"
then:
- x: "$Prefix"
- test:
- if: "substring($NavCommand, $CommandOffset) = 'In'"
then: [T: "イン"] # phrase(zoom 'in' to see more details)
- else_if: "substring($NavCommand, $CommandOffset) = 'InAll'"
# HACK: '\uF8FE' is used internally for the concatenation char by 'ct' -- this gets "ed" concatenated to "zoom"
then: [t: "\uF8FEインを最大にしました"] # phrase(zoom 'out all of the way' to see more details)
- else_if: "substring($NavCommand, $CommandOffset) = 'Out'"
then: [T: "アウト"] # phrase(zoom 'out' to see more details)
- else_if: "substring($NavCommand, $CommandOffset) = 'OutAll'"
# HACK: '\uF8FE' is used internally for the concatenation char by 'ct' -- this gets "ed" concatenated to "zoom"
then: [t: "\uF8FEアウトを最大にしました"] # phrase(zoom 'out all of the way' to see more details)
- else_if: "substring($NavCommand, $CommandOffset) = 'Next'"
then: [T: "右"] # phrase(move to the 'right')
- else_if: "substring($NavCommand, $CommandOffset) = 'Previous'"
then: [T: "左"] # phrase(move to the 'left')
- else_if: "substring($NavCommand, $CommandOffset) = 'Current'"
then: [T: "現在"] # phrase(who is the 'current' president)
- else_if: "substring($NavCommand, $CommandOffset) = 'LineStart'"
then: [T: "行の先頭へ"] # phrase(move 'to start of line')
- else_if: "substring($NavCommand, $CommandOffset) = 'LineEnd'"
then: [T: "行の末尾へ"] # phrase(move 'to end of line')
# The Zoom commands keep the English order because ズーム + イン
# is read as one loanword, and the concatenation below needs the
# prefix first. The others put the target and its particle before
# the verb (右 に 移動 / 右 を 読み上げ), as Japanese requires.
if: "starts-with($NavCommand, 'Zoom')"
then:
- x: "$Prefix"
- test:
- if: "substring($NavCommand, $CommandOffset) = 'In'"
then: [T: "イン"] # phrase(zoom 'in' to see more details)
- else_if: "substring($NavCommand, $CommandOffset) = 'InAll'"
# HACK: '\uF8FE' is the internal concatenation char, so this joins onto the prefix: ズーム + インを最大にしました
then: [T: "\uF8FEインを最大にしました"] # phrase(zoom 'in all of the way')
- else_if: "substring($NavCommand, $CommandOffset) = 'Out'"
then: [T: "アウト"] # phrase(zoom 'out' to see more details)
- else_if: "substring($NavCommand, $CommandOffset) = 'OutAll'"
# HACK: '\uF8FE' is the internal concatenation char, so this joins onto the prefix: ズーム + アウトを最大にしました
then: [T: "\uF8FEアウトを最大にしました"] # phrase(zoom 'out all of the way')
else:
- test:
# $Particle is に for Move and を for Read/Describe. It is emitted
# inside each branch so a command with no matching suffix still
# falls back to the bare verb, the way it does in en.
- if: "substring($NavCommand, $CommandOffset) = 'Next'"
then: [T: "右", x: "$Particle"] # phrase(move to the 'right')
- else_if: "substring($NavCommand, $CommandOffset) = 'Previous'"
then: [T: "左", x: "$Particle"] # phrase(move to the 'left')
- else_if: "substring($NavCommand, $CommandOffset) = 'Current'"
then: [T: "現在", x: "$Particle"] # phrase(who is the 'current' president)
- else_if: "substring($NavCommand, $CommandOffset) = 'LineStart'"
then: [T: "行の先頭", x: "$Particle"] # phrase(move 'to start of line')
- else_if: "substring($NavCommand, $CommandOffset) = 'LineEnd'"
then: [T: "行の末尾", x: "$Particle"] # phrase(move 'to end of line')
- x: "$Prefix"
- pause: "medium"
- set_variables: [MatchCounter: "$MatchCounter + 1"]

Expand Down Expand Up @@ -1204,13 +1217,13 @@
- test:
if: "$MatchCounter = 0 and $NavVerbosity = 'Verbose'"
then:
- T: "右に" # phrase(move 'right')
- test:
# the particle belongs to the verb: に移動 but を読み上げ / を説明
- if: "$NavCommand = 'MoveNext'"
then: [t: "移動"] # phrase('move' to next entry in table)
then: [T: "右に移動"] # phrase(cannot 'move right')
- else_if: "$NavCommand = 'ReadNext'"
then: [T: "読み上げ"] # phrase('read' next entry in table)
else: [T: "説明"] # phrase('describe' next entry in table)
then: [T: "右を読み上げ"] # phrase(cannot 'read' to the right)
else: [T: "右を説明"] # phrase(cannot 'describe' to the right)
- T: "できません" # phrase('cannot' move right in expression)
- pause: short
- T: "数式の末尾" # phrase(move 'end of math')
Expand Down Expand Up @@ -1678,11 +1691,11 @@
- test:
if: "$NavVerbosity = 'Verbose'"
then:
- T: "現在" # phrase('current' entry in table)
- test:
- if: "$NavCommand = 'ReadCurrent'"
then: [T: "読み上げ"] # phrase('read' next entry in table)
else: [T: "説明"] # phrase('describe' next entry in table)
- T: "現在" # phrase('current' entry in table)
then: [T: "を読み上げ"] # phrase('read' next entry in table)
else: [T: "を説明"] # phrase('describe' next entry in table)
- pause: long
- set_variables: [NavNode: "@id"]

Expand Down
77 changes: 77 additions & 0 deletions tests/Languages/ja/navigate.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
//! What the Japanese navigation commands announce.
//!
//! These cover the command prefix only (the part say-command produces); the
//! description that follows it comes from NavigationParts and is asserted
//! elsewhere, so each check compares everything up to the first pause.

use crate::common::*;
use anyhow::Result;
use std::panic::{catch_unwind, AssertUnwindSafe};

fn init_nav(mathml: &str) -> Result<()> {
set_rules_dir(abs_rules_dir_path())?;
set_preference("Language", "ja")?;
set_preference("SpeechStyle", "SimpleSpeak")?;
set_preference("Verbosity", "Medium")?;
set_preference("NavMode", "Enhanced")?;
set_preference("NavVerbosity", "Verbose")?;
set_preference("AutoZoomOut", "False")?;
set_preference("Overview", "False")?;
set_mathml(mathml)?;
Ok(())
}

fn assert_command_prefix(mathml: &str, commands: &[&str], expected: &str) -> Result<()> {
init_panic_handler();
let result = catch_unwind(AssertUnwindSafe(|| {
init_nav(mathml)?;
let mut speech = String::new();
for command in commands {
speech = do_navigate_command(command)?;
}
let prefix = speech.split(';').next().unwrap_or("").trim().to_string();
assert_eq!(prefix, expected, "full speech was {speech:?}");
Ok(())
}));
report_any_panic(result)
}

const EXPR: &str = r#"<math><mrow><msup><mi>x</mi><mn>2</mn></msup><mo>+</mo><mn>1</mn></mrow></math>"#;

/// The prefix used to be the English word "zoom", spoken as-is by a Japanese
/// synthesiser. ズーム + イン also reads as the ordinary loanword.
#[test]
fn zoom_prefix_is_japanese() -> Result<()> {
assert_command_prefix(EXPR, &["ZoomIn"], "ズーム イン")
}

#[test]
fn zoom_out_prefix_is_japanese() -> Result<()> {
assert_command_prefix(EXPR, &["ZoomIn", "ZoomOut"], "ズーム アウト")
}

/// Japanese puts the target before the verb, with the particle the verb takes:
/// 右 に 移動, not 移動 右.
#[test]
fn move_says_target_before_verb() -> Result<()> {
assert_command_prefix(EXPR, &["ZoomIn", "MoveNext"], "右 に 移動")
}

/// Read and describe take を, not に, on the same direction word.
#[test]
fn read_takes_its_own_particle() -> Result<()> {
assert_command_prefix(EXPR, &["ZoomIn", "ReadNext"], "右 を 読み上げ")
}

/// The U+F8FE concatenation joins the suffix onto the prefix with no space,
/// so this has to come out as one word.
#[test]
fn zoom_in_all_is_one_phrase() -> Result<()> {
assert_command_prefix(EXPR, &["ZoomInAll"], "ズームインを最大にしました")
}

/// ReadCurrent is announced by its own rule, which has to use the same order.
#[test]
fn read_current_says_target_first() -> Result<()> {
assert_command_prefix(EXPR, &["ZoomIn", "ReadCurrent"], "現在 を読み上げ")
}
1 change: 1 addition & 0 deletions tests/languages.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ mod Languages {
mod fr;
mod ja {
mod ja;
mod navigate;
}
mod vi {
mod vi;
Expand Down