Updates to iOS localization docs (#35)

* Updated **Info.plist** section of /docs/ios/app-fundamentals/localization/index.md

* Clarifications

* Simplification

* Made Settings bold everywhere

* Updating some code fences

* PR fixes

* Added a missing period

* A bit more cleanup on the localization doc: removing some commented-out content, fixing a reference to Apple's Xcode release notes

* Fixing some formatting
This commit is contained in:
Brad Umbaugh 2018-03-09 17:09:10 -07:00 коммит произвёл Craig Dunn
Родитель 91c984e575
Коммит 314f8935aa
1 изменённых файлов: 106 добавлений и 134 удалений

Просмотреть файл

@ -25,53 +25,48 @@ This section describes some of the localization features in iOS. Skip to the
### Language
Users choose their language in the **Settings** app. This setting affects the
language strings and images displayed by the operating system as well as applications
that detect language settings.
language strings and images displayed by the operating system and in apps.
This is where users will decide whether they want to see English, Spanish,
Japanese, French or other language displayed in their apps.
The actual list of supported languages in iOS 7 is:
English (U.S.), English (UK), Chinese (Simplified), Chinese (Traditional), French, German, Italian, Japanese, Korean, Spanish, Arabic, Catalan, Croatian, Czech, Danish, Dutch, Finnish, Greek, Hebrew, Hungarian, Indonesian, Malay, Norwegian, Polish, Portuguese, Portuguese (Brazil), Romanian, Russian, Slovak, Swedish, Thai, Turkish, Ukrainian, Vietnamese, English (Australian), Spanish (Mexican).
The current language can be queried by accessing the first element of the `PreferredLanguages` array:
To determine the language being used in an app, get the first element
of `NSBundle.MainBundle.PreferredLocalizations`:
```csharp
var lang = NSBundle.MainBundle.PreferredLocalizations[0];
```
This value will be a language code such as `en` for English, `es` for Spanish,
`ja` for Japanese, etc. _The value returned is restricted to one of the localizations supported by the application (using fallback rules to determine the best match)._
`ja` for Japanese, etc. The value returned is restricted to one of the
localizations supported by the application (using fallback rules to
determine the best match).
Application code does not always need to check for this value - Xamarin and iOS both
Application code does not always need to check for this value Xamarin and iOS both
provide features that help to automatically provide the correct string or resource
for the user's language. These features are described in the remainder of this document.
> [!NOTE]
> **NOTE:** Prior to iOS 9, the recommended code was `var lang = NSLocale.PreferredLanguages [0];`.
>
> The results returned by this code changed in iOS 9 - see [Technical Note TN2418](https://developer.apple.com/library/content/technotes/tn2418/_index.html) for more information.
>
> You can continue to use `NSLocale.PreferredLanguages [0]` to determine the
> actual values selected by the user (regardless of the localizations your app supports).
> Use `NSLocale.PreferredLanguages` to determine the user's language
> preferences, regardless of the localizations supported by
> the app. The values returned by this method changed in iOS 9; see
> [Technical Note TN2418](https://developer.apple.com/library/content/technotes/tn2418/_index.html)
> for details.
### Locale
Users choose their locale in the **Settings** app. This setting affects the way
that dates, times, numbers and currency are formatted.
that dates, times, numbers, and currency are formatted.
This lets users choose whether they see 12 hour or 24 hour time formats, whether
This lets users choose whether they see 12-hour or 24-hour time formats, whether
their decimal separator is a comma or a point, and the order of day, month and
year in date display.
With Xamarin you have access to both Apples iOS classes (`NSNumberFormatter`) as
well as the .NET classes in System.Globalization. Developers should evaluate
which is better suited to their needs, as there are different features available
in each. In particular, if you are retrieving and displaying In App Purchase
prices using StoreKit you should definitely use Apples formatting classes for
in each. In particular, if you are retrieving and displaying In-App Purchase
prices using StoreKit you should use Apples formatting classes for
the price information returned.
The current locale can be queried by either:
The current locale can be queried by either of two ways:
- `NSLocale.CurrentLocale.LocaleIdentifier`
- `NSLocale.AutoUpdatingCurrentLocale.LocaleIdentifier`
@ -80,12 +75,11 @@ The first value can be cached by the operating system and so might not always
reflect the users currently selected locale. Use the second value to obtain the
currently selected locale.
### NSCurrentLocaleDidChangeNotification
iOS generates an `NSCurrentLocaleDidChangeNotification` when the user updates
their locale. Applications can listen for this notification while they are
running, and make appropriate changes to the UI.
running and can make appropriate changes to the UI.
<a name="basics" />
@ -95,29 +89,70 @@ The following features of iOS are easily leveraged in Xamarin to provide
localized resources for display to the user. Refer to the [TaskyL10n sample](https://github.com/conceptdev/xamarin-samples/tree/master/TaskyL10n)
to see how to implement these ideas.
### Info.plist
### Specifying default and supported languages in Info.plist
Before you begin, configure the **Info.plist** file with the following keys:
In [Technical Q&A QA1828: How iOS Determines the Language For Your App](https://developer.apple.com/library/content/qa/qa1828/_index.html),
Apple describes how iOS selects a language to use in an app. The following
factors impact which language is displayed:
- `CFBundleDevelopmentRegion` - the default language for the application (typically
the language spoken by the developers, and used in the storyboards and string and
image resources). In the example below, **en** (for English) is specified.
- `CFBundleLocalizations` - an array of other localizations supported by the
application, also using langauge codes like **es** (Spanish) and **pt-PT**
(Portuguese spoken in Portugal).
- The user's preferred languages (found in the **Settings** app)
- The localizations bundled with the app (.lproj folders)
- `CFBundleDevelopmentRegion` (**Info.plist** value specifying the default
language for the app)
- `CFBundleLocalizations` (**Info.plist** array specifying all supported
localizations)
As indicated in the Technical Q&A, `CFBundleDevelopmentRegion` represents an
app's default region and language. If the app doesn't explicitly support any
of a user's preferred languages, it will use the language specified by this
field.
> [!IMPORTANT]
> iOS 11 applies this language selection mechanism more strictly than did
> previous versions of the operating system. Because of this, any iOS 11 app
> that does not explicitly declare its supported localizations – either by
> including .lproj folders or setting a value for `CFBundleLocalizations`
> may display a different language in iOS 11 than it did in iOS 10.
If `CFBundleDevelopmentRegion` has not been specified in the **Info.plist**
file, the Xamarin.iOS build tools currently use a default value of
`en_US`. While this may change in a future release, it means that the
default language is English.
To ensure that your app selects an expected language, take the following
steps:
- Specify a default language. Open **Info.plist** and use the **Source**
view to set a value for the `CFBundleDevelopmentRegion` key; in XML, it
should look similar to the following:
```xml
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<string>es</string>
```
This example uses “es” to specify that when none of a users preferred
languages are supported, default to Spanish.
- Declare all supported localizations. In **Info.plist**, use the
**Source** view to set an array for the `CFBundleLocalizations` key; in
XML, it should look similar to the following:
```xml
<key>CFBundleLocalizations</key>
<array>
<string>de</string>
<string>es</string>
<string>ja</string>
...
<string>en</string>
<string>es</string>
...
</array>
```
Xamarin.iOS apps that have been localized using .NET mechanisms such as
.resx files must provide these **Info.plist** values as well.
For more information about these **Info.plist** keys, take a look at Apple's
[Information Property List Key Reference](https://developer.apple.com/library/content/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html).
### LocalizedString method
The `NSBundle.MainBundle.LocalizedString` method looks up localized text
@ -133,10 +168,10 @@ organized by language, in specially named directories with an **.lproj** suffix.
There can be a number of different **.strings** files in each language directory:
- **Localizable.strings** - the main list of localized text.
- **InfoPlist.strings** - certain specific keys are allowed in this file to
translate things like the application name.
- **<storyboard-name>.strings** - optional file that contains translations
- **Localizable.strings** the main list of localized text.
- **InfoPlist.strings** certain specific keys are allowed in this file to
translate things such as the application name.
- **<storyboard-name>.strings** optional file that contains translations
for user interface elements in a storyboard.
The **Build Action** for these files should be **Bundle Resource**.
@ -145,7 +180,7 @@ The **Build Action** for these files should be **Bundle Resource**.
The syntax for localized string values is:
```csharp
```console
/* comment */
"key"="localized-value";
```
@ -158,7 +193,7 @@ You should escape the following characters in strings:
This is an example **es/Localizable.strings** (ie. Spanish) file from the sample:
```csharp
```console
"<new task>" = "<new task>";
"Task Details" = "Detalles de la tarea";
"Name" = "Nombre";
@ -197,7 +232,7 @@ Use the standard naming conventions for the launch images (and the XIB or
Storyboard for iPhone 6 models) when placing them in
the **.lproj** directories for each language.
```csharp
```console
Default.png
Default@2x.png
Default-568h@2x.png
@ -209,7 +244,7 @@ LaunchScreen.xib
Placing an **InfoPlist.strings** file in an **.lproj** directory lets you
override some values from the app's **Info.plist**, including the application name:
```csharp
```console
"CFBundleDisplayName" = "LeónTodo";
```
@ -219,32 +254,6 @@ Other keys that you can use to [localize application-specific strings](https://d
- CFBundleShortVersionString
- NSHumanReadableCopyright
<!--
## App icon
Does not seem to be possible (although it definitely used to be!).
-->
### Localization Native Development Region
The default strings (located in the **Base.lproj** folder) will be assumed
to be the fallback language. This means that if a translation is requested in
the code and is not found for a the current language, the **Base.lproj** folder will
be searched for the default string to use (if no match is found, the translation
identifier string itself is displayed).
Developers can choose a different language to be the fallback by setting the
plist key `CFBundleDevelopmentRegionKey`. Its value should be set to the language
code for the native development language. This screenshot shows a plist in Xamarin
Studio with the Native Development Region set to Spanish (es):
![](images/cfbundledevelopmentregion.png "InfoPList.strings property")
If the default language used in your storyboards and throughout your code is not
English, set this value to reflect the native language being
used throughout the app code.
### Dates and Times
Although it is possible to use the built-in .NET date and time functions
@ -272,7 +281,7 @@ Debug.WriteLine ("Medium,None: " + df.StringFor(date));
Results for English in the United States:
```csharp
```console
Full,Long: Friday, August 7, 2015 at 10:29:32 AM PDT
Short,Short: 8/7/15, 10:29 AM
Medium,None: Aug 7, 2015
@ -280,7 +289,7 @@ Medium,None: Aug 7, 2015
Results for Spanish in Spain:
```csharp
```console
Full,Long: viernes, 7 de agosto de 2015, 10:26:58 GMT-7
Short,Short: 7/8/15 10:26
Medium,None: 7/8/2015
@ -295,16 +304,17 @@ date and time formatting, check both **iPhone Language** and **Region** settings
iOS provides a number of features to assist in building RTL-aware apps:
* Use **Auto-Layout** `leading` and `trailing` attributes for control aligment
(which corresponds to *left* and *right* for English, for example, but is reversed for RTL languages).
* Use auto layout's `leading` and `trailing` attributes for control aligment
(which corresponds to left and right for English, but is reversed for RTL languages).
The [`UIStackView`](~/ios/user-interface/controls/uistackview.md)
control is particularly useful for laying out controls to be RTL-aware.
* Use `TextAlignment = UITextAlignment.Natural` for text alignment (which will be *left*
for most languages but *right* for RTL).
* Use `TextAlignment = UITextAlignment.Natural` for text alignment (which will be left
for most languages but right for RTL).
* `UINavigationController` automatically flips the back button and reverses swipe direction.
The following screenshots show the [localized **Tasky** sample](https://github.com/conceptdev/xamarin-samples/tree/master/TaskyL10n) in Arabic and Hebrew (although
English has been entered in the fields):
The following screenshots show the
[localized Tasky sample](https://github.com/conceptdev/xamarin-samples/tree/master/TaskyL10n)
in Arabic and Hebrew (although English has been entered in the fields):
[![](images/rtl-ar-sml.png "Localization in Arabic")](images/rtl-ar.png#lightbox "Arabic")
@ -315,7 +325,6 @@ are placed inside `UIStackView` or aligned with Auto-Layout.
RTL text is localized using **.strings** files in the same
way as LTR text.
<a name="code"/>
## Localizing the UI in Code
@ -326,19 +335,17 @@ built in code (rather than XIBs or storyboards).
### Project Structure
![](images/solution-code.png "Resources tree")
### Localizable.strings file
As described above, the **Localizable.strings** file format
consists of key-value pairs, where the key is a user-selected string that
indicates
consists of key-value pairs. The key describes the intent of the string
and the value is the translated text to be used in the app.
The Spanish (**es**) localizations for the sample are shown below:
```csharp
```console
"<new task>" = "<new task>";
"Task Details" = "Detalles de la tarea";
"Name" = "Nombre";
@ -388,10 +395,11 @@ have been localized, to override the one present in **Base.lproj**.
When creating and editing controls in a storyboard, select each control
and check the ID to use for localization:
* in Visual Studio for Mac, it's located in the Properties pad and called **Localization ID**.
* in Xcode, it's called **Object ID**.
* In Visual Studio for Mac, it's located in the **Properties Pad** and is called **Localization ID**.
* In Xcode, it's called **Object ID**.
It is a string value that often has a form like **"NF3-h8-xmR"**:
This string value often has a form such as "NF3-h8-xmR", as shown in the
following screenshot:
![](images/xs-designer-localization-id.png "Xcode view of Storyboard localization")
@ -408,7 +416,7 @@ In the example **Mainstoryboard.strings** below you can see `UITextField`s have
a `placeholder` text property that can be localized; `UILabel`s have a `text`
property; and `UIButton`s default text is set using `normalTitle`:
```csharp
```console
"SXg-TT-IwM.placeholder" = "nombre de la tarea";
"Pqa-aa-ury.placeholder"= "otra información de tarea";
"zwR-D9-hM1.text" = "Detalles de la tarea";
@ -419,38 +427,17 @@ property; and `UIButton`s default text is set using `normalTitle`:
```
> [!IMPORTANT]
> **Using a storyboard with Size Classes** may result in the translations
not appearing. This is probably related to [this issue](http://stackoverflow.com/questions/24989208/xcode-6-does-not-localize-interface-builder)
where Apple's documentation says:
> Localization A storyboard or XIB will not localize correctly if all of the following three conditions are true: The storyboard or XIB uses size classes. The base localization and the build target are set to Universal. The build targets iOS 7.0.
> The fix is to duplicate your storyboard strings file into two identical files: **MainStoryboard~iphone.strings**
and **MainStoryboard~ipad.strings**:
> Using a storyboard with size classes may result in translations that do
> not appear in the application. [Apple's Xcode Release Notes](https://developer.apple.com/library/content/releasenotes/DeveloperTools/RN-Xcode/Chapters/Introduction.html)
> indicate that a storyboard or XIB will not localize correctly if three things
> are true: it uses size classes, the base localization and the build target
> are set to Universal, and the build targets iOS 7.0. The fix is to
> duplicate your storyboard strings file into two identical files:
> **MainStoryboard~iphone.strings** and **MainStoryboard~ipad.strings**, as
> shown in the following screenshot:
>
> ![](images/xs-dup-strings.png "Strings files")
<!--
# Native Formatting
Xamarin.iOS applications can take advantage of the .NET framework's formatting options for localizing
numbers and dates.
### Date string formatting
https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/DataFormatting/Articles/dfDateFormatting10_4.html#//apple_ref/doc/uid/TP40002369-SW1
NSDateFormatter formatter = new NSDateFormatter ();
formatter.DateFormat = "MMMM/dd/yyyy";
NSString dateString = new NSString (formatter.ToString (d));
### Number formatting
https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/DataFormatting/Articles/dfNumberFormatting10_4.html#//apple_ref/doc/uid/TP40002368-SW1
-->
<a name="appstore" />
## App Store listing
@ -460,20 +447,6 @@ to enter translations for each country your app is on sale. Note their warning
that the translations will only appear if your app also contains a localized
**.lproj** directory for the language.
<!--
Once youve entered your application into iTunes Connect the default language
metadata and screenshots will appear as shown:
![]( "itunes connect 1")
Use the language list on the right to select other languages to provide
translated application name, description, search keywords, URLs and screenshots.
The complete list of languages is shown in this screenshot:
![]( "itunes connect 2")
-->
## Summary
This article covers the basics of localizing iOS applications using the built-in
@ -482,7 +455,6 @@ resource handling and storyboard features.
You can learn more about i18n and L10n for iOS, Android and cross-platform apps
(including Xamarin.Forms) in [this cross-platform guide](~/cross-platform/app-fundamentals/localization.md).
## Related Links
- [Tasky (localized in code) (sample)](https://github.com/conceptdev/xamarin-samples/tree/master/TaskyL10n)