Enforce language (#1344)

* Assign text content and a language

* Remove _appendMultilineText

* Assign lang for createTextNode content

* Add language attributes to HTML pages
This commit is contained in:
toasted-nutbread 2021-02-08 17:52:35 -05:00 committed by GitHub
parent c6315cdb8c
commit 008809e0e7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 60 additions and 47 deletions

View File

@ -21,7 +21,7 @@
<ul> <ul>
<li> <li>
<strong>Downstep notation</strong> - <strong>Downstep notation</strong> -
<span class="format-preview"> <span class="format-preview" lang="ja">
<span class="term-pitch-accent-characters"><span class="term-pitch-accent-character" data-position="0" data-pitch="high" data-pitch-next="low"><span class="term-pitch-accent-character-inner"></span></span><span class="term-pitch-accent-character" data-position="1" data-pitch="low" data-pitch-next="low"><span class="term-pitch-accent-character-inner"></span></span></span> <span class="term-pitch-accent-characters"><span class="term-pitch-accent-character" data-position="0" data-pitch="high" data-pitch-next="low"><span class="term-pitch-accent-character-inner"></span></span><span class="term-pitch-accent-character" data-position="1" data-pitch="low" data-pitch-next="low"><span class="term-pitch-accent-character-inner"></span></span></span>
</span> </span>
</li> </li>

View File

@ -20,7 +20,7 @@
<div class="top-options"> <div class="top-options">
<div class="top-options-left"> <div class="top-options-left">
<div class="example-text-container"> <div class="example-text-container">
<input type="text" class="example-text example-text-input" id="example-text-input" value="読め" hidden> <input type="text" class="example-text example-text-input" id="example-text-input" value="読め" lang="ja" hidden>
<span class="example-text" id="example-text">読め</span> <span class="example-text" id="example-text">読め</span>
</div> </div>
</div> </div>

View File

@ -46,7 +46,7 @@
</div> </div>
</div> </div>
<div class="search-textbox-container"> <div class="search-textbox-container">
<textarea id="search-textbox" placeholder="Input a term, expression, sentence, or block of text" autocomplete="off" autofocus></textarea> <textarea id="search-textbox" placeholder="Input a term, expression, sentence, or block of text" autocomplete="off" lang="ja" autofocus></textarea>
<button id="search-button"><span class="icon" data-icon="magnifying-glass"></span></button> <button id="search-button"><span class="icon" data-icon="magnifying-glass"></span></button>
</div> </div>
</div> </div>

View File

@ -1179,7 +1179,7 @@
<div class="settings-item-description">Change what type of furigana is displayed for parsed text.</div> <div class="settings-item-description">Change what type of furigana is displayed for parsed text.</div>
</div> </div>
<div class="settings-item-right"> <div class="settings-item-right">
<select data-setting="parsing.readingMode"> <select data-setting="parsing.readingMode" lang="ja">
<option value="none">None</option> <option value="none">None</option>
<option value="hiragana">ひらがな</option> <option value="hiragana">ひらがな</option>
<option value="katakana">カタカナ</option> <option value="katakana">カタカナ</option>
@ -1281,7 +1281,7 @@
<div class="settings-item"><div class="settings-item-inner settings-item-inner-wrappable"> <div class="settings-item"><div class="settings-item-inner settings-item-inner-wrappable">
<div class="settings-item-left"> <div class="settings-item-left">
<div class="settings-item-label">Convert half width characters to full width</div> <div class="settings-item-label">Convert half width characters to full width</div>
<div class="settings-item-description">ヨミチャン&#x3000;&rarr;&#x3000;ヨミチャン</div> <div class="settings-item-description" lang="ja">ヨミチャン&#x3000;&rarr;&#x3000;ヨミチャン</div>
</div> </div>
<div class="settings-item-right"> <div class="settings-item-right">
<select data-setting="translation.convertHalfWidthCharacters"> <select data-setting="translation.convertHalfWidthCharacters">
@ -1294,7 +1294,7 @@
<div class="settings-item"><div class="settings-item-inner settings-item-inner-wrappable"> <div class="settings-item"><div class="settings-item-inner settings-item-inner-wrappable">
<div class="settings-item-left"> <div class="settings-item-left">
<div class="settings-item-label">Convert numeric characters to full width</div> <div class="settings-item-label">Convert numeric characters to full width</div>
<div class="settings-item-description">1234&#x3000;&rarr;&#x3000;</div> <div class="settings-item-description" lang="ja">1234&#x3000;&rarr;&#x3000;</div>
</div> </div>
<div class="settings-item-right"> <div class="settings-item-right">
<select data-setting="translation.convertNumericCharacters"> <select data-setting="translation.convertNumericCharacters">
@ -1307,7 +1307,7 @@
<div class="settings-item"><div class="settings-item-inner settings-item-inner-wrappable"> <div class="settings-item"><div class="settings-item-inner settings-item-inner-wrappable">
<div class="settings-item-left"> <div class="settings-item-left">
<div class="settings-item-label">Convert alphabetic characters to hiragana</div> <div class="settings-item-label">Convert alphabetic characters to hiragana</div>
<div class="settings-item-description">yomichan&#x3000;&rarr;&#x3000;よみちゃん</div> <div class="settings-item-description" lang="ja">yomichan&#x3000;&rarr;&#x3000;よみちゃん</div>
</div> </div>
<div class="settings-item-right"> <div class="settings-item-right">
<select data-setting="translation.convertAlphabeticCharacters"> <select data-setting="translation.convertAlphabeticCharacters">
@ -1320,7 +1320,7 @@
<div class="settings-item"><div class="settings-item-inner settings-item-inner-wrappable"> <div class="settings-item"><div class="settings-item-inner settings-item-inner-wrappable">
<div class="settings-item-left"> <div class="settings-item-left">
<div class="settings-item-label">Convert hiragana to katakana</div> <div class="settings-item-label">Convert hiragana to katakana</div>
<div class="settings-item-description">よみちゃん&#x3000;&rarr;&#x3000;ヨミチャン</div> <div class="settings-item-description" lang="ja">よみちゃん&#x3000;&rarr;&#x3000;ヨミチャン</div>
</div> </div>
<div class="settings-item-right"> <div class="settings-item-right">
<select data-setting="translation.convertHiraganaToKatakana"> <select data-setting="translation.convertHiraganaToKatakana">
@ -1333,7 +1333,7 @@
<div class="settings-item"><div class="settings-item-inner settings-item-inner-wrappable"> <div class="settings-item"><div class="settings-item-inner settings-item-inner-wrappable">
<div class="settings-item-left"> <div class="settings-item-left">
<div class="settings-item-label">Convert katakana to hiragana</div> <div class="settings-item-label">Convert katakana to hiragana</div>
<div class="settings-item-description">ヨミチャン&#x3000;&rarr;&#x3000;よみちゃん</div> <div class="settings-item-description" lang="ja">ヨミチャン&#x3000;&rarr;&#x3000;よみちゃん</div>
</div> </div>
<div class="settings-item-right"> <div class="settings-item-right">
<select data-setting="translation.convertKatakanaToHiragana"> <select data-setting="translation.convertKatakanaToHiragana">
@ -1346,7 +1346,7 @@
<div class="settings-item"><div class="settings-item-inner settings-item-inner-wrappable"> <div class="settings-item"><div class="settings-item-inner settings-item-inner-wrappable">
<div class="settings-item-left"> <div class="settings-item-left">
<div class="settings-item-label">Collapse emphatic character sequences</div> <div class="settings-item-label">Collapse emphatic character sequences</div>
<div class="settings-item-description">すっっごーーい&#x3000;&rarr;&#x3000;すっごーい / すごい</div> <div class="settings-item-description" lang="ja">すっっごーーい&#x3000;&rarr;&#x3000;すっごーい / すごい</div>
</div> </div>
<div class="settings-item-right"> <div class="settings-item-right">
<select data-setting="translation.collapseEmphaticSequences"> <select data-setting="translation.collapseEmphaticSequences">
@ -2228,7 +2228,7 @@
Change which voice is used for text-to-speech audio playback. Change which voice is used for text-to-speech audio playback.
</p> </p>
<div class="horizontal-flex"> <div class="horizontal-flex">
<input type="text" value="よみちゃん" id="text-to-speech-voice-test-text" autocomplete="off"> <input type="text" value="よみちゃん" id="text-to-speech-voice-test-text" autocomplete="off" lang="ja">
<button id="text-to-speech-voice-test">Test</button> <button id="text-to-speech-voice-test">Test</button>
<a class="more-toggle" data-parent-distance="3">Hide&hellip;</a> <a class="more-toggle" data-parent-distance="3">Hide&hellip;</a>
</div> </div>
@ -2770,7 +2770,7 @@
<div class="anki-card-templates-test-table-header">Scanned text</div> <div class="anki-card-templates-test-table-header">Scanned text</div>
<div class="anki-card-templates-test-table-header">Card field</div> <div class="anki-card-templates-test-table-header">Card field</div>
<div></div> <div></div>
<input type="text" id="anki-card-templates-test-text-input" class="form-control" value="読め" placeholder="Preview text" autocomplete="off"> <input type="text" id="anki-card-templates-test-text-input" class="form-control" value="読め" placeholder="Preview text" autocomplete="off" lang="ja">
<div class="anki-card-templates-test-input-container"> <div class="anki-card-templates-test-input-container">
<input type="text" class="input-with-suffix-button" id="anki-card-templates-test-field-input" value="{expression}" placeholder="{marker}" autocomplete="off" spellcheck="false"> <input type="text" class="input-with-suffix-button" id="anki-card-templates-test-field-input" value="{expression}" placeholder="{marker}" autocomplete="off" spellcheck="false">
<button class="input-suffix-button input-suffix-icon-button" id="anki-card-templates-test-field-menu-button" data-menu="anki-card-all-field-menu" data-menu-position="below left"><span class="icon icon-button-icon-light" data-icon="material-down-arrow"></span></button> <button class="input-suffix-button input-suffix-icon-button" id="anki-card-templates-test-field-menu-button" data-menu="anki-card-all-field-menu" data-menu-position="below left"><span class="icon icon-button-icon-light" data-icon="material-down-arrow"></span></button>
@ -2926,9 +2926,9 @@
<div class="translation-text-replacement-test-label translation-text-replacement-test-node">Test Input:</div> <div class="translation-text-replacement-test-label translation-text-replacement-test-node">Test Input:</div>
<div class="translation-text-replacement-test-container translation-text-replacement-test-node"> <div class="translation-text-replacement-test-container translation-text-replacement-test-node">
<input type="text" class="translation-text-replacement-test-input"> <input type="text" class="translation-text-replacement-test-input" lang="ja">
<div class="translation-text-replacement-test-label-inner">Output:</div> <div class="translation-text-replacement-test-label-inner">Output:</div>
<input type="text" class="translation-text-replacement-test-output" readonly> <input type="text" class="translation-text-replacement-test-output" lang="ja" readonly>
</div> </div>
</div></template> </div></template>
@ -2991,10 +2991,10 @@
</select> </select>
</td> </td>
<td> <td>
<input type="text" class="sentence-termination-character-input1" maxlength="1"> <input type="text" class="sentence-termination-character-input1" maxlength="1" lang="ja">
</td> </td>
<td> <td>
<input type="text" class="sentence-termination-character-input2" maxlength="1"> <input type="text" class="sentence-termination-character-input2" maxlength="1" lang="ja">
<div class="sentence-termination-character-input2-alt">&mdash;</div> <div class="sentence-termination-character-input2-alt">&mdash;</div>
</td> </td>
<td> <td>

View File

@ -1000,6 +1000,9 @@ button.action-button[data-icon=source-term]::before {
.term-glossary-item::marker { .term-glossary-item::marker {
color: var(--text-color-light3); color: var(--text-color-light3);
} }
.term-glossary {
white-space: pre-line;
}
.term-definition-disambiguation-list { .term-definition-disambiguation-list {
color: var(--text-color-light3); color: var(--text-color-light3);
} }
@ -1337,6 +1340,9 @@ button.action-button[data-icon=source-term]::before {
.term-glossary-image-link-text::after { .term-glossary-image-link-text::after {
content: ']'; content: ']';
} }
.term-glossary-image-description {
white-space: pre-line;
}
/* Kanji */ /* Kanji */
@ -1398,6 +1404,9 @@ button.action-button[data-icon=source-term]::before {
.kanji-glossary-item::marker { .kanji-glossary-item::marker {
color: var(--text-color-light3); color: var(--text-color-light3);
} }
.kanji-glossary {
white-space: pre-line;
}
/* Progress bar */ /* Progress bar */

View File

@ -130,7 +130,7 @@ class DisplayGenerator {
const codepointsContainer = node.querySelector('.kanji-codepoints'); const codepointsContainer = node.querySelector('.kanji-codepoints');
const dictionaryIndicesContainer = node.querySelector('.kanji-dictionary-indices'); const dictionaryIndicesContainer = node.querySelector('.kanji-dictionary-indices');
glyphContainer.textContent = details.character; this._setTextContent(glyphContainer, details.character, 'ja');
const groupedFrequencies = DictionaryDataUtil.groupKanjiFrequencies(details.frequencies); const groupedFrequencies = DictionaryDataUtil.groupKanjiFrequencies(details.frequencies);
const dictionaryTag = this._createDictionaryTag(details.dictionary); const dictionaryTag = this._createDictionaryTag(details.dictionary);
@ -157,7 +157,7 @@ class DisplayGenerator {
const node = this._templates.instantiateFragment('footer-notification-tag-details'); const node = this._templates.instantiateFragment('footer-notification-tag-details');
const details = tagNode.dataset.details; const details = tagNode.dataset.details;
node.querySelector('.tag-details').textContent = details; this._setTextContent(node.querySelector('.tag-details'), details);
let disambiguation = null; let disambiguation = null;
try { try {
@ -182,6 +182,7 @@ class DisplayGenerator {
const segments = this._japaneseUtil.distributeFurigana(expression, reading); const segments = this._japaneseUtil.distributeFurigana(expression, reading);
const disambiguationItem = document.createElement('span'); const disambiguationItem = document.createElement('span');
disambiguationItem.className = 'tag-details-disambiguation'; disambiguationItem.className = 'tag-details-disambiguation';
disambiguationItem.lang = 'ja';
this._appendFurigana(disambiguationItem, segments, (container, text) => { this._appendFurigana(disambiguationItem, segments, (container, text) => {
container.appendChild(document.createTextNode(text)); container.appendChild(document.createTextNode(text));
}); });
@ -196,13 +197,13 @@ class DisplayGenerator {
const content = this._templates.instantiate('footer-notification-anki-errors-content'); const content = this._templates.instantiate('footer-notification-anki-errors-content');
const header = content.querySelector('.anki-note-error-header'); const header = content.querySelector('.anki-note-error-header');
header.textContent = (errors.length === 1 ? 'An error occurred:' : `${errors.length} errors occurred:`); this._setTextContent(header, (errors.length === 1 ? 'An error occurred:' : `${errors.length} errors occurred:`), 'en');
const list = content.querySelector('.anki-note-error-list'); const list = content.querySelector('.anki-note-error-list');
for (const error of errors) { for (const error of errors) {
const div = document.createElement('li'); const div = document.createElement('li');
div.className = 'anki-note-error-message'; div.className = 'anki-note-error-message';
div.textContent = isObject(error) && typeof error.message === 'string' ? error.message : `${error}`; this._setTextContent(div, isObject(error) && typeof error.message === 'string' ? error.message : `${error}`);
list.appendChild(div); list.appendChild(div);
} }
@ -234,6 +235,8 @@ class DisplayGenerator {
node.dataset.readingIsSame = `${!reading || reading === expression}`; node.dataset.readingIsSame = `${!reading || reading === expression}`;
node.dataset.frequency = termFrequency; node.dataset.frequency = termFrequency;
expressionContainer.lang = 'ja';
this._appendFurigana(expressionContainer, furiganaSegments, this._appendKanjiLinks.bind(this)); this._appendFurigana(expressionContainer, furiganaSegments, this._appendKanjiLinks.bind(this));
this._appendMultiple(tagContainer, this._createTag.bind(this), termTags); this._appendMultiple(tagContainer, this._createTag.bind(this), termTags);
this._appendMultiple(tagContainer, this._createSearchTag.bind(this), searchQueries); this._appendMultiple(tagContainer, this._createSearchTag.bind(this), searchQueries);
@ -244,7 +247,7 @@ class DisplayGenerator {
_createTermReason(reason) { _createTermReason(reason) {
const fragment = this._templates.instantiateFragment('term-reason'); const fragment = this._templates.instantiateFragment('term-reason');
const node = fragment.querySelector('.term-reason'); const node = fragment.querySelector('.term-reason');
node.textContent = reason; this._setTextContent(node, reason);
node.dataset.reason = reason; node.dataset.reason = reason;
return fragment; return fragment;
} }
@ -282,7 +285,7 @@ class DisplayGenerator {
_createTermGlossaryItemText(glossary) { _createTermGlossaryItemText(glossary) {
const node = this._templates.instantiate('term-glossary-item'); const node = this._templates.instantiate('term-glossary-item');
const container = node.querySelector('.term-glossary'); const container = node.querySelector('.term-glossary');
this._appendMultilineText(container, glossary); this._setTextContent(container, glossary);
return node; return node;
} }
@ -330,7 +333,7 @@ class DisplayGenerator {
if (typeof description === 'string') { if (typeof description === 'string') {
const container = node.querySelector('.term-glossary-image-description'); const container = node.querySelector('.term-glossary-image-description');
this._appendMultilineText(container, description); this._setTextContent(container, description);
} }
return node; return node;
@ -351,27 +354,27 @@ class DisplayGenerator {
_createTermDisambiguation(disambiguation) { _createTermDisambiguation(disambiguation) {
const node = this._templates.instantiate('term-definition-disambiguation'); const node = this._templates.instantiate('term-definition-disambiguation');
node.dataset.term = disambiguation; node.dataset.term = disambiguation;
node.textContent = disambiguation; this._setTextContent(node, disambiguation, 'ja');
return node; return node;
} }
_createKanjiLink(character) { _createKanjiLink(character) {
const node = document.createElement('a'); const node = document.createElement('a');
node.className = 'kanji-link'; node.className = 'kanji-link';
node.textContent = character; this._setTextContent(node, character, 'ja');
return node; return node;
} }
_createKanjiGlossaryItem(glossary) { _createKanjiGlossaryItem(glossary) {
const node = this._templates.instantiate('kanji-glossary-item'); const node = this._templates.instantiate('kanji-glossary-item');
const container = node.querySelector('.kanji-glossary'); const container = node.querySelector('.kanji-glossary');
this._appendMultilineText(container, glossary); this._setTextContent(container, glossary);
return node; return node;
} }
_createKanjiReading(reading) { _createKanjiReading(reading) {
const node = this._templates.instantiate('kanji-reading'); const node = this._templates.instantiate('kanji-reading');
node.textContent = reading; this._setTextContent(node, reading, 'ja');
return node; return node;
} }
@ -392,8 +395,8 @@ class DisplayGenerator {
const node = this._templates.instantiate('kanji-info-table-item'); const node = this._templates.instantiate('kanji-info-table-item');
const nameNode = node.querySelector('.kanji-info-table-item-header'); const nameNode = node.querySelector('.kanji-info-table-item-header');
const valueNode = node.querySelector('.kanji-info-table-item-value'); const valueNode = node.querySelector('.kanji-info-table-item-value');
nameNode.textContent = details.notes || details.name; this._setTextContent(nameNode, details.notes || details.name);
valueNode.textContent = details.value; this._setTextContent(valueNode, details.value);
return node; return node;
} }
@ -407,7 +410,7 @@ class DisplayGenerator {
const inner = node.querySelector('.tag-inner'); const inner = node.querySelector('.tag-inner');
node.title = details.notes; node.title = details.notes;
inner.textContent = details.name; this._setTextContent(inner, details.name);
node.dataset.details = details.notes || details.name; node.dataset.details = details.notes || details.name;
node.dataset.category = details.category; node.dataset.category = details.category;
if (details.redundant) { node.dataset.redundant = 'true'; } if (details.redundant) { node.dataset.redundant = 'true'; }
@ -473,7 +476,7 @@ class DisplayGenerator {
node.dataset.tagCount = `${tags.length}`; node.dataset.tagCount = `${tags.length}`;
let n = node.querySelector('.term-pitch-accent-position'); let n = node.querySelector('.term-pitch-accent-position');
n.textContent = `${position}`; this._setTextContent(n, `${position}`, '');
n = node.querySelector('.term-pitch-accent-tag-list'); n = node.querySelector('.term-pitch-accent-tag-list');
this._appendMultiple(n, this._createTag.bind(this), tags); this._appendMultiple(n, this._createTag.bind(this), tags);
@ -493,7 +496,7 @@ class DisplayGenerator {
n1.dataset.position = `${i}`; n1.dataset.position = `${i}`;
n1.dataset.pitch = highPitch ? 'high' : 'low'; n1.dataset.pitch = highPitch ? 'high' : 'low';
n1.dataset.pitchNext = highPitchNext ? 'high' : 'low'; n1.dataset.pitchNext = highPitchNext ? 'high' : 'low';
n2.textContent = mora; this._setTextContent(n2, mora, 'ja');
n.appendChild(n1); n.appendChild(n1);
} }
@ -510,14 +513,14 @@ class DisplayGenerator {
for (const exclusiveExpression of exclusiveExpressions) { for (const exclusiveExpression of exclusiveExpressions) {
const node = this._templates.instantiate(templateName); const node = this._templates.instantiate(templateName);
node.dataset.type = 'expression'; node.dataset.type = 'expression';
node.textContent = exclusiveExpression; this._setTextContent(node, exclusiveExpression, 'ja');
container.appendChild(node); container.appendChild(node);
} }
for (const exclusiveReading of exclusiveReadings) { for (const exclusiveReading of exclusiveReadings) {
const node = this._templates.instantiate(templateName); const node = this._templates.instantiate(templateName);
node.dataset.type = 'reading'; node.dataset.type = 'reading';
node.textContent = exclusiveReading; this._setTextContent(node, exclusiveReading, 'ja');
container.appendChild(node); container.appendChild(node);
} }
@ -590,9 +593,9 @@ class DisplayGenerator {
const frequency = frequencies.join(', '); const frequency = frequencies.join(', ');
node.querySelector('.frequency-disambiguation-expression').textContent = expression; this._setTextContent(node.querySelector('.frequency-disambiguation-expression'), expression, 'ja');
node.querySelector('.frequency-disambiguation-reading').textContent = (reading !== null ? reading : ''); this._setTextContent(node.querySelector('.frequency-disambiguation-reading'), (reading !== null ? reading : ''), 'ja');
node.querySelector('.frequency-value').textContent = frequency; this._setTextContent(node.querySelector('.frequency-value'), frequency, 'ja');
node.dataset.expression = expression; node.dataset.expression = expression;
node.dataset.reading = reading; node.dataset.reading = reading;
@ -610,7 +613,7 @@ class DisplayGenerator {
const frequency = frequencies.join(', '); const frequency = frequencies.join(', ');
node.querySelector('.frequency-value').textContent = frequency; this._setTextContent(node.querySelector('.frequency-value'), frequency, 'ja');
node.dataset.character = character; node.dataset.character = character;
node.dataset.dictionary = dictionary; node.dataset.dictionary = dictionary;
@ -620,6 +623,7 @@ class DisplayGenerator {
} }
_appendKanjiLinks(container, text) { _appendKanjiLinks(container, text) {
container.lang = 'ja';
const jp = this._japaneseUtil; const jp = this._japaneseUtil;
let part = ''; let part = '';
for (const c of text) { for (const c of text) {
@ -675,15 +679,6 @@ class DisplayGenerator {
} }
} }
_appendMultilineText(container, text) {
const parts = text.split('\n');
container.appendChild(document.createTextNode(parts[0]));
for (let i = 1, ii = parts.length; i < ii; ++i) {
container.appendChild(document.createElement('br'));
container.appendChild(document.createTextNode(parts[i]));
}
}
_createDictionaryTag(dictionary) { _createDictionaryTag(dictionary) {
return { return {
name: dictionary, name: dictionary,
@ -695,4 +690,13 @@ class DisplayGenerator {
redundant: false redundant: false
}; };
} }
_setTextContent(node, value, language) {
node.textContent = value;
if (typeof language === 'string') {
node.lang = language;
} else if (this._japaneseUtil.isStringPartiallyJapanese(value)) {
node.lang = 'ja';
}
}
} }