处理i18n国际电话区号的代码实践
本文转载至 http://adad184.com/2015/08/18/practice-in-i18n-dialling-code/
前言
上周在忙产品的国际化(i18n)的问题 其中一个很重要的地方就是电话号码的国际化(我们以电话号码为主账号) 电话号码有个很重要的部分就是区号

上图是我们产品的区号选择 除了常规的电话号码之外 后面还有一个区号 代表这个电话号码所属的是哪个国家和地区 关于区号的概念 可以看一下维基百科
看到这里 可能有人奇怪 这有什么难的? 不就是按照列表来展示吗? 这样有几个问题
- 由于是支持多语言 那么不同的语言环境的系统 显示出来的国家名称是不一样的 比如“中国” 简体中文是“中国” 英文是“China” 韩文是“중화인민공화국” 其在各个语言中的显示排序都是不一样的
- 如果根据不同国家和语言来维护一张这样的表 工作量太大 一般的公司估计做不来
所以这个工作我们就会放到本地来做 不过iOS已经帮我们做了一部分工作了 我们可以根据国家代码来获取某个国家或在当前区域中的本地化名称
1 |
//获取当前locale |
我们简单测试一下
1 |
NSArray *countryArray = [NSLocale ISOCountryCodes]; |
结果
1 |
zh_CN AD 安道尔 |
已经介绍完iOS帮我们做的一部分工作了 那么另一部分就得我们自己来了
我们需要有一张 地区->区号 的列表 不过这个也简单 网上一抓一大把 我也是网上找的 文件内容如下(diallingcode.json)
1 |
[ |
维护这样一张表就很简单了我们可以存在本地 也可以放在服务器(“name”字段其实是不必须的 只是为了好看)
研究
我们暂时先把代码放一放 来看一看其他产品是怎么做的
这个是微信的
微信的问题还是挺多的
- 左边是中文环境 按拼音分组是分对了 但是文字排序却出错了 “阿”开头的国家并没有排列在一起
- 右边是法语环境 这些衍生拉丁字母 并没有正确的归类
这个是Twitter的
Twitter在中文环境下还是挺奇怪的 但是却没有犯微信第二个错误
Facebook的呢? 人家的工程师比较聪明(懒) 压根就不支持索引
接下来我们会解决出现的这几个问题
代码
先简历一个Modal 用来表示国家相关的信息
1 |
@interface MMCountry : NSObject @property (nonatomic, strong) NSString *name; //国家名(本地化后的版本) |
然后我们要把区号从配置文件中读取出来 并以区号为key 建立索引
1 |
NSData *data = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"diallingcode" ofType:@"json"]]; |
接着获取这些国家的本地话名称
1 |
NSLocale *locale = [NSLocale currentLocale]; |
这里要注意的是 把字母拉丁文化 解决了微信的第二个问题 使非基本拉丁字母也可以按照基本拉丁字母来排序 其函数如下
1 |
- (NSString*)latinize:(NSString*)str |
这里有两步
- 先将文字 转成拉丁字母(kCFStringTransformToLatin)
- 再将拉丁字母去掉变音符(kCFStringTransformStripDiacritics)
这里是微信犯的第一个错误 也就是没有正确归类的错误 因为微信在第一步的时候只针对汉字进行了处理 其他字符则没有处理 导致第二步没有得到正确的基本拉丁字符(kCFStringTransformMandarinLatin 参见注释掉的代码)
我们来测试一下这两步会造成得到效果 还是之前的例子
1 |
NSArray *countryArray = [NSLocale ISOCountryCodes]; |
结果
1 |
zh_CN AD 安道尔 | an dao er |
可以到看 系统会根据不同国家和不同语言的特点 将同一个国家的不同表达形式转化成不同的拉丁字母
接下来 我们把获取过的数据根据’A’-‘Z’进行归类
1 |
NSMutableDictionary *dicSort = [@{} mutableCopy];
for ( MMCountry *c in dicCountry.allValues )
|
最后 将每个归类下面的数据 排序重新整理
1 |
for ( NSString *key in dicSort.allKeys ) |
这样dicSort就是我们最终得到的结果集
这里是微信犯的第二个错误 微信的排序是按照latin来排序的(见注释掉的代码) 所以导致了相同汉字的国家排不到一起的情况 正确的方式是用
localizedStandardCompare来排序 这也是iOS已为我们提供好了的本地化比较函数
看看之前的图中 挑三个国家出来 比如:阿尔巴尼亚 爱尔兰 阿鲁巴 他们的拼音是 aerbabiya aierlan aluba 如果按照拼音排序的话 这样的排序就是正确的
我们来看看最终的效果
是不是比微信的更好?
讨论
虽然代码是写完了 但是问题并没有结果 有一个关键的问题就是 为什么我们要按照’A’-‘Z’来索引排序呢? 比如Twitter在日文和韩文环境下是这样的
其实按照不同国家的语言特点来进行对应的索引 应该才是最优的解决办法(PS:看到Twitter在中文环境下的糟糕结果 我也不确定其在日文和韩文下的结果是否是正确的(¯﹃¯)
当然 如果真要这样做 其实改动量也不大 只要在索引的那块稍微修改一下就行了
小结
文中的demo可以在这里找到
正如讨论中说的一样 本文所讨论的方案 并不是最终的解决方案 如果需要更好的体验的话 还要深入研究各国的文化才行 所以 国际化并不单纯是个技术问题 更是个社会工程啊~~~~
处理i18n国际电话区号的代码实践的更多相关文章
- 支持中英文和国旗的android国家代码/国际电话区号选择器
最近在做app登录的时候,因为需要支持国外手机号注册和登录,所以就涉及到国际电话区号的选择.在github上面找了一下,国家名称基本都是只有英文版本,而手动的去把中文一个个加上实在是一件费时费力的事情 ...
- 国际电话区号SQL
CREATE TABLE `phone_prefix` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `country` varchar(30) N ...
- 国际电话号码的区号mysql数据表
-- phpMyAdmin SQL Dump-- version 3.5.2-- http://www.phpmyadmin.net---- Host: localhost-- Generation ...
- 分享,iOS国家手机区号代码.plist
APP注册需要手机号码的时候,如果有在其他国家的时候需要填写手机区号 一份有国家名字和区号的plist 参照微信注册的时候 格式是 <Array> <Array> <Ar ...
- 生活常用类API调用的代码示例合集:邮编查询、今日热门新闻查询、区号查询等
以下示例代码适用于 www.apishop.net 网站下的API,使用本文提及的接口调用代码示例前,您需要先申请相应的API服务. 邮编查询:通过邮编查询地名:通过地名查询邮编 今日热门新闻查询:提 ...
- Android 国际区号注册手机号编码 以及常用城市列表
附上 国际区号编码:我是定义到arrays.xml里面了 <?xml version="1.0" encoding="utf-8"?> <re ...
- [原创]JAVA号码工具类:实现手机固话号码判断与区号截取
工具类说明 该工具类主要是用于判断号码的类型,如果是手机类型,则返回号码前7位,便于后面继续判断号码归属地:如果是固话类型,则截取固话的区号,同样也是为了后面判断号码的归属地. 在获取到这些信息之后, ...
- HtmlAgilityPack解析全国区号页面到XML
需求:完成一个城市和区号的xml配置文件 处理思路:通过HtmlAgilityPack解析一个区号页面,生产xml文件 页面:http://www.hljboli.gov.cn/html/code.h ...
- java利用爬虫技术抓取(省、市(区号\邮编)、县)数据
近期项目须要用到 城市的地址信息,但从网上下载的xml数据没有几个是最新的地址信息.....数据太老,导致有些地区不全.所以才想到天气预报官网特定有最新最全的数据.贴出代码,希望能给有相同困惑的朋友. ...
随机推荐
- [转]Idea2016 使用Maven配置简单Web项目(受益比较多的一篇)
最近被同事一直吵着用Idea写Java,于是偷偷的去试用了一下Idea.确实不错,无论界面还是智能提醒都是蛮符合我的使用习惯,但是刚从Eclipse出来,使用Idea还是不太习惯的.所以这里写出来,供 ...
- SAP 物料移动类型查询表
Goods movement w/o referenceB Goods movement for purchase orderF Goods movement for production order ...
- linux下locale中的各环境变量的含义
本文来自:http://blog.sina.com.cn/s/blog_406127500101dk26.html Locale是软件在运行时的语言环境, 它包括语言(Language), 地域 (T ...
- 第三百三十一节,web爬虫讲解2—Scrapy框架爬虫—Scrapy安装—Scrapy指令
第三百三十一节,web爬虫讲解2—Scrapy框架爬虫—Scrapy安装—Scrapy指令 Scrapy框架安装 1.首先,终端执行命令升级pip: python -m pip install --u ...
- Java如何查看线程的优先级?
Java编程中,如何查看线程的优先级? 以下示例演示如何使用Thread类的getPriority()方法检查线程的优先级. package com.yiibai; public class Thre ...
- (转)LCD:LCD常用接口原理篇
关键词:android LCD TFT TTL(RGB) LVDS EDP MIPI TTL-LVDS TTL-EDP平台信息:内核:linux2.6/linux3.0系统:android/a ...
- python_smtplib
import smtplib smtpserver = 'smtp.qq.com' fromaddr = 'fromaddr@qq.com' toaddrs = 'toaddr@qq.com' msg ...
- 互联网公司GitHub repo 语言使用情况
转自: https://laike9m.com/blog/hu-lian-wang-gong-si-github-repo-yu-yan-shi-yong-qing-kuang,56/ 现在基本上所有 ...
- discuz密码找回:[1]忘记UCENTER创始人密码
人们都是健忘的,何况每天的事情很多,有些站长更是兼职做,赚点外快而已,而ucenter更是不常用,所以忘记密码是在正常不过的事情,如果密码忘记怎么找回呢?方法有很多种,例如用comsenz tools ...
- Solaris 11中的变化
Solaris 11发布了好几个月了,用了后感觉好多配置的东东变化不小,写写自己遇到的问题和大家分享一下, 1,如何设置root密码 Solaris 11中root作为一个Role来存在,已经不能直接 ...