7

I'm building a version of an App I have already released, but with a few changes. It's not quite a lite/full version relationship, but they're similar enough that I'm using the same project with a different target.

I'd like to reword almost all of the strings I have used in the first version for the new version, and was wondering the best way to approach this. Rather than use #ifdef/#else statements before the declaration of each string, I was thinking of using NSLocalizedStrings. However, the actual language is still the same.

I read in this post that you can set the language yourself, so presumably I can invent my own language and set it to that. But I'm wondering if this is the best way to go about things? Any advice would be most welcome.

Community
  • 1
  • 1
Smikey
  • 8,106
  • 3
  • 46
  • 74

3 Answers3

13

You can have multiple string tables for any given language (that is multiple .strings files). When you want a localised string, you can obtain it through:

NSString *str;

// Look up string in Full.strings
str = [[NSBundle mainBundle] localizedStringForKey:@"SomeKey"
                                             value:@"DefaultValue"
                                             table:@"Full"];

// Look up strings in Lite.strings
str = [[NSBundle mainBundle] localizedStringForKey:@"SomeKey"
                                             value:@"DefaultValue"
                                             table:@"Lite"];

Since the table for this method can be variable, you can even switch it at runtime. The above assumes you have a Full.strings table and a Lite.strings table.

Full.strings

"SomeKey" = "This string appears in the full version";

Lite.strings

"SomeKey" = "This string appears in the lite version";

You may not want to ship them together, if that is the case, you can configure your Info.plist to contain the name of the table to use for a specific target (if you add an entry called "TableToUse", you can get it via [[[NSBundle mainBundle] infoDictionary] objectForKey:@"TableToUse"])

Community
  • 1
  • 1
dreamlax
  • 93,976
  • 29
  • 161
  • 209
  • 1
    +1 Very interesting and helpful. Maybe one wants to define a macro for these two long calls like `NSLocalizedString()` is one, AFAIK. – GorillaPatch Feb 21 '11 at 12:54
  • 1
    @GorillaPatch: There's always [`NSLocalizedStringFromTable()`](http://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Miscellaneous/Foundation_Functions/Reference/reference.html#//apple_ref/doc/uid/20000055-SW16), it may look cleaner and the result is identical, but personally I prefer the full route, it feels more Cocoa-y to me. – dreamlax Feb 21 '11 at 13:15
2

NSLocalizedStrings actually is a macro defined as

#define NSLocalizedString(key, comment) \
        [[NSBundle mainBundle] localizedStringForKey:(key) value:@"" table:nil]

With table parameter set as nil, the code will use the default one "Localizable" so if we add another localized string file, we should call [[NSBundle mainBundle] localizedStringForKey:value:table: directly instead of calling NSLocalizedStrings

Qiulang
  • 10,295
  • 11
  • 80
  • 129
0

I'd be very hesitant to invent my own language, but you probably don't need to either. If you use NSLocalizedString in the appropriate places and then use genstrings to extract these to a Localizable.strings (see the docs), then you could simple have two versions of this file and then copy the correct version in each target.

Martin Gjaldbaek
  • 2,987
  • 4
  • 20
  • 29
  • Giving this the answer as it seems to be a more elegant solution. I'll give it a go :) – Smikey Feb 22 '11 at 11:48
  • Btw, what's the best way to copy the localizable.strings file? I tried creating a new folder in the project folder, and dragging it in to xcode's Resource folder (choosing to 'Create Folder References for any added folder'), then copying the localizable.strings file into the new folder in Finder. This made it automatically appear in Xcode, but I can't seem to drag it in to Xcode to ensure it's added correctly (i.e. UTF-16). And I'm not sure this was the best approach anyway... – Smikey Feb 22 '11 at 15:07
  • I'd probably go with right click on whichever group you want to add it to->Add->Existing Files... to ensure that the encoding is correct. As for whether this or dreamlax's approach is better - I use this approach for all files that are different when building my free and paid app using targets - but I haven't needed to use it with Localizable.strings so YMMV. I was quite impressed with dreamlax's approach too, so feel free to change your accepted answer if you go with it after all. – Martin Gjaldbaek Feb 22 '11 at 15:22
  • I'm still a bit confused. Obviously I can't have 2 files with the same name in the same folder. Groups in Xcode are flattened in Finder, so I need to add a new folder in Finder and then add it to Xcode right? So I create a new folder in the program folder in Finder, then drag it in to xcode, choosing to Create Folder References (creates a blue rather than yellow folder). If I then try Add->Existing Files, Localizable.strings is greyed out (as are all the other files). If I try to drag Localizable.strings on to the new blue folder, nothing happens... Am I doing something wrong? Thanks! – Smikey Feb 22 '11 at 15:57
  • Localizable.strings is being greyed out if it is already included in the project. If you want to add it again (to make sure the encoding is right) you have to first remove it from the project, which somewhat aggressively is called "deleting" it in Xcode (right click->Delete->Delete References). – Martin Gjaldbaek Feb 22 '11 at 16:09
  • 1
    You are right that you can't have multiple files with the same name in the same folder in Finder (whereas Xcode has no such restriction for groups). I'd suggest making two folders in your project directory (e.g. MyApp/StringsForTarget1 and MyApp/StringsForTarget2). Furthermore you should have a folder called en.lproj for each of the Localizable.stings versions (read the docs I referred to in my answer), so the final path is MyApp/StringsForTarget1/en.lproj/Localizable.strings, etc. – Martin Gjaldbaek Feb 22 '11 at 16:15
  • 1
    Then when you include the two folders (StringsForTarget1 and StringsForTarget2) in your project set it to recursively create folders and make sure each of them are only included in the appropriate target (you can change this later if you mess it up by adding or deleting them from the "Copy Bundle Resources" step on the two targets) – Martin Gjaldbaek Feb 22 '11 at 16:17
  • Brilliant - it seems to have worked! I'm not sure I entirely grasp how files and folders should be created/added. Xcode has created groups to represent the folders I created in Finder but usually groups in Xcode don't exist in Finder... Seems a bit inconsistent? I've noticed that Xcode can represent folders in Finder with blue rather than yellow icons, but I don't have this in my currently working setup and I don't really want to break it. Is it up to the programmer then to keep things tidy, and only use Groups in xcode when there is an equivalent Folder? – Smikey Feb 22 '11 at 17:11
  • Also - my understanding was that I didn't actually need to create an .lproj subdirectory since I'm not actually doing any localisation. If an .lproj folder isn't found, the compiler just looks for Localizable.strings directly? Thanks SO MUCH for all this help by the way :) – Smikey Feb 22 '11 at 17:12
  • You're welcome. I didn't know that you could use a Localizable.strings without the en.lproj folder, but if it works, then who am I to argue? :) About the groups vs. folders - basically both are just there to help you keep things tidy, and you can choose to just keep it flat if you choose (the exception being, as you mentioned, when the filesystem prevents you from having two files with the same name in the same folder). Generally, keeping groups and folders aligned may help you navigate, but there's no strict enforcement of this. I generally have a lot more groups than folders. – Martin Gjaldbaek Feb 23 '11 at 10:11