0

I have read a few tutorials about iOS's tools and processes for i18n/l10n, and am unpleasantly surprised with what I'm seeing. It seems there isn't a solid way of externalizing user-facing strings out of objective C files. Am I missing something?

Description of the problem: There is a tendency to place English strings directly into the .m file, and the Apple documentation seems to encourage this. While this is also possible in Android, as least in Android there is a clear distinction between externalized and non-externalized strings. With iOS, on the other hand, code that calls for a string tends to look like this:

NSLocalizedString(@"There was an error loading the image.", nil)

In this case, "There was an error loading the image." is the key for this string resource. Therefore if I want to make another reference to the same string in some other place we have to again write code like this:

NSLocalizedString(@"There was an error loading the image.", nil)

But now I have to make sure that I spelled these two strings the same and there is no compile time check to help me confirm that. I could write a helper function called createErrorString, but that's not fun. And I could replace "There was an error loading the image." with a more sensible key like "ERROR_IMAGE_LOAD", but that does not seem to be a common practice, and Apple seems to discourage this sensible behavior. Here is what their documentation states:

"A common convention when developing applications is to use a key name that equals the value in the language used to develop the application."

It looks like Apple is recommending that you put the full English string in your source code. So I'll have to try to convince my colleagues to go against Apple's guidance.

Now that I've got all of these user-facing English strings (or keys) in the source code, Apple includes a tool called genstrings that parses the .m files, and spits out a Localizable.strings file that I can then send out for translation. This might work if you are only going to get your app localized one time, but in our company localization is an ongoing iterative process. Look at what the Apple documentation recommends:

"For subsequent runs, it is a good idea to save a copy of your current strings files before running genstrings. You can then diff the new and old versions to determine which strings were added to (or changed in) your project. You can then use this information to update any already localized versions of your strings files, rather than replacing those files and localizing them again."

That doesn't seem very good. In Android and Windows8, you internationalize your source tree one time, and from that moment on your externalized strings are owned in the xml files where they belong; in iOS they are owned in source code (sort of) and then tabulated into some intermediate file (or is it?) by some crazy tool. Is the Localizable.strings file an intermediate file or should it be committed into git - we are still debating this at my company.

(And from what I can tell, this is only the beginning. In xib-land, which is where 90% of your user-facing strings live, there also seems to be an inefficient mechanism for l10n. Wil Shipley's article describes this at length.)

Does anyone have any suggestions on a good way to externalize strings in iOS? My main question concerns objective-C strings, but answers pertaining to xib files would also be much appreciated. Thanks!

Jo Jo
  • 7,245
  • 5
  • 34
  • 49
  • 2
    I think you could define your localized string variables in a common file, such as Common.m, then extern those variables in Common.h, and import, re-use in any files you want – dthien Feb 15 '13 at 01:36
  • 1
    Nothing is preventing you from doing `NSLocalizedString(ERROR_MESSAGE, @"error message displayed to the user")`, then localizing for all your languages. – nielsbot Feb 15 '13 at 01:37
  • Yep, what @dthien said. What we've been doing here is to `#define` all the user-facing strings in `uistrings.h` -- pretty it ain't, but it works. – 323go Feb 15 '13 at 01:39
  • i18n means 'internationalization'. It means to design and prepare your source code so that it can be localized into foreign languages. – Jo Jo Feb 15 '13 at 01:50
  • You're right -- it's a deficiency relative Android. The common .h file,, or a common .m containing a string-serving method are the only techniques I can think of. I've used both. – Hot Licks Feb 15 '13 at 01:50
  • why do you need that common .h file? that ugly capital letters with underscores makes the code less readable. – AlexWien Feb 15 '13 at 01:53
  • @AlexWien - OK, we'll make it an amazingly unique and creative .h file. – Hot Licks Feb 15 '13 at 02:11

2 Answers2

2

I found the recommendation to name the key like the english string strange, too.
I name the keys, value e.g "Menu1SettingsTitle" = "Settings".
I dont need genstrings tool, just externalize manually.
And no, the string files is not an intermediate step, they should be in git.

However with that approach i noticed three drawbacks:
1) I detected duplicate names, but that can be moved to a common section for strings like "cancel, delete"

2) If you forget to put a string into that language file, it cannot be found and then the key is displayed, which looks very strange, of course. Otherwise with apples reccomendation, If the key is the english word, it looks "only english" but not worse.

3) The translation process is easier if english is always left, instead of "Menu1SettingsTitle". to solve that i put a comment above, but dont know if the translation service would be happy with that.

AlexWien
  • 28,470
  • 6
  • 53
  • 83
  • Thanks everyone for the responses. I'll try ignoring genstrings and introducing keys like the Menu1SettingsTitle example you mentioned. – Jo Jo Feb 15 '13 at 19:32
  • Here's an article I just found about iOS localization deficiencies and some advice on how to cope. http://www.mobiata.com/blog/2012/02/08/twine-string-management-ios-mac-os-x – Jo Jo Feb 16 '13 at 00:53
  • Thanks, I will look tomorrow on that – AlexWien Feb 16 '13 at 04:29
  • Just found another SO question that is very similar to this one: http://stackoverflow.com/questions/9895621/best-practice-using-nslocalizedstring – Jo Jo Feb 28 '13 at 19:17
  • By the way, Alex, I was able to implement your suggestion and it is working exactly like I want. I'm committing the Localizable.strings file into git having us manually edit that file when we want to add/modify a string. I have also added a Run Script into Xcode that runs genstrings but only for purposes of finding keys that do not appear in the existing Localizable.strings file (the one that gets committed). – Jo Jo Mar 01 '13 at 00:48
  • Can anyone tell me what is meaning of "user-facing strings"? – Developer Jan 23 '17 at 08:00
1

After a couple of hours searching I decided to use two different approaches: one for the storyboards and one for the text inside the .m files. The result are two files Localizable.strings for the Objective C text and the internationalized storyboard.

The update_storyboard_strings.sh can automatically extract translatable strings from storyboards and update strings files. The source code (by mikezang) can be found at:

http://forums.macrumors.com/showpost.php?p=16060008&postcount=4

For the objective C NLS I use another script around the xcode-tools by Frédéric Sagnes: https://github.com/ndfred/xcode-tools

I had to call it for each language in order to get the desired results:

python scripts/xcode-tools/update_strings.py --import=MyProject/Base.lproj/Localizable.strings MyProject/Base.lproj/Localizable.strings

python scripts/xcode-tools/update_strings.py --import=MyProject/de.lproj/Localizable.strings MyProject/de.lproj/Localizable.strings

Now put both in one script and add it to your Xcode project as a last build phase.