Successful App
Localisation
Or: Safely navigating the pitfalls
https://www.wordcrafts.de
Felix Bartz, Linguist, Co-founder, CTO
Slide 2
Slide 2 text
• Is localizing worth the effort?
• Fundamentals, such as: work with volunteers or professionals?
• How do I internationalize my app?
What I am not going to talk about
Slide 3
Slide 3 text
• Pitfall 1: Concepts
• Pitfall 2: Time constraints
• Pitfall 3: Organizational skills
• Pitfall 4: Tools & Platforms
What I am going to talk about
Slide 4
Slide 4 text
Concepts
Or: how can I provide the basis for good localization?
Slide 5
Slide 5 text
The User Interface Concepts > User Interface
Slide 6
Slide 6 text
The User Interface Concepts > User Interface
Tabs
DON’T DO THIS
Slide 7
Slide 7 text
The User Interface Concepts > User Interface
Buttons
Calendar App #1 Calendar App #2
Slide 8
Slide 8 text
The User Interface Concepts > User Interface
Buttons
Calendar App #1 In German
Slide 9
Slide 9 text
The User Interface Concepts > User Interface
Buttons
Calendar App #2 In German
Slide 10
Slide 10 text
The User Interface Concepts > User Interface
• Provide sufficient space: other languages are up to 20% longer
• Look for ways to shorten space-constrained strings
• Custom font? Does it do special characters?
What did we learn?
Slide 11
Slide 11 text
String Design Concepts > String Design
Placeholders and their pains
Slide 12
Slide 12 text
String Design Concepts > String Design
Placeholders and their pains
/* No comment provided by engineer. */
"server_down" = "We are working on it and expect to restore service by %s.";
Day of the week? am Dienstag
Date? am 24.12.2014
Time? um 23:00 Uhr
What could %s be?
Slide 13
Slide 13 text
String Design Concepts > String Design
Placeholders and their pains
/* %s will be replaced by local time, e.g. 3:00 AM. */
"server_down" = "We are working on it and expect to restore service by %s.";
What could %s be?
✓
/* %s e.g. 3:00 AM. */
"server_down" = "We are working on it and expect to restore service by %s.";
or
Slide 14
Slide 14 text
String Design Concepts > String Design
Placeholders and their pains
Articles in front of placeholders…
"notification" = "%1$@ sent you a %2$@";
"text_message" = "text message";
"video" = "video";
Slide 15
Slide 15 text
String Design Concepts > String Design
Placeholders and their pains
Yes, it works in English…
Slide 16
Slide 16 text
String Design Concepts > String Design
Placeholders and their pains
But not in German, for example…
Slide 17
Slide 17 text
String Design Concepts > String Design
Placeholders and their pains
Solution?
"notification" = "%1$@ sent you a %2$@";
"text_message" = "text message";
"video" = "video";
"notification" = "%1$@ sent you %2$@";
"text_message" = "a text message";
"video" = "a video";
Add articles and prepositions to the placeholder content.
Slide 18
Slide 18 text
String Design Concepts > String Design
Placeholders and their pains - what did we learn?
• Use the comment for vital information
• Communicate what type of data the placeholder represents
• Just because something works in English, this does not necessarily
apply to other languages
Slide 19
Slide 19 text
String Design Concepts > String Design
Multiple Use of Strings
Slide 20
Slide 20 text
String Design Concepts > String Design
Multiple Use of Strings
/* No comment provided by engineer. */
"me" = "Me";
In this chat group: Me
Chat group created by: Me
Gruppenteilnehmer: Ich
Gruppe erstellt von: Mir
Slide 21
Slide 21 text
String Design Concepts > String Design
Use of Generic Terms and Phrases
(to make them re-usable)
Slide 22
Slide 22 text
String Design Concepts > String Design
Use of Generic Terms and Phrases
/* No comment provided by engineer. */
"success" = "Success";
YouTube copy link: Geschafft
Slide 23
Slide 23 text
String Design Concepts > String Design
Use of Generic Terms and Phrases
Copy link: Geschafft?
Slide 24
Slide 24 text
String Design Concepts > String Design
Use of Generic Terms and Phrases
DON’T DO THIS
/* No comment provided by engineer. */
"success" = "Success";
AT LEAST ADD A COMMENT
String Design Concepts > String Design
Concatenated Strings
"desc_backup_everything" = "BBB will clone to .";
"desc_local_vol" = "the volume %@";
"desc_network_vol" = "the network volume %@";
"desc_folder_network_vol" = "the folder %1$@ on the network volume %2$@";
"desc_folder_local" = "the folder %1$@ on the volume %2$@";
"desc_local_vol" = "the volume %@";
Slide 27
Slide 27 text
String Design Concepts > String Design
Concatenated Strings
"desc_backup_everything" = "BBB will clone to .";
"desc_local_vol" = "the volume %@";
In German?
Slide 28
Slide 28 text
String Design Concepts > String Design
Concatenated Strings
"desc_backup_everything" = "BBB will clone to .";
"desc_local_vol" = "the volume %@";
"desc_backup_everything" = "";
"desc_local_vol" = "";
"desc_local_vol" = "das Volume %@";
"desc_backup_everything" = "BBB kopiert auf .";
Slide 29
Slide 29 text
BBB kopiert das Volume X auf das Volume Y.
String Design
Concatenated Strings
Concepts > String Design
Slide 30
Slide 30 text
String Design Concepts > String Design
Concatenated Strings
"desc_backup_everything" = "BBB will clone to .";
"desc_network_vol" = "the network volume %@";
"desc_folder_network_vol" = "the folder %1$@ on the network volume %2$@";
"desc_folder_local" = "the folder %1$@ on the volume %2$@";
"desc_local_vol" = "the volume %@"; ✓
"desc_network_vol" = "the network volume %@"; ✓
"desc_folder_local" = "the folder %1$@ on the volume %2$@"; ?
Slide 31
Slide 31 text
String Design Concepts > String Design
Concatenated Strings
"desc_backup_everything" = "BBB will clone to .";
"desc_folder_local" = "the folder %1$@ on the volume %2$@";
"desc_backup_everything" = "BBB kopiert auf .";
"desc_local_vol" = "the volume %@";
"desc_local_vol" = "";
"desc_local_vol" = "das Volume %@";
"desc_folder_local" = "";
"desc_folder_local" = „den Ordner %1$@ auf dem Volume %2$@";
Slide 32
Slide 32 text
String Design Concepts > String Design
Concatenated Strings
BBB kopiert das Volume A auf den Ordner B auf dem Volume C.
Slide 33
Slide 33 text
BBB kopiert das Volume A in den Ordner B auf dem Volume C.
String Design Concepts > String Design
Concatenated Strings
String Design
Slide 34
Slide 34 text
String Design Concepts > String Design
Concatenated Strings
"desc_backup_everything" = "BBB will clone to .";
"desc_folder_network_vol" = "the folder %1$@ on the network volume %2$@";
"desc_local_vol" = "the volume %@"; ✓
"desc_network_vol" = "the network volume %@"; ✓
"desc_folder_local" = "the folder %1$@ on the volume %2$@";
✗
✗
"desc_folder_network_vol" = "the folder %1$@ on the network volume %2$@";
Slide 35
Slide 35 text
String Design Concepts > String Design
Concatenated Strings
"desc_backup_everything" = "BBB will clone to .";
"desc_backup_everything" = "BBB will clone to .";
"desc_backup_everything" = "BBB will clone to .";
Why do we fail here?
"desc_local_vol" = "the volume %@";
"desc_network_vol" = "the network volume %@";
"desc_folder_local" = "the folder %1$@ on the volume %2$@";
"desc_folder_network_vol" = "the folder %1$@ on the network volume %2$@";
Slide 36
Slide 36 text
String Design Concepts > String Design
Concatenated Strings
BBB will clone to the folder %1$@ on network volume %2$@.
CCC clonerà sulla cartella %1$@ sul volume di rete %2$@.
BBB will clone to the network volume %@.
CCC clonerà sul volume di rete %@.
Slide 37
Slide 37 text
String Design Concepts > String Design
Concatenated Strings
"desc_backup_everything" = "BBB will clone to .";
"desc_folder_local" = "the folder %1$@ on the volume %2$@";
How do we succeed?
"desc_backup_everything" = "BBB will clone to .";
"desc_folder_local" = "the folder %1$@ on the volume %2$@";
& use the same pool of strings
Slide 38
Slide 38 text
String Design Concepts > String Design
Concatenated Strings
Solution - Step 1
"desc_backup_everything" = "BBB will clone to .";
"source_desc_folder_local" = "the folder %1$@ on the volume %2$@";
"source_desc_folder_local" = "the folder %1$@ on the volume %2$@";
"dest_desc_folder_local" = "the folder %1$@ on the volume %2$@";
"desc_backup_everything" = "BBB will clone to .";
Separate strings pools for &
Slide 39
Slide 39 text
String Design Concepts > String Design
Concatenated Strings
"desc_backup_everything" = "BBB will clone to .";
Solution - Step 2
"desc_backup_everything" = "BBB will clone .";
Move the preposition “to” into the ‘Destination’ string.
"source_desc_folder_local" = "the folder %1$@ on the volume %2$@";
"dest_desc_folder_local" = "the folder %1$@ on the volume %2$@";
"source_desc_folder_local" = "the folder %1$@ on the volume %2$@";
"dest_desc_folder_local" = "to the folder %1$@ on the volume %2$@";
Slide 40
Slide 40 text
String Design Concepts > String Design
Concatenated Strings
In German
"desc_backup_everything" = "BBB kopiert .";
"source_desc_folder_local" = "den Ordner %1$@ auf dem Volume %2$@";
"dest_desc_folder_local" = "in den Ordner %1$@ auf dem Volume %2$@";
Slide 41
Slide 41 text
BBB kopiert den Ordner A auf dem Volume B
in den Ordner C auf dem Volume D.
Slide 42
Slide 42 text
String Design Concepts > String Design
Concatenated Strings
In German
"desc_backup_everything" = "BBB kopiert .";
"source_desc_local_vol" = "das Volume %@";
"dest_desc_local_vol" = "auf das Volume %@";
Slide 43
Slide 43 text
BBB kopiert das Volume A auf das Volume B.
Slide 44
Slide 44 text
String Design Concepts > String Design
Concatenated Strings – what did we learn?
• Works in one language ≠ works in other languages
• Move mean little fellas such as prepositions or articles into the
placeholder strings
• Provide for order changes by using %1$@
Slide 45
Slide 45 text
String Design Concepts > String Design
The Plural - often underestimated
Slide 46
Slide 46 text
String Design Concepts > String Design
"%tu matches found" = "%tu matches found";
The Plural - enemy of the state
Most languages only have one plural.
Slide 47
Slide 47 text
String Design Concepts > String Design
"%tu matches found" = "%tu matches found";
The Plural - enemy of the state
"%tu matches found" = "%tu Treffer";
"%tu matches found" = "%tu resultados";
"%tu matches found" = "%tu risultati";
Slide 48
Slide 48 text
String Design Concepts > String Design
The Plural - enemy of the state
Unfortunately, not all languages have only one plural …
Slide 49
Slide 49 text
String Design Concepts > String Design
The Plural - enemy of the state
Russian
Slide 50
Slide 50 text
String Design Concepts > String Design
The Plural - enemy of the state
Plurals in “western” languages
1 = Singular
2 – ∞ = Plural
Slide 51
Slide 51 text
String Design Concepts > String Design
The Plural - enemy of the state
Plurals in most Asian languages
1 – ∞ = One consistent form
Slide 52
Slide 52 text
String Design Concepts > String Design
The Plural - enemy of the state
1 = Singular
0, 5-20, 25-30, … = Plural Form 2
1, 21, 31, 41, 51, 61, … = Singular
2, 3, 4, 22-24, … = Plural Form 1
Plurals in Russian
Slide 53
Slide 53 text
String Design Concepts > String Design
The Plural - enemy of the state
Solution?
A .stringsdict file
Slide 54
Slide 54 text
String Design Concepts > String Design
The Plural - enemy of the state
NSStringFormatSpecTypeKey
NSStringPluralRuleType
NSStringFormatValueTypeKey
tu
zero
No matches found
one
%tu match found
other
%tu matches found
NSStringFormatSpecTypeKey
NSStringPluralRuleType
NSStringFormatValueTypeKey
tu
zero
Совпадений не обнаружено
one
%tu совпадение обнаружено
many
%tu совпадений обнаружено
other
%tu совпадения обнаружено
English Russian
Slide 55
Slide 55 text
String Design Concepts > String Design
The Plural – what did we learn?
• Not every language has just one plural form
• Apple offers a simple solution
• Expect the unexpected!
Slide 56
Slide 56 text
String Design Concepts > String Design
Conclusion
• Be aware: there are languages that use a different syntax
• You do not need to know the syntax of every single language
• If in doubt: ask someone who is good at this stuff
• Important: You don’t have to be an expert.
But expect this to need time during the translation.
Slide 57
Slide 57 text
Time Constraints
Or: Good things are worth waiting for…
Slide 58
Slide 58 text
Time Constraints
The main question is:
How long will it take?
Slide 59
Slide 59 text
Time Constraints
General answer:
it depends …
Slide 60
Slide 60 text
Time Constraints
Depends on what?
• Word count of the resources
• Possible specialization in a certain topic
• Customization level and complexity of the UI
• Your internationalization efforts
• Thoroughness of the translators
Slide 61
Slide 61 text
Time Constraints
Depends on what?
• Thoroughness of the translators
Slide 62
Slide 62 text
Time Constraints
Depends on what?
Typically, an Initial localization requires
*2-3 reviews.
Slide 63
Slide 63 text
Time Constraints
Depends on what?
*2-3 reviews
• (Typos)
• Length constraints
• Context correctness
• Undiscovered issues of all sorts (gender, plurals, prepositions, order)
Slide 64
Slide 64 text
Time Constraints
Standard iPhone App:
1500 words in resources
350 words in App Store
Translation
Data exchange
Review
Initial Localization
Month
M T W T F S S
Do you see the
issue?
Slide 65
Slide 65 text
Time Constraints
Standard Update:
200 words in resources
70 words release notes
Translation
Data exchange
Review
Update Localization
Month
M T W T F S S
Slide 66
Slide 66 text
Time Constraints
Ecosystem biorhythm
Value Axis
0
12.5
25
37.5
50
Category Axis
Jan Feb Mar Apr May June Juy Aug Sep Oct Nov Dec
Calendar year
Workload
Pre-WWDC
Pre-iTC Xmas shutdown
OS releases
Slide 67
Slide 67 text
Time Constraints
Conclusion
• Very often the main effort is not the translation, but the Review
• Plan for sufficient time – also consider time zone related losses
• Inform your translators ahead of time
• Ecosystem biorhythm: WWDC, Xmas, OS releases, iTC downtimes, …
Slide 68
Slide 68 text
Or: how can I make it comfy for my translators?
Organizational Skills
Slide 69
Slide 69 text
Organizational Skills
As much info material as possible, such as video tutorials, support
documents, review guides, etc.
The Learning Curve
Slide 70
Slide 70 text
Organizational Skills
Always provide the app itself. It is the best context source. Ever!
Context2
Slide 71
Slide 71 text
Organizational Skills
Stick to your deadlines. Because you expect that as well.
Reliability
Slide 72
Slide 72 text
Organizational Skills
Agree on one single contact. Ideally: a lead developer!
Agree on Q&A methods and schedule sessions
Communication
Slide 73
Slide 73 text
Organizational Skills
Don’t lack words. Become “The Explainer”.
Comments
/* */
File Formats & Tools
File Formats
Native resources Exchange file formats
• xibs, plist, strings, stringsdict, …
• json, …
• xliff, …
• xlsx, docx, …
The bigger / complex your project is, the better it is to use native files.
Slide 76
Slide 76 text
File Formats & Tools
File Formats
Native resources Exchange file formats
• Can be versioned easily
• Contain ALL context
• Are context themselves
• Versioning difficult
• Prone to loosing context
• Error source
Include translators in the decision
Slide 77
Slide 77 text
File Formats & Tools
Tools / Platforms
Self-services on the web Full services on the web
• No file format hassle
• Easy and quick
• Anonymous translators
• Status tracking and statistics
• Q&A handling
• No file format hassle
• Easy and quick
• You bring your own translators
• Status tracking and statistics
• Q&A handling
Made for your comfort, typically inefficient for translators
Slide 78
Slide 78 text
File Formats & Tools
Conclusion
• Either work with files or online platforms - include translators
• Most online platforms are very inefficient for translators
• Choose wisely and be aware of dependencies and error sources
Slide 79
Slide 79 text
News from WWDC17
New Pséùdôlängùágès (incl. RTL)
New Autolayout constraints checks and warnings
Stringsdicts can now be exported into Xliff (meh)
Watch WWDC17 Session 401 (Localizing with Xcode 9)