Automating iOS Storyboard Localization

This guide will guide you through an automated approach to storyboard localization for iOS in Xcode If your iOS app has several storyboards.

It’s easy to integrate automated translation into your app using our translation 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/
      • UpdateTranslations.sh
    • 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
 localizationsPath="Resources/Localizations"
 # The path to your controllers folders (assuming you follow these naming conventions: http://goo.gl/19dSgW)
 controllersPath="Controllers"
 # 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
    fi
  done
done

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

Summary

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 UpdateTranslations.sh script here.

Keep exploring

Photo-realistic sheet music featuring developer-style translation code in place of musical notes. The staff lines show snippets like t('auth.signin.button') and JSON structures, combining the aesthetics of musical notation with programming syntax to illustrate the idea of “composable localization.”

Blog post

Localization as code: a composable approach to localization

Why is localization still a manual, disconnected process in a world where everything else is already “as code”? Learn how a composable, developer-friendly approach brings localization into your CI/CD pipeline, with automation, observability, and Git-based workflows built in.

A woman in a light sweater sits in a home office, focused on her laptop, representing a developer or content manager working on WordPress localization tasks in a calm, professional environment.

Blog post

How to build a scalable WordPress i18n workflow

WordPress powers the web, but translating it well takes more than plugins. Discover how to build a scalable localization workflow using gettext, best practices, and the Phrase plugin.

Blog post

Localizing Unity games with the official Phrase plugin

Want to localize your Unity game without the CSV chaos? Discover how the official Phrase Strings Unity plugin simplifies your game’s localization workflow—from string table setup to pulling translations directly into your project. Whether you’re building for German, Serbian, or beyond, this guide shows how to get started fast and localize like a pro.

Blog post

Internationalization beyond code: A developer’s guide to real-world language challenges

Discover how language affects your UI. From text expansion to pluralization, this guide explores key i18n pitfalls and best practices for modern web developers.

A digital artwork featuring the Astro.js logo in bold yellow and purple tones, floating above Earth's horizon with a stunning cosmic nebula in the background. The vibrant space setting symbolizes the global and scalable nature of Astro’s localization capabilities, reinforcing the article’s focus on internationalization in web development.

Blog post

Astro.js localization part 2: dynamic content localization

Learn how to localize your Astro.js website with static and dynamic content translation. Explore Astro’s built-in i18n features and Paraglide for handling UI elements, navigation, and dynamic text seamlessly.