Localizable.strings failing to load every other build?
This issue occurs when:
- you have at least two files
*/<locale>.lproj/<table_name>.strings
, eg two files*/en.lproj/Localizable.strings
- you support more than one language with your
*.strings
files
You probably wouldn't create two+ .strings
files with the same name. This problem usually occurs when you use external library that has Localizable.strings
file(s) in its resources. You probably have Localizable.strings
file(s) in your resources - and that's the conflict that XCode fails to resolve.
TL; DR; General tip: if you create a library to be used as a third party code by other developers, instead of creating Localizable.strings
file and using NSLocalizedString()
in it, create custom-named localizable strings table (e.g. MyLibName.strings
) and use NSLocalizedStringFromTable
.
Problem example and detailed description:
I've created a "problem-demo" repository: https://github.com/kajot/LocalizedStringsMergingFailure
Specifically with a test that fails every other run: https://github.com/kajot/LocalizedStringsMergingFailure/blob/master/LocalizedStringsMergingFailureTests/LocalizedStringsMergingFailureTests.m
│ ├── KJAppDelegate.h
│ ├── KJAppDelegate.m
│ ├── Localizations1
│ │ ├── de.lproj
│ │ │ └── Localizable.strings
│ │ └── en.lproj
│ │ └── Localizable.strings
│ ├── Localizations2
│ │ ├── de.lproj
│ │ │ └── Localizable.strings
│ │ └── en.lproj
│ │ └── Localizable.strings
Every OTHER build, XCode will create a corrupted Localizable.strings
file in the bundle. Solution: do NOT create/add more than one LocalizedString
table with the same name to the same target.
LocalizedString
table is a set of */<locale>.lproj/<tableName>.strings
files. In the example above, there are two tables, each named Localizable
(default name for a table).
If a table is called Localizable
, you get localized strings from the table by using
`NSLocalizedString(key, optionalComment)`.
Solution:
You can either merge those two tables (concatenate corresponding files with translations from the same languages) or change the name of one of the tables.
Example of the second approach (changed name of one of the tables):
│ ├── KJAppDelegate.h
│ ├── KJAppDelegate.m
│ ├── Localizations1
│ │ ├── de.lproj
│ │ │ └── Localizable.strings
│ │ └── en.lproj
│ │ └── Localizable.strings
│ ├── Localizations2
│ │ ├── de.lproj
│ │ │ └── NewTableName.strings
│ │ └── en.lproj
│ │ └── NewTableName.strings
Now you can get a translation from the new table (NewTableName
) by using NSLocalizedStringFromTable(key, @"NewTableName", optionalComment)
and from the "original" table (Localizable
) using NSLocalizedString(key, optionalComment)
.
I cannot give you a straight out answer but can suggest some ways to proceed. I don't actually have a multi language app now, so most of this is what I've gleaned by reading up (I may have one soon so your issue is of interest to me):
1) Apple has deprecated the user of English.lproj in favor of en.lproj. In any case, its important that if you use "English" as your CFBundleDevelopmentRegion value, that the folder be named "English" and not "en".
2) Your strings file should be UTF16, and noted as such in the file inspector (that right most pane in Xcode)
3) There is a nice previous question that has some graphical pointers on insuring that your localization files are correctly entered in Xcode (so Xcode knows about then, and knows it must process them).
4) Its possible your file has gotten corrupt, the Resource Guide says you can run "plutil -lint Localizable.strings" on it to verify correctness
5) As a side note, a number of people have pointed to Mac App Store App as a nice utility to merge (not overwrite) strings files (as you make additions).
6) If things still look good, then add the following to your AppDelegate "didFinishLaunchingWithOptions" (at the top) when the app first launches:
NSBundle *bundle = [NSBundle bundleForClass:[self class]];
NSLog(@"Strings file: %@", [bundel pathForResource:@"Localizable" ofType:@".strings"]);
NSLog(@"Localizations: %@" [bundle localizations]);
NSLog(@"Local Dict: %@", [bundle localizedInfoDictionary]];
NSLog(@"localizedStringForKey: %@", [bundle localizedStringForKey:@"ReallyNewGame"value:@"WTF???" table:nil];
NSLog(@"Localized String: %@", NSLocalizedString(@"ReallyNewGame", @"Are you sure you want to start a new game?"));
exit(0); // just testing the above for now
Run the app several times. The output should be the same. If its not add a comment to this answer and we can drill down further. If it is the same, well, then something is causing corruption further on in your app.
In case it helps anyone else:
I encountered exactly the same problem: every other build the localizations would not work. I found when I inspected the bundle contents that the Localizable.strings in the en.lproj were corrupt - the file was only 76 bytes long when it should have been 4k. The next build the corruption was gone, then back again, then gone...
It turned out that I had copied over an extra Localizable.strings folder into my project when I had copied a folder from another project. When I deleted the extra Localizable.strings folder everything magically worked. Whew!