beta
beta

Reputation: 647

Localizable.strings failing to load every other build?

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: How it looks when correct

Incorrect: How it looks when 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

Answers (7)

Anibal Itriago
Anibal Itriago

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!

For example: This works great: As you can see, the NSLocalizationString commands replaces correctly the strings at the template

Now, note the double semicolon

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

kajot
kajot

Reputation: 303

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).

Upvotes: 3

user2338215
user2338215

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

holex
holex

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

If value is 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

Maverick1st
Maverick1st

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

David Hoerl
David Hoerl

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

iXcoder
iXcoder

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

Related Questions