Add language catalog selector
This commit is contained in:
@@ -0,0 +1,172 @@
|
||||
import Foundation
|
||||
|
||||
public struct LocalLanguageCatalog: Sendable {
|
||||
public let items: [LanguageCatalogItem]
|
||||
|
||||
public init(items: [LanguageCatalogItem] = LocalLanguageCatalog.worldwideItems) {
|
||||
self.items = items
|
||||
}
|
||||
|
||||
public var familyCategories: [String] {
|
||||
Array(Set(items.map(\.familyCategory)))
|
||||
.sorted { $0.localizedCaseInsensitiveCompare($1) == .orderedAscending }
|
||||
}
|
||||
|
||||
public func languages(
|
||||
matching query: String,
|
||||
familyCategory: String? = nil
|
||||
) -> [LanguageCatalogItem] {
|
||||
let searchTokens = Self.searchTokens(for: query)
|
||||
let selectedFamilyCategory = familyCategory?.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
|
||||
return items
|
||||
.filter { item in
|
||||
let matchesSearch = searchTokens.isEmpty || searchTokens.allSatisfy { token in
|
||||
Self.searchableTerms(for: item).contains { $0.contains(token) }
|
||||
}
|
||||
let matchesFamily = selectedFamilyCategory?.isEmpty != false || item.familyCategory == selectedFamilyCategory
|
||||
return matchesSearch && matchesFamily
|
||||
}
|
||||
.sorted { $0.name.localizedCaseInsensitiveCompare($1.name) == .orderedAscending }
|
||||
}
|
||||
|
||||
public static let worldwideItems: [LanguageCatalogItem] =
|
||||
middleEastAndNorthAfrica + europe + southAsia + eastAsia + southeastAsia + africa + americas + oceaniaAndPacific
|
||||
|
||||
private static let middleEastAndNorthAfrica: [LanguageCatalogItem] = [
|
||||
item("arabic", "Arabic", "Middle East & North Africa", aliases: ["العربية"], terms: ["عربي"]),
|
||||
item("hebrew", "Hebrew", "Middle East & North Africa", aliases: ["עברית"]),
|
||||
item("persian", "Persian", "Middle East & North Africa", aliases: ["Farsi", "فارسی"]),
|
||||
item("turkish", "Turkish", "Middle East & North Africa", aliases: ["Türkçe"]),
|
||||
item("kurdish", "Kurdish", "Middle East & North Africa", aliases: ["Kurdî"]),
|
||||
item("armenian", "Armenian", "Middle East & North Africa"),
|
||||
item("azerbaijani", "Azerbaijani", "Middle East & North Africa", aliases: ["Azeri"]),
|
||||
item("tamazight", "Tamazight", "Middle East & North Africa", aliases: ["Berber"])
|
||||
]
|
||||
|
||||
private static let europe: [LanguageCatalogItem] = [
|
||||
item("english", "English", "Europe", aliases: ["English language"]),
|
||||
item("german", "German", "Europe", aliases: ["Deutsch"]),
|
||||
item("french", "French", "Europe", aliases: ["Français"]),
|
||||
item("spanish", "Spanish", "Europe", aliases: ["Español"]),
|
||||
item("portuguese", "Portuguese", "Europe", aliases: ["Português"]),
|
||||
item("italian", "Italian", "Europe", aliases: ["Italiano"]),
|
||||
item("russian", "Russian", "Europe", aliases: ["Русский"]),
|
||||
item("ukrainian", "Ukrainian", "Europe", aliases: ["Українська"]),
|
||||
item("polish", "Polish", "Europe", aliases: ["Polski"]),
|
||||
item("dutch", "Dutch", "Europe", aliases: ["Nederlands"]),
|
||||
item("swedish", "Swedish", "Europe", aliases: ["Svenska"]),
|
||||
item("norwegian", "Norwegian", "Europe", aliases: ["Norsk"]),
|
||||
item("danish", "Danish", "Europe", aliases: ["Dansk"]),
|
||||
item("finnish", "Finnish", "Europe", aliases: ["Suomi"]),
|
||||
item("greek", "Greek", "Europe", aliases: ["Ελληνικά"]),
|
||||
item("romanian", "Romanian", "Europe", aliases: ["Română"]),
|
||||
item("czech", "Czech", "Europe", aliases: ["Čeština"]),
|
||||
item("hungarian", "Hungarian", "Europe", aliases: ["Magyar"]),
|
||||
item("serbian", "Serbian", "Europe"),
|
||||
item("croatian", "Croatian", "Europe"),
|
||||
item("bulgarian", "Bulgarian", "Europe")
|
||||
]
|
||||
|
||||
private static let southAsia: [LanguageCatalogItem] = [
|
||||
item("hindi", "Hindi", "South Asia", aliases: ["हिन्दी"]),
|
||||
item("urdu", "Urdu", "South Asia", aliases: ["اردو"]),
|
||||
item("punjabi", "Punjabi", "South Asia", aliases: ["ਪੰਜਾਬੀ"]),
|
||||
item("bengali", "Bengali", "South Asia", aliases: ["বাংলা"]),
|
||||
item("tamil", "Tamil", "South Asia", aliases: ["தமிழ்"]),
|
||||
item("telugu", "Telugu", "South Asia", aliases: ["తెలుగు"]),
|
||||
item("marathi", "Marathi", "South Asia", aliases: ["मराठी"]),
|
||||
item("gujarati", "Gujarati", "South Asia", aliases: ["ગુજરાતી"]),
|
||||
item("malayalam", "Malayalam", "South Asia", aliases: ["മലയാളം"]),
|
||||
item("kannada", "Kannada", "South Asia", aliases: ["ಕನ್ನಡ"]),
|
||||
item("sinhala", "Sinhala", "South Asia"),
|
||||
item("nepali", "Nepali", "South Asia", aliases: ["नेपाली"]),
|
||||
item("pashto", "Pashto", "South Asia", aliases: ["پښتو"])
|
||||
]
|
||||
|
||||
private static let eastAsia: [LanguageCatalogItem] = [
|
||||
item("mandarin-chinese", "Mandarin Chinese", "East Asia", aliases: ["Mandarin", "中文", "普通话"]),
|
||||
item("cantonese", "Cantonese", "East Asia", aliases: ["廣東話"]),
|
||||
item("japanese", "Japanese", "East Asia", aliases: ["日本語"]),
|
||||
item("korean", "Korean", "East Asia", aliases: ["한국어"]),
|
||||
item("mongolian", "Mongolian", "East Asia")
|
||||
]
|
||||
|
||||
private static let southeastAsia: [LanguageCatalogItem] = [
|
||||
item("indonesian", "Indonesian", "Southeast Asia", aliases: ["Bahasa Indonesia"]),
|
||||
item("malay", "Malay", "Southeast Asia", aliases: ["Bahasa Melayu"]),
|
||||
item("vietnamese", "Vietnamese", "Southeast Asia", aliases: ["Tiếng Việt"]),
|
||||
item("thai", "Thai", "Southeast Asia", aliases: ["ไทย"]),
|
||||
item("tagalog", "Tagalog", "Southeast Asia", aliases: ["Filipino"]),
|
||||
item("burmese", "Burmese", "Southeast Asia", aliases: ["Myanmar"]),
|
||||
item("khmer", "Khmer", "Southeast Asia"),
|
||||
item("lao", "Lao", "Southeast Asia"),
|
||||
item("javanese", "Javanese", "Southeast Asia")
|
||||
]
|
||||
|
||||
private static let africa: [LanguageCatalogItem] = [
|
||||
item("swahili", "Swahili", "Africa", aliases: ["Kiswahili"]),
|
||||
item("amharic", "Amharic", "Africa", aliases: ["አማርኛ"]),
|
||||
item("hausa", "Hausa", "Africa"),
|
||||
item("yoruba", "Yoruba", "Africa"),
|
||||
item("igbo", "Igbo", "Africa"),
|
||||
item("zulu", "Zulu", "Africa"),
|
||||
item("xhosa", "Xhosa", "Africa"),
|
||||
item("somali", "Somali", "Africa"),
|
||||
item("oromo", "Oromo", "Africa"),
|
||||
item("afrikaans", "Afrikaans", "Africa"),
|
||||
item("wolof", "Wolof", "Africa"),
|
||||
item("shona", "Shona", "Africa")
|
||||
]
|
||||
|
||||
private static let americas: [LanguageCatalogItem] = [
|
||||
item("haitian-creole", "Haitian Creole", "Americas", aliases: ["Kreyòl"]),
|
||||
item("quechua", "Quechua", "Americas"),
|
||||
item("guarani", "Guarani", "Americas"),
|
||||
item("navajo", "Navajo", "Americas"),
|
||||
item("inuktitut", "Inuktitut", "Americas")
|
||||
]
|
||||
|
||||
private static let oceaniaAndPacific: [LanguageCatalogItem] = [
|
||||
item("maori", "Maori", "Oceania & Pacific", aliases: ["Te Reo Māori"]),
|
||||
item("hawaiian", "Hawaiian", "Oceania & Pacific"),
|
||||
item("samoan", "Samoan", "Oceania & Pacific"),
|
||||
item("tongan", "Tongan", "Oceania & Pacific"),
|
||||
item("fijian", "Fijian", "Oceania & Pacific")
|
||||
]
|
||||
|
||||
private static func item(
|
||||
_ id: String,
|
||||
_ name: String,
|
||||
_ familyCategory: String,
|
||||
aliases: [String] = [],
|
||||
terms: [String] = []
|
||||
) -> LanguageCatalogItem {
|
||||
LanguageCatalogItem(
|
||||
id: id,
|
||||
name: name,
|
||||
familyCategory: familyCategory,
|
||||
aliases: aliases,
|
||||
searchTerms: terms
|
||||
)
|
||||
}
|
||||
|
||||
private static func searchableTerms(for item: LanguageCatalogItem) -> [String] {
|
||||
searchTokens(for: [item.name, item.familyCategory] + item.aliases + item.searchTerms)
|
||||
}
|
||||
|
||||
private static func searchTokens(for query: String) -> [String] {
|
||||
searchTokens(for: [query])
|
||||
}
|
||||
|
||||
private static func searchTokens(for values: [String]) -> [String] {
|
||||
values
|
||||
.joined(separator: " ")
|
||||
.folding(
|
||||
options: [.caseInsensitive, .diacriticInsensitive, .widthInsensitive],
|
||||
locale: Locale(identifier: "en_US_POSIX")
|
||||
)
|
||||
.split(whereSeparator: { $0.isWhitespace || $0 == "-" })
|
||||
.map(String.init)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user