英文:
How can I get list Languages from NaturalLanguage
问题
func LanguagesList () {
let allLanguages = Locale.isoLanguageCodes
let locale = Locale(identifier: "en_US")
for languageCode in allLanguages {
if let languageName = locale.localizedString(forIdentifier: languageCode) {
print("\(languageCode): \(languageName)")
}
}
let recognizer = NLLanguageRecognizer()
let textRecognitionLanguages = recognizer.supportedRecognitionLanguages
print(textRecognitionLanguages)
}
英文:
I want to get a list of available languages for text translations. The text is unknown.
I created a simple project:
import SwiftUI
import Foundation
import NaturalLanguage
struct ContentView: View {
func LanguagesList () {
let allLanguages = Locale.isoLanguageCodes
let locale = Locale(identifier: "en_US")
for languageCode in allLanguages {
if let languageName = locale.localizedString(forIdentifier: languageCode) {
print("\(languageCode): \(languageName)")
}
}
let recognizer = NLLanguageRecognizer()
recognizer.
let textRecognitionLanguages = recognizer.availableRecognitionLanguages(for: .text)
print(textRecognitionLanguages)
}
var body: some View {
VStack {
Image(systemName: "globe")
.imageScale(.large)
.foregroundColor(.accentColor)
Text("Hello, world!")
Button("Languages list") {
LanguagesList()
}
}
.padding()
}
}
I tried to ask ChatGPT. It claims that this is how it should work (SDK 14, NaturalLanguage version 2.0). I updated the OS.
I have Xcode 14.3 includes Swift 5.8 and SDKs for iOS 16.4, iPadOS 16.4, tvOS 16.4, watchOS 9.4, and macOS Ventura 13.3.
The compiler throws 2 errors:
1. Cannot infer contextual base in reference to member 'text'
2. Value of type 'NLLanguageRecognizer' has no member 'availableRecognitionLanguages'
Is there a way to get a list of available languages for text translations. The text is not known in advance?
答案1
得分: 1
(从我的评论): 正如@HangarRash
所说,availableRecognitionLanguages
不存在。要查看完整的NLLanguage
列表,请参阅枚举的文档:NLLanguage
。对于许多枚举,尤其是您创建的枚举,有一个用于循环遍历所有情况的有用协议,这正是您尝试在上面执行的操作。这个协议称为CaseIterable
,它不是NLLanguage
符合的协议,但正如这篇Hacking with Swift文章所说,我们可以自己添加这个协议。以下是添加此符合性的示例:
extension NLLanguage: CaseIterable {
public static var allCases: [NLLanguage] {
[.amharic, .arabic, .armenian, .bengali, .bulgarian, .burmese, .catalan, .cherokee, .croatian, .czech, .danish, .dutch, .english, .finnish, .french, .georgian, .german, .greek, .gujarati, .hebrew, .hindi, .hungarian, .icelandic, .indonesian, .italian, .japanese, .kannada, .kazakh, .khmer, .korean, .lao, .malay, .malayalam, .marathi, .mongolian, .norwegian, .oriya, .persian, .polish, .portuguese, .punjabi, .romanian, .russian, .simplifiedChinese, .sinhalese, .slovak, .spanish, .swedish, .tamil, .telugu, .thai, .tibetan, .traditionalChinese, .turkish, .ukrainian, .urdu, .vietnamese, .undetermined]
}
}
然后我们可以像这样循环遍历每种情况:
print(NLLanguage.allCases)
//打印每一种情况
我们必须自己声明这个符合性,这也意味着如果苹果发布了新的NLLanguage
,我们必须更新它。以下是两个示例,一个是使用您上面提供的代码,另一个是通过ForEach
显示所有情况的列表。首先,对于您上面提供的代码:
import SwiftUI
import Foundation
import NaturalLanguage
struct ContentView: View {
func LanguagesList() {
for lang in NLLanguage.allCases {
let locale = Locale(identifier: lang.rawValue)
if let languageName = locale.localizedString(forIdentifier: lang.rawValue) {
print("\(lang.rawValue): \(languageName)")
}
}
print(NLLanguage.allCases.map({ lang in
lang.rawValue
}))
//或者,如果您想打印实际的语言名称,请使用以下内容:
// print(NLLanguage.allCases.map({ lang in
// Locale.current.localizedString(forIdentifier: lang.rawValue) ?? lang.rawValue
// }))
}
var body: some View {
VStack {
Image(systemName: "globe")
.imageScale(.large)
.foregroundColor(.accentColor)
Text("Hello, world!")
Button("Languages list") {
LanguagesList()
}
}
.padding()
}
}
接下来是ForEach
:
struct LanguagesListView: View {
var body: some View {
VStack{
ForEach(NLLanguage.allCases, id: \.self) { lang in
Text(Locale.current.localizedString(forIdentifier: lang.rawValue) ?? lang.rawValue)
}
}
}
}
请注意,在生产中使用id: \.self
并不是一个好主意,因为如果两个值相同,这可能导致未定义的行为。上面,我使用Locale
,因为它显示了语言的完整字符串,例如"英语"
,而不是语言标识符"en"
。如果您想显示原始值,只需传递lang.rawValue
。
英文:
(From my comment): As @HangarRash
said, availableRecognitionLanguages
does not exist. For a full list of NLLanguage
s, see the docs for the enum: NLLanguage
. For many enums, especially ones that you create, there is a useful protocol for looping over all of the cases, which is exactly what you are trying to do above. This protocol, called CaseIterable
, is not one that NLLanguage
conforms to, but as this Hacking with Swift article says, we can make it conform ourselves. Here is an example of adding this conformance:
extension NLLanguage: CaseIterable {
public static var allCases: [NLLanguage] {
[.amharic, .arabic, .armenian, .bengali, .bulgarian, .burmese, .catalan, .cherokee, .croatian, .czech, .danish, .dutch, .english, .finnish, .french, .georgian, .german, .greek, .gujarati, .hebrew, .hindi, .hungarian, .icelandic, .indonesian, .italian, .japanese, .kannada, .kazakh, .khmer, .korean, .lao, .malay, .malayalam, .marathi, .mongolian, .norwegian, .oriya, .persian, .polish, .portuguese, .punjabi, .romanian, .russian, .simplifiedChinese, .sinhalese, .slovak, .spanish, .swedish, .tamil, .telugu, .thai, .tibetan, .traditionalChinese, .turkish, .ukrainian, .urdu, .vietnamese, .undetermined]
}
}
And then we can loop over each case like this:
print(NLLanguage.allCases)
//Prints each and every case
We have to declare this conformance ourselves, which also means we have to update it if Apple releases a new NLLanguage
. Here are two examples, one with the code that you provided above, and one displaying a list (via ForEach
) of all of the cases. First, for the code you provided above:
import SwiftUI
import Foundation
import NaturalLanguage
struct ContentView: View {
func LanguagesList() {
for lang in NLLanguage.allCases {
let locale = Locale(identifier: lang.rawValue)
if let languageName = locale.localizedString(forIdentifier: lang.rawValue) {
print("\(lang.rawValue): \(languageName)")
}
}
print(NLLanguage.allCases.map({ lang in
lang.rawValue
}))
//Or, if you want to print the actual language names, use the following:
// print(NLLanguage.allCases.map({ lang in
// Locale.current.localizedString(forIdentifier: lang.rawValue) ?? lang.rawValue
// }))
}
var body: some View {
VStack {
Image(systemName: "globe")
.imageScale(.large)
.foregroundColor(.accentColor)
Text("Hello, world!")
Button("Languages list") {
LanguagesList()
}
}
.padding()
}
}
And next, a ForEach
:
struct LanguagesListView: View {
var body: some View {
VStack{
ForEach(NLLanguage.allCases, id: \.self) { lang in
Text(Locale.current.localizedString(forIdentifier: lang.rawValue) ?? lang.rawValue)
}
}
}
}
Please note that it is not a good idea to use id: \.self
in production, as if two values are the same, this can lead to undefined behavior. Above, I am using Locale
because this displays the full String
for the language - such as "English"
, rather than the language identifier "en"
. If you want to display the raw values, then just pass in lang.rawValue
.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论