zh-CN to zh-Hans
This commit is contained in:
1 parent
e7105ed45d
commit
78a023bb52
13 files changed
+86
-37
No files matched your search
@@ -2644,7 +2644,7 @@ extension WeakAgentUserInteraction: AgentUserInteractionHandling {}
|
||||
extension ConversationModel {
|
||||
public static func demo(language: AppLanguage = .english) -> ConversationModel {
|
||||
func text(_ en: String, _ zh: String) -> String {
|
||||
language == .simplifiedChineseChina ? zh : en
|
||||
language == .simplifiedChinese ? zh : en
|
||||
}
|
||||
let now = Date(timeIntervalSinceReferenceDate: 809_020_800)
|
||||
let user = ChatMessage(
|
||||
|
||||
@@ -29,7 +29,7 @@ public nonisolated enum AppLocalization {
|
||||
public nonisolated enum AppLanguage: String, CaseIterable, Identifiable, Sendable {
|
||||
case system
|
||||
case english = "en"
|
||||
case simplifiedChineseChina = "zh-Hans-CN"
|
||||
case simplifiedChinese = "zh-Hans"
|
||||
|
||||
public nonisolated var id: String { rawValue }
|
||||
|
||||
@@ -37,7 +37,7 @@ public nonisolated enum AppLanguage: String, CaseIterable, Identifiable, Sendabl
|
||||
switch self {
|
||||
case .system: String(localized: "Follow System")
|
||||
case .english: "English"
|
||||
case .simplifiedChineseChina: "简体中文(中国)"
|
||||
case .simplifiedChinese: "简体中文"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,7 +45,16 @@ public nonisolated enum AppLanguage: String, CaseIterable, Identifiable, Sendabl
|
||||
guard let rawValue = defaults.string(forKey: SettingsKey.appLanguage) else {
|
||||
return .system
|
||||
}
|
||||
return AppLanguage(rawValue: rawValue) ?? .system
|
||||
if let language = AppLanguage(rawValue: rawValue) {
|
||||
return language
|
||||
}
|
||||
let language = Locale(identifier: rawValue).language
|
||||
guard language.languageCode?.identifier == "zh",
|
||||
language.script?.identifier == "Hans"
|
||||
else { return .system }
|
||||
|
||||
store(.simplifiedChinese, in: defaults)
|
||||
return .simplifiedChinese
|
||||
}
|
||||
|
||||
/// Keeps the app's explicit choice separate from Apple's per-app language
|
||||
@@ -58,7 +67,7 @@ public nonisolated enum AppLanguage: String, CaseIterable, Identifiable, Sendabl
|
||||
switch language {
|
||||
case .system:
|
||||
defaults.removeObject(forKey: "AppleLanguages")
|
||||
case .english, .simplifiedChineseChina:
|
||||
case .english, .simplifiedChinese:
|
||||
defaults.set([language.rawValue], forKey: "AppleLanguages")
|
||||
}
|
||||
}
|
||||
@@ -67,7 +76,7 @@ public nonisolated enum AppLanguage: String, CaseIterable, Identifiable, Sendabl
|
||||
switch self {
|
||||
case .system: .autoupdatingCurrent
|
||||
case .english: Locale(identifier: "en")
|
||||
case .simplifiedChineseChina: Locale(identifier: rawValue)
|
||||
case .simplifiedChinese: Locale(identifier: rawValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -30,7 +30,7 @@ case "$language" in
|
||||
;;
|
||||
zh)
|
||||
apple_language="zh-Hans"
|
||||
apple_locale="zh_CN"
|
||||
apple_locale="zh-Hans"
|
||||
;;
|
||||
*)
|
||||
print -u2 "Unknown Demo language: $language"
|
||||
|
||||
@@ -6,6 +6,19 @@ struct MobileAppSettingsView: View {
|
||||
@AppStorage(SettingsKey.appLanguage) private var language = AppLanguage.system.rawValue
|
||||
@State private var launchLanguage = AppLanguage.stored()
|
||||
|
||||
private var selectedLanguage: AppLanguage {
|
||||
AppLanguage(rawValue: language) ?? AppLanguage.stored()
|
||||
}
|
||||
|
||||
private var languageSelection: Binding<AppLanguage> {
|
||||
Binding(
|
||||
get: { selectedLanguage },
|
||||
set: { language in
|
||||
self.language = language.rawValue
|
||||
AppLanguage.store(language)
|
||||
})
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
Form {
|
||||
Section("Appearance") {
|
||||
@@ -14,10 +27,10 @@ struct MobileAppSettingsView: View {
|
||||
Text("Light").tag("light")
|
||||
Text("Dark").tag("dark")
|
||||
}
|
||||
Picker("Language", selection: $language) {
|
||||
ForEach(AppLanguage.allCases) { Text($0.displayName).tag($0.rawValue) }
|
||||
Picker("Language", selection: languageSelection) {
|
||||
ForEach(AppLanguage.allCases) { Text($0.displayName).tag($0) }
|
||||
}
|
||||
if language != launchLanguage.rawValue {
|
||||
if selectedLanguage != launchLanguage {
|
||||
Text("The new language will be used after Termind relaunches.").font(.caption).foregroundStyle(
|
||||
.secondary)
|
||||
}
|
||||
@@ -43,6 +56,5 @@ struct MobileAppSettingsView: View {
|
||||
}
|
||||
}
|
||||
.navigationTitle("App")
|
||||
.onChange(of: language) { _, value in AppLanguage.store(AppLanguage(rawValue: value) ?? .system) }
|
||||
}
|
||||
}
|
||||
@@ -1138,14 +1138,17 @@ final class MobileWorkspace: Identifiable {
|
||||
operationError = String(localized: "The SFTP connection is not available.")
|
||||
return false
|
||||
}
|
||||
let connectionGeneration = generation
|
||||
do {
|
||||
guard let file = try await sftp.attributes(at: path), !file.isDirectory else {
|
||||
let file = try await sftp.attributes(at: path)
|
||||
guard generation == connectionGeneration, connected else { return false }
|
||||
guard let file, !file.isDirectory else {
|
||||
operationError = String(localized: "The remote file is no longer available.")
|
||||
return false
|
||||
}
|
||||
return download(file)
|
||||
} catch {
|
||||
if !handleSFTPConnectionError(error, connection: generation) {
|
||||
if !handleSFTPConnectionError(error, connection: connectionGeneration) {
|
||||
operationError = error.localizedDescription
|
||||
}
|
||||
return false
|
||||
|
||||
@@ -13,7 +13,7 @@ struct MobileAssistantRenderingTests {
|
||||
guard ProcessInfo.processInfo.environment["TERMIND_ASSISTANT_SCREENSHOTS"] == "1" else { return }
|
||||
for language in ["en", "zh-Hans"] {
|
||||
let app = try MobileAppModel(inMemory: true)
|
||||
let conversation = ConversationModel.demo(language: language == "en" ? .english : .simplifiedChineseChina)
|
||||
let conversation = ConversationModel.demo(language: language == "en" ? .english : .simplifiedChinese)
|
||||
app.assistant.library.insertAndSelect(conversation)
|
||||
conversation.composer.draft = language == "en" ? "Check the service logs first." : "先检查服务日志。"
|
||||
conversation.attach(ContextChip(kind: .file, label: "service.log", content: "Example log"))
|
||||
|
||||
@@ -78,7 +78,7 @@ import TermindApplication
|
||||
let language: AppLanguage
|
||||
switch languageValue {
|
||||
case "en": language = .english
|
||||
case "zh": language = .simplifiedChineseChina
|
||||
case "zh": language = .simplifiedChinese
|
||||
default: throw ParseError.unknownLanguage(languageValue)
|
||||
}
|
||||
return Self(scene: scene, language: language)
|
||||
@@ -267,7 +267,7 @@ import TermindApplication
|
||||
}
|
||||
|
||||
private func text(en: String, zh: String) -> String {
|
||||
language == .simplifiedChineseChina ? zh : en
|
||||
language == .simplifiedChinese ? zh : en
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -11,7 +11,7 @@ extension HostLibraryModel {
|
||||
/// persistence or networking exists.
|
||||
static func demo(language: AppLanguage = .english) -> HostLibraryModel {
|
||||
func text(_ en: String, _ zh: String) -> String {
|
||||
language == .simplifiedChineseChina ? zh : en
|
||||
language == .simplifiedChinese ? zh : en
|
||||
}
|
||||
func distribution(_ id: String) -> DetectedDistribution {
|
||||
guard let distribution = DetectedDistribution(id: id) else {
|
||||
|
||||
@@ -360,7 +360,16 @@ private struct AppSettings: View {
|
||||
@State private var launchLanguage = AppLanguage.stored()
|
||||
|
||||
private var selectedLanguage: AppLanguage {
|
||||
AppLanguage(rawValue: languageID) ?? .system
|
||||
AppLanguage(rawValue: languageID) ?? AppLanguage.stored()
|
||||
}
|
||||
|
||||
private var languageSelection: Binding<AppLanguage> {
|
||||
Binding(
|
||||
get: { selectedLanguage },
|
||||
set: { language in
|
||||
languageID = language.rawValue
|
||||
AppLanguage.store(language)
|
||||
})
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
@@ -378,9 +387,9 @@ private struct AppSettings: View {
|
||||
}
|
||||
}
|
||||
|
||||
Picker("Language", selection: $languageID) {
|
||||
Picker("Language", selection: languageSelection) {
|
||||
ForEach(AppLanguage.allCases) { language in
|
||||
Text(language.displayName).tag(language.rawValue)
|
||||
Text(language.displayName).tag(language)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -393,11 +402,6 @@ private struct AppSettings: View {
|
||||
}
|
||||
}
|
||||
}
|
||||
.onChange(of: languageID) {
|
||||
let language = AppLanguage(rawValue: languageID) ?? .system
|
||||
if language.rawValue != languageID { languageID = language.rawValue }
|
||||
AppLanguage.store(language)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,17 +20,38 @@ struct AppLanguageTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
func explicitLanguagesWriteFullAppleLanguageTags() throws {
|
||||
func explicitLanguagesWriteCanonicalLanguageTags() throws {
|
||||
let defaults = try makeDefaults()
|
||||
|
||||
AppLanguage.store(.english, in: defaults)
|
||||
#expect(AppLanguage.stored(in: defaults) == .english)
|
||||
#expect(defaults.stringArray(forKey: "AppleLanguages") == ["en"])
|
||||
|
||||
AppLanguage.store(.simplifiedChineseChina, in: defaults)
|
||||
#expect(AppLanguage.stored(in: defaults) == .simplifiedChineseChina)
|
||||
#expect(defaults.stringArray(forKey: "AppleLanguages") == ["zh-Hans-CN"])
|
||||
#expect(AppLanguage.simplifiedChineseChina.locale.identifier == "zh-Hans-CN")
|
||||
AppLanguage.store(.simplifiedChinese, in: defaults)
|
||||
#expect(AppLanguage.stored(in: defaults) == .simplifiedChinese)
|
||||
#expect(defaults.stringArray(forKey: "AppleLanguages") == ["zh-Hans"])
|
||||
#expect(AppLanguage.simplifiedChinese.locale.identifier == "zh-Hans")
|
||||
#expect(AppLanguage.simplifiedChinese.displayName == "简体中文")
|
||||
}
|
||||
|
||||
@Test(arguments: ["zh-Hans-CN", "zh-CN", "zh_CN", "zh-Hans-SG", "zh"])
|
||||
func legacySimplifiedChinesePreferencesMigrateToCanonicalTag(identifier: String) throws {
|
||||
let defaults = try makeDefaults()
|
||||
defaults.set(identifier, forKey: SettingsKey.appLanguage)
|
||||
defaults.set([identifier], forKey: "AppleLanguages")
|
||||
|
||||
#expect(AppLanguage.stored(in: defaults) == .simplifiedChinese)
|
||||
#expect(defaults.string(forKey: SettingsKey.appLanguage) == "zh-Hans")
|
||||
#expect(defaults.stringArray(forKey: "AppleLanguages") == ["zh-Hans"])
|
||||
}
|
||||
|
||||
@Test(arguments: ["zh-Hant", "unsupported"])
|
||||
func nonSimplifiedChinesePreferencesContinueToFollowSystem(identifier: String) throws {
|
||||
let defaults = try makeDefaults()
|
||||
defaults.set(identifier, forKey: SettingsKey.appLanguage)
|
||||
|
||||
#expect(AppLanguage.stored(in: defaults) == .system)
|
||||
#expect(defaults.string(forKey: SettingsKey.appLanguage) == identifier)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -38,7 +59,7 @@ struct AppLanguageTests {
|
||||
let suiteName = "AppLanguageTests.\(UUID().uuidString)"
|
||||
let defaults = try #require(UserDefaults(suiteName: suiteName))
|
||||
defaults.removePersistentDomain(forName: suiteName)
|
||||
defaults.set(["zh-Hans-SG"], forKey: "AppleLanguages")
|
||||
defaults.set(["zh-Hans"], forKey: "AppleLanguages")
|
||||
|
||||
AppLanguage.store(.system, in: defaults)
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ struct ChatMessageTimestampTests {
|
||||
@Test
|
||||
func todayUsesOnlyTheLocalizedShortTime() throws {
|
||||
let timeZone = try #require(TimeZone(identifier: "Asia/Shanghai"))
|
||||
let locale = Locale(identifier: "zh_CN")
|
||||
let locale = Locale(identifier: "zh-Hans")
|
||||
var calendar = Calendar(identifier: .gregorian)
|
||||
calendar.timeZone = timeZone
|
||||
let message = try #require(
|
||||
|
||||
@@ -16,7 +16,7 @@ import TermindRemoteInfrastructure
|
||||
func parsesEverySceneAndLanguageCombination() throws {
|
||||
let languages: [(argument: String, language: AppLanguage)] = [
|
||||
("en", .english),
|
||||
("zh", .simplifiedChineseChina),
|
||||
("zh", .simplifiedChinese),
|
||||
]
|
||||
|
||||
for scene in ScreenshotDemoConfiguration.Scene.allCases {
|
||||
@@ -90,7 +90,7 @@ import TermindRemoteInfrastructure
|
||||
|
||||
@Test
|
||||
func appSettingsSceneUsesTheProductionSettingsRouteInBothLanguages() {
|
||||
for language in [AppLanguage.english, .simplifiedChineseChina] {
|
||||
for language in [AppLanguage.english, .simplifiedChinese] {
|
||||
let configuration = ScreenshotDemoConfiguration(scene: .appSettings, language: language)
|
||||
let window = configuration.makeWindow(hosts: .demo())
|
||||
#expect(window.selectedDestination == .settings)
|
||||
|
||||
@@ -189,7 +189,7 @@ struct WindowToolbarFindTests {
|
||||
let window = WindowModel()
|
||||
window.selectAssistant()
|
||||
|
||||
let locale = Locale(identifier: "zh-Hans-CN")
|
||||
let locale = Locale(identifier: "zh-Hans")
|
||||
#expect(VaultWindowTitleProvider().title(in: window, locale: locale) == nil)
|
||||
#expect(AssistantWindowTitleProvider().title(in: window, locale: locale) != nil)
|
||||
}
|
||||
@@ -203,7 +203,7 @@ struct WindowToolbarFindTests {
|
||||
store.insert(conversation)
|
||||
let window = WindowModel(assistantLibrary: AssistantLibraryModel(store: store))
|
||||
let title = AssistantWindowTitleProvider()
|
||||
let locale = Locale(identifier: "zh-Hans-CN")
|
||||
let locale = Locale(identifier: "zh-Hans")
|
||||
|
||||
window.selectAssistant()
|
||||
#expect(title.title(in: window, locale: locale) == AppLocalization.string("New Chat", locale: locale))
|
||||
@@ -218,7 +218,7 @@ struct WindowToolbarFindTests {
|
||||
@Test
|
||||
func workspaceTitleLocalizesOnlyBuiltInFallbacks() {
|
||||
let store = HostLibraryModel()
|
||||
let locale = Locale(identifier: "zh-Hans-CN")
|
||||
let locale = Locale(identifier: "zh-Hans")
|
||||
let first = Pane(.empty)
|
||||
let second = Pane(.empty)
|
||||
let workspace = Workspace(pane: first)
|
||||
|
||||
Reference in new issue
Block a user