Commit c9ae9ed2 authored by Akihiro Ota's avatar Akihiro Ota Committed by Commit Bot

ChromeVox: Don't announce 'en-us' -> 'en', or vice versa.

This change adds a special case to the voice switching code to
suppress announcements when switching from 'en-us' to 'en', or vice
versa. This was done for two main reasons:

1. This case frequently appears in the real-world, e.g. Docs, which
was leading to overly verbose announcements.
2. This logic shouldn't be generalized to other languages. For example,
'pt' -> 'pt-br' or 'pt-br' -> 'pt' still warrants an announcement
since Brazilian Portuguese is quite different from European Portuguese.

Tests are included to confirm new behavior.

switching is active.

Bug: 1098548
Change-Id: Ifcfdcd53e12863fffd25ffb2dfafe8d91a718e4c
AX-Relnotes: ChromeVox gives less frequent announcements when voice
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2402152
Commit-Queue: Akihiro Ota <akihiroota@chromium.org>
Reviewed-by: default avatarDavid Tseng <dtseng@chromium.org>
Cr-Commit-Position: refs/heads/master@{#816253}
parent 87a37bfd
...@@ -60,10 +60,10 @@ LocaleOutputHelper = class { ...@@ -60,10 +60,10 @@ LocaleOutputHelper = class {
contextNode.detectedLanguage || contextNode.language || ''; contextNode.detectedLanguage || contextNode.language || '';
const newLocale = this.computeNewLocale_(nodeLocale); const newLocale = this.computeNewLocale_(nodeLocale);
let outputString = text; let outputString = text;
const shouldAlert = newLocale !== this.currentLocale_; const shouldAnnounce = this.shouldAnnounceLocale_(newLocale);
if (this.hasVoiceForLocale_(newLocale)) { if (this.hasVoiceForLocale_(newLocale)) {
this.setCurrentLocale_(newLocale); this.setCurrentLocale_(newLocale);
if (shouldAlert) { if (shouldAnnounce) {
// Prepend the human-readable locale to |outputString|. // Prepend the human-readable locale to |outputString|.
const displayLanguage = const displayLanguage =
chrome.accessibilityPrivate.getDisplayNameForLocale( chrome.accessibilityPrivate.getDisplayNameForLocale(
...@@ -135,6 +135,29 @@ LocaleOutputHelper = class { ...@@ -135,6 +135,29 @@ LocaleOutputHelper = class {
} }
} }
/**
* @param {string} newLocale
* @return {boolean}
* @private
*/
shouldAnnounceLocale_(newLocale) {
// Note: currentLocale_ and newLocale are guaranteed to contain a language
// code. However, they might not contain a country code.
const [currentLanguage, currentCountry] = this.currentLocale_.split('-');
const [newLanguage, newCountry] = newLocale.split('-');
if (currentLanguage !== newLanguage) {
return true;
}
if (!currentCountry || !newCountry) {
// If one of the countries is blank, then we don't want to announce the
// locale. For example, we don't want to announce 'en' -> 'en-us'.
return false;
}
return currentCountry !== newCountry;
}
// =============== Static Methods ============== // =============== Static Methods ==============
/** /**
......
...@@ -162,20 +162,16 @@ ChromeVoxLocaleOutputHelperTest = class extends ChromeVoxNextE2ETest { ...@@ -162,20 +162,16 @@ ChromeVoxLocaleOutputHelperTest = class extends ChromeVoxNextE2ETest {
get chineseDoc() { get chineseDoc() {
return ` return `
<p lang="en-us">United States</p> <p lang="en-us">United States</p>
<p lang="zh">Chinese</p>
<p lang="zh-hans">Simplified Chinese</p> <p lang="zh-hans">Simplified Chinese</p>
<p lang="zh-hant">Traditional Chinese</p> <p lang="zh-hant">Traditional Chinese</p>
<p lang="zh">Chinese</p>
`; `;
} }
get portugueseDoc() { get portugueseDoc() {
return ` return `
<p lang="en-us">United States</p> <p lang="en-us">United States</p>
<p lang="pt">Portuguese</p>
<p lang="pt-br">Brazil</p> <p lang="pt-br">Brazil</p>
<p lang="pt-pt">Portugal</p> <p lang="pt-pt">Portugal</p>
<p lang="pt">Portuguese</p>
`; `;
} }
}; };
...@@ -208,7 +204,7 @@ TEST_F( ...@@ -208,7 +204,7 @@ TEST_F(
this.setAvailableVoices(); this.setAvailableVoices();
mockFeedback.call(doCmd('jumpToTop')) mockFeedback.call(doCmd('jumpToTop'))
.expectSpeechWithLocale( .expectSpeechWithLocale(
'en', 'English: In the morning, I sometimes eat breakfast.'); 'en', 'In the morning, I sometimes eat breakfast.');
mockFeedback.call(doCmd('nextLine')) mockFeedback.call(doCmd('nextLine'))
.expectSpeechWithLocale( .expectSpeechWithLocale(
'fr', 'français: Dans l\'apres-midi, je dejeune.'); 'fr', 'français: Dans l\'apres-midi, je dejeune.');
...@@ -303,7 +299,7 @@ TEST_F( ...@@ -303,7 +299,7 @@ TEST_F(
mockFeedback.call(doCmd('jumpToTop')) mockFeedback.call(doCmd('jumpToTop'))
.expectSpeechWithLocale( .expectSpeechWithLocale(
'en', 'en',
'English: This entire object should be read in English, even' + 'This entire object should be read in English, even' +
' the following French passage: ' + ' the following French passage: ' +
'salut mon ami! Ca va? Bien, et toi? It\'s hard to' + 'salut mon ami! Ca va? Bien, et toi? It\'s hard to' +
' differentiate between latin-based languages.'); ' differentiate between latin-based languages.');
...@@ -457,7 +453,7 @@ TEST_F('ChromeVoxLocaleOutputHelperTest', 'WordNavigationTest', function() { ...@@ -457,7 +453,7 @@ TEST_F('ChromeVoxLocaleOutputHelperTest', 'WordNavigationTest', function() {
this.setAvailableVoices(); this.setAvailableVoices();
mockFeedback.call(doCmd('jumpToTop')) mockFeedback.call(doCmd('jumpToTop'))
.expectSpeechWithLocale( .expectSpeechWithLocale(
'en', 'English: In the morning, I sometimes eat breakfast.') 'en', 'In the morning, I sometimes eat breakfast.')
.call(doCmd('nextLine')) .call(doCmd('nextLine'))
.expectSpeechWithLocale( .expectSpeechWithLocale(
'fr', 'français: Dans l\'apres-midi, je dejeune.') 'fr', 'français: Dans l\'apres-midi, je dejeune.')
...@@ -509,7 +505,7 @@ TEST_F( ...@@ -509,7 +505,7 @@ TEST_F(
this.setAvailableVoices(); this.setAvailableVoices();
mockFeedback.call(doCmd('jumpToTop')) mockFeedback.call(doCmd('jumpToTop'))
.expectSpeechWithLocale( .expectSpeechWithLocale(
'en', 'English: In the morning, I sometimes eat breakfast.') 'en', 'In the morning, I sometimes eat breakfast.')
.call(doCmd('nextLine')) .call(doCmd('nextLine'))
.expectSpeechWithLocale( .expectSpeechWithLocale(
'fr', 'français: Dans l\'apres-midi, je dejeune.') 'fr', 'français: Dans l\'apres-midi, je dejeune.')
...@@ -556,15 +552,11 @@ TEST_F( ...@@ -556,15 +552,11 @@ TEST_F(
mockFeedback.call(doCmd('jumpToTop')) mockFeedback.call(doCmd('jumpToTop'))
.expectSpeechWithLocale('en-us', 'United States') .expectSpeechWithLocale('en-us', 'United States')
.call(doCmd('nextLine')) .call(doCmd('nextLine'))
.expectSpeechWithLocale('zh', '中文: Chinese')
.call(doCmd('nextLine'))
.expectSpeechWithLocale( .expectSpeechWithLocale(
'zh-hans', '中文(简体): Simplified Chinese') 'zh-hans', '中文(简体): Simplified Chinese')
.call(doCmd('nextLine')) .call(doCmd('nextLine'))
.expectSpeechWithLocale( .expectSpeechWithLocale(
'zh-hant', '中文(繁體): Traditional Chinese') 'zh-hant', '中文(繁體): Traditional Chinese');
.call(doCmd('nextLine'))
.expectSpeechWithLocale('zh', '中文: Chinese');
mockFeedback.replay(); mockFeedback.replay();
}); });
}); });
...@@ -579,13 +571,49 @@ TEST_F( ...@@ -579,13 +571,49 @@ TEST_F(
mockFeedback.call(doCmd('jumpToTop')) mockFeedback.call(doCmd('jumpToTop'))
.expectSpeechWithLocale('en-us', 'United States') .expectSpeechWithLocale('en-us', 'United States')
.call(doCmd('nextLine')) .call(doCmd('nextLine'))
.expectSpeechWithLocale('pt', 'português: Portuguese')
.call(doCmd('nextLine'))
.expectSpeechWithLocale('pt-br', 'português (Brasil): Brazil') .expectSpeechWithLocale('pt-br', 'português (Brasil): Brazil')
.call(doCmd('nextLine')) .call(doCmd('nextLine'))
.expectSpeechWithLocale('pt-pt', 'português (Portugal): Portugal') .expectSpeechWithLocale('pt-pt', 'português (Portugal): Portugal');
.call(doCmd('nextLine'))
.expectSpeechWithLocale('pt', 'português: Portuguese');
mockFeedback.replay(); mockFeedback.replay();
}); });
}); });
TEST_F(
'ChromeVoxLocaleOutputHelperTest', 'DoNotAnnounceLocaleFirstCase',
function() {
const mockFeedback = this.createMockFeedback();
this.runWithLoadedTree(
`
<p lang="en">Start</p>
<p lang="en-us">End</p>
`,
function() {
localStorage['languageSwitching'] = 'true';
this.setAvailableVoices();
mockFeedback.call(doCmd('jumpToTop'))
.expectSpeechWithLocale('en', 'Start')
.call(doCmd('nextObject'))
.expectSpeechWithLocale('en-us', 'End')
.replay();
});
});
TEST_F(
'ChromeVoxLocaleOutputHelperTest', 'DoNotAnnounceLocaleSecondCase',
function() {
const mockFeedback = this.createMockFeedback();
this.runWithLoadedTree(
`
<p lang="en-us">Start</p>
<p lang="en">End</p>
`,
function() {
localStorage['languageSwitching'] = 'true';
this.setAvailableVoices();
mockFeedback.call(doCmd('jumpToTop'))
.expectSpeechWithLocale('en-us', 'Start')
.call(doCmd('nextObject'))
.expectSpeechWithLocale('en', 'End')
.replay();
});
});
...@@ -198,7 +198,6 @@ TEST_F('ChromeVoxPanelTest', 'InternationalFormControlsMenu', function() { ...@@ -198,7 +198,6 @@ TEST_F('ChromeVoxPanelTest', 'InternationalFormControlsMenu', function() {
this.assertActiveMenuItem( this.assertActiveMenuItem(
'panel_menu_form_controls', 'español: Prueba Button'); 'panel_menu_form_controls', 'español: Prueba Button');
this.fireMockEvent('ArrowUp')(); this.fireMockEvent('ArrowUp')();
this.assertActiveMenuItem( this.assertActiveMenuItem('panel_menu_form_controls', 'Test Button');
'panel_menu_form_controls', 'English: Test Button');
}); });
}); });
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment