SlideShare a Scribd company logo
Localizing Mobile Apps
Daniel Schneller, CenterDevice GmbH
Agenda
I18N vs. L10N
Languages and Regions
Text
Date and Time
Numbers
Images and other Resources
https://github.com/dschneller/I18N-Example
I18N vs. L10N
I18N
L10N
I — 18 Characters — N
L-10 Characters-N
Internationalization
I — 18 Characters — N
Localization
L-10 Characters-N
Internationalization
Internationalization
[…] process of designing a software application so that it
can potentially be adapted to various languages and
regions without engineering changes. […]*
* Wikipedia
Localization
Localization
[…] the process of adapting internationalized software for
a specific region or language by adding locale-specific
components and translating text. […]*
* Wikipedia
Localizing Mobile Apps
I18N L10NApp
Localized

App
!"#$%&!
! 🌐 🌐 !"#
$%&
Languages and Regions
Languages and Regions
Language ≠ Region
12h time used by an American living in Germany
„Jänner“ – „Januar“ [German in Austria vs. in Germany for January]
Localization ≠ Locale
German user might prefer English user interface texts
But: 24h time display
Languages and Regions
Languages and Regions
Languages and Regions
Languages and Regions
Scheme Launch Arguments
-AppleLanguages (ar,de,fr)
Order determines preference
-AppleLocale en_US
NSLocale
Encapsulates Region Settings
+ (id)autoupdatingCurrentLocale

+ (id)currentLocale
NSCurrentLocaleDidChangeNotification
[[NSNotificationCenter defaultCenter]

addObserver:self

selector:@selector(localeDidChange:)

name:NSCurrentLocaleDidChangeNotification

object:nil]
Refresh formatters, caches NSLocale instances
Refresh screen content
NSLocale
-[NSLocale objectForKey:]
NSString* NSLocaleIdentifier NSString* NSLocaleMeasurementSystem
NSString* NSLocaleLanguageCode NSString* NSLocaleDecimalSeparator
NSString* NSLocaleCountryCode NSString* NSLocaleGroupingSeparator
NSString* NSLocaleScriptCode NSString* NSLocaleCurrencySymbol
NSString* NSLocaleVariantCode NSString* NSLocaleExemplarCharacterSet
NSString* NSLocaleCurrencyCode NSString* NSLocaleCollatorIdentifier
NSString* NSLocaleCalendar NSString* NSLocaleQuotationBeginDelimiterKey
NSString* NSLocaleCollationIdentifier NSString* NSLocaleQuotationEndDelimiterKey
NSString* NSLocaleUsesMetricSystem
NSLocale
Does not contain the current language!
Locale ≠ Localization
[NSBundle mainBundle].localizations; // NSArray, (all)
[NSBundle mainBundle].preferredLocalizations[0]; // (current)
Caveats
Localizations of InfoPlist.strings determine content of „localizations“
Intersected with user’s region preferences in Settings.app
AppleLanguages launch parameter
Text
Localizing Mobile Apps
Localizing Mobile Apps
Text ≠ Text
Language of messages, buttons, labels etc.
Writing direction & alignment
Writing systems (Latin, Hebrew, Arabic…)
Numbers in text
Names & addresses
Phrases, idioms and terminology
Plurals
Sorting
…
Text ≠ Text
Language of messages, buttons, labels etc.
Writing direction & alignment
Writing systems (Latin, Hebrew, Arabic…)
Numbers in text
Names & addresses
Phrases, idioms and terminology
Plurals
Sorting
…
Base Localization
Base Localization
One leading (base)
language
Base Localization
One leading (base)
language
Add Localization
Base Localization
One leading (base)
language
Add Localization
Base Localization
One leading (base)
language
Add Localization
“.strings”files
Base Localization
One leading (base)
language
Add Localization
“.strings”files
genstrings
Base Localization
One leading (base)
language
Add Localization
“.strings”files
genstrings
ibtool
Base Localization
One leading (base)
language
Add Localization
“.strings”files
genstrings
ibtool
One copy per language
Base Localization
One leading (base)
language
Add Localization
“.strings”files
genstrings
ibtool
One copy per language
“.lproj”Ordner
Base Localization
Eine Leitsprache (Base)
“.strings”Files
genstrings
ibtool
Eine Kopie pro Sprache
“.lproj”Ordner
Base Localization
Eine Leitsprache (Base)
“.strings”Files
genstrings
ibtool
Eine Kopie pro Sprache
“.lproj”Ordner
Base Localization
Eine Leitsprache (Base)
“.strings”Files
genstrings
ibtool
Eine Kopie pro Sprache
“.lproj”Ordner
Base Localization
…
/* Class = "IBUILabel"; text = "Loaded by SecondViewController"; ObjectID =
"NDk-cv-Gan"; */
"NDk-cv-Gan.text" = "Loaded by SecondViewController";
"
/* Class = "IBUILabel"; text = "First View"; ObjectID = "KQZ-1w-vlD"; */
"KQZ-1w-vlD.text" = "First View";
…
Base Localization
Preview in Assistant Editor
Xcode 6: Pick Language
Double-Length Pseudo-
Language
Auto Layout
NSLocalizedString
Family of macros
NSLocalizedString

NSLocalizedStringFromTable

NSLocalizedStringFromTableInBundle

NSLocalizedStringWithDefaultValue
Access “.strings”files
Utilize NSBundle
-[[NSBundle mainBundle] localizedStringForKey:value:table:]
NSLocalizedString
Example
[button setTitle:NSLocalizedString(@"reset.counter.button.title", 

@"Reset Counter action button")

forState:…];
genstrings — Localizable.strings
/* Reset Counter action button */

"reset.counter.button.title" = "Zurücksetzen";
.strings Files
Updates?
.strings Files
Updates?
Use ibtool every time you update your labels and text.

In the Base.lproj folder:



ibtool ChangedNib.xib --generate-strings-
file NewStrings.strings



Open the generated output file and copy all new string
entries to ChangedNib.strings in each lproj.
#fail
Do not normalize text
Do not normalize text
DRY! — Do Repeat Yourself
[NSString stringWithFormat:@”…”]
Do not normalize text
DRY! — Do Repeat Yourself
[NSString stringWithFormat:@”…”]
Localizable.strings
“count” = “Anzahl”
“game” = “Spiel”
“reset” = “zurücksetzen”
“save” = “sparen”
“thumbnail” = “Daumennagel”
Do not normalize text
DRY! — Do Repeat Yourself
[NSString stringWithFormat:@”…”]
Localizable.strings
“count” = “Anzahl”
“game” = “Spiel”
“reset” = “zurücksetzen”
“save” = “sparen”
“thumbnail” = “Daumennagel”
“reset count”
”zurücksetzen Anzahl”
“save game”
“sparen Spiel”
…
Do not normalize text
Do not normalize text
Context and grammar are lost
Do not normalize text
Context and grammar are lost
Structure of sentences
Do not normalize text
Context and grammar are lost
Structure of sentences
Declination & conjugation …
Do not normalize text
Context and grammar are lost
Structure of sentences
Declination & conjugation …
Use dedicated strings per use case
Do not normalize text
Context and grammar are lost
Structure of sentences
Declination & conjugation …
Use dedicated strings per use case
“reset.counter.button” = “Auf 0 stellen”
Do not normalize text
Context and grammar are lost
Structure of sentences
Declination & conjugation …
Use dedicated strings per use case
“reset.counter.button” = “Auf 0 stellen”
Context for translators
Do not normalize text
Context and grammar are lost
Structure of sentences
Declination & conjugation …
Use dedicated strings per use case
“reset.counter.button” = “Auf 0 stellen”
Context for translators
Use self explanatory keys
Do not normalize text
Context and grammar are lost
Structure of sentences
Declination & conjugation …
Use dedicated strings per use case
“reset.counter.button” = “Auf 0 stellen”
Context for translators
Use self explanatory keys
Provide useful comments (button vs. label, approx. length, etc.)
Variables
Parameters
[NSString stringWithFormat:

NSLocalizedString(@"click.counter.label",

@"P1: Current Click Count."),

self.clickCount]
"
/* P1: Current Click Count. */

"click.counter.label" = "%1d x geklickt”;
Variables
Document parameter order!
“Zeige 4 von 12 gesamt”
“Total 12 — Showing 4”
/* … Param 1: current page; Param 2: total count */

"current.page.label" = “Zeige %1d von %2d gesamt”;



/* … Param 1: current page; Param 2: total count */

"current.page.label" = “Total %2d — Showing %1d”;
Special cases: 0 and 1
Plurals
Englisch German
0 No books Keine Bücher
1 One book Ein Buch
sonstiges 100 books 100 Bücher
Localizable.strings
“books.0” = “No Books”
“books.1” = “One Book”
“books.n” = “%1d books”
“books.0” = “Keine Bücher”
“books.1” = “Ein Buch”
“books.n” = “%1d Bücher”
If-else-clause in the code: Problem solved.
Englisch Deutsch
0 No books Keine Bücher
1 1 book 1 Buch
Vielleicht nicht ganz…
Plural
Englisch Deutsch
0 No books Keine Bücher
1 1 book 1 Buch
2 2 books 2 Bücher
wenige 3 books 3 Bücher
viele 11 books 11 Bücher
sonstiges 100 books 100 Bücher
Vielleicht nicht ganz…
Plural
0
1
2
wenige
viele
sonstiges
Englisch
No books
1 book
2 books
3 books
11 books
100 books
German
Keine Bücher
1 Buch
2 Bücher
3 Bücher
11 Bücher
100 Bücher
Or is it…?
Plural
0
1
2
wenige
viele
sonstiges
Englisch
No books
1 book
2 books
3 books
11 books
100 books
German
Keine Bücher
1 Buch
2 Bücher
3 Bücher
11 Bücher
100 Bücher
Arabic
‫كتاب‬ ٠
‫كتاب‬
‫كتابان‬
‫كتب‬ ٣
‫ا‬ً‫ب‬‫كتا‬ ١١
‫كتاب‬ ١٠٠
Or is it…?
Plural
.strings + .stringsdict
* http://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html#ar
.strings + .stringsdict
Available since iOS7
* http://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html#ar
.strings + .stringsdict
Available since iOS7
Implements (Unicode*) localization rules for
Plural
Gender [rdar://16670931]
* http://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html#ar
.strings + .stringsdict
Available since iOS7
Implements (Unicode*) localization rules for
Plural
Gender [rdar://16670931]
Plist Format
Name must match .strings
.strings must exist, but may be empty
* http://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html#ar
.strings + .stringsdict
https://developer.apple.com/library/ios/releasenotes/Foundation/↩︎
RN-Foundation/index.html#//apple_ref/doc/uid/TP30000742-CH2-SW56
<dict>

    <key>files.selected.label.%d</key>

    <dict>

        <key>NSStringLocalizedFormatKey</key>

<string>%#@num_files_are@ selected</string>

        <key>num_files_are</key>

 <dict>

            <key>NSStringFormatSpecTypeKey</key>

<string>NSStringPluralRuleType</string>

            <key>NSStringFormatValueTypeKey</key>

<string>d</string>

            <key>zero</key>    <string>No file is</string>

            <key>one</key>     <string>A file is</string>

            <key>other</key>   <string>%d files are</string>

        </dict>

    </dict>

</dict>
.stringsdict
Categories per language according to Unicode
iOS additionally supports„zero“ category for all languages
Others, e. g.„few“, depend on language
String Tables
Localizable.strings
Default used by NSLocalizedString()
Big projects — big file
Can be split
NSLocalizedStringFromTable(“MyController”,“Key”,“Comment”)
MyController.strings
Project structure — Context for translators
3rd party code
Also works for .stringsdict
Date and Time
Date and Time NSDateFormatter
Date and Time
Transforms between NSDate and NSString
+[NSDateFormatter localizedStringFromDate:dateStyle:timeStyle:]

-[NSDateFormatter setLocale:]
NSDateFormatter
Date and Time
Transforms between NSDate and NSString
+[NSDateFormatter localizedStringFromDate:dateStyle:timeStyle:]

-[NSDateFormatter setLocale:]
NSDateFormatterStyle
NSDateFormatter
Date and Time
Transforms between NSDate and NSString
+[NSDateFormatter localizedStringFromDate:dateStyle:timeStyle:]

-[NSDateFormatter setLocale:]
NSDateFormatterStyle
German / Germany Englisch / USA
NSDateFormatter
Date and Time
Transforms between NSDate and NSString
+[NSDateFormatter localizedStringFromDate:dateStyle:timeStyle:]

-[NSDateFormatter setLocale:]
NSDateFormatterStyle
German / Germany Englisch / USA
Short 08.07.14 22:32 7/8/14,10:32 PM
NSDateFormatter
Date and Time
Transforms between NSDate and NSString
+[NSDateFormatter localizedStringFromDate:dateStyle:timeStyle:]

-[NSDateFormatter setLocale:]
NSDateFormatterStyle
German / Germany Englisch / USA
Short 08.07.14 22:32 7/8/14,10:32 PM
Medium 08.07.2014 22:32:36 Jul 8, 2014, 10:32:36 PM
NSDateFormatter
Date and Time
Transforms between NSDate and NSString
+[NSDateFormatter localizedStringFromDate:dateStyle:timeStyle:]

-[NSDateFormatter setLocale:]
NSDateFormatterStyle
German / Germany Englisch / USA
Short 08.07.14 22:32 7/8/14,10:32 PM
Medium 08.07.2014 22:32:36 Jul 8, 2014, 10:32:36 PM
Long 8. Juli 2014 22:32:36 MESZ Jul 8, 2014, 10:32:36 PM GMT+2
NSDateFormatter
Date and Time
Transforms between NSDate and NSString
+[NSDateFormatter localizedStringFromDate:dateStyle:timeStyle:]

-[NSDateFormatter setLocale:]
NSDateFormatterStyle
German / Germany Englisch / USA
Short 08.07.14 22:32 7/8/14,10:32 PM
Medium 08.07.2014 22:32:36 Jul 8, 2014, 10:32:36 PM
Long 8. Juli 2014 22:32:36 MESZ Jul 8, 2014, 10:32:36 PM GMT+2
Full Dienstag, 8. Juli 2014 12:32:36
Mitteleuropäische Sommerzeit
Tuesday, July 8, 2014 at 12:39:16 PM
Central European Summer Time
NSDateFormatter
Date and Time
Transforms between NSDate and NSString
+[NSDateFormatter localizedStringFromDate:dateStyle:timeStyle:]

-[NSDateFormatter setLocale:]
NSDateFormatterStyle
German / Germany Englisch / USA
Short 08.07.14 22:32 7/8/14,10:32 PM
Medium 08.07.2014 22:32:36 Jul 8, 2014, 10:32:36 PM
Long 8. Juli 2014 22:32:36 MESZ Jul 8, 2014, 10:32:36 PM GMT+2
Full Dienstag, 8. Juli 2014 12:32:36
Mitteleuropäische Sommerzeit
Tuesday, July 8, 2014 at 12:39:16 PM
Central European Summer Time
No - -
NSDateFormatter
Date and Time
NSDateFormatter.h
typedef enum {

NSDateFormatterNoStyle = …,

NSDateFormatterShortStyle = …,

NSDateFormatterMediumStyle = …,

NSDateFormatterLongStyle = …,

NSDateFormatterFullStyle = …

} NSDateFormatterStyle
Combine for date and time portions
NSDateFormatterNoStyle — only date / time
Get updated with the OS
NSDateFormatter
Date and Time NSDateFormatter
* http://www.unicode.org/reports/tr35/tr35-dates.html#Contents
Date and Time
What if defaults are not suitable?
NSDateFormatter
* http://www.unicode.org/reports/tr35/tr35-dates.html#Contents
Date and Time
What if defaults are not suitable?
Do not use hard coded format strings!
NSDateFormatter
* http://www.unicode.org/reports/tr35/tr35-dates.html#Contents
Date and Time
What if defaults are not suitable?
Do not use hard coded format strings!
Unicode Locale Data Markup Language*
NSDateFormatter
* http://www.unicode.org/reports/tr35/tr35-dates.html#Contents
Date and Time
What if defaults are not suitable?
Do not use hard coded format strings!
Unicode Locale Data Markup Language*
[f setDateFormat:[NSDateFormatter

dateFormatFromTemplate:@"u QQ" 

options:0

locale:LOCALE_EN_US]];



NSLog(@“%@", [f stringFromDate:july8th);
NSDateFormatter
* http://www.unicode.org/reports/tr35/tr35-dates.html#Contents
Date and Time
What if defaults are not suitable?
Do not use hard coded format strings!
Unicode Locale Data Markup Language*
[f setDateFormat:[NSDateFormatter

dateFormatFromTemplate:@"u QQ" 

options:0

locale:LOCALE_EN_US]];



NSLog(@“%@", [f stringFromDate:july8th);
Q3 2014
NSDateFormatter
* http://www.unicode.org/reports/tr35/tr35-dates.html#Contents
Relative formatting
[formatter setDoesRelativeDateFormatting:YES];



NSLog(@“%@, %@, %@…", [formatter stringFromDate:GESTERN],

[formatter stringFromDate:HEUTE],

[formatter stringFromDate:MORGEN]);

Gestern, Heute, Morgen… [de_DE]
Yesterday, Today, Tomorrow… [en_US]
Yesterday, Today, Tomorrow…
NSDateComponentsFormatter
Formats durations
[f stringFromTimeInterval:1234.0]) // seconds
About 20 minutes remaining
NSDateIntervalFormatter
Formats time intervals
[f stringFromDate:NOW toDate:LATER])
09.07.14 12:10-13:13
Coming up next: iOS8
Numbers
Numbers
Numbers
“Plain”Numbers
Numbers
MassDistance
LengthCurrency
Percentage
Data Volume
WeightEnergy
Spelled Out
“Plain”Numbers
Numbers
Decimal separators
Grouping characters
Currency symbols
…
"
NSNumberFormatter
API similar to NSDateFormatter
Numbers NSNumberFormatter
German / Germany English / USA
No 1234,56 1234.56
Decimal 1.234,56 1,234.56
Currency 1.234,56 € $1,234.56
Percent 123.456% 123,456%
Scientific 1,23456E+03 1.23456E3
SpellOut eintausendzweihundertvier-
unddreißig Komma fünf sechs
one thousand two hundred thirty-
four point five six
Numbers
NSNumberFormatter.h
enum {

NSNumberFormatterNoStyle = …,

NSNumberFormatterDecimalStyle = …,

NSNumberFormatterCurrencyStyle = …,

NSNumberFormatterPercentStyle = …,

NSNumberFormatterScientificStyle = …,

NSNumberFormatterSpellOutStyle = …

}

typedef NSUInteger NSNumberFormatterStyle
Numbers NSNumberFormatter
Numbers
NSNumberFormatter* f = [[NSNumberFormatter alloc] init];

f.numberStyle = NSNumberFormatterNoStyle;
f.locale = LOCALE_DE_AT;

NSLog(@"NoStyle de_AT: %@", [f stringFromNumber:@(1234.56)]);
f.locale = LOCALE_EN_US;

f.maximumFractionDigits = 2;

NSLog(@“NoStyle en_US: %@", [f stringFromNumber:@(1234.56)]);
NSNumberFormatter
Numbers
NSNumberFormatter* f = [[NSNumberFormatter alloc] init];

f.numberStyle = NSNumberFormatterNoStyle;
f.locale = LOCALE_DE_AT;

NSLog(@"NoStyle de_AT: %@", [f stringFromNumber:@(1234.56)]);
f.locale = LOCALE_EN_US;

f.maximumFractionDigits = 2;

NSLog(@“NoStyle en_US: %@", [f stringFromNumber:@(1234.56)]);
NoStyle de_AT: 1235
NoStyle en_US: 1234.56
NSNumberFormatter
Numbers
Many more customization options
maximumFractionDigits
usesSignificantDigits
minimum/maximumSignificantDigits
paddingCharacter
roundingMode, roundingIncrement
…
NSNumberFormatter
Data Volume
NSByteCountFormatter
File size, amount of memory
Picks suitable unit automatically
Non-numeric display
Allow Non-Numeric Zero KB
File 1,234.57 GB
Memory 1,149.78 GB
Coming up next: iOS8
NSEnergyFormatter
Energy in joule, calories etc.
NSLengthFormatter
Distance, in miles, kilometers etc.
NSMassFormatter
Mass and weight in pounds, kg etc.
Images and other
Resources
Images
Buttons
UI Elements
UI Elements
-[UIImage imageNamed:@"myImage"];
Put image files into .lproj folders
Does not work for asset catalogues
Launch Image
Disable asset catalogue
Launch images in .lproj folders
Follows usual naming conventions for
Retina
Orientation
iPhone vs. iPad
Other Ressources
Same as images
Lookup via
-[[NSBundle mainBundle] pathForResource:ofType:]
Use cases
HTML
Text files
App Name
Info.plist
Application has localized Display Name
<key>LSHasLocalizedDisplayName</key>

<true />
InfoPlist.strings
"CFBundleDisplayName" = "国际范例";
Wrap up
Cover the Basics
Locale based formatting
NSDateFormatter
NSNumberFormatter
NSByteCountFormatter
Careful and diligent translation
Remember resources besides the source code
Next Steps
Images resources
Launch Images (if relevant)
Addresses, names
Right-to-left support
Location based pre-selection of units (miles, km etc.)
Pre-selection for pickers, options etc.
Color scheme
…
Summary
Initialer effort can be significant
Full translation
Code refactoring
Create workflows and pick tools
Ongoing maintenance rather easy
Consider relevance of individual measures for your
audience
Merci!
Hvala!
Vielen Dank! Thank You!
Grazie!
Questions?
Daniel Schneller — @dschneller 

daniel.schneller@centerdevice.com

More Related Content

PDF
Lokalisierung für Mobile Apps
PDF
Private Cloud mit Ceph und OpenStack
PDF
Ceph Object Store
PPTX
Build a compiler using C#, Irony and RunSharp.
PDF
Language Search
PDF
Poetic APIs
PDF
Ingo Muschenetz: Titanium Studio Deep Dive
PDF
Class 6: Lists & dictionaries
Lokalisierung für Mobile Apps
Private Cloud mit Ceph und OpenStack
Ceph Object Store
Build a compiler using C#, Irony and RunSharp.
Language Search
Poetic APIs
Ingo Muschenetz: Titanium Studio Deep Dive
Class 6: Lists & dictionaries

Similar to Localizing Mobile Apps (20)

PPTX
2015 bioinformatics python_strings_wim_vancriekinge
PDF
Internationalizing Your Apps
PDF
What we can learn from Rebol?
PPTX
First steps in C-Shell
KEY
Make GUI Apps with Shoes
PDF
Bioinformatica: Esercizi su Perl, espressioni regolari e altre amenità (BMR G...
PDF
Beginning iOS App Localization
PPTX
Perl bhargav
DOCX
What is a shell script
PPTX
I18nize Scala programs à la gettext
ODP
Multilingual drupal 7
PDF
Dealing with a search engine in your application - a Solr approach for beginners
PPTX
Ui testing on multi lingual
PPT
Linux: Beyond ls and cd
PDF
python.pdf
PDF
The Ring programming language version 1.5.1 book - Part 38 of 180
PPT
Ijet Talk
PPTX
Enriching the semantic web tutorial session 1
PDF
Was können wir von Rebol lernen?
PDF
Perl6 for-beginners
2015 bioinformatics python_strings_wim_vancriekinge
Internationalizing Your Apps
What we can learn from Rebol?
First steps in C-Shell
Make GUI Apps with Shoes
Bioinformatica: Esercizi su Perl, espressioni regolari e altre amenità (BMR G...
Beginning iOS App Localization
Perl bhargav
What is a shell script
I18nize Scala programs à la gettext
Multilingual drupal 7
Dealing with a search engine in your application - a Solr approach for beginners
Ui testing on multi lingual
Linux: Beyond ls and cd
python.pdf
The Ring programming language version 1.5.1 book - Part 38 of 180
Ijet Talk
Enriching the semantic web tutorial session 1
Was können wir von Rebol lernen?
Perl6 for-beginners
Ad

Recently uploaded (20)

PDF
Transform Your ITIL® 4 & ITSM Strategy with AI in 2025.pdf
PDF
project resource management chapter-09.pdf
PDF
Enhancing emotion recognition model for a student engagement use case through...
PPTX
A Presentation on Touch Screen Technology
PDF
Heart disease approach using modified random forest and particle swarm optimi...
PDF
1 - Historical Antecedents, Social Consideration.pdf
PDF
ENT215_Completing-a-large-scale-migration-and-modernization-with-AWS.pdf
PPTX
cloud_computing_Infrastucture_as_cloud_p
PDF
DASA ADMISSION 2024_FirstRound_FirstRank_LastRank.pdf
PDF
From MVP to Full-Scale Product A Startup’s Software Journey.pdf
PDF
MIND Revenue Release Quarter 2 2025 Press Release
PDF
Assigned Numbers - 2025 - Bluetooth® Document
PDF
Microsoft Solutions Partner Drive Digital Transformation with D365.pdf
PPTX
Tartificialntelligence_presentation.pptx
PPTX
OMC Textile Division Presentation 2021.pptx
PDF
Hybrid model detection and classification of lung cancer
PDF
Encapsulation_ Review paper, used for researhc scholars
PDF
A novel scalable deep ensemble learning framework for big data classification...
PPTX
TLE Review Electricity (Electricity).pptx
PPTX
Chapter 5: Probability Theory and Statistics
Transform Your ITIL® 4 & ITSM Strategy with AI in 2025.pdf
project resource management chapter-09.pdf
Enhancing emotion recognition model for a student engagement use case through...
A Presentation on Touch Screen Technology
Heart disease approach using modified random forest and particle swarm optimi...
1 - Historical Antecedents, Social Consideration.pdf
ENT215_Completing-a-large-scale-migration-and-modernization-with-AWS.pdf
cloud_computing_Infrastucture_as_cloud_p
DASA ADMISSION 2024_FirstRound_FirstRank_LastRank.pdf
From MVP to Full-Scale Product A Startup’s Software Journey.pdf
MIND Revenue Release Quarter 2 2025 Press Release
Assigned Numbers - 2025 - Bluetooth® Document
Microsoft Solutions Partner Drive Digital Transformation with D365.pdf
Tartificialntelligence_presentation.pptx
OMC Textile Division Presentation 2021.pptx
Hybrid model detection and classification of lung cancer
Encapsulation_ Review paper, used for researhc scholars
A novel scalable deep ensemble learning framework for big data classification...
TLE Review Electricity (Electricity).pptx
Chapter 5: Probability Theory and Statistics
Ad

Localizing Mobile Apps

  • 2. Agenda I18N vs. L10N Languages and Regions Text Date and Time Numbers Images and other Resources https://github.com/dschneller/I18N-Example
  • 5. I — 18 Characters — N L-10 Characters-N
  • 6. Internationalization I — 18 Characters — N Localization L-10 Characters-N
  • 8. Internationalization […] process of designing a software application so that it can potentially be adapted to various languages and regions without engineering changes. […]* * Wikipedia
  • 10. Localization […] the process of adapting internationalized software for a specific region or language by adding locale-specific components and translating text. […]* * Wikipedia
  • 14. Languages and Regions Language ≠ Region 12h time used by an American living in Germany „Jänner“ – „Januar“ [German in Austria vs. in Germany for January] Localization ≠ Locale German user might prefer English user interface texts But: 24h time display
  • 18. Languages and Regions Scheme Launch Arguments -AppleLanguages (ar,de,fr) Order determines preference -AppleLocale en_US
  • 19. NSLocale Encapsulates Region Settings + (id)autoupdatingCurrentLocale
 + (id)currentLocale NSCurrentLocaleDidChangeNotification [[NSNotificationCenter defaultCenter]
 addObserver:self
 selector:@selector(localeDidChange:)
 name:NSCurrentLocaleDidChangeNotification
 object:nil] Refresh formatters, caches NSLocale instances Refresh screen content
  • 20. NSLocale -[NSLocale objectForKey:] NSString* NSLocaleIdentifier NSString* NSLocaleMeasurementSystem NSString* NSLocaleLanguageCode NSString* NSLocaleDecimalSeparator NSString* NSLocaleCountryCode NSString* NSLocaleGroupingSeparator NSString* NSLocaleScriptCode NSString* NSLocaleCurrencySymbol NSString* NSLocaleVariantCode NSString* NSLocaleExemplarCharacterSet NSString* NSLocaleCurrencyCode NSString* NSLocaleCollatorIdentifier NSString* NSLocaleCalendar NSString* NSLocaleQuotationBeginDelimiterKey NSString* NSLocaleCollationIdentifier NSString* NSLocaleQuotationEndDelimiterKey NSString* NSLocaleUsesMetricSystem
  • 21. NSLocale Does not contain the current language! Locale ≠ Localization [NSBundle mainBundle].localizations; // NSArray, (all) [NSBundle mainBundle].preferredLocalizations[0]; // (current) Caveats Localizations of InfoPlist.strings determine content of „localizations“ Intersected with user’s region preferences in Settings.app AppleLanguages launch parameter
  • 22. Text
  • 25. Text ≠ Text Language of messages, buttons, labels etc. Writing direction & alignment Writing systems (Latin, Hebrew, Arabic…) Numbers in text Names & addresses Phrases, idioms and terminology Plurals Sorting …
  • 26. Text ≠ Text Language of messages, buttons, labels etc. Writing direction & alignment Writing systems (Latin, Hebrew, Arabic…) Numbers in text Names & addresses Phrases, idioms and terminology Plurals Sorting …
  • 28. Base Localization One leading (base) language
  • 29. Base Localization One leading (base) language Add Localization
  • 30. Base Localization One leading (base) language Add Localization
  • 31. Base Localization One leading (base) language Add Localization “.strings”files
  • 32. Base Localization One leading (base) language Add Localization “.strings”files genstrings
  • 33. Base Localization One leading (base) language Add Localization “.strings”files genstrings ibtool
  • 34. Base Localization One leading (base) language Add Localization “.strings”files genstrings ibtool One copy per language
  • 35. Base Localization One leading (base) language Add Localization “.strings”files genstrings ibtool One copy per language “.lproj”Ordner
  • 36. Base Localization Eine Leitsprache (Base) “.strings”Files genstrings ibtool Eine Kopie pro Sprache “.lproj”Ordner
  • 37. Base Localization Eine Leitsprache (Base) “.strings”Files genstrings ibtool Eine Kopie pro Sprache “.lproj”Ordner
  • 38. Base Localization Eine Leitsprache (Base) “.strings”Files genstrings ibtool Eine Kopie pro Sprache “.lproj”Ordner
  • 39. Base Localization … /* Class = "IBUILabel"; text = "Loaded by SecondViewController"; ObjectID = "NDk-cv-Gan"; */ "NDk-cv-Gan.text" = "Loaded by SecondViewController"; " /* Class = "IBUILabel"; text = "First View"; ObjectID = "KQZ-1w-vlD"; */ "KQZ-1w-vlD.text" = "First View"; …
  • 40. Base Localization Preview in Assistant Editor Xcode 6: Pick Language Double-Length Pseudo- Language Auto Layout
  • 42. NSLocalizedString Example [button setTitle:NSLocalizedString(@"reset.counter.button.title", 
 @"Reset Counter action button")
 forState:…]; genstrings — Localizable.strings /* Reset Counter action button */
 "reset.counter.button.title" = "Zurücksetzen";
  • 44. .strings Files Updates? Use ibtool every time you update your labels and text.
 In the Base.lproj folder:
 
 ibtool ChangedNib.xib --generate-strings- file NewStrings.strings
 
 Open the generated output file and copy all new string entries to ChangedNib.strings in each lproj. #fail
  • 46. Do not normalize text DRY! — Do Repeat Yourself [NSString stringWithFormat:@”…”]
  • 47. Do not normalize text DRY! — Do Repeat Yourself [NSString stringWithFormat:@”…”] Localizable.strings “count” = “Anzahl” “game” = “Spiel” “reset” = “zurücksetzen” “save” = “sparen” “thumbnail” = “Daumennagel”
  • 48. Do not normalize text DRY! — Do Repeat Yourself [NSString stringWithFormat:@”…”] Localizable.strings “count” = “Anzahl” “game” = “Spiel” “reset” = “zurücksetzen” “save” = “sparen” “thumbnail” = “Daumennagel” “reset count” ”zurücksetzen Anzahl” “save game” “sparen Spiel” …
  • 50. Do not normalize text Context and grammar are lost
  • 51. Do not normalize text Context and grammar are lost Structure of sentences
  • 52. Do not normalize text Context and grammar are lost Structure of sentences Declination & conjugation …
  • 53. Do not normalize text Context and grammar are lost Structure of sentences Declination & conjugation … Use dedicated strings per use case
  • 54. Do not normalize text Context and grammar are lost Structure of sentences Declination & conjugation … Use dedicated strings per use case “reset.counter.button” = “Auf 0 stellen”
  • 55. Do not normalize text Context and grammar are lost Structure of sentences Declination & conjugation … Use dedicated strings per use case “reset.counter.button” = “Auf 0 stellen” Context for translators
  • 56. Do not normalize text Context and grammar are lost Structure of sentences Declination & conjugation … Use dedicated strings per use case “reset.counter.button” = “Auf 0 stellen” Context for translators Use self explanatory keys
  • 57. Do not normalize text Context and grammar are lost Structure of sentences Declination & conjugation … Use dedicated strings per use case “reset.counter.button” = “Auf 0 stellen” Context for translators Use self explanatory keys Provide useful comments (button vs. label, approx. length, etc.)
  • 58. Variables Parameters [NSString stringWithFormat:
 NSLocalizedString(@"click.counter.label",
 @"P1: Current Click Count."),
 self.clickCount] " /* P1: Current Click Count. */
 "click.counter.label" = "%1d x geklickt”;
  • 59. Variables Document parameter order! “Zeige 4 von 12 gesamt” “Total 12 — Showing 4” /* … Param 1: current page; Param 2: total count */
 "current.page.label" = “Zeige %1d von %2d gesamt”;
 
 /* … Param 1: current page; Param 2: total count */
 "current.page.label" = “Total %2d — Showing %1d”;
  • 60. Special cases: 0 and 1 Plurals Englisch German 0 No books Keine Bücher 1 One book Ein Buch sonstiges 100 books 100 Bücher Localizable.strings “books.0” = “No Books” “books.1” = “One Book” “books.n” = “%1d books” “books.0” = “Keine Bücher” “books.1” = “Ein Buch” “books.n” = “%1d Bücher” If-else-clause in the code: Problem solved.
  • 61. Englisch Deutsch 0 No books Keine Bücher 1 1 book 1 Buch Vielleicht nicht ganz… Plural
  • 62. Englisch Deutsch 0 No books Keine Bücher 1 1 book 1 Buch 2 2 books 2 Bücher wenige 3 books 3 Bücher viele 11 books 11 Bücher sonstiges 100 books 100 Bücher Vielleicht nicht ganz… Plural
  • 63. 0 1 2 wenige viele sonstiges Englisch No books 1 book 2 books 3 books 11 books 100 books German Keine Bücher 1 Buch 2 Bücher 3 Bücher 11 Bücher 100 Bücher Or is it…? Plural
  • 64. 0 1 2 wenige viele sonstiges Englisch No books 1 book 2 books 3 books 11 books 100 books German Keine Bücher 1 Buch 2 Bücher 3 Bücher 11 Bücher 100 Bücher Arabic ‫كتاب‬ ٠ ‫كتاب‬ ‫كتابان‬ ‫كتب‬ ٣ ‫ا‬ً‫ب‬‫كتا‬ ١١ ‫كتاب‬ ١٠٠ Or is it…? Plural
  • 65. .strings + .stringsdict * http://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html#ar
  • 66. .strings + .stringsdict Available since iOS7 * http://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html#ar
  • 67. .strings + .stringsdict Available since iOS7 Implements (Unicode*) localization rules for Plural Gender [rdar://16670931] * http://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html#ar
  • 68. .strings + .stringsdict Available since iOS7 Implements (Unicode*) localization rules for Plural Gender [rdar://16670931] Plist Format Name must match .strings .strings must exist, but may be empty * http://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html#ar
  • 69. .strings + .stringsdict https://developer.apple.com/library/ios/releasenotes/Foundation/↩︎ RN-Foundation/index.html#//apple_ref/doc/uid/TP30000742-CH2-SW56 <dict>
     <key>files.selected.label.%d</key>
     <dict>
         <key>NSStringLocalizedFormatKey</key>
 <string>%#@num_files_are@ selected</string>
         <key>num_files_are</key>
  <dict>
             <key>NSStringFormatSpecTypeKey</key>
 <string>NSStringPluralRuleType</string>
             <key>NSStringFormatValueTypeKey</key>
 <string>d</string>
             <key>zero</key>    <string>No file is</string>
             <key>one</key>     <string>A file is</string>
             <key>other</key>   <string>%d files are</string>
         </dict>
     </dict>
 </dict>
  • 70. .stringsdict Categories per language according to Unicode iOS additionally supports„zero“ category for all languages Others, e. g.„few“, depend on language
  • 71. String Tables Localizable.strings Default used by NSLocalizedString() Big projects — big file Can be split NSLocalizedStringFromTable(“MyController”,“Key”,“Comment”) MyController.strings Project structure — Context for translators 3rd party code Also works for .stringsdict
  • 73. Date and Time NSDateFormatter
  • 74. Date and Time Transforms between NSDate and NSString +[NSDateFormatter localizedStringFromDate:dateStyle:timeStyle:]
 -[NSDateFormatter setLocale:] NSDateFormatter
  • 75. Date and Time Transforms between NSDate and NSString +[NSDateFormatter localizedStringFromDate:dateStyle:timeStyle:]
 -[NSDateFormatter setLocale:] NSDateFormatterStyle NSDateFormatter
  • 76. Date and Time Transforms between NSDate and NSString +[NSDateFormatter localizedStringFromDate:dateStyle:timeStyle:]
 -[NSDateFormatter setLocale:] NSDateFormatterStyle German / Germany Englisch / USA NSDateFormatter
  • 77. Date and Time Transforms between NSDate and NSString +[NSDateFormatter localizedStringFromDate:dateStyle:timeStyle:]
 -[NSDateFormatter setLocale:] NSDateFormatterStyle German / Germany Englisch / USA Short 08.07.14 22:32 7/8/14,10:32 PM NSDateFormatter
  • 78. Date and Time Transforms between NSDate and NSString +[NSDateFormatter localizedStringFromDate:dateStyle:timeStyle:]
 -[NSDateFormatter setLocale:] NSDateFormatterStyle German / Germany Englisch / USA Short 08.07.14 22:32 7/8/14,10:32 PM Medium 08.07.2014 22:32:36 Jul 8, 2014, 10:32:36 PM NSDateFormatter
  • 79. Date and Time Transforms between NSDate and NSString +[NSDateFormatter localizedStringFromDate:dateStyle:timeStyle:]
 -[NSDateFormatter setLocale:] NSDateFormatterStyle German / Germany Englisch / USA Short 08.07.14 22:32 7/8/14,10:32 PM Medium 08.07.2014 22:32:36 Jul 8, 2014, 10:32:36 PM Long 8. Juli 2014 22:32:36 MESZ Jul 8, 2014, 10:32:36 PM GMT+2 NSDateFormatter
  • 80. Date and Time Transforms between NSDate and NSString +[NSDateFormatter localizedStringFromDate:dateStyle:timeStyle:]
 -[NSDateFormatter setLocale:] NSDateFormatterStyle German / Germany Englisch / USA Short 08.07.14 22:32 7/8/14,10:32 PM Medium 08.07.2014 22:32:36 Jul 8, 2014, 10:32:36 PM Long 8. Juli 2014 22:32:36 MESZ Jul 8, 2014, 10:32:36 PM GMT+2 Full Dienstag, 8. Juli 2014 12:32:36 Mitteleuropäische Sommerzeit Tuesday, July 8, 2014 at 12:39:16 PM Central European Summer Time NSDateFormatter
  • 81. Date and Time Transforms between NSDate and NSString +[NSDateFormatter localizedStringFromDate:dateStyle:timeStyle:]
 -[NSDateFormatter setLocale:] NSDateFormatterStyle German / Germany Englisch / USA Short 08.07.14 22:32 7/8/14,10:32 PM Medium 08.07.2014 22:32:36 Jul 8, 2014, 10:32:36 PM Long 8. Juli 2014 22:32:36 MESZ Jul 8, 2014, 10:32:36 PM GMT+2 Full Dienstag, 8. Juli 2014 12:32:36 Mitteleuropäische Sommerzeit Tuesday, July 8, 2014 at 12:39:16 PM Central European Summer Time No - - NSDateFormatter
  • 82. Date and Time NSDateFormatter.h typedef enum {
 NSDateFormatterNoStyle = …,
 NSDateFormatterShortStyle = …,
 NSDateFormatterMediumStyle = …,
 NSDateFormatterLongStyle = …,
 NSDateFormatterFullStyle = …
 } NSDateFormatterStyle Combine for date and time portions NSDateFormatterNoStyle — only date / time Get updated with the OS NSDateFormatter
  • 83. Date and Time NSDateFormatter * http://www.unicode.org/reports/tr35/tr35-dates.html#Contents
  • 84. Date and Time What if defaults are not suitable? NSDateFormatter * http://www.unicode.org/reports/tr35/tr35-dates.html#Contents
  • 85. Date and Time What if defaults are not suitable? Do not use hard coded format strings! NSDateFormatter * http://www.unicode.org/reports/tr35/tr35-dates.html#Contents
  • 86. Date and Time What if defaults are not suitable? Do not use hard coded format strings! Unicode Locale Data Markup Language* NSDateFormatter * http://www.unicode.org/reports/tr35/tr35-dates.html#Contents
  • 87. Date and Time What if defaults are not suitable? Do not use hard coded format strings! Unicode Locale Data Markup Language* [f setDateFormat:[NSDateFormatter
 dateFormatFromTemplate:@"u QQ" 
 options:0
 locale:LOCALE_EN_US]];
 
 NSLog(@“%@", [f stringFromDate:july8th); NSDateFormatter * http://www.unicode.org/reports/tr35/tr35-dates.html#Contents
  • 88. Date and Time What if defaults are not suitable? Do not use hard coded format strings! Unicode Locale Data Markup Language* [f setDateFormat:[NSDateFormatter
 dateFormatFromTemplate:@"u QQ" 
 options:0
 locale:LOCALE_EN_US]];
 
 NSLog(@“%@", [f stringFromDate:july8th); Q3 2014 NSDateFormatter * http://www.unicode.org/reports/tr35/tr35-dates.html#Contents
  • 89. Relative formatting [formatter setDoesRelativeDateFormatting:YES];
 
 NSLog(@“%@, %@, %@…", [formatter stringFromDate:GESTERN],
 [formatter stringFromDate:HEUTE],
 [formatter stringFromDate:MORGEN]);
 Gestern, Heute, Morgen… [de_DE] Yesterday, Today, Tomorrow… [en_US] Yesterday, Today, Tomorrow…
  • 90. NSDateComponentsFormatter Formats durations [f stringFromTimeInterval:1234.0]) // seconds About 20 minutes remaining NSDateIntervalFormatter Formats time intervals [f stringFromDate:NOW toDate:LATER]) 09.07.14 12:10-13:13 Coming up next: iOS8
  • 95. Numbers Decimal separators Grouping characters Currency symbols … " NSNumberFormatter API similar to NSDateFormatter
  • 96. Numbers NSNumberFormatter German / Germany English / USA No 1234,56 1234.56 Decimal 1.234,56 1,234.56 Currency 1.234,56 € $1,234.56 Percent 123.456% 123,456% Scientific 1,23456E+03 1.23456E3 SpellOut eintausendzweihundertvier- unddreißig Komma fünf sechs one thousand two hundred thirty- four point five six
  • 97. Numbers NSNumberFormatter.h enum {
 NSNumberFormatterNoStyle = …,
 NSNumberFormatterDecimalStyle = …,
 NSNumberFormatterCurrencyStyle = …,
 NSNumberFormatterPercentStyle = …,
 NSNumberFormatterScientificStyle = …,
 NSNumberFormatterSpellOutStyle = …
 }
 typedef NSUInteger NSNumberFormatterStyle
  • 99. Numbers NSNumberFormatter* f = [[NSNumberFormatter alloc] init];
 f.numberStyle = NSNumberFormatterNoStyle; f.locale = LOCALE_DE_AT;
 NSLog(@"NoStyle de_AT: %@", [f stringFromNumber:@(1234.56)]); f.locale = LOCALE_EN_US;
 f.maximumFractionDigits = 2;
 NSLog(@“NoStyle en_US: %@", [f stringFromNumber:@(1234.56)]); NSNumberFormatter
  • 100. Numbers NSNumberFormatter* f = [[NSNumberFormatter alloc] init];
 f.numberStyle = NSNumberFormatterNoStyle; f.locale = LOCALE_DE_AT;
 NSLog(@"NoStyle de_AT: %@", [f stringFromNumber:@(1234.56)]); f.locale = LOCALE_EN_US;
 f.maximumFractionDigits = 2;
 NSLog(@“NoStyle en_US: %@", [f stringFromNumber:@(1234.56)]); NoStyle de_AT: 1235 NoStyle en_US: 1234.56 NSNumberFormatter
  • 101. Numbers Many more customization options maximumFractionDigits usesSignificantDigits minimum/maximumSignificantDigits paddingCharacter roundingMode, roundingIncrement … NSNumberFormatter
  • 102. Data Volume NSByteCountFormatter File size, amount of memory Picks suitable unit automatically Non-numeric display Allow Non-Numeric Zero KB File 1,234.57 GB Memory 1,149.78 GB
  • 103. Coming up next: iOS8 NSEnergyFormatter Energy in joule, calories etc. NSLengthFormatter Distance, in miles, kilometers etc. NSMassFormatter Mass and weight in pounds, kg etc.
  • 106. UI Elements -[UIImage imageNamed:@"myImage"]; Put image files into .lproj folders Does not work for asset catalogues
  • 107. Launch Image Disable asset catalogue Launch images in .lproj folders Follows usual naming conventions for Retina Orientation iPhone vs. iPad
  • 108. Other Ressources Same as images Lookup via -[[NSBundle mainBundle] pathForResource:ofType:] Use cases HTML Text files
  • 109. App Name Info.plist Application has localized Display Name <key>LSHasLocalizedDisplayName</key>
 <true /> InfoPlist.strings "CFBundleDisplayName" = "国际范例";
  • 111. Cover the Basics Locale based formatting NSDateFormatter NSNumberFormatter NSByteCountFormatter Careful and diligent translation Remember resources besides the source code
  • 112. Next Steps Images resources Launch Images (if relevant) Addresses, names Right-to-left support Location based pre-selection of units (miles, km etc.) Pre-selection for pickers, options etc. Color scheme …
  • 113. Summary Initialer effort can be significant Full translation Code refactoring Create workflows and pick tools Ongoing maintenance rather easy Consider relevance of individual measures for your audience
  • 115. Questions? Daniel Schneller — @dschneller 
 daniel.schneller@centerdevice.com