The Webview folks. Not sure how much that would help though.
According to the W3C working draft, it seems to be the expected behavior that line breaks are not allowed in ruby text. So it is unlikely that Chrome or FireFox will revert to the previous behavior, and it is likely that other browser engines will also disallow line breaks in ruby text in the future.
This is the html code generated by Anki (only the <div>
containing the card content):
<div id="qa_box" class="card card2 svelte-192a69y"><div id="qa" class="svelte-192a69y"><style>.card {
font-family: arial;
font-size: 20px;
text-align: center;
color: black;
background-color: white;
}
.jp { font-size: 50pt }
.hint { font-size: 30pt }
</style><div class="jp"> <ruby><rb>言</rb><rt>い<br>i</rt></ruby><ruby><rb>います</rb><rt>imasu</rt></ruby> </div><br>
<hr id="answer">
masu<br>
ます<br>
Form<br>
<br>
<br>
sagen</div> <br></div>
I found out that Chrome changed the way they are handling Furigana aka <ruby>
elements in version 128: https://developer.chrome.com/blog/line-breakable-ruby
. This may be related to the fact that <br>
in <ruby>
elements are ignored.
Ok, so I need to find another way to associate more than one annotation with the same base text. Is it possible to have double-sided ruby in Anki as explained here? https://w3c.github.io/i18n-drafts/articles/ruby/styling.en#double_position
Of the two methods described there, the one using the <rtc>
element, which is now deprecated, seems to work only in FireFox. The nested <ruby>
method works for me on both the latest Anki desktop (only tested the Qt6 build) and AnkiDroid.
But here you hard-coded the furigana into the Front Template. How could this be done using Anki’s {{furigana:front}}
variables?
It is not possible to add ruby on both sides using {{furigana:}}
syntax. Sorry if I gave you the wrong impression. I just wanted to let you know if the HTML and CSS mentioned on that page would work with the web engine used by Anki Desktop or AnkiDroid.
In the first place, do you really need alphabetic ruby for hiragana and katakana? Learning the readings of hiragana and katakana is the very first stage of learning Japanese, so after a week or so of study, wouldn’t it just be annoying to have ruby on hiragana and katakana? If you feel that way, you could remove the alphabetical ruby using the AnkI browser’s replace function.
I have refreshed my Javascript skills and wrote this.
Front template:
<div id="fldExpression" class="jp">{{masu-form}}</div>
<br><br>
{{#Sample}}
<div id="fldSample" class="jp hint">{{Sample}}</div>
{{/Sample}}
<div id="fldReading" class="jp hint" style="display: none;">{{furigana:masu-reading}}</div>
<br><br>
<script language="javascript">
/*
* Use nested markup for double-sided ruby positioning
* https://w3c.github.io/i18n-drafts/articles/ruby/styling.en#double_position
*/
function setupCard() {
var ex = document.getElementById('fldExpression');
var rd = document.getElementById('fldReading');
var rt = document.createElement('b');
// Select the ruby elements
const rubyElements = rd.querySelectorAll('ruby');
// Create a new div to hold the transformed structure
const newDiv = document.createElement('div');
newDiv.className = 'jp';
// Add parent ruby element for nested markup
newDiv.appendChild(document.createElement('ruby'));
const parentRuby = newDiv.children[0];
// Iterate through each ruby element and transform it
rubyElements.forEach((ruby) => {
const rb = ruby.querySelector('rb');
// Select the rt elements
const rtElements = ruby.querySelectorAll('rt');
// Create a new ruby element for the rb text
const newRuby = document.createElement('ruby');
newRuby.appendChild(document.createTextNode(rb.textContent));
// Append the new ruby to the parent ruby
parentRuby.appendChild(newRuby);
// Append rt elements to the new ruby
rtElements.forEach((rt) => {
// Split rt text at <br>
//var arr = rt.innerText.split(/\r?\n|\r|\n/g);
//var arr = rt.innerText.split(/<br\s*\/?>/i);
var arr = $(rt).html().split('<br>');
alert("br0: " + arr[0]);
// Create new rt element for hiragana furigana
const newRt = document.createElement('rt');
newRt.appendChild(document.createTextNode(arr[0]));
// Append the new furigana to the new ruby
newRuby.appendChild(newRt);
// Is there is a second furigana (after <br>)?
if (arr[1]) {
// Create a new rt for the romaji furigana
const newRt = document.createElement('rt');
newRt.appendChild(document.createTextNode(arr[1]));
// Append this directly to the parent ruby
// (for nested markup)
parentRuby.appendChild(newRt);
//alert("br1: " + arr[1]);
// Append a rb element (for nested markup)
parentRuby.appendChild(document.createElement('rb'));
}
});
});
// Replace jp div content by the transformed HTML
rd.innerHTML = newDiv.innerHTML + '<br>';
//alert( newDiv.innerHTML );
var isSame = ex.innerText.valueOf() === rd.innerText.valueOf();
if(!isSame) {
window.setTimeout(function() {rd.style.display = 'block';},5000);
}
}
window.setTimeout(setupCard, 1000);
</script>
Back template:
<div id="fldReading" class=jp> {{furigana:masu-reading}} </div><br>
<hr id=answer>
masu<br>
ます<br>
Form<br>
<br>
{{#Sample}}
<div id="fldSample" class="jp hint">{{Sample}}</div>
{{/Sample}}
<br>
{{Meaning}}
<script language="javascript">
/*
* Use nested markup for double-sided ruby positioning
* https://w3c.github.io/i18n-drafts/articles/ruby/styling.en#double_position
*/
function setupCard() {
var rd = document.getElementById('fldReading');
// Select the ruby elements
const rubyElements = rd.querySelectorAll('ruby');
// Create a new div to hold the transformed structure
const newDiv = document.createElement('div');
newDiv.className = 'jp';
// Add parent ruby element for nested markup
newDiv.appendChild(document.createElement('ruby'));
const parentRuby = newDiv.children[0];
// Iterate through each ruby element and transform it
rubyElements.forEach((ruby) => {
const rb = ruby.querySelector('rb');
// Select the rt elements
const rtElements = ruby.querySelectorAll('rt');
// Create a new ruby element for the rb text
const newRuby = document.createElement('ruby');
newRuby.appendChild(document.createTextNode(rb.textContent));
// Append the new ruby to the parent ruby
parentRuby.appendChild(newRuby);
// Append rt elements to the new ruby
rtElements.forEach((rt) => {
// Split rt text at <br>
//var arr = rt.innerText.split(/\r?\n|\r|\n/g);
//var arr = rt.innerText.split(/<br\s*\/?>/i);
var arr = $(rt).html().split('<br>');
//alert("br0: " + arr[0]);
// Create new rt element for hiragana furigana
const newRt = document.createElement('rt');
newRt.appendChild(document.createTextNode(arr[0]));
// Append the new furigana to the new ruby
newRuby.appendChild(newRt);
// Is there is a second furigana (after <br>)?
if (arr[1]) {
// Create a new rt for the romaji furigana
const newRt = document.createElement('rt');
newRt.appendChild(document.createTextNode(arr[1]));
// Append this directly to the parent ruby
// (for nested markup)
parentRuby.appendChild(newRt);
//alert("br1: " + arr[1]);
// Append a rb element (for nested markup)
parentRuby.appendChild(document.createElement('rb'));
}
});
});
// Replace jp div content by the transformed HTML
rd.innerHTML = newDiv.innerHTML + '<br>';
//alert( newDiv.innerHTML );
}
window.setTimeout(setupCard, 0);
</script>
Styling:
.card {
font-family: arial;
font-size: 20px;
text-align: center;
color: black;
background-color: white;
}
.jp { font-size: 50pt }
.hint { font-size: 30pt }
.win .jp { font-family: "MS Mincho", "MS 明朝"; }
.mac .jp { font-family: "Hiragino Mincho Pro", "ヒラギノ明朝 Pro"; }
.linux .jp { font-family: "Kochi Mincho", "東風明朝"; }
.mobile .jp { font-family: "Hiragino Mincho ProN"; }
ruby { ruby-position: under; }
ruby ruby { ruby-position: over; }
This places the furigana before <br>
above and those after <br>
below the base text using nested markup as explained here: https://w3c.github.io/i18n-drafts/articles/ruby/styling.en#double_position
.
This works in AnkiDroid using WebView version 128.
Unfortunately it does not work with older Chrome versions or Firefox.
I am learning Japanese alongside my job in an adult education center (ger. “Volkshochschule (VHS)”). We have lessons of 90min per week and in the average I may have 30min a day for learning (while on public transport, or before falling asleep). It took me way longer to learn hiragana and katakana then a few weeks.
I fixed my setupCard()
function so it now also works in browsers (tested with Chrome and Firefox on Linux). The issue was that jQuery is not available in browsers. And loading it as explained here did not work either.
So now I am converting the <br>
elements by \n
before splitting them:
var textWithLineBreaks = rt.innerHTML.replace(/<br\s*\/?>/gi, '\n');
var arr = textWithLineBreaks.split('\n');
This is the complete recognition front template:
<div class="jp" id="fldExpression">{{masu-form}}</div>
<br><br>
{{#Sample}}
<div class="jp hint" id="fldSample">{{Sample}}</div>
{{/Sample}}
<br><br>
<div class="jp hint" id="fldReading" style="display: none;">{{furigana:masu-reading}}</div>
<br><br>
<script language="javascript">
var ex = document.getElementById('fldExpression');
var rd = document.getElementById('fldReading');
function setupCard() {
var rubyElements = rd.querySelectorAll('ruby');
var newDiv = document.createElement('div');
newDiv.className = 'jp';
newDiv.appendChild(document.createElement('ruby'));
var parentRuby = newDiv.children[0];
rubyElements.forEach((ruby) => {
var rb = ruby.querySelector('rb');
var rtElements = ruby.querySelectorAll('rt');
var newRuby = document.createElement('ruby');
newRuby.appendChild(document.createTextNode(rb.textContent));
parentRuby.appendChild(newRuby);
rtElements.forEach((rt) => {
var textWithLineBreaks = rt.innerHTML.replace(/<br\s*\/?>/gi, '\n');
var arr = textWithLineBreaks.split('\n');
var newRt = document.createElement('rt');
newRt.appendChild(document.createTextNode(arr[0]));
newRuby.appendChild(newRt);
if (arr[1]) {
var newRt = document.createElement('rt');
newRt.appendChild(document.createTextNode(arr[1]));
parentRuby.appendChild(newRt);
parentRuby.appendChild(document.createElement('rb'));
}
});
});
rd.innerHTML = newDiv.innerHTML + '<br>';
}
var isSame = ex.innerText.valueOf() === rd.innerText.valueOf();
if(!isSame) {
window.setTimeout(function() {rd.style.display = 'block';},5000);
}
window.setTimeout(setupCard, 1000);
</script>
I fixed my setupCard()
function to also keep the text nodes found in {{furigana:Reading}}
after conversion to double-sided ruby positioning.
<div class="jp" id="fldReading"> {{furigana:Reading}} </div><br>
<hr id=answer>
{{Meaning}}
<script language="javascript">
var rd = document.getElementById('fldReading');
/*
* Use nested markup for double-sided ruby positioning
* https://w3c.github.io/i18n-drafts/articles/ruby/styling.en#double_position
*/
function setupCard() {
var newDiv;
var parentRuby;
var rubyDiv;
/* Create a new div to hold the transformed structure */
newDiv = document.createElement('div');
/* Create a new div to hold the next ruby */
rubyDiv = document.createElement('div');
rubyDiv.className = 'jp';
//alert( rd.innerText );
//alert( rd.innerHTML );
/* Iterate through all elements to transform the structure */
for (var child = rd.firstChild; child; child = child.nextSibling) {
//alert( child.innerHTML + '<br>' + child.innerText + '<br>' + child.textContent);
if (child.nodeType != 3) {
//alert( child.textContent );
/* Add parent ruby element for nested markup */
rubyDiv.appendChild(document.createElement('ruby'));
parentRuby = rubyDiv.children[0];
if(child.tagName === "RUBY") {
/* get rb element */
var rb = child.querySelector('rb');
if(rb) {
//alert( rb.innerHTML );
/* Select the rt elements */
var rtElements = child.querySelectorAll('rt');
/* Create a new ruby element for the rb text */
var newRuby = document.createElement('ruby');
newRuby.appendChild(document.createTextNode(rb.textContent));
/* Append the new ruby to the parent ruby */
parentRuby.appendChild(newRuby);
/* Append rt elements to the new ruby */
rtElements.forEach((rt) => {
//alert( rt.innerHTML );
/* Split rt text at <br> */
var textWithLineBreaks = rt.innerHTML.replace(/<br\s*\/?>/gi, '\n');
var arr = textWithLineBreaks.split('\n');
/* Create new rt element for hiragana furigana */
var newRt = document.createElement('rt');
newRt.appendChild(document.createTextNode(arr[0]));
/* Append the new furigana to the new ruby */
newRuby.appendChild(newRt);
/* Is there is a second furigana (after <br>)? */
if (arr[1]) {
/* Create a new rt for the romaji furigana */
var newRt = document.createElement('rt');
newRt.appendChild(document.createTextNode(arr[1]));
/* Append this directly to the parent ruby */
/* (for nested markup) */
parentRuby.appendChild(newRt);
/* Append a rb element (for nested markup) */
parentRuby.appendChild(document.createElement('rb'));
}
});
/* append the ruby structure */
newDiv.appendChild(rubyDiv);
}
}
if(child.tagName === "BR") {
rubyDiv = document.createElement('div');
rubyDiv.className = 'jp';
/* Add parent ruby element for nested markup */
rubyDiv.appendChild(document.createElement('ruby'));
parentRuby = rubyDiv.children[0];
}
} else {
//alert( child.textContent );
/* append the text node */
rubyDiv.appendChild(document.createTextNode(child.textContent));
newDiv.appendChild(rubyDiv);
}
};
/* Replace jp div content by the transformed HTML */
rd.innerHTML = newDiv.innerHTML;
//alert( newDiv.innerHTML );
}
setupCard();
</script>
This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.