I have a project with multiple targets.
Most localizations are shared by all targets.
I have them in Localizable.strings.
In addition, each target has strings to localize that occur only in that target.
Is there a preferred way to have an additional target specific .strings file?
If so, how can I use NSLocalizedString to search localizations
in Localizable.strings and/or the target specific .strings?
Technically I could put all localizations for all targets into Localizable.strings and deploy the with all targets (No problem, there are no target specific localizations for the same string).
But this would a little messy to maintain.
So is there a way to use a target specific additional .strings file?
Related
I have a project that have 3 build configurations: Debug, Beta and Release. These configurations have different app name each. I am doing this using a variable like APP_DISPLAY_NAME and using it in Info.plist file.
I need to localize these app names.
Using InfoPlist.strings file with "CFBundleDisplayName", overrides these configuration names.
So how can I do this?
I have checked this and a couple more questions but still no result.
Here's how you can have different InfoPlist.strings for different build configurations in the same target.
In your Build Settings:
Specify a different Info.plist File (INFOPLIST_FILE) for each configuration.
Set Adjust Strings File Names for Info.plist (STRINGS_FILE_INFOPLIST_RENAME) to Yes. On Xcode 14, it was set to Yes by default.
Create .strings files with the base name of your Info.plist filename + Plist.strings.
For example, if your Info.plist filename is Beta-Info.plist, your strings file should have the name Beta-InfoPlist.strings. Make sure you include all of these strings file to your build.
Do not include an InfoPlist.strings file in your target.
The key to making this work is Adjust Strings File Names for Info.plist in the Build Settings Reference.
Adjust Strings File Names for Info.plist.
Setting name: STRINGS_FILE_INFOPLIST_RENAME
If enabled, renames .strings files whose basename matches that of the target’s Info.plist file, to InfoPlist.strings in the built product.
Example
Here's an example in my app which has 3 different variants (AdSupported, AdSupported-Dev, Pro) that require different app names.
Build settings. (I have debug & release configurations for each variant, but you could also do this with just Debug / Beta / Release.)
Strings files. They are all included in my target.
Info plist files. As usual, they are specified in the Build Settings and NOT included in my target.
I have multiple targets in my project, and only one target needs to be using localized strings. How do I make it so only that target will be localized (with .lproj) and the rest continues to use the development language? Currently Xcode allows you to add Localization to the entire project, not a specific target.
I have a project with 3 targets. Each target needs to suppport only one language, but the language is not the same for each target.
Currently I have
Target 1 (es)
Target 2 (es)
Target 3 (pt)
Most of my strings are in a Localizable.strings file, and I simply target a different file for each target. However, a number of strings are in my storyboards. My problem is that it does not seem possible to create different storyboard localization files for each target. If I change the targeting of the portuguese file, the targeting of the spanish file changes automatically.
A possible solution is to duplicate each Storyboard for each target, but this won't scale well as the number of tagets grow. I could also modify all the text with NSLocalizedString in each ViewController, but this seems tedious and error prone.
Is there a better solution?
Shared Storyboard across targets
While this answer is the preferred approach, you can assign different Storyboard localizations to different targets, while sharing the same Storyboard across all targets.
Prerequisites:
Follow this instructions in this answer.
Concept:
You want to have the Main.storyboard in each target, but a different Main.strings in each target. Additionally, you do not want all localizations to be available in each target.
To achieve this, you must manipulate the .lproj directly, a process which is hidden when merely using the File Inspector.
Step by step:
Create all the pieces by following the steps in this answer.
From any target, remove the Main.storyboard. Of course, select Remove Reference to keep the storyboard around.
In the Finder, locate Base.lproj. Drag and drop Main.storyboard back to your project, and select every target.
In the File Inspector, ensure that the languages are not selected, and that you are still using Localizable Strings.
In the Finder again, locate en.lproj, es.lproj, fr.lproj, etc. Notice that they each contain a version of Main.strings. Drag these .lproj (the entire directories) back into your project. This time, do not select any target
One last time, in File inspector, associate each Main.strings to the desired target. Repeat for each .strings.
Conclusion
By decoupling the .lproj from the .storyboard in the Project Navigator, you can associate files and targets freely.
Demo:
See it at work using a French target, on a device with language set to Français in the Settings:
► Find this solution on GitHub and additional details on Swift Recipes.
Shared localizations across targets
Assuming you already have multiple languages in your project, in the Project Navigator, select your storyboard (say Main.storyboard)
In the File Inspector, under Localization, add English. Pick Localizable Strings which is the default. This will create a Main.string for each language, and share your Storyboard across all languages.
Merely clicking that checkbox in step 2. will add a Main.string (English) for that language, specifically for that Main.Storyboard. Pay special attention to the new hierarchy, these are not Localizable.strings but Main.strings, derived from Main.storyboard:
Localize in each language file to your heart content.
For example, starting with a UILabel which message was in Esperanto, it will appear in English when the device runs in English:
/* Class = "UILabel"; text = "Tiu mesaĝo estas en Esperanto"; ObjectID = "acC-pA-eMt"; */
"acC-pA-eMt.text" = "This message is in English";
Start here to add multiple languages to your project:
In the event you need to add more languages, follow these steps:
In the Project Navigator, select your Project
In the Project and Target List, select, once again, the Project
Select the Info tab
Under Localizations, keep Use Base Internationalization (unless your UI itself must change across languages)
Click +, pick a new language. In the dialog presented to you, select every Storyboard you want to have multiple localizations for.
If you missed Storyboards at Step 5. you can simply add a new language to that a storyboard by following the steps in Assuming you already have multiple languages.
All you need: to make common xcode workspace for your app, then to create a duplicates of main xcodeproj file for your set of languages and make different targets for all of them, also then you can set language for individual project settings in new xcodeproj's. Also you easy can tune build phase 'Copy Bundle Resourses' and others. I use this method. If you have a Xcode's crash during adding project in workspace - open project with Xcode, rename it and rename or duplicate targets (I think same names cause this issue).
I have 2 Apps : Free & Full
I have 2 Languages : English & German
This results in 4 different App-Names
How can I achieve this.
Actually all my targets have the name "Free" in it, even it the the Full Version.
I know:
I have 1 InfoPlist.strings File, which is multiplied by Localization and I can assign them to targets. So for 1 App I can localize the BundleDisplayName.
But how can I assign the specific names for the second app ?
PlistBuddy is your friend here. What you need to do is update your plist in a build time.
You have to create custom scheme for every target you have (I assume you are already has that)
In your xcode go to scheme and add post action like that to custom scheme target:
Here is the code:
infoplist="$BUILT_PRODUCTS_DIR/$INFOPLIST_PATH"
/usr/libexec/PlistBuddy -c "Set CFBundleName some_new_name_here" "$infoplist"
Important thing with this approach is that you're not change nothing in your plist file but with post-actions you already changing the packet prepared for device, so you keep your code repository nice and clean.
Associate InfoPlist.strings to targets
From the Apple Developer Technical Notes:
If your app supports localization, be sure to localize CFBundleDisplayName by adding it to all your language-specific InfoPlist.strings files. Furthermore, be sure to use a name that complies with the App Review Guidelines for your app.
Prerequisites
I am assuming you already have multiple targets.
I am also assuming you already have an InfoPlist.strings file. If your do not, code > File > File... > Resource > Strings File > Next > Save As: InfoPlist > Base.lproj > Target: the english target > Create
Ensure you have enabled this in your Info.plist:
<key>LSHasLocalizedDisplayName</key>
<true/>
Step by step
In Project Navigator, select InfoPlist.strings.
In File Inspector > Localization, select all the languages. This will create and/or copy said InfoPlist.strings into their respective locations.
Would you want to add languages, you achieve this in Project Navigator > project > Project & Target List > Project > Info > Localizations > +. Again, keep Use Base Internationalization.
Unfortunately, when you execute step 2., Xcode does all the magic for you. It is worth noting that in versions of Xcode where that magic did not happen, you had to do the associations by hand. Step 5. is about reverting the magic.
Remove InfoPlist.strings from the Project Navigator. Of course, only Remove References when prompted.
In the Finder, locate en.lproj, drag it onto your Project Navigator, pick Create Groups, add to target your English, or Base target, Finish
Repeat step 6 with de.lproj, fr.lproj, each time dragging the entire .lproj from the Finder, and associating with the appropriate target.
Some .lproj may contain other localized files for which you want to enjoy the magic of step 3. Simply remove their references.
You are done.
The final setup, for say the German language, will look like this in the File Inspector:
References:
Share localization across targets:
This is the general method to achieving localization. See https://stackoverflow.com/a/33749062/218152.
Specific localization to specific targets:
This is only useful if you want to explicitly control which languages go into which target. See https://stackoverflow.com/a/33791181/218152.
I have a couple of targets for my app. I am trying to localize them differently. I have found this to be pretty easy when dealing with a Localizable.strings file and the NSLocalizedString macro. To get this to work I simply adjust the target membership of the Localizable.strings file for the target I am working with. So my project file structure looks something like:
project
target1
en.lproj
Localizable.strings
it.lproj
Localizable.strings
target2
en.lproj
Localizable.strings
it.lproj
Localizable.strings
Now my project has 2 targets being built with completely different english translations. Perfect, this is what I want.
My difficulty comes into play when I try to do the same thing for the *.strings files that are generated when localizing a view. My deployment target is 6.0 and I am using storyboards with base internationalization. So when I add a view to my project structure it will look like:
project
target1
Base.lproj
SomeStoryboard.storyboard
en.lproj
Localizable.strings
SomeStoryboard.strings
it.lproj
Localizable.strings
SomeStoryboard.strings
target2
en.lproj
Localizable.strings
SomeStoryboard.strings
it.lproj
Localizable.strings
SomeStoryboard.strings
My goal was to let each target have a different localization for each target, yet maintain the same Base storyboard. I also wanted to avoid something like: naming the target2 storyboard string files something like REPLACEMENT_SomeStoryboard.string and then writing a script that for every file named such in a given target delete SomeStoryboard.string and rename REPLACEMENT_SomeStoryboard.string to SomeStoryboard.string.
Attempt #1
So what I tried to do was remove the target1 en.lproj/SomeStoryboard.strings & it.lproj/SomeStoryboard.strings from the target2 membership. But this also removed the Base.lproj/SomeStoryboard.storyboard from the target2 membership. So basically membership was managed as if it were one file, which makes sense.
Attempt #2
The second thing I tried was to add target1 SomeStoryboard.storyboard to the membership of target2 and also create a SomeStoryboard.strings file and add that to the membership of target2. I tried adding this extra strings file into the Copy Bundle Resources Phase. I also tried adding the Copy Files Phase (after the Copy Bundle Resources Phase). Either way it appeared to only occasionally replace the SomeStoryboard.strings from target1. So the end result was that sometimes target2 picked up the localization from target1 and sometimes it was localized from target2.
Try using the method described at http://smoothlocalize.com/ (click on the first tutorial in the first main box). You download a small library that allows you to use Localizable.string for your resource strings the same way you do for .m files.