Swift获取iOS设备系统语言 真机始终返回en_US问题排查
问题成因
- 核心逻辑缺陷:
Locale.preferredLanguages返回的是符合BCP 47标准的完整语言标签,真实用户的系统默认语言通常会携带地区后缀,例如乌克兰地区用户返回uk-UA、克罗地亚地区用户返回hr-HR。原有代码直接拿完整标签字符串匹配枚举rawValue(枚举中乌克兰语、克罗地亚语的rawValue是不带后缀的"uk"、"hr"),匹配失败后直接回退到默认英文。 - 测试场景偏差:本地手动切换系统语言时,选择的是无地区后缀的通用语言选项,标签格式和真实用户的默认配置不一致,因此本地测试正常、线上用户异常。
- 代码疏漏:
availableLanguages数组声明了土耳其语、荷兰语、瑞典语三个支持项,但Languages枚举中未定义对应的case,会直接触发编译错误。
修复方案
调整匹配逻辑,不要直接用完整语言标签做硬匹配,按分层逻辑匹配:
- 优先尝试匹配完整语言标签,覆盖
en-GB这类带地区的英语变体场景 - 完整标签匹配失败时,提取标签中的纯语言代码做二次匹配,覆盖
uk-UA、hr-HR这类带地区后缀的通用语言场景 - 补全枚举中缺失的语言case
- 兼容不同iOS版本的语言代码提取逻辑
修改后可正常运行的代码如下:
extension Locale { static var currentLanguage: Languages { let defaultLanguage = Languages.English_US guard let preferredLanguage = preferredLanguages.first else { return defaultLanguage } // 兼容高低版本iOS提取纯语言代码 let languageCode: String? if #available(iOS 16, *) { languageCode = Locale(identifier: preferredLanguage).language.languageCode?.identifier } else { languageCode = preferredLanguage.split(separator: "-").first.map(String.init) } guard let code = languageCode else { return defaultLanguage } // 先匹配完整语言标签,再匹配纯语言代码 if let fullMatch = Languages(rawValue: preferredLanguage), availableLanguages.contains(fullMatch) { return fullMatch } if let codeMatch = Languages(rawValue: code), availableLanguages.contains(codeMatch) { return codeMatch } return defaultLanguage } } /// 应用支持的语言列表 let availableLanguages : [Languages] = [.English_US, .Turkish, .Dutch, .Swedish, .Croatian, .Ukrainian] enum Languages: String, CaseIterable, Codable, Equatable, Comparable { case Croatian = "hr" case English_US = "en" case English_UK = "en-GB" case English_Australian = "en-AU" case English_Canadian = "en-CA" case French = "fr" case French_Canadian = "fr-CA" case Ukrainian = "uk" // 补全之前缺失的枚举项 case Turkish = "tr" case Dutch = "nl" case Swedish = "sv" }
额外校验:需确保项目Info.plist中
CFBundleLocalizations字段正确填写了所有应用支持的语言代码,否则系统会自动过滤掉未声明的语言,导致preferredLanguages返回结果不符合预期。
内容的提问来源于stack exchange,提问作者ursan526
相关产品推荐
相关产品推荐

