Software localization

Implementing App Store Localization for Higher Downloads

Optimize your iOS app's appeal by implementing App Store localization strategies to rank higher, increase downloads, and reach a wider audience.
Apple app store blog post featured image | Phrase

Successful iOS apps appeal to as wide an audience as possible. Achieving this appeal will invariably include a look at iOS localization: adapting the app’s user experience to the language, culture, and other specifics of a country or region.

While developers are increasingly getting better at localizing apps, not everyone may pay attention to localizing App Store pages—and herein lies a great opportunity: Localized App Store pages rank higher in App Store search results and have better download rates.

This tutorial will go over localizing your App Store page step by step, including the app’s name, description, screenshots, and other metadata. We’ll cover both manual and automated localization. Let’s get it started!

Our App Store localization project

To learn all about localizing App Store pages, we will use a mobile app called “Motivate Me,” a simple SwiftUI application that shows random motivational quotes when you tap a button:

Localizing iOS App Store pages en screenshot | Phrase Localizing iOS App Store pages fr 2 screenshot | Phrase

How to localize app details

Let’s start by looking at how to localize additional supported locales for our App Store page, and how to add text translations and localize our screenshots.

Adding supported locales

Visit App Store Connect, select your project, and click App Information. This screen shows the basic information of your App Store product.

App information | Phrase

On the Localizable Information section, you’ll see the base language, English(U.S.), selected in the drop-down near the upper-right of the page. To localize our App Store page to another language, we need to click on this drop-down and click the language we would like to support.

Language selector | Phrase

The drop-down has 2 sections. The first is a list of languages we already have localizations for. The second is a list of languages so far unsupported by our App Store page. We will add French localization to our App Store listing, so let’s select French from the list.

Language french selector | Phrase

French will now show in the list of localized languages. The Primary Language section now shows a drop-down that allows selecting the App Store page’s primary or default language. This will be the language shown when a user with an unsupported locale views our App Store page or when our page isn’t localized.

Localizing app details

French is now selected as the active locale, shown in blue next to a downward arrow. All the information currently displayed is what a user of the active locale will see when they visit our page. Let’s change the Subtitle to something in French, along with the Name, and click the Save button.

🗒️ Note » You don’t always have to translate literally. It sometimes makes sense to choose different words or phrases to appeal better to the audience of the active locale.

French app information | Phrase

Let’s move on to another section of the app page where we can localize more information in our App Store listing.

Click on the latest build version we have for our app, in our case 1.0. The screen that opens displays more information that appears on our store page. Just past the Screenshots section, we should see details for Promotional Text, Description, Keywords, etc. We can localize them by following the same steps we did for the App Information section.

🗒️ Note » We will come back to screenshot localization shortly.

Click the active language drop-down, switch to any other supported language, and change the details. We can save the changes and repeat the process for other languages.

More app details | Phrase

🗒️ Note » Localization on the App Store generally follows this same workflow. Change the active language to the one you want to localize ➞ make changes ➞ click the Save button. Whenever you see the language selector, you know localization is possible for that section.

That’s it! Very simple and straightforward.

How to localize screenshots

Screenshots give a visual representation of how our application will look on our user’s device. Screenshots are very important for conversion rates. So they should look good and help potential users envision themselves using our app.

Let’s scroll back up on the Version Information page to get to the iOS Previews and Screenshots section. We can drag and drop the image files to upload the screenshots we want to show for our base language.

Screenshots | Phrase

When we switch the language to French we see the screenshots section is empty for that locale. We can then design localized screenshots that fit our French audience. Once they’re ready, we can drag and drop them to the dedicated section and click the Save button. And, as you may have guessed, we can repeat this process for each language our app supports.

Drag and drop | Phrase

That’s it for App Store localization. Not too bad, right? Now our app can conquer the world!

Well, for a few languages, this workflow isn’t too bad. But what happens when we have 10+, 20+, or 30+ locales we want to support? I know you are yawning already because that sounds like a tedious task. You’re probably asking yourself if there is an easier way, right? Well, yes! We are about to learn how to do this more efficiently with the power of automation.

Automating localization through fastlane

Fastlane is a simple, powerful tool that can streamline the process of localizing apps. With fastlane, we can automate many of the tedious and time-consuming tasks associated with localization, such as translating text, updating screenshots, and submitting updates to the App Store. We can also use the tool to easily create and submit new versions of our app, with all the necessary localization changes. All this can be done from the command line, which saves significant time and effort. It’s also relatively cheap: We don’t need complex cloud infrastructure to use it, just our local machine. Let’s see how to use fastlane to automate App Store localization.

A note about development environments

Fastlane setup can differ depending on your development environment. Luckily fastlane has very good documentation that is constantly updated. You need to follow these steps to set up the best environment to run your automation.

The environment we’re using for this article is:

- macOS Ventura 13.1
- ruby 2.7.5p203 (2021-11-24 revision f69aeb8314) [arm64-darwin22]
- fastlane 2.211.0
- Swift version 5.7.2
- Xcode Version 14.2Code language: plaintext (plaintext)

The setup

After installing fastlane, with the help of the setup instructions, we’re ready for some automation. Let’s open our project folder from the command line and start fastlane with the following command:

% fastlane initCode language: Bash (bash)

Fastlane init | Phrase

The command presents a prompt that asks us how we will start using fastlane. Let’s choose option 3, Automate App Store distribution, for this tutorial.

🗒️ Note » Choosing one option doesn’t lock us in. We can always add more automation tasks later.

Fastlane will present a series of prompts about our developer account and app details. Once we’re done answering all the prompts, we should see some new files that fastlane generated: A fastlane folder containing all we need to automate our App Store listing. Notice that fastlane localizes store data by default, placing stubs in our app’s base language, e.g. under fastlane/metadata/en-US.

Fastlane folders | Phrase

If we don’t see the fastlane/metadata folder, we can use the following command to generate it:

% fastlane deliver download_metadata\\
  --username {{App Store username}}\\
  --app_identifier {{bundle id}}\\
  --force trueCode language: Bash (bash)

Localizing App Store details

The fastlane subfolders and file names are self-explanatory and descriptive. They often map one-to-one with the info we see in App Store Connect. For example, fastlane’s first_name.txt file corresponds to the app contact’s First name field in App Store Connect. We will highlight all the mandatory files that need to be populated before fastlane can do its job.

🗒️ Note » We will use the term “lane” moving forward. A lane is a set of actions you want fastlane to take. Without a lane, fastlane can’t work so always make sure there is at least one lane. The generated Fastfile comes with a lane already provided and that is what we’ll be using throughout this tutorial.

  • Appfile: stores useful information that is used across all fastlane tools, like our Apple ID or the application Bundle Identifier. This info is used to deploy our lanes faster and is tailored to our project needs. [Official Appfile documentation]
  • Fastfile: stores the automation configuration that is used to run fastlane. [Official Fastfile documentation].
  • copyright.txt: the copyright of the app e.g. Phrase inc @ 2023
  • primary_category.txt: the primary category of our application e.g. LIFESTYLE
  • review_information: found in the metadata folder, its information Apple’s testers will use to access our application. The required files in the review information related to your team’s point of contact for testers: email_address.txt, frist_name.txt, last_name.txt, and phone_number.txt. Fastlane requires that these files have data before you can push updates to the App Store.
  • name.txt: the name of our app.
  • subtitle.txt: the subtitle of our application. This is normally a tagline or something short to describe our application.

🗒️ Note » Keep in mind that name.txt and subtitle.txt have a thirty (30) character limit each.

Let’s update the required fastlane files:

# fastlane/metadata/en-US/copyright.txt

Phrase inc @ 2023Code language: Ruby (ruby)
# fastlane/metadata/en-US/primary_category.txt

LIFESTYLECode language: Ruby (ruby)
# fastlane/metadata/en-US/review_information/email_address.txt

myemail@gmail.comCode language: Ruby (ruby)
# fastlane/metadata/en-US/review_information/frist_name.txt

JohnCode language: Ruby (ruby)
# fastlane/metadata/en-US/review_information/last_name.txt

DoeCode language: Ruby (ruby)
# fastlane/metadata/en-US/review_information/phone_number.txt

+233000000000Code language: Ruby (ruby)
# fastlane/metadata/en-US/name.txt

Motivate MeCode language: Ruby (ruby)
# fastlane/metadata/en-US/subtitle.txt

For your daily dose of motivationCode language: Ruby (ruby)

🗒️ Note » The initial files generated are based on the default language of our App Store listing, which is en-US in this case.

With the required metadata entered, let’s run the deliver command to upload this data to our App Store page:

% fastlane deliverCode language: Bash (bash)

This should use the info in fastlane/metadata to update our App Store listing.

🗒️ Note » The command has other important features that we won’t cover in the scope of this tutorial. Check out the documentation to learn everything fastlane deliver has to offer.

Adding other locales

There are 2 main ways to add locales when working with fastlane. We can duplicate the metadata folder of our base language, e.g. en-US, and rename it to the locale we want to support, e.g. fr-FR for French – France. After that, we can enter French translations in the new fr-FR folder. The next time we run fastlane deliver, fastlane will automatically add the locale to our supported locales in our App Store listing.

Alternatively, we can add another locale in App Store Connect and run the fastlane deliver download_metadata command. This will create all the metadata in our local project for all supported locales. We can then edit the localized files and run fastlane deliver to upload our changes.

An example of localizing subtitles for English and French would be:

# fastlane/metadata/en-US/subtitle.txt

For your daily dose of motivationCode language: plaintext (plaintext)
# fastlane/metadata/fr-FR/subtitle.txt

Motivation au quotidienCode language: plaintext (plaintext)

Automating screenshot localization

Manually taking screenshots and uploading them individually for all locales can be a pain. Fastlane has a screenshot automation tool called snapshot to make this a lot easier. Screenshots are generated by integrating fastlane into the automated UI tests of our project. It takes a few steps to set up, but once it’s done, it’s smooth sailing.

Setting up UI tests

The backbone of automating screenshots is using UI Tests. You can skip this section if you already have UI Tests set up for your project. Fastlane will take snapshots of our UI tests and use that as screenshots of your App Store listing. We will create a UI Test target that will be used to run our UI tests.

The first step is to create a UI Test Target. Click FileNewTarget.

Create target | Phrase

In the Template sheet that appears, search “UI Test” ➞ Select UI Testing Bundle ➞ Click the Next button.

UI testing bundle | Phrase

On the Create Target sheet that appears make any edits if necessary and click the Finish button.

Create target sheet | Phrase

If all went well, Xcode will create a folder with two files using the Product Name from the Create Target sheet.

Target files | Phrase

Next, we will verify that our target is ready to run our tests. For our target to be able to run UI Tests, it has to be present in the Test scheme. Click ProductSchemeEdit Scheme.

Edit scheme | Phrase

Select Test on the left panel. This will show relevant information related to testing. The target we created should be shown and should be checked ☑️.

Test scheme | Phrase

All set! Now we can confidently run our UI tests. In the newly created folder with our UI Tests, select the one that ends in UITests, in our case Motivate_MeUITests.

To run the UI Test, click the Run icon next to a function, or a class to run all its test functions. After a successful test, a green checkmark ✅ will appear next to each passed test.

Run UI test | Phrase

Setting up snapshot

With our UI tests properly set up, we can introduce fastlane’s snapshot to help us with generating localized screenshots.

Run fastlane snapshot init in your project folder. This command will create 2 files under the .fastlane folder, Snapfile and SnapshotHelper.swift. The Snapfile configures configuration snapshot. SnapshotHelper has functions needed for fastlane to capture screenshots during testing.

Now you need to add the newly created SnapshotHelper.swift to your UI Test target. Click on the UI Test Target folder, in our case Motivate MeUITests ➞ Click Add files to “Project Name..”. On the sheet that appears, locate the SnapshotHelper.swift and select it. Check UI Test target if it’s not checked ➞ click Add. The SnapshotHelper.swift should be visible in your UI Test Target folder.

Add snapshot helper | Phrase

Add snapshot sheet | Phrase

Snapshot helper added | Phrase

🗒️ Note » (Objective C only) Add the bridging header to your test class. The bridging header is named after your test target with -Swift.h appended.

// Motivate_MeUITests-Swift.h

import "MYUITests-Swift.h"

// Rest of testCode language: Objective-C (objectivec)

The most important function for capturing screenshots for fastlane is snapshot(IndexNameOfScreen). It’s what tells fastlane to take a screenshot of the current state of our UI test. Here are the signatures for Swift and Objective C:

  • Swift: snapshot("01YourScreen")
  • Objective C: [Snapshot snapshot:@"01YourScreen" timeWaitingForIdle:10];

Let’s update our test to make use of snapshot. In the code below we take a snapshot every time a button is pressed and this tells fastlane when to capture a screenshot.

//  Motivate_MeUITests.swift

final class Motivate_MeUITests: XCTestCase {

 var app: XCUIApplication!

 override func setUpWithError() throws {
     // UI tests must launch the application that they test.
    app = XCUIApplication()

    // Important for fastlane to capture test results.
    // Without this line fastlane won't work
    setupSnapshot(app) 

    app.launch()
 }

 // Put teardown code here. This method is called after
 // the invocation of each test method in the class.
 override func tearDownWithError() throws {
 
 }

 func testGenerateRandomQuote() throws {
    let randomQuoteButton = app.buttons.element(boundBy: 0)
    snapshot("01-Quote")

    randomQuoteButton.tap()
    snapshot("02-Quote")

    randomQuoteButton.tap()
    snapshot("03-Quote")

    randomQuoteButton.tap()
    snapshot("04-Quote")

    randomQuoteButton.tap()
    snapshot("05-Quote")
 }
}Code language: Swift (swift)

🗒️ Note » snapshot(IndexNameOfScreen) is the recommended naming convention to follow; it makes it easy to identify screenshots.

Click the Run icon next to the test function(i.e testGenerateRandomQuote() in our case), or the Run icon next to the class(i.e Motivate_MeUITests in our case) to run all its test functions. After a successful test, a green checkmark ✅ will appear next to each passed test.

Remember our Motivate Me application? This is what we’ll be using to demonstrate screenshot automation.

Motivate me | Phrase

Generating screenshots

In our fastlane folder, we should notice there has been an additional file added.

Snapfile | Phrase

🗒️ Note » If you don’t see this file, run fastlane snapshot init.

The Snapfile has configuration details for snapshot capturing. Here is the sample Snapfile for our test application:

# fastlane/Snapfile

devices([
 "iPhone 13 Pro",
 "iPhone 13 Pro Max",
 "iPhone 8 Plus",
 "iPhone SE (3rd generation)",
 "iPad Pro (12.9-inch) (6th generation)",
 "iPad Pro (11-inch) (4th generation)"
])

languages([
 "en-US",
 "fr-FR",
])

scheme("Your Test Scheme")

output_directory("./fastlane/screenshots")

clear_previous_screenshots(true)Code language: Ruby (ruby)

The most important things here are the devices to generate the screenshots on, the locales supported, and the scheme used to run the tests. Devices are particularly important because the generated images should match Apple’s resolution guidelines. You can use this guideline to help you choose.

🗒️ Note » There’s a lot more fastlane can do with screenshots, such as framing them. Visit fastlane’s documentation on snapshot to learn more.

Run this command to generate snapshots:

fastlane snapshotCode language: Bash (bash)

You’ll have to wait for a while for fastlane to do its magic. After everything is successful, fastlane will open a report of all the generated screenshots. You should also see a screenshots folder at the location specified in your Snapfile.

Fastlane snap CLI | Phrase

Generated snapshots scaled | Phrase

Deploying to the App Store

Now that we have all we need to fully localize our App Store, it’s time to deploy our changes.

In our Fastfile, we should add the action to capture and upload our generated screenshots in our lane.

# fastlane/Fastfile

platform :ios do
    desc "Description of what the lane does"
    lane :custom_lane do
        capture_screenshots
        upload_to_app_store
     end
endCode language: Ruby (ruby)

Run the deliver command to upload your screenshots and App Store details.

fastlane deliverCode language: Bash (bash)

Fastlane deliver | Phrase

After completion, you should see a screen similar to this. Fastlane does a good job of pointing out errors in case you have any.

And if you visit App Store Connect, you should see the screenshots fastlane uploaded.

Final upload | Phrase

🔗 Resource »  fastlane deliver updates your App Store details so you can submit them for review if everything looks right. Fastlane can also deploy to your application and even submit it for review. Read all about fastlane deployment in the official documentation.

Well done!

We hope that this tutorial has shown you that localizing your App Store page is not too hard, and for all super-optimizers, we hope our coverage of fastlane has shown you a good way to automate the process. With a localized App Store page, you can increase app downloads—resulting in greater revenue.

To make the most of it, consider streamlining your app translation process with a specialized software localization tool such as Phrase Strings. Designed to automate manual and repetitive tasks, it can help you efficiently manage translation strings for your mobile app and continually release updated translations over the air.

With a strong API and native integrations with GitHub, GitLab, Bitbucket, and other tools, Phrase Strings provides a comprehensive strings editor that enables translators to access all the content you’ve pushed for translation from one location. Once the translation is complete, you can effortlessly retrieve the translated content and incorporate it back into your project.

As your software product grows, you can seamlessly connect Phrase Strings with a cutting-edge translation management system (TMS) to unlock the full power of traditional CAT tools and machine translation capabilities.

Check out all Phrase features for developers and see for yourself how they can streamline your software localization workflows from day one.

String Management UI visual | Phrase

Phrase Strings

Take your web or mobile app global without any hassle

Adapt your software, website, or video game for global audiences with the leanest and most realiable software localization platform.

Explore Phrase Strings