将部分本地化字符串设为粗体 swift
Making part of localised string bold swift
我有一个字符串,让我们说“我的名字是 %@,我在 class %@ 学习”,现在我想将我将要插入的占位符文本加粗,以便结果看起来像像这样:“我的名字是 Harsh,我在 class 10 学习”,我会在标签上显示它
我已经尝试使用 NSAttributedString,但由于字符串将被本地化,我无法使用属性字符串的范围参数将其设为粗体。
我可以使用 NSRegularExpression
提供一个简单的解决方案,无需任何复杂/可怕的正则表达式。我相信还有比这更多的最佳解决方案。
这些步骤与上面发布的意思非常接近
- 将要注入的字符串 (Harsh, 13) 等存储在数组中
- 有一个包含占位符的本地化字符串
- 使用 REGEX 查找占位符的位置并将这些位置存储在
locations array
中
- 通过用字符串数组中的值替换占位符来更新本地化字符串
- 从更新的本地化字符串
创建NSMutableAttributedString
- 遍历字符串以注入数组并更新
locations array
定义的 NSMutableAttributedString
区域
这是我使用的代码和一些注释来解释:
// This is not needed, just part of my UI
// Only the inject part is relevant to you
@objc
private func didTapSubmitButton()
{
if let inputText = textField.text
{
let input = inputText.components(separatedBy: ",")
let text = "My name is %@ and I am %@ years old"
inject(input, into: text)
}
}
// The actual function
private func inject(_ strings: [String],
into text: String)
{
let placeholderString = "%@"
// Store all the positions of the %@ in the string
var placeholderIndexes: [Int] = []
// Locate the %@ in the original text
do
{
let regex = try NSRegularExpression(pattern: placeholderString,
options: .caseInsensitive)
// Loop through all the %@ found and store their locations
for match in regex.matches(in: text,
options: NSRegularExpression.MatchingOptions(),
range: NSRange(location: 0,
length: text.count))
as [NSTextCheckingResult]
{
// Append your placeholder array with the location
placeholderIndexes.append(match.range.location)
}
}
catch
{
// handle errors
print("error")
}
// Expand your string by inserting the parameters
let updatedText = String(format: text, arguments: strings)
// Configure an NSMutableAttributedString with the updated text
let attributedText = NSMutableAttributedString(string: updatedText)
// Keep track of an offset
// Initially when you store the locations of the %@ in the text
// My name is %@ and my age is %@ years old, the location is 11 and 27
// But when you add Harsh, the next location should be increased by
// the difference in length between the placeholder and the previous
// string to get the right location of the second parameter
var offset = 0
// Loop through the strings you want to insert
for (index, parameter) in strings.enumerated()
{
// Get the corresponding location of where it was inserted
// Plus the offset as discussed above
let locationOfString = placeholderIndexes[index] + offset
// Get the length of the string
let stringLength = parameter.count
// Create a range
let range = NSRange(location: locationOfString,
length: stringLength)
// Set the bold font
let boldFont
= UIFont.boldSystemFont(ofSize: displayLabel.font.pointSize)
// Set the attributes for the given range
attributedText.addAttribute(NSAttributedString.Key.font,
value: boldFont,
range: range)
// Update the offset as discussed above
offset = stringLength - placeholderString.count
}
// Do what you want with the string
displayLabel.attributedText = attributedText
}
最终结果:
本地化字符串的粗体部分参数化字符串粗体SwiftNSAttributedStringiOS
这应该足够灵活,可以处理字符串中存在的任意数量的占位符,您不需要跟踪不同的占位符。
let descriptionString = String(format: "localised_key".localized(), Harsh, 10)
let description = NSMutableAttributedString(string: descriptionString, attributes: [NSAttributedString.Key.font: UIFont(name: "NotoSans-Regular", size: 15.7)!, NSAttributedString.Key.foregroundColor: UIColor(rgb: 0x000b38), NSAttributedString.Key.kern: 0.5])
let rangeName = descriptionString.range(of: "Harsh")
let rangeClass = descriptionString.range(of: "10")
let nsrangeName = NSRange(rangeName!, in: descriptionString)
let nsrangeClass = NSRange(rangeClass!, in: descriptionString)
description.addAttributes([NSAttributedString.Key.font: UIFont(name: "NotoSans-Bold", size: 15.7)!, NSAttributedString.Key.foregroundColor: UIColor(rgb: 0x000b38), NSAttributedString.Key.kern: 0.5], range: nsrangeName)
description.addAttributes([NSAttributedString.Key.font: UIFont(name: "NotoSans-Bold", size: 15.7)!, NSAttributedString.Key.foregroundColor: UIColor(rgb: 0x000b38), NSAttributedString.Key.kern: 0.5], range: nsrangeClass)
如需更多参考,请使用 this
let withFormat = "my name is %@ and i study in class %@"
有多种方法可以做到这一点,但在我看来,最简单的方法之一是使用标签:
在占位符周围使用标签(以及其他部分,如果需要的话):
let withFormat = "my name is <b>%@</b> and i study in class <b>%@</b>"
let withFormat = "my name is [b]%@[/b] and i study in class [b]%@[/b]"
let withFormat = "my name is **%@** and i study in class **%@**"
标签可以是 HTML、Markdown、BBCode 或任何您喜欢的自定义,然后替换占位符值:
let localized = String(format: withFormat, value1, value2)
现在,根据你想怎么做,或者你使用了哪个标签,你可以使用 HTML 中 NSAttributedString
的初始化、Markdown 等,或者简单地使用 NSAttributedString(string: localized)
, 自己寻找标签并应用所需的渲染效果。
这是一个小例子:
let tv = UITextView(frame: CGRect(x: 0, y: 0, width: 300, height: 130))
tv.backgroundColor = .orange
let attributedString = NSMutableAttributedString()
let htmled = String(format: "my name is <b>%@</b> and i study in class <b>%@</b>", arguments: ["Alice", "Wonderlands"])
let markdowned = String(format: "my name is **%@** and i study in class **%@**", arguments: ["Alice", "Wonderlands"])
let bbcoded = String(format: "my name is [b]%@[/b] and i study in class [b]%@[/b]", arguments: ["Alice", "Wonderlands"])
let separator = NSAttributedString(string: "\n\n")
let html = try! NSAttributedString(data: Data(htmled.utf8), options: [.documentType : NSAttributedString.DocumentType.html], documentAttributes: nil)
attributedString.append(html)
attributedString.append(separator)
let markdown = try! NSAttributedString(markdown: markdowned, baseURL: nil) //iO15+
attributedString.append(markdown)
attributedString.append(separator)
let bbcode = NSMutableAttributedString(string: bbcoded)
let regex = try! NSRegularExpression(pattern: "\[b\](.*?)\[\/b\]", options: [])
let matches = regex.matches(in: bbcode.string, options: [], range: NSRange(location: 0, length: bbcode.length))
let boldEffect: [NSAttributedString.Key: Any] = [.font: UIFont.boldSystemFont(ofSize: 12)]
//We use reversed() because if you replace the first one, you'll remove [b] and [/b], meaning that the other ranges will be affected, so the trick is to start from the end
matches.reversed().forEach { aMatch in
let valueRange = aMatch.range(at: 1) //We use the regex group
let replacement = NSAttributedString(string: bbcode.attributedSubstring(from: valueRange).string, attributes: boldEffect)
bbcode.replaceCharacters(in: aMatch.range, with: replacement)
}
attributedString.append(bbcode)
tv.attributedText = attributedString
输出:
我有一个字符串,让我们说“我的名字是 %@,我在 class %@ 学习”,现在我想将我将要插入的占位符文本加粗,以便结果看起来像像这样:“我的名字是 Harsh,我在 class 10 学习”,我会在标签上显示它
我已经尝试使用 NSAttributedString,但由于字符串将被本地化,我无法使用属性字符串的范围参数将其设为粗体。
我可以使用 NSRegularExpression
提供一个简单的解决方案,无需任何复杂/可怕的正则表达式。我相信还有比这更多的最佳解决方案。
这些步骤与上面发布的意思非常接近
- 将要注入的字符串 (Harsh, 13) 等存储在数组中
- 有一个包含占位符的本地化字符串
- 使用 REGEX 查找占位符的位置并将这些位置存储在
locations array
中
- 通过用字符串数组中的值替换占位符来更新本地化字符串
- 从更新的本地化字符串 创建
- 遍历字符串以注入数组并更新
locations array
定义的
NSMutableAttributedString
NSMutableAttributedString
区域
这是我使用的代码和一些注释来解释:
// This is not needed, just part of my UI
// Only the inject part is relevant to you
@objc
private func didTapSubmitButton()
{
if let inputText = textField.text
{
let input = inputText.components(separatedBy: ",")
let text = "My name is %@ and I am %@ years old"
inject(input, into: text)
}
}
// The actual function
private func inject(_ strings: [String],
into text: String)
{
let placeholderString = "%@"
// Store all the positions of the %@ in the string
var placeholderIndexes: [Int] = []
// Locate the %@ in the original text
do
{
let regex = try NSRegularExpression(pattern: placeholderString,
options: .caseInsensitive)
// Loop through all the %@ found and store their locations
for match in regex.matches(in: text,
options: NSRegularExpression.MatchingOptions(),
range: NSRange(location: 0,
length: text.count))
as [NSTextCheckingResult]
{
// Append your placeholder array with the location
placeholderIndexes.append(match.range.location)
}
}
catch
{
// handle errors
print("error")
}
// Expand your string by inserting the parameters
let updatedText = String(format: text, arguments: strings)
// Configure an NSMutableAttributedString with the updated text
let attributedText = NSMutableAttributedString(string: updatedText)
// Keep track of an offset
// Initially when you store the locations of the %@ in the text
// My name is %@ and my age is %@ years old, the location is 11 and 27
// But when you add Harsh, the next location should be increased by
// the difference in length between the placeholder and the previous
// string to get the right location of the second parameter
var offset = 0
// Loop through the strings you want to insert
for (index, parameter) in strings.enumerated()
{
// Get the corresponding location of where it was inserted
// Plus the offset as discussed above
let locationOfString = placeholderIndexes[index] + offset
// Get the length of the string
let stringLength = parameter.count
// Create a range
let range = NSRange(location: locationOfString,
length: stringLength)
// Set the bold font
let boldFont
= UIFont.boldSystemFont(ofSize: displayLabel.font.pointSize)
// Set the attributes for the given range
attributedText.addAttribute(NSAttributedString.Key.font,
value: boldFont,
range: range)
// Update the offset as discussed above
offset = stringLength - placeholderString.count
}
// Do what you want with the string
displayLabel.attributedText = attributedText
}
最终结果:
本地化字符串的粗体部分参数化字符串粗体SwiftNSAttributedStringiOS
这应该足够灵活,可以处理字符串中存在的任意数量的占位符,您不需要跟踪不同的占位符。
let descriptionString = String(format: "localised_key".localized(), Harsh, 10)
let description = NSMutableAttributedString(string: descriptionString, attributes: [NSAttributedString.Key.font: UIFont(name: "NotoSans-Regular", size: 15.7)!, NSAttributedString.Key.foregroundColor: UIColor(rgb: 0x000b38), NSAttributedString.Key.kern: 0.5])
let rangeName = descriptionString.range(of: "Harsh")
let rangeClass = descriptionString.range(of: "10")
let nsrangeName = NSRange(rangeName!, in: descriptionString)
let nsrangeClass = NSRange(rangeClass!, in: descriptionString)
description.addAttributes([NSAttributedString.Key.font: UIFont(name: "NotoSans-Bold", size: 15.7)!, NSAttributedString.Key.foregroundColor: UIColor(rgb: 0x000b38), NSAttributedString.Key.kern: 0.5], range: nsrangeName)
description.addAttributes([NSAttributedString.Key.font: UIFont(name: "NotoSans-Bold", size: 15.7)!, NSAttributedString.Key.foregroundColor: UIColor(rgb: 0x000b38), NSAttributedString.Key.kern: 0.5], range: nsrangeClass)
如需更多参考,请使用 this
let withFormat = "my name is %@ and i study in class %@"
有多种方法可以做到这一点,但在我看来,最简单的方法之一是使用标签:
在占位符周围使用标签(以及其他部分,如果需要的话):
let withFormat = "my name is <b>%@</b> and i study in class <b>%@</b>"
let withFormat = "my name is [b]%@[/b] and i study in class [b]%@[/b]"
let withFormat = "my name is **%@** and i study in class **%@**"
标签可以是 HTML、Markdown、BBCode 或任何您喜欢的自定义,然后替换占位符值:
let localized = String(format: withFormat, value1, value2)
现在,根据你想怎么做,或者你使用了哪个标签,你可以使用 HTML 中 NSAttributedString
的初始化、Markdown 等,或者简单地使用 NSAttributedString(string: localized)
, 自己寻找标签并应用所需的渲染效果。
这是一个小例子:
let tv = UITextView(frame: CGRect(x: 0, y: 0, width: 300, height: 130))
tv.backgroundColor = .orange
let attributedString = NSMutableAttributedString()
let htmled = String(format: "my name is <b>%@</b> and i study in class <b>%@</b>", arguments: ["Alice", "Wonderlands"])
let markdowned = String(format: "my name is **%@** and i study in class **%@**", arguments: ["Alice", "Wonderlands"])
let bbcoded = String(format: "my name is [b]%@[/b] and i study in class [b]%@[/b]", arguments: ["Alice", "Wonderlands"])
let separator = NSAttributedString(string: "\n\n")
let html = try! NSAttributedString(data: Data(htmled.utf8), options: [.documentType : NSAttributedString.DocumentType.html], documentAttributes: nil)
attributedString.append(html)
attributedString.append(separator)
let markdown = try! NSAttributedString(markdown: markdowned, baseURL: nil) //iO15+
attributedString.append(markdown)
attributedString.append(separator)
let bbcode = NSMutableAttributedString(string: bbcoded)
let regex = try! NSRegularExpression(pattern: "\[b\](.*?)\[\/b\]", options: [])
let matches = regex.matches(in: bbcode.string, options: [], range: NSRange(location: 0, length: bbcode.length))
let boldEffect: [NSAttributedString.Key: Any] = [.font: UIFont.boldSystemFont(ofSize: 12)]
//We use reversed() because if you replace the first one, you'll remove [b] and [/b], meaning that the other ranges will be affected, so the trick is to start from the end
matches.reversed().forEach { aMatch in
let valueRange = aMatch.range(at: 1) //We use the regex group
let replacement = NSAttributedString(string: bbcode.attributedSubstring(from: valueRange).string, attributes: boldEffect)
bbcode.replaceCharacters(in: aMatch.range, with: replacement)
}
attributedString.append(bbcode)
tv.attributedText = attributedString
输出: