Reputation: 193
I need to use html tags for Japanese characters in Swift.
I've been using the following string extension below:
extension String{
func convertHtml() -> NSAttributedString{
guard let data = data(using: .utf8) else { return NSAttributedString() }
do{
return try NSAttributedString(data: data, options: [.documentType: NSAttributedString.DocumentType.html, .characterEncoding: String.Encoding.utf8.rawValue], documentAttributes: nil)
}catch{
return NSAttributedString()
}
}
And then testing it out with a textView as follows:
textView.attributedText = "<!DOCTYPE html><html><body>これは<ruby>日<rt>に</rt>本<rt>ほん</rt>語<rt>ご</rt></ruby>です。</body></html>".convertHtml()
This is how it should actually look:
これは<ruby>日<rt>に</rt>本<rt>ほん</rt>語<rt>ご</rt></ruby>です。
But it ends up looking like this. It doesn't line up properly, and there is a strange line break after every single use of the ruby tag.
Is there something I'm doing wrong here, and a way to fix this?
Thank you!
Upvotes: 2
Views: 1511
Reputation: 71
Here's an easy way which I use.
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style>
fg:before {
content: attr(t);
display: block;
font-size: 50%;
text-align: start;
line-height: 1.5;
}
fg {
display: inline-block;
text-indent: 0px;
line-height: normal;
-webkit-text-emphasis: none;
text-align: center;
line-height: 1;
}
</style>
</head>
<body>
<fg t="わたし">私</fg>はケンです。<br><br>
</body>
</html>
See if that might work. It works fine for me in all the browsers I tested.
Upvotes: 0
Reputation: 6112
The whole line of Japanese text should be enclosed in <ruby>
tags. This is because the <ruby>
element sets up its own inline context, yet its sub-elements such as <rb>
, <rt>
, <rp>
, and <rtc>
also set up their own contexts like 'block' that only really make sense when the whole line is enclosed in a <ruby>
element.
<!DOCTYPE html>
<html>
<head>
<!-- In case you'd like to try opening this page in desktop Safari! -->
<meta charset="UTF-8">
</head>
<body>
<ruby>
<rb>これ</rb><rt></rt>
<rb>は</rb><rt></rt>
<rb>日</rb><rt>に</rt>
<rb>本</rb><rt>ほん</rt>
<rb>語</rb><rt>ご</rt>
<rb>です</rb><rt></rt>
<rb>。</rb><rt></rt>
</ruby>
<span>But this <em>isn't</em> Japanese.</span>
</body>
</html>
I find it's best to be explicit about every <ruby>
sub-element, and to also pair every <rb>
(ruby base text) with a corresponding <rt>
(ruby transcription). Sure, it looks more redundant and less clean, but it's a lot more semantic and you can be sure it's going to look the same in all browsers.
Below, I provide a screenshot of it working. Here's how I invoked it:
let webView: WKWebView = WKWebView(frame: self.view.frame, configuration: WKWebViewConfiguration())
webView.loadHTMLString(
"<!DOCTYPE html><html><head><!-- In case you'd like to try opening this page in desktop Safari! --><meta charset=\"UTF-8\"></head><body><ruby><rb>これ</rb><rt></rt><rb>は</rb><rt></rt><rb>日</rb><rt>に</rt><rb>本</rb><rt>ほん</rt><rb>語</rb><rt>ご</rt><rb>です</rb><rt></rt><rb>。</rb><rt></rt></ruby><span>But this <em>isn't</em> Japanese.</span></body></html>",
baseURL: nil
)
If you copy-paste that as-is, do you have any more luck?
Seems like UITextView
interprets all ruby nodes as having a block context. I would therefore argue that either UITextView
/NSAttributedString
has not fully implemented the HTML5 specification, or it has bugs, or there is some further configuration to be done. Either way, the easiest way to display this ruby text correctly would be to use a true WKWebView
(although I understand this has its own tradeoffs like lack of text-to-speech support, and visibly increased time taken to render).
Upvotes: 2