Automate iOS Storyboard Localization

If your iOS app has several storyboards and you want the translation process to be fully automated, there is no best practice. This is why we decided to change our workflow a little bit and create a new custom script. This guide will show our approach to storyboard localization for iOS in Xcode.

Malte is the founder of Askano, a social recommendation app.

It’s easy to integrate automated translation into your app using our workflow or – if you’re okay with a manual step in your workflow – by using XLIFF – as explained in this tutorial.

Our Setup

We use this folder structure for our apps:

  • Application/
  • Controllers/
    • Controller1/
      • Controller1.storyboard
    • Controller2/
      • Controller2.storyboard
    • Controller3/
      • Controller3.storyboard
  • Library/
  • Models/
  • Ressources/
    • Scripts/
    • Localizations/
      • Localizable.strings
      • InfoPlist.strings
  • Vendors/

Our languages are en, es, fr and de.

The Script

The task is to automate the extraction of strings and the push & pull of all .strings files to/from the Phrase translation center. So we created the UpdateTranslations.shscript that takes care of it. You can run this script at any point in your deployment process (e.g. during your build phase).

In the first part of the script we are going to push the storyboard .strings files with a tag to Phrase. This way we can easily pull back only the needed translation keys afterwards. Part 2 of the script is basically the push of new translation keys to Phrase and the pull of translations. (See [our workflow] for details)

phraseapp_push_pull flowchart | Phrase

Script Config

 # The path to your standard Localizations.strings file
 # The path to your controllers folders (assuming you follow these naming conventions:
 # The languages that you want to translate
 languages=(de en es fr)
 # Your controllers that contain storyboards
 storyboards=(Controller1 Controller2 Controller3)

Part 1: Storyboard Translation

 # For each storyboard
 for storyboard in ${storyboards[@]} ; do
   # Push english translation file
   phrase push ${controllersPath}/${storyboard}/en.lproj/${storyboard}.strings --locale=en --tags=${storyboard}
   # Pull language translations and clean and rename folders for each language
   for language in ${languages[@]} ; do
     # Pull translation files into storyboard folder
     phrase pull ${language} --target=${controllersPath}/${storyboard}/ --format=strings --tag=${storyboard}

    # Clean and rename
    if [ -f ${controllersPath}/${storyboard}/${language}.lproj/Localizable.strings ] ; then
      rm -f ${controllersPath}/${storyboard}/${language}.lproj/${storyboard}.strings
      mv ${controllersPath}/${storyboard}/${language}.lproj/Localizable.strings ${controllersPath}/${storyboard}/${language}.lproj/${storyboard}.strings

Part 2: Push And Pull The Standard Translation Files

# Generate new entries in Base locale for new translation keys
find ./ -name "*.m" -print0 | xargs -0 genstrings -o ${localizationsPath}/Base.lproj
# Push to PhraseApp
phrase push ${localizationsPath}/Base.lproj/Localizable.strings --locale=Base --tags=Localizable
phrase push ${localizationsPath}/Base.lproj/InfoPlist.strings --locale=Base --tags=InfoPlist
# Pull from PhraseApp
phrase pull --target=${localizationsPath} --format=strings


It’s a little bit laborious to achieve this fully automated solution. But since a manual solution with XLIFF files was not an option for our processes, we needed this. The Phrase API documentation helped us to create a custom workflow that fits our needs.

You can find the complete script here.