Swift中英译法/德时UILabel超链接未高亮问题排查
多语言环境下UILabel超链接高亮异常问题
问题描述
我实现了一个带超链接的UILabel,相关代码如下。APP支持多语言切换,西班牙语和中文环境下翻译后的超链接可正常工作,但法语和德语环境下无法正常高亮,请问这两种语言需要特殊处理吗?
调用代码
let termsText = NSLocalizedString("To continue using this feature, please accept the Terms & Conditions", bundle: Bundle.terms, comment: "Continue") let linkText = NSLocalizedString("Terms & Conditions", bundle: Bundle.terms, comment: "Terms") termsLabel.setAttributedTextWithLinks(stringForAttributedText: termsText, linksText: [linkText], boldFont: false, underlined: false, fontSize: 14, textColor: UIColor(named: "Charcoal", in: Bundle(for: ViewController.self), compatibleWith: nil) ?? .black, linkColor: UIColor(named: "Blue", in: Bundle(for: ViewController.self), compatibleWith: nil) ?? .blue, paragraphStyle: nil) { [weak self] _ in self?.navigateToTermsAndConditionsVC() }
富文本生成代码
func setAttributedTextWithLinks(stringForAttributedText: String, linksText: [String], boldFont: Bool = false, underlined: Bool = false, fontSize: CGFloat = 14.0, textColor: UIColor = UIColor(named: "Carbon", in: Bundle(for: UILabelWithLink.self), compatibleWith: nil) ?? .black, linkColor: UIColor = UIColor(named: "Blue", in: Bundle(for: AlertViewController.self), compatibleWith: nil) ?? .blue, paragraphStyle: NSParagraphStyle? = nil, linkTapped: @escaping (UInt) -> Void) { font = UIFont.systemFont(ofSize: fontSize, weight: boldFont ? .semibold : .regular) let textAttributes = [NSAttributedString.Key.foregroundColor: textColor, NSAttributedString.Key.font: font] as [NSAttributedString.Key: Any] var linkAttributes = [NSAttributedString.Key.foregroundColor: linkColor, NSAttributedString.Key.font: font] as [NSAttributedString.Key: Any] if underlined { linkAttributes[NSAttributedString.Key.underlineStyle] = 1 } setAttributedTextWithLinks(stringForAttributedText: stringForAttributedText, textAttributes: textAttributes, isTextBold: boldFont, linksText: linksText, linkAttributes: linkAttributes, isLinkBold: boldFont, paragraphStyle: paragraphStyle, linkTapped: linkTapped) }
核心实现代码
func setAttributedTextWithLinks(stringForAttributedText: String, textAttributes: [NSAttributedString.Key: Any], isTextBold: Bool, linksText: [String], linkAttributes: [NSAttributedString.Key: Any], isLinkBold: Bool, paragraphStyle: NSParagraphStyle?, linkTapped: @escaping (UInt) -> Void) { self.linkTapped = linkTapped cachedLinksText = linksText let nsstringForAttributedText = stringForAttributedText as NSString var textAttributesVar = textAttributes var linkAttributesVar = linkAttributes updateAttributesForAsianCharacters(attributes: &textAttributesVar, isBold: isTextBold) updateAttributesForAsianCharacters(attributes: &linkAttributesVar, isBold: isLinkBold) let mutableAttributedText = NSMutableAttributedString(string: stringForAttributedText) let nonLinkComponents = stringForAttributedText.components(separatedBy: linksText) for regularText in nonLinkComponents { let range = nsstringForAttributedText.range(of: regularText) mutableAttributedText.addAttributes(textAttributesVar, range: range) } for linkText in linksText { let linkRange = nsstringForAttributedText.range(of: linkText) mutableAttributedText.addAttributes(linkAttributesVar, range: linkRange) } if paragraphStyle != nil { mutableAttributedText.addAttribute(NSAttributedString.Key.paragraphStyle, value: paragraphStyle!, range: nsstringForAttributedText.range(of: stringForAttributedText)) } attributedText = mutableAttributedText configureLinkTextForTouch() configureLayoutManagerTextStorageTextContainer() }
问题原因
核心问题出在字符串匹配逻辑上:
- 法语、德语存在特殊字符(如德语变音字母
ä/ö/ü、法语重音字符é/è/ê),默认的range(of:)匹配会严格区分这些字符变体 - 法语中常用非断空格(
U+00A0)替代普通空格,导致链接文本和主文本的空格不匹配 - 部分翻译可能存在大小写、标点的细微差异,导致
range(of:)无法定位到正确的链接范围,最终没应用链接样式
解决方案
方案1:使用本地化键拼接富文本(推荐)
避免直接匹配翻译后的文本,通过String(format:)用本地化键拼接完整文本,确保链接文本的位置绝对准确:
// 替换原调用代码中的文本获取逻辑 let baseTextKey = "continue_feature_accept_terms" let linkTextKey = "terms_conditions" // 本地化文件中对应键值示例: // continue_feature_accept_terms = "To continue using this feature, please accept the %@"; // terms_conditions = "Terms & Conditions"; let linkText = NSLocalizedString(linkTextKey, bundle: Bundle.terms, comment: "Terms") let fullTextFormat = NSLocalizedString(baseTextKey, bundle: Bundle.terms, comment: "Continue") let fullText = String(format: fullTextFormat, linkText) // 直接获取链接范围 let nsFullText = fullText as NSString let linkRange = nsFullText.range(of: linkText) // 构建富文本(可集成到原setAttributedTextWithLinks方法中) let mutableAttributedText = NSMutableAttributedString(string: fullText) // 先设置全局普通文本样式 mutableAttributedText.addAttributes(textAttributesVar, range: NSRange(location: 0, length: nsFullText.length)) // 覆盖链接文本样式 if linkRange.location != NSNotFound { mutableAttributedText.addAttributes(linkAttributesVar, range: linkRange) }
方案2:优化字符串匹配规则
如果要保留原有匹配逻辑,修改range(of:)的匹配选项,支持变音字符和大小写不敏感,同时处理非断空格:
// 替换原核心代码中的linkRange获取逻辑 for linkText in linksText { // 标准化空格:替换非断空格为普通空格 let normalizedFullText = stringForAttributedText.replacingOccurrences(of: "\u{00A0}", with: " ") let normalizedLinkText = linkText.replacingOccurrences(of: "\u{00A0}", with: " ") let nsNormalizedFullText = normalizedFullText as NSString // 使用不区分大小写和变音符号的匹配选项 let linkRange = nsNormalizedFullText.range(of: normalizedLinkText, options: [.caseInsensitive, .diacriticInsensitive]) if linkRange.location != NSNotFound { mutableAttributedText.addAttributes(linkAttributesVar, range: linkRange) } }
额外检查项
- 核对法语、德语本地化文件中,链接文本的翻译和主文本中的对应部分完全一致(包括空格、标点、变音符号)
- 检查
updateAttributesForAsianCharacters函数是否会修改欧洲语言的字体属性,导致链接样式被覆盖
内容的提问来源于stack exchange,提问作者niagara
相关产品推荐
相关产品推荐

