如何本地化国际地址,尤其是大道和次大道
Posted
技术标签:
【中文标题】如何本地化国际地址,尤其是大道和次大道【英文标题】:How to localize an international address especially thoroughfare and subthoroughfare 【发布时间】:2020-03-31 03:39:00 【问题描述】:我正在开发一款大量使用不同国家/地区地址的应用。我们有很多方法可以输入它们,从导入地址到在地图上放置图钉,再到反向地理编码我们当前的位置。
我目前的项目是正确格式化国际地址:
在美国:
18 Street Name
在挪威:
Street Name 18
我想出了很多方法来实例化CNMutablePostalAddress
和CLPlacemark
以获得一些相当不错的结果,我遇到的问题就是这个。
我只想将街道名称和号码作为单行字符串返回:
所以:
street1: placemarker.thoroughfare, (street name)
street2: placemarker.subThoroughfare (street number),
但 CNPostalAddress 只有一个 street
属性,所以要使用它,您需要执行以下操作:
cNPostalAddress.street = placemarker.subThoroughfare + " " + placemarker.thoroughfare
这不适用于像挪威这样受人尊敬的国家。
您可以破解它并使用从格式化地址中取出第一行:
CNPostalAddressFormatter.string(from: placemarker.mailingAddress , style: .mailingAddress)
但那太老套了,我相信它会与日本等邮寄地址顺序不同的国家/地区不同。
目前我什至找不到任何资源来告诉我哪些国家/地区反转了subThoroughfare
和 thoroughfare
,因为如果我有这样的列表,我可以手动反转它。
这是我目前管理的一些示例代码:
static func mulitLineAddress(from placemarker: CLPlacemark, detail: AddressDetail) -> String
let address = MailingAddress(
street1: placemarker.thoroughfare,
street2: placemarker.subThoroughfare,
city: placemarker.locality,
state: placemarker.administrativeArea,
postalCode: placemarker.postalCode,
countryCode: placemarker.country)
return self.mulitLineAddress(from: address, detail: detail)
static func mulitLineAddress(from mailingAddress: MailingAddress, detail: AddressDetail) -> String
let address = CNMutablePostalAddress()
let street1 = mailingAddress.street1 ?? ""
let street2 = mailingAddress.street2 ?? ""
let streetSpacing = street1.isEmpty && street2.isEmpty ? "" : " "
let streetFull = street1 + streetSpacing + street2
switch detail
case .street1:
address.street = street1
case .street2:
address.street = street2
case .streetFull:
address.street = streetFull
case .full:
address.country = mailingAddress.countryCode ?? ""
fallthrough
case .withoutCountry:
address.street = streetFull
address.city = mailingAddress.city ?? ""
address.state = mailingAddress.state ?? ""
address.postalCode = mailingAddress.postalCode ?? ""
return CNPostalAddressFormatter.string(from: address, style: .mailingAddress)
有什么想法吗?甚至像反转 street1
和 street2
的国家列表这样的资源也会很有用。
【问题讨论】:
【参考方案1】:我最终采用了混合方法。
对于CLPlacemark
到CNMutablePostalAddress()
,这非常简单:
cnPostalAddress.street = placemarker.postalAddress?.street
但是这对任何其他输入法都不起作用,并且不能修改为与CNMutablePostalAddress()
不同的格式
当从其他来源引入地址信息时,我需要手动完成,这里有一个适用于几个国家/地区的示例:
static private func generateLocalizedStreetAddress(from adderss: MailingAddress) -> String
guard adderss.localizedStreet.isEmpty else return adderss.localizedStreet ?? ""
let country = CountryCode.country(for: adderss.countryCode)
let thoroughfare = adderss.thoroughfare ?? ""
let subThoroughfare = adderss.subThoroughfare ?? ""
let delimiter = self.generateDelimiter(from: thoroughfare, and: subThoroughfare, with: country)
switch country
case .belgium, .czechRepublic, .denmark, .finland, .germany, .latvia, .netherlands, .norway, .poland, .portugal, .sweden:
return thoroughfare + delimiter + subThoroughfare
default:
return subThoroughfare + delimiter + thoroughfare
static private func generateDelimiter(from thoroughfare: String, and subThoroughfare: String, with country: Country) -> String
guard !thoroughfare.isEmpty && !subThoroughfare.isEmpty else return ""
switch country
case .spain:
return ", "
default:
return " "
【讨论】:
【参考方案2】:CNPostalAddressFormatter
有一个有趣的 API 可以获取 NSAttributedString
,其中标识了每个地址组件。您可以使用它来仅提取您想要的信息,例如街道,其中包括正确本地化的次干道和大道,无论它可能存在于邮政地址中的哪个位置。
let addressFormatter = CNPostalAddressFormatter()
let attributedAddress = addressFormatter.attributedString(from: postalAddress, withDefaultAttributes: [:])
let nsString = attributedAddress.string as NSString
let range = NSRange(location: 0, length: nsString.length)
var street: String?
attributedAddress.enumerateAttributes(in: range, options: []) result, range, stop in
if let component = result[NSAttributedString.Key(CNPostalAddressPropertyAttribute)] as? String
if component == CNPostalAddressStreetKey
street = nsString.substring(with: range)
stop.pointee = true
我还向 Apple 提交了反馈,以添加更强大和更灵活的 API:FB8648023 Template API 希望使用类似于DateFormatter.setLocalizedDateFormatFromTemplate
的指定组件格式化地址
【讨论】:
以上是关于如何本地化国际地址,尤其是大道和次大道的主要内容,如果未能解决你的问题,请参考以下文章