Skip to main content

Localize File Provider Domains and Document Roots Without Leaving English Files Labels

2026-11-06

Localize File Provider Domains and Document Roots Without Leaving English Files Labels

A multilingual cloud or document app can look finished inside its own browser and still greet users with an English location name in iOS Files, a stale Finder sidebar domain, or an English Storage Access Framework root on Android. Drivers of that bug are rarely missing in-app translations. File Provider and DocumentsProvider own those labels. Your ordinary string catalog never paints them unless you push localized values into domain registration and root queries before the OS shows the location list.

Treat Files and document-root labeling as a release surface. Inventory the strings, resolve them in the user's effective app language, re-register when language changes, and verify system pickers with the same rigor you already apply to the host UI.

Why Files roots drift from the app language

Document sync usually has two owners. Your app owns the in-app file list, account switcher, empty states, and settings. The operating system owns the Files location row, Finder sidebar domain, UIDocumentPickerViewController provider list, and Android's Storage Access Framework roots. Apple's displayName on NSFileProviderDomain is the name shown in that system UI. Android's DocumentsContract.Root.COLUMN_TITLE is the required user-visible root title returned from queryRoots.

That split creates a localization gap:

  1. Host UI strings live in a String Catalog or strings.xml. Files root labels are constructor arguments or cursor columns the extension returns to the OS.
  2. Domains and roots are often registered once at first sign-in with whatever language was active then.
  3. The user's in-app language can disagree with the device language the OS uses for surrounding Files chrome.
  4. A second account, team workspace, or personal vault needs a distinct label that still follows service-versus-account naming rules.
  5. Hardcoded English titles such as "Personal", "Work", or the English product name never reach translators because they never lived in the catalog that Files reads.

Practitioner reports match that model. A Stack Overflow author asks how to set a programmatic File Provider display name such as "Personal" in the Files app (Stack Overflow question). An Apple Developer Forums thread discusses custom naming around NSFileProviderDomain and notes Feedback about displayName behavior for single-domain setups and the inability to mutate an existing domain's name without re-registration. Nextcloud's File Provider Localization work treats shell-integration strings as their own localization surface. An ownCloud iOS issue discusses multi-account presentation inside the Files app. Those reports are project-specific, not proof of a universal OS defect. They still show the integration questions your workflow must answer.

General iOS localization guides, including Phrase's iOS localization overview and the live i18nAgent iOS guide, cover catalogs and UI strings. They do not connect File Provider domain names to app-language ownership. The Android localization guide likewise stops short of DocumentsProvider root-title rules.

Build a Files-root string inventory

Keep a separate Files-root string inventory for service titles, account suffixes, and empty-state summaries instead of reusing in-app browser chrome that never reaches Files.app or the Storage Access Framework.

For each root presentation string, record:

Field Why it matters
Stable key Shared meaning across iOS and Android when the root role matches
Apple surface NSFileProviderDomain.displayName, domain identifier, extension Info.plist name
Android surface COLUMN_TITLE, COLUMN_SUMMARY, COLUMN_ROOT_ID, root flags
Source of truth Product name, account display name, workspace label, or localized role template
Locale owner Effective app language, device language, or server-provided account name
Timing Available before first add(domain) / first queryRoots, or only after profile fetch
Fallback Localized product name, "Account", or truncated email local-part with translator review
Verification Files Locations, Finder sidebar, document picker, SAF picker, after language change

Map app locales to Files test locales deliberately. Shipping German in-app browsing does not prove the German Files path if every QA account still registers an English displayName from a staging fixture.

Put service titles and account role templates in the same translation pipeline as the rest of the app, with translator notes that the string appears in the system Files or document picker UI and should stay short. Avoid format strings that glue an unlocalized email to an English product suffix unless every locale has been reviewed for that pattern.

Resolve the effective app language before you register the root

Resolve NSFileProviderDomain.displayName and DocumentsProvider COLUMN_TITLE in the user's effective app language before domain add or queryRoots, because those APIs snapshot the string the OS will keep showing in Files and SAF.

On iOS and iPadOS, Apple's synchronizing File Provider guide shows constructing a domain with an explicit display name when calling NSFileProviderManager.add:

let displayName = String(
    localized: "file_provider.domain.personal",
    bundle: .main
)
let domain = NSFileProviderDomain(
    identifier: NSFileProviderDomainIdentifier(rawValue: accountID),
    displayName: displayName
)
NSFileProviderManager.add(domain) { error in
    // handle registration errors
}

Resolve displayName from the same effective locale you use for the host UI: the in-app language picker or the per-app language setting, not a hard-coded English product string. If the account profile returns a user-visible workspace name, decide whether that name is already localized by the server, needs client-side templating, or should be treated as a proper noun that stays unchanged.

On Android, return localized columns from queryRoots according to DocumentsContract.Root. Android's documentation states that COLUMN_TITLE is required and that a single storage service surfacing multiple accounts as different roots should use the service name as the title. Put account identity in COLUMN_SUMMARY or in distinct roots with carefully reviewed titles rather than shipping an English-only title cursor.

override fun queryRoots(projection: Array<out String>?): Cursor {
    val locale = appEffectiveLocale()
    val matrix = MatrixCursor(resolveRootProjection(projection))
    matrix.newRow()
        .add(Root.COLUMN_ROOT_ID, "primary")
        .add(Root.COLUMN_TITLE, context.getString(R.string.documents_root_service_title))
        .add(Root.COLUMN_SUMMARY, accountSummaryFor(locale))
        .add(Root.COLUMN_DOCUMENT_ID, ROOT_DOC_ID)
        .add(Root.COLUMN_FLAGS, Root.FLAG_SUPPORTS_CREATE or Root.FLAG_SUPPORTS_SEARCH)
        .add(Root.COLUMN_ICON, R.mipmap.ic_launcher)
    return matrix
}

Load those string resources through the provider context configured for the app's selected language, not only the device default. If your DocumentsProvider runs in a separate process, confirm it reads the same language override as the host app.

Treat language changes as re-registration, not as a catalog refresh

Treat an in-app language change as a provider re-registration event: remove and re-add File Provider domains or notify Android root changes, since displayName is not a live-bound catalog lookup.

Apple's domain model stores the display name you supplied when the domain was added. Forums Feedback around modifying an existing domain's display name is a signal that teams cannot assume a silent rename API. After the user switches language in your settings screen:

  1. Resolve the new localized displayName values for every active account domain.
  2. Remove the old domains through NSFileProviderManager.remove.
  3. Re-add domains with the new names and the same stable identifiers where the platform allows.
  4. Re-enumerate providers in QA on Files Locations and in a document picker sheet.
  5. Confirm offline and signed-out states still show a safe localized fallback rather than a blank row.

On Android, after a language change call ContentResolver.notifyChange on your roots URI, or otherwise ensure the next queryRoots returns titles from the new locale. If the system cached an English title, force a roots refresh path your QA script can trigger. Do not rely on relaunching the host Activity alone if the provider process kept the old configuration.

Also re-check extension-local resources. Some File Provider chrome comes from the extension target's Info.plist display name and localized InfoPlist strings. Keep those keys in the Files-root inventory so translators see them beside domain titles.

Multi-account naming without English defaults

Multi-account products create the most visible English leftovers. Users compare "Personal" and "Work" side by side in Files. If only the host app translated those words, the system list still looks unfinished.

Decide a naming contract up front:

  • Service title: the product or provider name shown as the primary root title when Android guidance calls for the service name.
  • Account discriminator: email, workspace name, or localized role such as Personal / Work.
  • Collision rule: what happens when two accounts would otherwise share a display name.
  • Server-provided names: whether a backend workspace title is user language, org language, or invariant.

Document that contract for engineering and localization. Ship every discriminator through the translation pipeline, including the empty-account and signed-out placeholders. When you create the second domain or root, resolve its label with the same effective app language helper used for the first.

ownCloud's multi-account Files discussion and Nextcloud's shell-integration localization work both show that Files presentation is an explicit product surface, not an accident of the first English build.

Verify system pickers like any other release surface

Add Files and SAF checks to localization QA:

  1. Fresh install in a non-English app language, then open Files Locations / SAF picker before opening the host browser.
  2. Sign in a second account and confirm both roots are localized and distinguishable.
  3. Switch the in-app language and confirm domains or roots refresh without requiring reinstall.
  4. Open UIDocumentPickerViewController or Android's document tree picker and confirm provider labels match Files.
  5. Kill the app, reboot if needed, and confirm the OS still shows the localized root.
  6. Pseudo-localize domain titles to catch truncation in the sidebar.

Fail the release if the host UI is translated but any root remains English or stuck on a previous language. That gate matches the one you already use for widgets, share extensions, and CallKit labels: the OS surface is part of the product.

How this fits an app localization workflow

Wire Files-root strings into the same ownership model you use for other system surfaces:

  • Engineers own registration timing and re-add / roots-notify behavior.
  • Localization owns service titles, role templates, and translator notes about Files chrome.
  • QA owns language-change and multi-account matrices on real Files and SAF UIs.
  • Product owns whether account emails appear raw in the sidebar or behind a localized template.

Closest related workflows in this series cover in-app language changes without stale UI, share extensions, and platform setup in the iOS and Android guides. None of those replace a dedicated File Provider and DocumentsProvider root inventory.

Release checklist

Before you ship a multilingual document provider:

  • Files-root inventory exists and is separate from in-app browser strings
  • displayName and COLUMN_TITLE resolve in the effective app language before first registration
  • Language-change path removes/re-adds domains or refreshes roots
  • Multi-account discriminators are translated and collision-tested
  • Extension Info.plist / provider labels are included in the same review
  • QA signed off Files, Finder or document picker, and SAF in at least two non-English locales

When those boxes are green, Files no longer advertises an English product the moment users leave your custom browser.

Key takeaways

  • Files.app, Finder, and Android SAF roots are OS-owned surfaces fed by File Provider and DocumentsProvider APIs.
  • Snapshot localized domain and root titles at registration time in the user's effective app language.
  • Re-register or refresh roots after language changes; do not expect catalog hot-reload to rename system locations.
  • Keep a dedicated string inventory for service titles, account suffixes, and summaries.
  • Gate releases on system picker verification, not only on the in-app file browser.

Extensions that run outside the main app share this problem; see how to keep share extensions in the app's selected language.