处理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数据没有几个是最新的地址信息.....数据太老,导致有些地区不全.所以才想到天气预报官网特定有最新最全的数据.贴出代码,希望能给有相同困惑的朋友. ...
随机推荐
- EasyUI 验证
使用过程中的一积累,备查. EasyUI 验证框使用方法://***************************missingMessage:未填写时显示的信息validType:验证类型见下示例 ...
- Mac eclipse 快捷键 f6、f8 失效
解决方法:
- iOS开发OC基础:Xcode中常见英文总结,OC常见英文错误
在开发的过程中难免会遇到很多的错误,可是当看到系统给出的英文时,又不知道是什么意思.所以这篇文章总结了Xcode中常见的一些英文单词及词组,可以帮助初学的人快速了解给出的提示.多练习,就肯定能基本掌握 ...
- SpringMVC系列(九)自定义视图、重定向、转发
一.自定义视图 1. 自定义一个视图HelloView.java,使用@Component注解交给Spring IOC容器处理 package com.study.springmvc.views; i ...
- Spring JDBC多批次操作
以下示例将演示如何使用spring jdbc在单个调用中进行多批次更新. 我们将在批量大小为1的多批次操作中更新student表中的记录. student表的结果如下 - CREATE TABLE s ...
- POJ 3126 --Father Christmas flymouse【scc缩点构图 && SPFA求最长路】
Father Christmas flymouse Time Limit: 1000MS Memory Limit: 131072K Total Submissions: 3007 Accep ...
- Miniconda 安装测试
背景: conda 是一个python的计算环境,minicoda 可以看做是conda的精简版 官网: https://conda.io/miniconda.html 安装: miniconda 支 ...
- fiddler 工具使用配置
前言: 之前为了手动测试项目组之间提供的接口,确定到底是哪一个接口出了问题.一般情况下,我们都直接采用了 Google 浏览器上,F12 后,Network 找到想要的 URL,然后,直接在浏览器上访 ...
- array_multisort—对多个数组或多维数组进行排序
From: http://www.cnblogs.com/lwbqqyumidi/archive/2013/01/31/2887188.html PHP中array_multisort可以用来一次对多 ...
- 配置IP
配置目的:配置IP为静态,让IP地址不变,方便长时间连接. 几个命令: dhclient 自动获取IP; 杀死进程:dhclient -r ip addr 显示网卡情况,了解到IP地址: 编辑配置文件 ...