Good day everyone. I have a problem with displaying hyphenated justified text using TextKit with a textview. I've tried to make hyphenation through paragraph style and NSLayoutManager, but without expected results. Paragraph style example:
let paragraph = NSMutableParagraphStyle()
paragraph.alignment = .justified
paragraph.lineBreakMode = .byWordWrapping
paragraph.hyphenationFactor = 0.85 //here goes the black magic :)
Problem is that justified text without hyphenation looks awful, because it stretches the space between letters (not words). Everything looks fine if hyphenation is working. But here's another problem - hyphenation is applied to the text with a rules of current phone preferred language. It means, if the phones preferred language is English and text is cyrillic (ex. Russian or Ukrainian lang), hyphenation is not applied at all and a problem with stretched text occurs. Here's how this problem looks like:
Changing phones preferred language to the texts language causes native hyphenation working nice, and justified text is also rendered correctly:
So my solution was to determine text language and change apps preferred language to this one using NaturalLanguage framework. To determine texts language I am using this snippet:
import NaturalLanguage
extension String {
func dominantLanguage() -> Locale? {
let languageRecognizer = NLLanguageRecognizer()
languageRecognizer.processString(self)
if let code = languageRecognizer.dominantLanguage?.rawValue {
let language = Locale.init(identifier: code)
return language
} else if let code = languageRecognizer.languageHypotheses(withMaximum: 3).sorted(by: { (arg0, arg1) -> Bool in
return arg0.value > arg1.value
}).first?.key.rawValue {
let language = Locale.init(identifier: code)
return language
} else {
return nil
}
}
}
let locale = "qwerty".dominantLanguage()
But there's different problem with this solution: 1) It's not working 100% correctly. As an example, if the text starts with a table (as on the screenshots above), languageRecognizer.dominantLanguage returns nil, and languageHyphoteses may return wrong locale. I may not rely on this at all. 2) It's kinda a hack to change the preferred language of an app everytime.
I need to find great solutions to solve this issues, and I want to be sure that nothing brakes in different edge-cases. Also, I found that CoreText is not suitable for my other purposes, and I found that TextKit will work perfect for me, but I have this problem and I don't know how to solve it correctly.
Also, I found that hyphenation (with any text language) and justified text may be easily done by using WebView and CSS -webkit-hyphens but I really don't want to dive into working with WebView as same as CoreText (doesn't fit for my other app purposes). Is there any idea how to achieve that results using TextKit? I am looking for solid solutions. Thank you.
dominantLanguage()
logic and pre-process the string before passing it to thelanguageRecognizer.processString(PRE_PROCESSED_STRING)
. There are some APIs that can help you to split the string into paragraphs, for example, and you can run thelanguageRecognizer.dominantLanguage?
function on the paragraphs until you find a proper value. I am pretty sure that this solution will affect the performance, but it will do the job finding a proper dominant language. – Photogene