Swift: How to I get the list of downloaded system fonts which support the localised language?

203 views Asked by At

I will like to provide the list of fonts that support the localised language. I could not find anything in UIFont and Font; but found something in CTFont and implemented the code below.

HOWEVER, I keep getting warnings like "CoreText note: Client requested name ".SFUI-BoldG4", it will get TimesNewRomanPSMT rather than the intended font. All system UI font access should be through proper APIs such as CTFontCreateUIFontForLanguage() or +[UIFont systemFontOfSize:]."

Is there a better alternative in Swift to retrieve the system font list of a specific language?

import CoreText
import Foundation
import SwiftUI

extension CTFont {
    
    func supportedLanguages(_ fontName: String, _ size: CGFloat = DEFAULT_USER_FONT_SIZE) -> [String] {
        
        let font = CTFontCreateWithName(fontName as CFString, size, nil)
        let languageIds = CTFontCopySupportedLanguages(font) as! [String]
        
        return languageIds
    }

}

extension UIFont {
    
    
    static func supportedFontNames(language: String = "", size: CGFloat = DEFAULT_USER_FONT_SIZE) -> [String] {
        
        var fontNames: [String] = []
        
        for familyName in UIFont.familyNames {
            for fontName in UIFont.fontNames(forFamilyName: familyName) {
                if !fontNames.contains(fontName), CTFont(fontName as CFString, size: size).supportedLanguages(fontName, size).contains(language) {
                    fontNames.append(fontName)
                }
            }
        }
        
        return fontNames
    }
    
}

2

There are 2 answers

1
Rob Napier On

This can be more easily implemented using a CTFontCollection:

extension UIFont {
    static func supportedFontNames(language: String) -> [String] {
        // Create the query descriptor
        let query = [kCTFontLanguagesAttribute: [language] as CFArray] as CFDictionary
        let descriptor = CTFontDescriptorCreateWithAttributes(query)

        // Perform the query and create a collection
        let collection = CTFontCollectionCreateWithFontDescriptors([descriptor] as CFArray,
                                                                   nil)

        // Extract the name attributes
        return CTFontCollectionCopyFontAttribute(collection,
                                                 kCTFontNameAttribute,
                                                 []) as! [String]
   }
}
0
user14341201 On

Thanks to answer Rob Napier's answer, I've now updated his solution to also support iOS14 below:

    static func supportedFontNames(language: String) -> [String] {
        // Create the query descriptor
        let query = [kCTFontLanguagesAttribute: [language] as CFArray] as CFDictionary
        let descriptor = CTFontDescriptorCreateWithAttributes(query)

        // Perform the query and create a collection
        let collection = CTFontCollectionCreateWithFontDescriptors([descriptor] as CFArray,
                                                                   nil)
        
        if #available(iOS 15.0, *) {
            // Extract the name attributes
            return CTFontCollectionCopyFontAttribute(collection,
                                                     kCTFontNameAttribute,
                                                     []) as? [String] ?? []
        } else {
            
            var fontNames: [String] = []
            if let fontDescriptorArray = CTFontCollectionCreateMatchingFontDescriptors(collection) as? [CTFontDescriptor] {
                
                fontNames = fontDescriptorArray.compactMap { descriptor -> String? in
                    return CTFontDescriptorCopyAttribute(descriptor, kCTFontNameAttribute) as? String
                }
                
            }
            return fontNames
        }
   }