A translated iPad, Mac, or Android tablet app can pass every screenshot review and still fail the first German user who reaches for a shortcut. Picture a Back command whose menu title is correctly translated as "Zurück" while its shortcut is still Command-[. On a German layout the [ character sits behind Option-5, so the user who tries the shortcut ends up pressing Option-Command-5 instead. A Stack Overflow author described exactly this with an Xcode shortcut on a German MacBook keyboard: [ can only be typed with Option-5, so the documented shortcut was unusable.
Keyboard shortcuts are a localization surface with more moving parts than menu titles. A shortcut has a key, a set of modifiers, a direction (sometimes), and one or more human-readable labels that the operating system shows outside your screens. Translators usually see only the labels. Engineers usually treat the key as code. Nobody owns the question of whether the key still works for a person on a Swiss, Russian, or Arabic setup.
This guide covers the decisions that matter on Apple platforms and Android: when to rely on system remapping, when to localize shortcut keys yourself, how to handle right-to-left mirroring, which labels need translation, and what a release test matrix should include.
Why shortcuts break after translation
Three different failures hide behind "our shortcuts don't work in some languages."
Reachability. Apple's SwiftUI documentation for keyboardShortcut(_:modifiers:localization:) states the root cause directly: the key you pass is always defined in relation to the US-English keyboard layout. Punctuation moves or disappears on other layouts. Apple uses the same example as the Xcode user above: Command-[ is easy on a US keyboard, but a German user would have to type Option-Command-5.
Direction. Some shortcuts encode a direction. Back and Forward in a browser, previous and next page, seek backward and forward. In a right-to-left interface, "back" points the other way, so a bracket that meant "go left" now means the wrong thing.
Labels. The system displays shortcut names in places your string audit may never reach. On iPad, discoverabilityTitle is shown in the discoverability heads-up display, falling back to the command's title, and Mac Catalyst shows it as a tooltip. On Android, Keyboard Shortcuts Helper (Android 7.0 and later, opened with Meta+/) lists the groups and labels your activity publishes. Those labels are registered in code, separately from layouts and screens.
A fourth issue appears when teams try to fix the first three by hand, localizing shortcut letters themselves while the system is also remapping them.
Mobile localization checklists rarely mention any of this. The maclaunch checklist and Lang-Q's mobile localization guide cover internationalization, text expansion, translator context, images, store metadata, and testing, but say nothing about keyboard shortcuts. The i18nAgent iOS localization guide and Android localization guide focus on string catalogs and resource files. Microsoft's globalization documentation is the main exception, and its advice differs from Apple's default.
What Apple remaps for you
Since iOS 15, iPadOS 15, Mac Catalyst 15, and macOS 12, Apple remaps shortcuts automatically. UIKeyCommand.allowsAutomaticLocalization defaults to true. Apple's documentation explains that localized keyboards sometimes rearrange or replace punctuation marks to make room for a language's characters, and that the system "can automatically remap shortcuts, as needed, to accommodate the connected keyboard." It also limits the behavior: the system does not remap when the keys have identical positions on both keyboards or when the shortcut is still easily reachable. The remapping is transparent to your app.
AppKit has the same switch for menu key equivalents in NSMenuItem.allowsAutomaticKeyEquivalentLocalization. SwiftUI expresses it through KeyboardShortcut.Localization, which has three values:
| Option | Behavior Apple documents |
|---|---|
.automatic |
Default. Remap to international counterparts and mirror for right-to-left when appropriate |
.withoutMirroring |
Remap, but never flip direction. For shortcuts with a fixed direction |
.custom |
No automatic remapping. You handle international layouts yourself |
For the German case, the SwiftUI documentation says automatic remapping converts Command-[ to Command-Ö. For most apps that started with US-centric shortcuts, leaving the default in place is the cheapest correct choice. You still need to test it, because "transparent to your app" also means your own help screens and onboarding text can show a shortcut the user's keyboard no longer uses.
override var keyCommands: [UIKeyCommand]? {
let back = UIKeyCommand(
title: String(localized: "command.back.title"),
action: #selector(goBack),
input: "[",
modifierFlags: .command
)
back.discoverabilityTitle = String(localized: "command.back.discoverability")
// allowsAutomaticLocalization stays true: the system remaps "[" where it
// is hard to reach and mirrors it in right-to-left interfaces.
return [back]
}
If your onboarding, tooltips, or web help hard-code "Press ⌘[ to go back," they can disagree with what a remapped layout expects. Prefer pointing users at the system's own shortcut list (the iPad discoverability HUD or the Mac menu bar) instead of hard-coding glyphs, and check on a remapped layout what that list actually displays.
Choose remapping or per-language keys, not both
Pick one shortcut localization strategy per command: if you hand-localize shortcut keys per language, turn off Apple's automatic remapping with allowsAutomaticLocalization, allowsAutomaticKeyEquivalentLocalization, or the custom option, because Apple tells apps that already localize shortcuts to opt out and opting out also disables mirroring.
Microsoft and Apple start from different defaults. Microsoft's Keyboard shortcuts and localization page says shortcut keys often use the first letter of the action name, and that when action names are localized you should also update the shortcut keys. Its example: bold is Ctrl+B in English and Ctrl+G in French. The same page says that for languages that need an input method editor, such as Japanese, it is best to keep the original shortcuts. Apple's model instead keeps your US-defined key and remaps it per keyboard.
Either approach can work. Running both on the same command causes trouble. Apple's allowsAutomaticLocalization documentation says that if you already localize shortcuts for different languages, or let people customize shortcuts, you can set the property to false, after which you are responsible for supporting localized keyboards. It adds that setting it to false also disables automatic mirroring, as described for allowsAutomaticMirroring. The AppKit and SwiftUI equivalents behave the same way.
A practical decision rule:
- If your shortcuts follow platform conventions (copy, paste, undo, find, back, forward), keep system remapping. Users expect the same physical habits across apps.
- If your product deliberately derives letters from translated command names, as Microsoft describes for Office-style apps, own that table per language and opt out on every command that uses it.
- If users can customize shortcuts, opt out for customized commands so the system does not move a key the user chose on purpose.
- Keep the original shortcuts for IME-based languages unless you have a specific reason not to, following Microsoft's guidance.
When you opt out, the code makes the ownership explicit:
let boldKey = shortcutTable.key(for: .bold, language: currentLanguage)
let bold = UIKeyCommand(
title: String(localized: "command.bold.title"),
action: #selector(toggleBold),
input: boldKey,
modifierFlags: .command
)
bold.allowsAutomaticLocalization = false
// Mirroring is now off too. Handle right-to-left yourself if this
// command has a direction.
Practitioner opinion leans toward consistency. On a WPF team's question about strategies for localising keyboard shortcuts, one answer warns against symbol keys because they move between layouts, and suggests letting users keep English shortcuts if you switch letters per language. A UX Stack Exchange answer argues that consistency across languages matters more than mnemonic letters, since common Ctrl or Command shortcuts with X, C, V, A, W, and Q are standard in many languages without any mnemonic link. Those are author opinions, not platform rules, but they line up with Apple's default.
Separate keyboard layout from app language
Key shortcut decisions to the connected keyboard layout, not the app language: Apple remaps for the keyboard that is attached, and practitioners report users who read a translated UI on a US layout or switch layouts during the day.
Apple's documentation describes remapping in terms of "the connected keyboard" and "the current keyboard," not the app's localization. A person can run your app in Romanian on a US layout, or in English on a German layout. The answer quoted in the strategies for localising keyboard shortcuts thread summarizes a blog post that makes this point with a Romanian example: most computers there use a US layout, power users switch between several layouts, and layouts can change at any time. Treat those figures as one author's report. The design implication holds regardless of the exact numbers.
Non-Latin layouts add another wrinkle. A JavaScript developer asking about shortcuts on non-Latin alphabet keyboards wanted Ctrl+L to work on Cyrillic layouts. The top-voted answer notes that most such keyboards print both Latin and native characters and that users switch between modes, so a shortcut keyed on the typed character can stop matching the moment the user switches to the native alphabet. That thread is about web apps, but the same question applies to any native shortcut defined by character.
What to do differently:
- Never derive the shortcut key from the app's UI language alone. If you own a per-language table, decide whether it follows UI language or keyboard layout and document the choice.
- On Android, decide deliberately between the two
KeyboardShortcutInfoconstructors. One takes achar baseCharacter, documented as "the character that triggers the shortcut." The other takes anint keycodefromKeyEvent. The Keyboard Shortcuts Helper guide does not describe an automatic layout remapping equivalent to Apple's, so test both a non-US Latin layout and a non-Latin layout before you ship. - In translator notes, say whether a label refers to a letter that may change. Microsoft's page asks teams to give localization enough context to choose and set the right shortcut for a translated string, and to establish clear ownership for correct, working shortcuts at runtime.
Mirror navigation, not alignment
Mark absolute-direction shortcuts withoutMirroring: Apple mirrors bracket, brace, parenthesis, angle-bracket, and arrow shortcuts in right-to-left interfaces, which is right for Back and Forward but wrong for Align Left and Align Right.
allowsAutomaticMirroring states that iOS 15 and later swap input strings containing brackets [], braces {}, parentheses (), angle brackets <>, or arrow keys when the interface direction changes. Safari's Command-[ for back and Command-] for forward is Apple's example. allowsAutomaticKeyEquivalentMirroring documents the same for macOS 12 menu items, using Finder.
Mirroring is correct for navigation because "back" in Arabic or Hebrew points right. It is wrong for commands whose meaning is a fixed physical side. The SwiftUI documentation for KeyboardShortcut.Localization says to use .withoutMirroring for shortcuts that always have a specific direction, like aligning something on the right, and not to use it for navigational shortcuts like Go Back.
CommandMenu("Format") {
Button("Align Left") { alignLeft() }
.keyboardShortcut("{", modifiers: .command, localization: .withoutMirroring)
Button("Align Right") { alignRight() }
.keyboardShortcut("}", modifiers: .command, localization: .withoutMirroring)
Button("Back") { goBack() }
.keyboardShortcut("[", modifiers: .command) // .automatic: remapped and mirrored
}
Audit every command whose key is a bracket, brace, parenthesis, angle bracket, or arrow. Classify each as navigational (mirror) or absolute (do not mirror). Text alignment, left and right panel toggles, rotate left, and nudge-left in a design tool are typical absolute commands. Previous and next item, and back and forward, usually follow the interface direction. This pairs with the view-level mirroring work covered in general RTL guidance; shortcut direction is a separate inventory because it lives in command definitions, not layouts.
Localize the labels the system shows
Shortcut labels reach users through system UI, so treat them as first-class strings:
| Surface | Where the string comes from | What to check |
|---|---|---|
| iPad discoverability HUD | discoverabilityTitle, else title |
Translated, short enough to scan |
| Mac Catalyst tooltip | discoverabilityTitle |
Translated, not a raw key |
| macOS and iPadOS menus | Command title / SwiftUI button label |
Matches the screen terminology |
| Android Keyboard Shortcuts Helper | KeyboardShortcutGroup and KeyboardShortcutInfo labels |
Resolved from resources |
Android's own guide is a useful warning. Its sample passes literal English strings such as "Cursor movement," "Up," and "Send a message" into KeyboardShortcutGroup and KeyboardShortcutInfo. That works for a sample, but a shipped multilingual app needs translated labels there. The KeyboardShortcutInfo reference describes the label as the text "that identifies the action performed by this shortcut," and the helper shows it to users. Resolve it from string resources:
override fun onProvideKeyboardShortcuts(
data: MutableList<KeyboardShortcutGroup>?,
menu: Menu?,
deviceId: Int
) {
val navigation = KeyboardShortcutGroup(
getString(R.string.shortcut_group_navigation),
listOf(
KeyboardShortcutInfo(
getString(R.string.shortcut_next_item),
KeyEvent.KEYCODE_N,
KeyEvent.META_CTRL_ON
)
)
)
data?.add(navigation)
}
Resolving labels inside the callback with the activity's resources, rather than caching English strings at startup, is a reasonable way to keep them aligned with the current app language. Verify that after an in-app language change rather than assuming it.
On Apple platforms, give title and discoverabilityTitle their own catalog keys with comments. The discoverability title is often longer and more descriptive than the menu title, and translators need to know it appears in a heads-up list of shortcuts rather than on a button.
Check for collisions after localization
Localized shortcuts can collide in ways the source language never did. Microsoft's guidance asks teams to verify that shortcuts are functional, match the localized UI, and are not duplicated in a given part of the UI. Apple's SwiftUI documentation explains why a duplicate is silent: when multiple controls are associated with the same shortcut, the first one found is used. Nothing crashes; the second command stops responding.
Collisions usually come from two sources:
- A per-language table assigns the same letter to two commands because two translated names start with the same character.
- Automatic remapping produces a key that your app already uses for something else on that layout.
The first is testable offline: export the shortcut table per language and fail the build when two commands in the same scope share a key and modifier set. The second needs a device or simulator with the target hardware layout, because the remapped key is chosen by the system.
Release test matrix
Before you call shortcut localization done, run at least this matrix:
| Case | Example setup | Pass condition |
|---|---|---|
| Non-US Latin layout | German keyboard, German UI | Punctuation shortcuts reachable; record what the HUD and menus display |
| Mismatched layout | US keyboard, translated UI | Shortcuts follow your documented strategy, not the UI language by accident |
| Non-Latin layout | Russian keyboard in Cyrillic mode | Character-based shortcuts still trigger, or the limitation is documented |
| Right-to-left | Arabic or Hebrew UI | Navigation shortcuts mirror; alignment and absolute commands do not |
| Opted-out commands | Any command with remapping disabled | Per-language key works and RTL direction handled by your code |
| Labels | Every shipped language | HUD, tooltips, menus, and Android helper show translated labels |
| Collisions | Per-language shortcut table | No duplicate key and modifier set within one scope |
Assign owners. Engineering owns key definitions, remapping flags, and mirroring classification. Localization owns label strings, translator notes, and any per-language key table. QA owns the hardware-layout and RTL passes, which a screenshot-only review cannot cover.
Common mistakes
- Translating menu titles and assuming shortcuts are "just code." The key may be unreachable and the label may be English in the system list.
- Hand-localizing letters while leaving system remapping on, then wondering why a shortcut moved.
- Turning off remapping to fix one command and forgetting that mirroring is now off too.
- Mirroring every bracket shortcut, including Align Left and Align Right.
- Copying Android's sample code with literal English labels into production.
- Writing shortcut glyphs into help articles and onboarding copy that the system may remap on other layouts.
Next step
Start with an inventory: every command with a shortcut, its key and modifiers, whether it has a direction, whether its key is punctuation, every label string the system displays for it, and which strategy (system remapping or your own table) owns it. Review that table with every release, alongside the string catalogs and resource files your translators already work in.
