An app may ship with translated screens and storefront copy but still show an English name on the home screen. The installed label does not come from ordinary interface copy or store metadata. iOS and Android read it from platform-specific bundle resources, and a cross-platform build tool may overwrite those resources whenever it generates a new project.
Treat the launcher label as its own localization artifact. Assign an owner, map the value to CFBundleDisplayName on iOS and android:label on Android, then inspect the installed application in each launch locale. This keeps fallback names and stale manual edits out of release builds.
Understand which name the user is seeing
A mobile product can expose several names at once:
- The store listing name used for discovery and product-page presentation.
- The installed name shown by the launcher or home screen.
- A navigation title or brand label rendered inside the app.
- A legal entity or subscription product name shown in another system surface.
These values may begin with the same phrase, but separate systems control them. Translating a store listing does not modify the binary. An in-app String Catalog may not touch bundle metadata either. When the tracker collapses all three names into one field, it can show complete even though the installed package contains only the source value.
Apple defines CFBundleDisplayName as the user-visible name of the bundle. Android defines the application android:label as a user-readable label and allows it to reference a string resource. These two fields control the installed name.
Write down the distinction before changing code:
| Surface | Example | Owner | Release artifact |
|---|---|---|---|
| Store listing | Acme Tasks | Growth or product marketing | Store metadata |
| Installed app | Acme | Mobile engineering | App bundle resources |
| In-app title | Your tasks | Product UI | String catalog or resource file |
The phrases can match by policy, but they should not be coupled accidentally. A store team may use a longer keyword-aware name while the launcher needs a concise label that remains recognizable when space is limited.
Choose one source and explicit platform outputs
Create one source record for each platform's installed label. A small manifest is enough:
app_display_name:
source_locale: en
source: Acme
platforms:
ios: CFBundleDisplayName
android: app_name
targets:
fr: Acme
ja: アクミー
de: Acme
The manifest does not need to replace native localization files. Its job is to identify ownership and let the build produce or validate those files. If your translation system already manages InfoPlist.strings and Android XML, keep those formats as the source of truth and store equivalent ownership metadata beside them.
Use four rules when selecting the source:
- The launcher label has one accountable product owner.
- Translators receive a note that this text appears under the installed icon.
- Platform outputs are generated or reviewed together.
- Store metadata is compared during release, but it is not silently copied into the binary.
Without that shared review, Android may receive a translated app_name while iOS depends on a hand-edited Xcode value. Storefront copy can drift into a third spelling in a separate spreadsheet.
Localize the iOS display name
Keep the base bundle configuration stable and place localized display names in information-property-list localization resources. A minimal French resource contains:
/* Name shown below the installed app icon */
"CFBundleDisplayName" = "Acme";
Place the entry in the French InfoPlist.strings resource and include that resource in the application target. Repeat it for every supported launch locale. Keep a base or development-language value available so unsupported locales resolve to a deliberate name rather than a missing field.
Do not confuse CFBundleDisplayName with an arbitrary in-app key named app_name. The system reads the bundle property for the installed label. Your navigation bar can use a different string from the main String Catalog if product requirements call for different wording.
Target membership matters. A localized file can exist in the repository while being absent from the built application. After adding or generating resources, inspect the target configuration and the final product. Install the build rather than assuming an Xcode file preview proves that the operating system will resolve the value.
Generated projects need another control. A Unity developer described knowing how to edit InfoPlist.strings in Xcode but needing to repeat the error-prone change after each generated build in a Stack Overflow app-name localization question. Automate that edit in the project generator, a post-build hook, or the native template instead of adding another manual release step.
A post-build check can fail when the expected locale resource is absent:
from pathlib import Path
required = ["en", "fr", "ja", "de"]
root = Path("GeneratedApp")
for locale in required:
resource = root / f"{locale}.lproj" / "InfoPlist.strings"
text = resource.read_text(encoding="utf-8")
if '"CFBundleDisplayName"' not in text:
raise SystemExit(f"Missing iOS display name for {locale}")
Adapt the paths to the generated project. Run regeneration and validation through the same automated path.
Localize the Android launcher label
Point the application label at a string resource instead of hardcoding text in the manifest:
<application
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme">
</application>
Define the development-language value in the default resource set:
<!-- res/values/strings.xml -->
<resources>
<string name="app_name">Acme</string>
</resources>
Then add translated values in locale-qualified resource directories:
<!-- res/values-ja/strings.xml -->
<resources>
<string name="app_name">アクミー</string>
</resources>
The Android manifest reference explicitly allows android:label to use a string resource. That indirection lets Android resolve the label through its normal resource selection rather than freezing one language in the manifest.
Check activity-level labels as well as the application element. An activity can declare its own label, and launcher behavior can therefore differ from what the top-level application value suggests. Record intentional overrides. Remove accidental ones or point them to the same owned resource.
Cross-platform frameworks often generate the manifest and resource tree. Modify the framework's native template or build plugin rather than editing generated XML after every build. Add a negative test that deletes one target app_name entry and confirms the validation job fails. A validator that remains green after the resource disappears does not protect the release.
Keep launcher and storefront names aligned without merging them
The launcher and storefront names need an explicit relationship, but they do not need one shared field. Record both values in a release manifest:
{
"locale": "ja",
"installedDisplayName": "アクミー",
"storeListingName": "アクミー タスク管理",
"inAppBrandName": "アクミー",
"reviewedBy": "mobile-l10n",
"sourceRevision": "release-42"
}
A release check should flag unexplained differences, not reject every difference. The longer Japanese store name above may be an approved discovery choice. The check passes when the difference has an owner and review record. It fails when the installed name falls back to English while the listing and product UI use Japanese.
Do not derive the launcher label from live store data at runtime. The installed name belongs to the application package and must be available before the app launches. Store metadata can still act as a comparison input during release review.
Build the change into the localization workflow
Add the launcher label to the same workflow that handles other release-critical strings:
- Product approves the source installed name and its relationship to store names.
- Localization sends the field with launcher context and concise-length guidance.
- Translation review approves each target value.
- The build writes or verifies native iOS and Android resources.
- Static validation checks required locales, target membership, and manifest references.
- Mobile QA installs release candidates and records the resolved labels.
- Release management compares launcher, store, and in-app naming before submission.
Translation review alone does not complete the field. Require a built artifact before closing it. The build exposes malformed resources, missing target membership, generator bugs, and fallback behavior that source-file checks cannot observe.
For monorepos, keep the platform outputs in the same change as the source record. A pull request that updates only iOS or only Android should fail unless the manifest marks the other platform as intentionally unchanged. This is a workflow recommendation, not a platform requirement, but it prevents silent platform drift.
Test installed builds with a small risk matrix
Test the package that users will receive. Use clean installs because launcher caches and previous application state can hide resource changes. At minimum, cover:
- The development language.
- One target language with a translated name.
- One regional locale that should use a parent-language value.
- One unsupported locale that should use the deliberate default.
- A script with different width or glyph characteristics.
- An upgrade from the previous release.
- A newly generated cross-platform project.
For each case, record the platform, OS version, selected device or app language, expected label, observed label, and artifact revision. Capture the home screen or launcher, but keep the text result in machine-readable test output too.
Avoid declaring a universal character limit for launcher labels. Available width depends on the device, display settings, launcher, and script. The same text expansion and truncation checks that protect in-app layouts apply here, on a much tighter budget. Choose a concise name, then inspect representative devices for truncation and ambiguity. A clipped label may still be acceptable if the brand remains recognizable; a translated label that becomes indistinguishable from another installed app is not.
Diagnose failures by artifact boundary
When iOS shows the source name, inspect the built product for the expected localized information-property-list resource. Confirm the file belongs to the app target and contains CFBundleDisplayName for the selected locale. If the source project is generated, compare output before and after the generator hook.
When Android shows the wrong label, inspect the merged manifest to identify the effective android:label. Then verify the resolved string resource in the selected configuration. Look for activity-level overrides and library manifest contributions instead of checking only the source manifest.
When both platforms are correct but the store name differs, route the defect to storefront metadata ownership. Do not patch native resources to compensate for a store workflow failure. When the in-app title differs, check the UI string owner separately.
Use a boundary-focused incident record:
Surface: Android launcher
Locale: ja-JP
Expected: アクミー
Observed: Acme
Merged label: @string/app_name
Resolved resource: default values/strings.xml
Cause: values-ja resource omitted from generated bundle
Fix owner: Android build pipeline
This record explains where resolution failed. A screenshot labeled "translation wrong" does not.
Common mistakes to reject in review
Hardcoding the Android label in the manifest blocks normal resource selection. Editing generated iOS resources by hand creates a fix that disappears on the next build. Reusing storefront copy without review ignores the different presentation context. Checking only repository files misses packaging and merge errors.
Another mistake is localizing a framework configuration value while leaving native outputs unchanged. The framework setting matters only if the generator writes it into the correct platform resources. Validate the final .app, archive, APK, or app bundle path used for release.
A successful default-language install does not prove localization works. Defaults are designed to resolve. Select a target locale and verify the exact label after a clean install.
Verify the app display name before release
Use this release checklist:
- The installed name has one source owner.
- Translators know the string appears under the app icon.
- iOS localizations contain
CFBundleDisplayNamein the application target. - Android
android:labelreferences an owned string resource. - Activity-level Android label overrides are intentional.
- Generated projects recreate localized resources automatically.
- Every supported launch locale has a reviewed value or explicit fallback.
- Store, launcher, and in-app names were compared without forcing them to match.
- Clean-install tests passed on both platforms.
- The final release artifacts, not only source files, were inspected.
Start with one target locale that currently shows the source name. Add the native resource, automate its generation, install both release candidates, and save the observed launcher labels as build evidence. Once that path is repeatable, expand the same check to every launch locale.
References
- Apple: CFBundleDisplayName defines the bundle key used for the user-visible installed application name.
- Android Developers: application manifest element defines
android:labeland its use of a string resource. - Stack Overflow: Localize iOS app name in Unity documents a generated-project workflow where manual iOS app-name localization must otherwise be repeated after builds.
