Files
wehub-resource-sync 1d1286fadb
Build / Build and test (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:18:38 +08:00

100 lines
2.8 KiB
Swift

import Foundation
import NaturalLanguage
protocol LanguageDetecting: Sendable {
func detect(_ text: String) -> TranslatorLanguage?
}
struct LanguageDetector: LanguageDetecting {
func detect(_ text: String) -> TranslatorLanguage? {
let trimmedText = text.trimmingCharacters(in: .whitespacesAndNewlines)
guard !trimmedText.isEmpty else {
return nil
}
let recognizer = NLLanguageRecognizer()
recognizer.processString(trimmedText)
if let language = recognizer.dominantLanguage,
let translatorLanguage = Self.map(language) {
return translatorLanguage
}
return Self.detectByScript(trimmedText)
}
private static func map(_ language: NLLanguage) -> TranslatorLanguage? {
switch language {
case .simplifiedChinese:
return .simplifiedChinese
case .traditionalChinese:
return .traditionalChinese
case .english:
return .english
case .japanese:
return .japanese
case .korean:
return .korean
case .french:
return .french
case .german:
return .german
case .spanish:
return .spanish
case .portuguese:
return .portuguese
case .italian:
return .italian
case .russian:
return .russian
default:
return nil
}
}
private static func detectByScript(_ text: String) -> TranslatorLanguage? {
var hasLatinLetter = false
for scalar in text.unicodeScalars {
if Self.isJapaneseScript(scalar) {
return .japanese
}
if Self.isKoreanScript(scalar) {
return .korean
}
if Self.isCJKScript(scalar) {
return .simplifiedChinese
}
if Self.isLatinLetter(scalar) {
hasLatinLetter = true
}
}
return hasLatinLetter ? .english : nil
}
private static func isJapaneseScript(_ scalar: UnicodeScalar) -> Bool {
(0x3040...0x309F).contains(Int(scalar.value)) ||
(0x30A0...0x30FF).contains(Int(scalar.value))
}
private static func isKoreanScript(_ scalar: UnicodeScalar) -> Bool {
(0xAC00...0xD7AF).contains(Int(scalar.value)) ||
(0x1100...0x11FF).contains(Int(scalar.value)) ||
(0x3130...0x318F).contains(Int(scalar.value))
}
private static func isCJKScript(_ scalar: UnicodeScalar) -> Bool {
(0x4E00...0x9FFF).contains(Int(scalar.value))
}
private static func isLatinLetter(_ scalar: UnicodeScalar) -> Bool {
(0x0041...0x005A).contains(Int(scalar.value)) ||
(0x0061...0x007A).contains(Int(scalar.value))
}
}