iOS Hyphenation with TextKit and justified text
Asked Answered
M

1

6

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:

Stretched text without hyphenation

Changing phones preferred language to the texts language causes native hyphenation working nice, and justified text is also rendered correctly:

Nicely rendered text

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.

Michealmicheil answered 1/6, 2020 at 22:18 Comment(3)
I do not think that there is a generic solution to the problem. My best guess is to extend dominantLanguage() logic and pre-process the string before passing it to the languageRecognizer.processString(PRE_PROCESSED_STRING). There are some APIs that can help you to split the string into paragraphs, for example, and you can run the languageRecognizer.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
Hi there, I think the iOS automatically handle this. Just use UITextView instead of UILabel. Refer : #19709965 Handle by hand is very hard. There's a lot of languages you don't know which value should be right.Chaperon
@Chaperon I am not using UILabel. I am using UITextView.Michealmicheil
A
0

Use of UITextView instead UILabel is the way how to make this work right.

The hyphenationFactor (either as a NSParagraphStyle attribute or as a NSLayoutManager property) should work as expected. - https://mcmap.net/q/961957/-hyphenation-in-native-ios-app

Acrefoot answered 8/6, 2020 at 8:47 Comment(1)
I'm not using UILabel. I am using UITextViewMichealmicheil

© 2022 - 2024 — McMap. All rights reserved.