Reputation: 181
My problem is that I have blocks of texts in different languages in my app, in some languages(hi german) words can be tooo long and I am using hyphenationFactor to have proper layout... But as said in the docs: "This property detects the user-selected language by examining the first item in preferredLanguages." and in my case there could be english in settings and german text on screen, so the grammar rules for hyphenation is wrong.
Is there a way to change language for this property or maybe some hack around of this? Thank you in advance!
Upvotes: 2
Views: 789
Reputation: 181
Update 2022:
Before iOS 15, Apple strictly followed soft hyphen, while in iOS 15 they now only consider those as hyphenation opportunities.
So basically now we should use languageIdentifier attribute, lesser opportunities for our own custom hyphenation rules (like remove ugly, one side short, hyphenation break), but works grammatically correctly.
Old answer:
In the end a real help was this extension by Frank Rausch https://gist.github.com/frankrausch/0d2c91fad5e417a84aaa43bfb9c9aec8
Made some addition to detect dominant language of string and limit the words that should hyphenate by characters count.
import Foundation
import NaturalLanguage
extension String {
func detectedLanguage(for string: String) -> String? {
let recognizer = NLLanguageRecognizer()
recognizer.processString(string)
guard let languageCode = recognizer.dominantLanguage?.rawValue else { return nil }
let detectedLanguage = Locale.current.localizedString(forIdentifier: languageCode)
return detectedLanguage
}
func autoHyphenated() -> String {
return self.hyphenated(languageCode: detectedLanguage(for: self) ?? "")
}
func hyphenated(languageCode: String) -> String {
let locale = Locale(identifier: languageCode)
return self.hyphenated(locale: locale)
}
func hyphenated(locale: Locale, wordMinimumLenght: Int = 13) -> String {
guard CFStringIsHyphenationAvailableForLocale(locale as CFLocale) else { return self }
var s = self
var words = s.components(separatedBy: " ")
for index in 0..<words.count {
if words[index].count > wordMinimumLenght && !words[index].contains("-") {
let fullRange = CFRangeMake(0, words[index].utf16.count)
var hyphenationLocations = [CFIndex]()
for (i, _) in words[index].utf16.enumerated() {
let location: CFIndex = CFStringGetHyphenationLocationBeforeIndex(words[index] as CFString, i, fullRange, 0, locale as CFLocale, nil)
if hyphenationLocations.last != location {
hyphenationLocations.append(location)
}
}
for l in hyphenationLocations.reversed() {
guard l > 0 else { continue }
let strIndex = String.Index(utf16Offset: l, in: words[index])
words[index].insert("\u{00AD}", at: strIndex)
}
}
}
s = words.joined(separator: " ")
return s
}
}
Upvotes: 2