zh-CN to zh-Hans

This commit is contained in:
Kaede Akino committed 2026-09-12 13:20:56 +08:00
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)
}
}
}
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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"))
+2 -2
View File
@@ -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 {
+12 -8
View File
@@ -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)
}
}
}
+27 -6
View File
@@ -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)
+1 -1
View File
@@ -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(
+2 -2
View File
@@ -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)
+3 -3
View File
@@ -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)