The Flutter i18n guide notes that iOS apps should define supported locales in an Info.plist
file. The guide then proceeds to give instructions that, as far as I understand, apply to the Xcode GUI. However, I do not have Xcode - or even a mac - and am planning on using GitHub actions to produce iOS builds. How can I perform the documented actions manually?
Typically, iOS applications define key application metadata, including supported locales, in an Info.plist file that is built into the application bundle. To configure the locales supported by your app, use the following instructions:
- Open your project’s ios/Runner.xcworkspace Xcode file.
- In the Project Navigator, open the Info.plist file under the Runner project’s Runner folder.
- Select the Information Property List item. Then select Add Item from the Editor menu, and select Localizations from the pop-up menu.
- Select and expand the newly-created Localizations item. For each locale your application supports, add a new item and select the locale you wish to add from the pop-up menu in the Value field. This list should be consistent with the languages listed in the supportedLocales parameter.
- Once all supported locales have been added, save the file.
I managed to add localizations without using Xcode. This is how I did it.
Info.plist
(within <dict>
):<key>CFBundleLocalizations</key>
<array>
<string>en</string>
<string>it</string>
</array>
I created an empty file called InfoPlist.strings
in the Runner
folder. You can put default strings here; I didn't.
I created folders Runner/en.lproj
and Runner/it.lproj
. In each folder I created another InfoPlist.strings
file.
I filled these InfoPlist.strings
with the localized strings, e.g.:
CFBundleDisplayName="Guidi Tu";
NSMotionUsageDescription="Due minigiochi usano l'accelerometro.";
project.pbxproj
. The tricky part starts now. Choose random IDs: two for Runner/InfoPlist.strings
and one for each of the localized Runner/*.jproj/InfoPlist.strings
files.I chose:
899999999999999999900000
and 999999999999999999900000
for the generic file;999999999999999999900001
for the English localization;999999999999999999900002
for the Italian localization.You need two IDs for the generic file because it is linked both as a "build file" and as a "file reference" in different sections of project.pbxproj
.
The IDs are 24 bytes long, you can use [0-9A-F] for each of the 24 digits, as long as they are new and unique they should be fine.
PBXBuildFile
section of project.pbxproj
:899999999999999999900000 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 999999999999999999900000 /* InfoPlist.strings */; };
PBXFileReference
section:999999999999999999900001 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
999999999999999999900002 /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/InfoPlist.strings; sourceTree = "<group>"; };
fileRef
!) to the generic file in the PBXGroup
section, within the Runner
group: 97C146F01CF9000F007C117D /* Runner */ = {
isa = PBXGroup;
children = (
97C146FA1CF9000F007C117D /* Main.storyboard */,
97C146FD1CF9000F007C117D /* Assets.xcassets */,
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
97C147021CF9000F007C117D /* Info.plist */,
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
999999999999999999900000 /* InfoPlist.strings */,
);
path = Runner;
sourceTree = "<group>";
};
PBXResourcesBuildPhase
section, within this Resources
build phase: 97C146EC1CF9000F007C117D /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
899999999999999999900000 /* InfoPlist.strings in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
fileRef
) in the PBXResourcesBuildPhase
section, setting all localized files as variants: 999999999999999999900000 /* InfoPlist.strings */ = {
isa = PBXVariantGroup;
children = (
999999999999999999900001 /* en */,
999999999999999999900002 /* it */,
);
name = InfoPlist.strings;
sourceTree = "<group>";
};
That's it. It works now.
Check carefully each step if you want to reproduce the process.