Reputation: 647
I have been having a strange problem with the localization system built into Cocoa. I used genstrings to create a localizable.strings file for my project, and the file loads and replaces the strings as expected in my app.
However, it appears to only work every other build. I will build the code with XCode, test it on my device, and it will display the correct strings no problem. The next build, however, will fail to load the strings file (At least, that's what I'm assuming.) This is not random, but predictably every other build. I am doing nothing fancy with the Localizable.strings file.
I have no idea where to even start in diagnosing this issue, and I was wondering if anyone had experience with doing localizations on Cocoa.
I am using NSLocalizedString throughout my code base like so:
NSLocalizedString(@"ReallyNewGame", @"Are you sure you want to start a new game?")
The corresponding entry in my Localizable.strings file:
/* Are you sure you want to start a new game? */
"ReallyNewGame" = "Do you really want to start a new game?";
Here are the relavent parts of my Info.plist:
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
Here is a screenshot of what happens every other build of the app:
Correct:
Incorrect:
I am baffled as to why this happens. I do not do anything manually with the Localizable.strings file and I have cleaned my project several times on XCode. Any pointers in the right direction would be greatly appreciated. If you need any more information, I will attempt to provide it.
Thanks!
Upvotes: 12
Views: 7430
Reputation: 1051
I just found something that was killing me! I had the same issue: Depending on the STRINGS file, sometimes it Works, some times doesn't/
What I found, is that if some line in your .strings file finishes with double semicolon
;;
all the lines below ware ignored!
The upper image works great: As you can see, the NSLocalizationString commands replaces correctly the strings at the template But the other image shows that, before the double semicolon, it will ignore everything. It is a complete mess! No resources compilation error, nothing. Just a nightmare!
Hope it helps someone to don't get insomnia!
Upvotes: 0
Reputation: 303
This issue occurs when:
*/<locale>.lproj/<table_name>.strings
, eg two files */en.lproj/Localizable.strings
*.strings
filesYou 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)
.
Upvotes: 3
Reputation: 831
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!
Upvotes: 6
Reputation: 24031
the behaviour, what you've experienced, is totally normal. why?
if you check these lines, the relevant part of original macro definition of the NSLocalizedString
:
#define NSLocalizedString(key, comment) \
[[NSBundle mainBundle] localizedStringForKey:(key) value:@"" table:nil]
you could see the comment
parameter is deceptive parameter, it is never used. (it is just for the developer who reads the code)
futhermore, if you check the NSBundle
class Reference, you could read the following interesting thing about the return value of the -localizedStringForKey:value:table:
method:
Return Value
nil
or an empty string, and a localized string is not found in the table, returns key.this is why you get back your key because probably there is no value for this key in your Localizable.string
files.
sad news, but it is normal.
the solution would be the following:
NSLocalizedString(@"Are you sure you want to start a new game?", @"");
and in your Localizable.string
file:
@"Are you sure you want to start a new game?" = "Do you really want to start a new game?";
Upvotes: 0
Reputation: 3770
I had an similar issue regarding my app-icon. I had several targets in my app and all with different app-icons. For some reason one of the app-icons was corrupt and thus all of my targets switched through the app-icons of the other targets. which is pretty odd, because one target should not know of the other targets app-icon, if it is not used for both targets and marked for both targets in xcode.
I solved this issue through deleting the corrupt png and adding it anew to the project. If you do this with your i18n file it might help, too. But be sure, to remove not only the reference from xcode but the complete file. Best would be to open the file in some external editor like textwrangler and copy the text to a new file and then use this instead.
Good Luck.
Upvotes: 0
Reputation: 41642
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.
Upvotes: 7
Reputation: 1564
other thread may helps... Multiple Localizable.strings files in one iOS app
again, maybe you can cleanup and then build the app from xcode...
Upvotes: 0