I developed a Safari extension which includes multi-language support. In order to test it properly, I decided to go for the following setup: Instead of switching languages by hand, I let Xcode do it: one scheme per platform and language, and for the iOS simulator pre-action script that switches the Simulator’s language before the app launches.
The idea
For each language I created two schemes:
App (macOS) - DE App (iOS) - DE
App (macOS) - EN App (iOS) - EN
In Xcode, you can pick a scheme, press Run, and the app starts in that language.
Part 1: Language and region in the Run action
Every scheme is a normal copy of the base scheme. The only difference in the macOS schemes sits in the LaunchAction:
<LaunchAction
buildConfiguration = "Debug"
language = "de"
region = "DE"
...>
This is the same as Edit Scheme → Run → Options → App Language / App Region. It launches the app with -AppleLanguages (de) and the matching region. That is enough on macOS: the app and its Safari extension resources come up localized, and the system stays untouched.
Part 2: Making the iOS Simulator follow along
On iOS the scheme language only affects the host app. The Safari extension is loaded by Safari, which follows the Simulator’s system language. So the iOS schemes also have a Run → Pre-actions entry, such as “Set Simulator Language to German”, that runs before the app launches. It is stored in the scheme as a ShellScriptAction:
<PreActions>
<ExecutionAction ActionType = "...ShellScriptAction">
<ActionContent
title = "Set Simulator Language to German"
scriptText = "..."
shellToInvoke = "/bin/sh">
The script looks as follows:
LANG="German"; APPLANG="de"; APPLOCALE="de_DE"
exec > "$LOGFILE" 2>&1 # keep a log, Xcode hides pre-action output
# 1. Find the Simulator Xcode is about to use
UDID="${TARGET_DEVICE_IDENTIFIER:-${SIMULATOR_UDID:-}}"
[ -z "$UDID" ] && UDID=$(simctl list devices booted | awk -F '[()]' '/Booted/{print $2; exit}')
PLIST="$HOME/Library/Developer/CoreSimulator/Devices/$UDID/data/Library/Preferences/.GlobalPreferences.plist"
# 2. Shut the device down so the change is not overwritten
simctl shutdown "$UDID" || true; sleep 2
# 3. Rewrite language and locale
PlistBuddy -c "Delete :AppleLanguages" "$PLIST" || true
PlistBuddy -c "Add :AppleLanguages array" "$PLIST"
PlistBuddy -c "Add :AppleLanguages:0 string $APPLANG" "$PLIST"
PlistBuddy -c "Set :AppleLocale $APPLOCALE" "$PLIST" || PlistBuddy -c "Add :AppleLocale string $APPLOCALE" "$PLIST"
Xcode then boots the Simulator, which comes up in German, with Safari and the extension’s popup in German too.
Michael Hülsen