如何按手机设置的地区和语言设置时间显示
[NSLocale localeWithLocaleIdentifier:[NSLocale currentLocale].collatorIdentifier]
每当我们讨论国际化(i18n)或者本地化(l10n)的时候,我们有必要弄清楚两者之间的区别:
国际化是本地化的必要不充分条件,它也是这篇文章主要讨论的东西。本地化,包括将一些文本和资源翻译成指定语言的操作,将会在NSHipster之后的内容中涉及到。
让国际化变得困难的是,你需要摆脱你的文化环境去思考。像排序或者分类之类的工作,之前你觉得很微不足道而不想去管,但现在你必须得与这种情绪做斗争了,而且还得重视一些极小差别可能带来的痛苦或者困惑。
不过幸运的是,你不是一个人在战斗,现在来介绍NSLocale
:
NSLocale
NSLocale
是一个包含这所有地区的语言与文化习俗的基础类。一个NSLocale
的实例包含了针对这个地区内特定一群人的所有语言文化基准,其中包括:
每一个NSLocale
实例对应着一个地区标识符,例如en_US
,fr_FR
,ja_JP
和en_GB
,这些标识符包含一个语言码(例如en
代表英语)和一个地区码(例如US
代表美国)。
地区标识符还能标识更多更详尽的货币、日历系统或者数字表示的一些使用偏好。例如de_DE@collation=phonebook,currency=DDM
就表示了说德语的德国人,文字使用电话本排序,使用的货币在加入欧盟之前是德国马克。
用户可以在“语言和地区”(在早期版本的OS X里是“国际化”)选项里改变他们的系统设置,在iOS里是在“通用>多语言环境”里设置。
尽管NSLocale
包含了大量的不同区域的信息,但它的一般用法还是很保守的。
如果你要从NSLocale
里只学一样东西,那就是你需要把[NSLocale currentLocale]
传进NSDateFormatter
和NSNumberFormatter
的实例,这样做能确保日期、数字和货币能根据用户设置的地点信息显示正确的格式。
实际上,当你需要展示任何有关日期或者数字的时候,你最好永远用NSDateFormatter
或者NSNumberFormatter
,这须成为你的一个最基本的知识。
不过还是让我们来看看NSLocale
一些更棒的内容吧。
-objectForKey:
NSLocale
也有Foundation中对领域专有的迂腐特征,而没有比-objectForKey:
这个方法更明显地体现这个迂腐了。这是这个方法里key的常量的列表:
NSLocaleIdentifier
NSLocaleLanguageCode
NSLocaleCountryCode
NSLocaleScriptCode
NSLocaleVariantCode
NSLocaleExemplarCharacterSet
NSLocaleCalendar
NSLocaleCollationIdentifier
NSLocaleUsesMetricSystem
NSLocaleMeasurementSystem
NSLocaleDecimalSeparator
NSLocaleGroupingSeparator
NSLocaleCurrencySymbol
NSLocaleCurrencyCode
NSLocaleCollatorIdentifier
NSLocaleQuotationBeginDelimiterKey
NSLocaleQuotationEndDelimiterKey
NSLocaleAlternateQuotationBeginDelimiterKey
NSLocaleAlternateQuotationEndDelimiterKey
尽管这些东西看起来都有些难懂,但如果为了让自己的应用有更好的体验,你会惊讶于你使用这些常数的频率的。
与这些常量相关的配置全都是些小东西,例如你必须知道引号在不同地区其实有不同用法:
英语: “I can eat glass, it doesn't harm me.” 德语: „Ich kann Glas essen, das tut mir nicht weh.“ 日语:「私はガラスを食べられます。それは私を傷つけません。」
所以如果你在实现一个为任意文本加上引号的组件,那么你需要用到NSLocaleQuotationBeginDelimiterKey
和NSLocaleAlternateQuotationEndDelimiterKey
,而不是仅仅用英文的这个引号@"\""
。
-displayNameForKey:value:
另一个需要注意的、却也基本没什么用的方法是-displayNameForKey:value:
,它返回一个地区标识符用来展示的名字。
NSLocale *frLocale = [[NSLocale alloc] initWithLocaleIdentifier:@"fr_FR"];
NSLog(@"fr_FR: %@", [frLocale displayNameForKey:NSLocaleIdentifier value:@"fr_FR"]);
NSLog(@"en_US: %@", [frLocale displayNameForKey:NSLocaleIdentifier value:@"en_US"]);
fr_FR: français (France) en_US: anglais (États-Unis)
你应该在需要展示用户当前地区或者有其他地区可以选择的情况下使用这个方法,就想iOS设置里展示的一样:
+preferredLanguages
最后一个值得一提的方法是NSLocale +preferredLanguages
,它会根据用户的偏好返回一个IETF BCP 47 语言标识符的字符串数组。
与服务器交互的应用可以用这些值来定义HTTP头里面的Accept-Language
字段,而后服务器就能选择相应的本地化资源:
NSMutableURLRequest *request = ...;
[request setValue:[NSString stringWithFormat:@"%@", [[NSLocale preferredLanguages] componentsJoinedByString:@", "]], forHTTPHeaderField:@"Accept-Language"];
即使你的服务器并没有本地化的资源,把这个属性放进去会让你在需要的时候用到,而不必更新客户端。着实干净利落!
NSDateFormatter格式化时间
之前的文章,讲到过:[NSDate和NSString相互转换](http://www.superqq.com/blog/2015/06/26/nsdatehe-nsstringxiang-hu-zhuan-huan/)。里面提到过如何讲NSDate转化成NSString。代码如下:
//获取系统当前时间
NSDate*currentDate=[NSDatedate];
//用于格式化NSDate对象
NSDateFormatter*dateFormatter=[[NSDateFormatteralloc]init];
//设置格式:zzz表示时区
[dateFormattersetDateFormat:@"yyyy-MM-ddHH:mm:sszzz"];
//NSDate转NSString
NSString*currentDateString=[dateFormatterstringFromDate:currentDate];
//输出currentDateString
NSLog(@"%@",currentDateString);
运行起来,看看打印的内容:
2015-07-0722:08:57.422TestDemo[6756:1555205]2015-07-0722:08:57
这样写是不是没有什么问题。看着应该是没什么问题,其实问题很大。但是如果你改一下系统设置:语言设置成印度尼西亚文,时间设置成12小时制。
大家应该知道如何去设置吧,不会设置的请不要告诉我你是一名[iOS开发工程师](http://www.superqq.com/blog/2015/06/25/ru-he-cheng-wei-%5B%3F%5D-ming-you-xiu-de-ioskai-fa-gong-cheng-shi/)。再次编译起来,看看打印内容如下:
2015-07-0722:09:14.928TestDemo[6762:1555466]2015-07-0710.09.14PM
是不是愣住了,怎么会这么奇葩,时间怎么是.呢?还有更奇葩的呢,你去设置设置其他语言试试,也许有更多的收获。
如何正确的格式化时间
这也是我们这两天遇到的问题,跟用户几经沟通之后,终于抓到log,发现问题竟然是格式化导致的。怎么解决呢?
这个时候NSLocale的重要性就体现出来了。NSLocale作为大家都不常用的一个类,NSLocale类是将与国家和语言相关的信息进行简单的组合,包括货币、语言、国家等的信息。
所以很简单,我们把dateFormatter的locale属性改一下即可解决这个问题。将下面代码放在dateFormatter初始化之后:
NSLocale*usLocale=[[NSLocalealloc]initWithLocaleIdentifier:@"en_US"];
dateFormatter.locale=usLocale;
看看问题解决没有,编译一下:
2015-07-0722:20:08.411TestDemo[6769:1556968]2015-07-0722:20:08
果然,问题得到完美解决了。
NSLocale用法简介
1. 获取国家、货币、语言地区编码
既然谈到NSLocale,我们就来简单了解一下:
+ISOCountryCodes//所有的ISO定义的国家地区编码
+ISOCurrencyCodes//所有的ISO定义的货币编码
+ISOLanguageCodes//所有ISO定义的语言编码
以上我们可以用NSLog打印出来看一看。
2. 监听用户本地化的设置信息
FOUNDATION_EXPORTNSString*constNSCurrentLocaleDidChangeNotificationNS_AVAILABLE(10_5,2_0);
3. 获取当前系统设置语言的标识符
[[NSLocalecurrentLocale]localeIdentifier];