App的国际化和本地化(五) —— 使用区域设置格式化数据(一)

版本记录

版本号 时间
V1.0 2018.05.10

前言

很多APP都有国际化版本,常见于一些大公司的产品,比如Facebook、Wechat等,那么国际化需要我们APP做哪些更改呢,接下来这几篇就一起来看一下APP的国际化和本地化。感兴趣的可以看上面几篇。
1. App的国际化和本地化(一) —— 简单介绍(一)
2. App的国际化和本地化(二) —— 查看语言和区域设置(一)
3. App的国际化和本地化(三) —— 国际化用户界面(一)
4. App的国际化和本地化(四) —— 国际化代码(一)

回顾

上一篇主要介绍国际化代码,本篇主要介绍使用区域设置格式化数据。


Formatting Data Using the Locale Settings - 使用区域设置格式化数据

不同的国家和地区对于数字和时间信息的格式有不同的约定。 区域设置提供有关当前用户使用的格式的信息,在编写处理面向用户的数据类型的代码时必须考虑这些信息。 用户通过在iOS设备的设置和Mac上的系统首选项中选择区域来设置区域设置。 用户还可以在应用程序运行时更改区域设置。 因此,如果您在代码中操作数据对象并将其呈现给用户,请使用locale APIs正确格式化数据。

您不需要知道如何格式化所有不同地区中的数据。 您可以使用自动生成区域敏感格式的预设样式。 只要您在将它们呈现给用户之前将其转换为区域性敏感格式,就可以使用自定义格式。 本章介绍如何编写区域敏感代码。


About Locale Formats - 关于区域格式

区域设置表示特定用户的格式选择,而不是用户的首选语言。 这些通常是相同的,但可以不同。 例如,住在德国的讲英语的母语人士可能会选择英语作为语言,德国作为该地区。 文本以英文显示,但日期,时间和数字遵循德国格式规则。 日在月的前面和24小时的时间表示,如Table 4-1所示。

Table 4-1 Data formats in United States and Germany

在Mac上,您可以在系统偏好设置中预览修改的区域设置首选项。 从“地区”弹出式菜单中选择地理区域时,会显示日期,时间和数字格式的样本。 该屏幕截图显示了当英语是该语言并且日本是该地区时的示例数据格式:

Mac用户还可以通过单击Advanced按钮来自定义日期,时间和数字格式,如Reviewing Language and Region Preferences on Your Mac中所述。


Using the Locale Object - 使用地区对象

NSLocale对象封装有关特定区域的格式标准的信息。 在格式化面向用户的文本时,会传递一个代表用户所选区域的NSLocale对象。 NSLocale类提供用于获取用户的区域对象的类方法以及有关支持的区域的其他信息。

1. Getting the User’s Locale - 获取用户区域

您可以使用NSLocale类中的currentLocaleautoupdatingCurrentLocale类方法来获取用户的区域。

如果使用currentLocale方法,则保证返回对象的属性值不会更改。 因此,如果要执行需要一致的操作,请使用currentLocale方法。

如果使用autoupdatingCurrentLocale方法,那么当用户更改区域设置时,属性值可能会更改。 但是,如果返回的对象发生更改,则不会通知您。

要观察区域设置首选项更改,请阅读Registering for Locale and Time Zone Changes

提示:系统设置与用户设置不同。 不要使用systemLocale类方法来获取用户的区域。

2. Getting Information About a Locale - 获取关于区域的信息

使用NSLocale类中的objectForKey:方法来访问有关语言环境的信息。 例如,将NSLocaleUsesMetricSystem密钥传递给此方法以获取布尔数,该数字确定区域设置是否使用metric系统。

NSNumber *metricSystem = [[NSLocale currentLocale] objectForKey:NSLocaleUsesMetricSystem];

传递key为NSLocaleCurrencySymbol以获取代表当地符号的字符串。

NSString *currencySymbol = [[NSLocale currentLocale] objectForKey:NSLocaleCurrencySymbol];

对于区域keys的完整列表,请参考NSLocale Component Keys

3. Getting Localized Language and Dialect Names - 获取本地语言和方言名称

不应向用户显示API和文件夹名称中指定语言和方言的标识符,例如de-CHen-AUpt-PT。 要获得可读的本地化语言或方言名称,请在NSLocale类中使用displayNameForKey:value:方法,传递NSLocaleIdentifier作为关键参数。

To get the localized name for languages and dialects - 获取地区名称用于语言和方言

  • 获取APP正在使用的语言
NSString *languageID = [[NSBundle mainBundle] preferredLocalizations].firstObject;

返回的字符串是标识书面语言或方言的language ID,如Language and Locale IDs中所述。

  • 获取关联的地区对象
NSLocale *locale = [NSLocale localeWithLocaleIdentifier:languageID];

如果您将语言ID作为区域设置ID参数传递,则会返回该语言的区域设置。 例如,如果您将de-CH作为语言传递,则会返回瑞士语言环境。

  • 获取区域语言名称
NSString *localizedString = [locale displayNameForKey:NSLocaleIdentifier value:languageID];

字符串的格式是[Language]([Dialect])。 例如,如果language IDde-CH,则本地化语言字符串是Deutsch(Schweiz)。如果语言ID是de,则本地化语言字符串是Deutsch

4. Getting Language-Specific Quotes - 获取特定于语言的引号

可以从区域设置对象获取开始和结束引号,这些引号在不同的语言中有所不同。 使用Getting Localized Language and Dialect Names中描述的相同技术获取该语言的默认语言环境,然后使用区域键获取特定于语言的引号。

To create a string that uses locale-sensitive quotes - 使用区域敏感引号创建字符串

  • 获取APP正在使用的语言
NSString *languageID = [[NSBundle mainBundle] preferredLocalizations].firstObject;
  • 获取关联的区域对象
NSLocale *locale = [NSLocale localeWithLocaleIdentifier:languageID];
  • 从区域对象中获取引号的开始和结束符号
bQuote = [locale objectForKey:NSLocaleQuotationBeginDelimiterKey];
eQuote = [locale objectForKey:NSLocaleQuotationEndDelimiterKey];
  • 使用区域敏感的引号形成字符串
quotedString = [NSString stringWithFormat:@"%@%@%@", bQuote, myText, eQuote];

Table 4-2展示了不用区域,当myText“@iPhone”的不同结果。

Table 4-2 Quotes in China, France, and Japan

Formatting Strings - 格式字符串

如果可用,请为面向用户的文本使用替代的,区域敏感的NSString方法。 有语言环境敏感的方法来创建带格式的字符串,更改大小写,获取字符串的range以及比较字符串。

1. Creating Formatted Strings - 创建格式字符串

至少,在NSString类中使用localizedStringWithFormat:方法,而不是使用stringWithFormat:方法来格式化面向用户的文本。 对现有代码的一个简单修复就是在整个代码中用替代的localizedStringWithFormat:方法替换stringWithFormat:方法的出现,如下所示:

NSString *localizedString = [NSString localizedStringWithFormat:@"%3.2f", myNumber];

此方法使用系统区域设置。 要指定用户的区域设置首选项,请将[NSLocale currentLocale]作为区域设置参数传递给initWithFormat:locale:initWithFormat:locale:arguments:方法。 为了获得最佳结果,请使用Formatting Dates and Times以及Formatting Numbers中所述的数据特定格式化程序对象和预设样式。

2. Changing the Case of Strings - 更改字符串的大小写

在字符串中更改大小写的过程对于所有语言都不相同。 使用这些区域敏感的NSString方法来更改大小写:

如果您将nil作为区域设置参数传递,则会使用系统区域设置,这是不正确的。 要指定用户的区域首选项,请将[NSLocale currentLocale]作为语言环境参数传递。


Formatting Dates and Times - 格式化日期和时间

您可以使用NSDateFormatter类创建也是区域设置敏感的NSDate对象的本地化字符串表示。 NSDateFormatter对象通常直接附加到Interface Builder文件中的文本字段,但如果以编程方式创建NSDateFormatter对象,请确保使用返回本地化字符串表示形式的方法。

注意:NSDateFormatter类不是线程安全的。 详情请参阅Threading Programming Guide

1. Using Preset Date and Time Styles - 使用预设日期和时间样式

要使用预设样式获取日期和时间的本地化字符串表示形式,请在NSDateFormatter类中使用localizedStringFromDate:dateStyle:timeStyle:类方法:

NSString *localizedDateTime = [NSDateFormatter localizedStringFromDate:[NSDate date] dateStyle:NSDateFormatterMediumStyle timeStyle:NSDateFormatterShortStyle];

例如,通过将NSDateFormatterMediumStyle作为style参数传递,指定一个中等样式来缩写文本(例如Jun 10, 2013)。 通过将NSDateFormatterShortStyle作为style参数传递,为仅限数字的表示(例如6/10/1311:03 AM)指定短样式。 Table 4-3显示了当英语是该语言且美国是该地区时使用预设格式的结果。

Table 4-3 Preset date and time styles in English for the United States

Table 4-4显示了针对日期样式传递NSDateFormatterMediumStyle以及针对不同语言和区域传递时间样式的NSDateFormatterShortStyle的结果。

Table 4-4 Preset date and time styles in different languages and regions

日期:WWDC 2013 Making Your App World-Ready: Data Formatting > Preset Date Styles

2. Using Custom Date and Time Styles - 使用自定义日期和时间样式

仅当预设样式不符合您的需要时才使用自定义日期和时间样式。 但是,在获取日期和时间的字符串表示之前,请将自定义格式转换为区域敏感的格式。 NSDateFormatter类中的dateFormatFromTemplate:options:locale:方法重新排列给定的模板以符合指定的区域。

To get a localized string representation of a date and time using a custom style - 使用自定义样式获取日期和时间的本地化字符串表示形式

NSDateFormatter *dateFormatter = [NSDateFormatter new];
NSString *localeFormatString = [NSDateFormatter dateFormatFromTemplate:@"dMMM" options:0 locale:dateFormatter.locale];

dateFormatFromTemplate:options:locale:方法的模板参数应遵循Unicode Technical Standard #35,如Use Format Strings to Specify Custom Formats中所述。 例如,template @“dMMM”指定月份的日期和月份的缩写应该在格式字符串中。 模板中符号和任何非符号字符的顺序都将被忽略。

  • NSDateFormatter实例的格式设置为区域设置敏感的格式字符串。
dateFormatter.dateFormat = localeFormatString;
  • 使用stringFromDate:方法获取日期的本地化字符串表示形式。
NSString *localizedString = [dateFormatter stringFromDate:[NSDate date]];

例如,如果您不将@“MMM d”字符串转换为区域设置敏感格式,则结果不是本地化的,如表4-5中的第二列所示

Table 4-5 Non-localized and localized date formats in different regions

视频:WWDC 2013 Making Your App World-Ready: Date Formatting > Custom Date and Time Styles

3. Parsing Localized Date Strings - 解析本地日期字符串

用户使用本地化格式输入日期,因此相应地解析输入字符串。 使用NSDateFormatter对象将本地化的字符串转换为日期对象。 使用其中一种预设样式设置日期格式化器的样式。 (仅当预设样式不起作用时才使用模板格式字符串。)另外,允许日期格式化程序在解析字符串时使用启发式。

To convert a localized date string to a date object - 将本地化的日期字符串转换为日期对象

  • 创建日期格式对象
NSDateFormatter *dateFormatter = [NSDateFormatter new];
  • 设置日期格式样式为预设样式
dateFormatter.dateStyle = NSDateFormatterMediumStyle;

NSDateFormatterMediumStyle替换为您希望用户输入的样式。

  • 如果输入字符串不包含时间,请将时间样式设置为无。
dateFormatter.timeStyle = NSDateFormatterNoStyle;
  • leniency设置为YES(启用heuristics)。
dateFormatter.lenient = YES;
  • 将字符串转化为日期
NSDate *date = [dateFormatter dateFromString:inputString];

例如,如果区域为美国,输入字符串为9/3/14,预设样式为NSDateFormatterShortStyle,则日期解释为2014-09-03 07:00:00 +0000。 但是,如果区域设置为德国,则日期变为2014-03-09 08:00:00 +0000


Formatting Numbers - 格式化数字

区域设置会影响数字的格式,例如小数,千位分隔符,货币和百分比符号。 例如,意大利的数字1,234.56被格式化为1.234,56。 因此,使用NSNumberFormatter类来创建NSNumber对象的本地化字符串表示。

注意:NSNumberFormatter类不是线程安全的。 详情请参阅Threading Programming Guide

1. Using Preset Number Styles - 使用预设数组样式

要使用预设样式获取数字的本地化字符串表示形式,请在NSNumberFormatter类中使用localizedStringFromNumber:numberStyle:方法:

表4-6列出了可用的预设样式,并将美国预设格式与其他区域进行比较

Table 4-6 Preset number styles in different languages and regions

视频:WWDC 2013 Making Your App World-Ready: Number Formatting

2. Parsing Localized Number Strings - 解析本地数字字符串

用户可以使用本地化的格式输入数字,因此可以相应地解析这些输入字符串。 使用NSNumberFormatter对象将字符串转换为数字对象。 使用其中一种预设样式设置数字格式化程序的样式。 另外,允许数字格式化程序在解析字符串时使用启发式。

To convert a localized number string to a number object - 将本地化的数字字符串转换为数字对象

  • 创建一个数字格式化对象
NSNumberFormatter *numberFormatter = [NSNumberFormatter new];
  • 将格式化样式设置为预设样式
numberFormatter.numberStyle = NSNumberFormatterDecimalStyle;

NSNumberFormatterDecimalStyle
替换为您希望用户输入的样式。

  • 设置leniency为YES(启用heuristics)
numberFormatter.lenient = YES;
  • 将字符串转化为数字对象
NSNumber *number = [numberFormatter numberFromString:inputString];

Computing Dates Using Calendars - 使用日历计算日期

NSCalendar类封装了日历的所有区域差异和复杂性,如表4-7所示。 era在某些日历上的变化比其他日历上更频繁 - 例如,日历中的era随着每个新皇帝的变化而变化。 每年的月数可以是12或13个月。每个月的时间长短可能会有所不同。 即使在公历中,一周的第一天可能是周六,周日或周一。 NSCalendar对象了解时区以及哪些区域可以观察夏令时。 日历计算(如本月的第三个星期二)取决于用户的日历和地区。

Table 4-7 Variations in regional calendars

因此,对所有日历计算使用NSCalendar类,例如计算一个月中的天数,计算增量值以及获取日期的组件。 您可以使用NSDate对象进行内部计算,但使用NSCalendar对象计算面向用户的日期。

要获取用户区域设置的日历,请在NSCalendar类中使用currentCalendar类的方法:

NSCalendar *currentCalendar = [NSCalendar currentCalendar];

使用NSDateComponents对象获取date的calendar units

To get the components of a date - 获取date的组成

NSDateComponents *components = [[NSCalendar currentCalendar]
    components:NSDayCalendarUnit | NSMonthCalendarUnit | NSYearCalendarUnit | NSEraCalendarUnit
    fromDate:[NSDate date]];
  • 获取时代、年、月和日的值。
NSInteger day = [components day];
NSInteger month = [components month];
NSInteger year = [components year];
NSInteger era = [components era];

提示:任何时候您获取或设置年份,也可以获取或设置era。 Era不是Gregorian calendar所必需的,但它对于其他几种日历是必须的。

有关使用NSCalendarNSDateComponents类的更多信息,请阅读Date and Time Programming Guide或观看WWDC 2013: Solutions to Common Date and Time Challenges


Registering for Locale and Time Zone Changes - 注册区域和时区更改

要接收区域设置更改通知,请将您的对象添加为NSCurrentLocaleDidChangeNotification通知的观察者:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(localeDidChange :) name:NSCurrentLocaleDidChangeNotification object:nil];

要接收时区更改的通知,请观察NSSystemTimeZoneDidChangeNotification通知。 例如,如果用户在旅行,则在您的应用运行时,时区可能会发生变化。 自上次您的应用程序处于活动状态以来可能会过去很长一段时间。

实施更改通知方法,以使用用户的新区域设置重新格式化并显示所有面向用户的日期,时间和数字。

后记

本篇主要介绍了使用区域设置格式化数据,感兴趣的给个赞或者关注,谢谢~~~~

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,045评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,114评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,120评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,902评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,828评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,132评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,590评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,258评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,408评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,335评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,385评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,068评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,660评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,747评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,967评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,406评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,970评论 2 341

推荐阅读更多精彩内容