Localizing your iPhone OS applications in Xcode.

Discussion in 'iOS Development' started by SkylarEC, Aug 19, 2009.

  1. SkylarEC

    SkylarEC Super Moderator Emeritus Staff Member

    Joined:
    Sep 19, 2007
    Messages:
    6,642
    Likes Received:
    129
    Original post at: skylarcantu.com

    Localization from within Xcode is a little unnatural at first. And to tell you the truth, I still don't like it is handled. But that's neither here nor there. This post will show you how to add support for localization within your own application.

    Localizing​


    The first thing you need to do is localize your application into your native language. To do that, you must first create a Localizable.strings file. What you will do is select "New File..." from Xcode's dropdown menu. Highlight the "Other" menu and select "Strings File." Name this file "Localizable.strings."

    Please Register or Log in to view images



    Next, go ahead and move the Localizable.strings file into your Resources group in your project. Right click on the file and select "Get Info." When the info window pops up, select the "General" section and then the "Make file localizable" button on the bottom left of the window. You will see that "English" is added already. That means we're done with this part.

    Please Register or Log in to view images


    Please Register or Log in to view images


    Please Register or Log in to view images



    Go back into Xcode, and you will see that your Localizable.strings file now has an arrow next to it, similar to a standard folder or group. Go ahead and expand this folder, and you will see a new file named "English." As you'd expect, this is how Xcode is referring to the English translation of our Localizable.strings

    Please Register or Log in to view images


    Of course, this is worthless without some text to translate. Let's go quickly add some labels to our view. Open LocalizeMeViewController.m and add the following code to the -loadView method.
    [OBJC]- (void)loadView {
    [super loadView];

    self.view.backgroundColor = [UIColor blueColor];

    CGRect labelFrame = CGRectMake(0, 0, 320, 40);
    CGPoint labelCenter = CGPointMake(320/2, 140);

    for (int i = 0; i < 5; i++) {
    UILabel *label = [[UILabel alloc] initWithFrame:labelFrame];
    label.backgroundColor = [UIColor clearColor];
    label.textAlignment = UITextAlignmentCenter;
    label.tag = i + 1;
    switch (i) {
    case 0:
    label.text = @"One";
    break;
    case 1:
    label.text = @"Two";
    break;
    case 2:
    label.text = @"Three";
    break;
    case 3:
    label.text = @"Four";
    break;
    case 4:
    label.text = @"Five";
    break;
    default:
    break;
    }

    label.center = labelCenter;
    labelCenter.y += label.frame.size.height;

    [self.view addSubview:label];
    [label release];
    }
    }[/OBJC]


    The result will look like this:

    Please Register or Log in to view images


    To localize these five strings, we're going to have to make use of the NSLocalizedString() macro. NSLocalizedString takes two parameters. The first one is a key that will be used to look up the string in your Localizable.strings file. The second parameter is a comment, to help you remember. I choose to use the English translation as the comment, that way I know exactly what the string is supposed to say in my native language. Both parameters should be NSStrings. The macro should look like this when completed:
    NSLocalizedString(@"Key", @"Comment");

    So, let's update our -loadView method. I'm going to go ahead and make my keys all in capital letters. That way, if we miss any keys, or err in our Localizable.strings file, we will know instantly. Update your -loadView method with the following code.
    [OBJC]- (void)loadView {
    [super loadView];

    self.view.backgroundColor = [UIColor blueColor];

    CGRect labelFrame = CGRectMake(0, 0, 320, 40);
    CGPoint labelCenter = CGPointMake(320/2, 140);

    for (int i = 0; i < 5; i++) {
    UILabel *label = [[UILabel alloc] initWithFrame:labelFrame];
    label.backgroundColor = [UIColor clearColor];
    label.textAlignment = UITextAlignmentCenter;
    label.tag = i + 1;
    switch (i) {
    case 0:
    label.text = NSLocalizedString(@"ONE", @"One");
    break;
    case 1:
    label.text = NSLocalizedString(@"TWO", @"Two");
    break;
    case 2:
    label.text = NSLocalizedString(@"THREE", @"Three");
    break;
    case 3:
    label.text = NSLocalizedString(@"FOUR", @"Four");
    break;
    case 4:
    label.text = NSLocalizedString(@"FIVE", @"Five");
    break;
    default:
    break;
    }

    label.center = labelCenter;
    labelCenter.y += label.frame.size.height;

    [self.view addSubview:label];
    [label release];
    }
    }[/OBJC]


    Don't compile yet, we still have to set up our .strings file. Go back and open the English Localizable.strings. This should be an empty file now. To fill this out, we need to add an entry for each of the keys that we defined in our code. You will also want to put one key on each line. Start by placing the key in quotation marks. Do not use the @ sign in front of your quotation marks. Follow your key with an equals sign. Then, you will write your translation, also in quotes. Once again, omit the @ sign. End the line with a semicolon. Your key entry will look like this:
    "Key" = "This is the translation!";

    Follow this pattern to add the keys from our application. Your entries should look like this:
    [OBJC]"ONE" = "One";
    "TWO" = "Two";
    "THREE" = "Three";
    "FOUR" = "Four";
    "FIVE" = "Five";[/OBJC]


    Once you have this, save the file and compile. Your application should look exactly the same as it did before.



    Adding support for other languages will be easy, now that you have all the hard work done. Just like before, right click on Localizable.strings, select "Get Info" and finally "Add localization." On the iPhone, you may notice that your dropdown box with languages comatains fewer languages than the iPhone supports. That's okay. To enter support for another language, just enter its two letter country code. Ex, nl for the Netherlands. We're going to have to do that right now for Spanish. Enter the letters "es" and click "Add."

    Please Register or Log in to view images


    You'll notice that under Localizable.strings in your Xcode project, you have a new file called es. Opening it reveals that it is identical to your English.lproj. This is to easily translate the new keys without having to reenter all the keys again. Let's go ahead and add the Spanish translations now.
    [OBJC]"ONE" = "Uno";
    "TWO" = "Dos";
    "THREE" = "Tres";
    "FOUR" = "Cuatro";
    "FIVE" = "Cinco";[/OBJC]

    Save this file and compile. On the iPhone Simulator, change the language to Spanish and reopen your application. It should now have the Spanish translation.

    Please Register or Log in to view images



    Localizing a .xib

    Setting up localization for any other resource works exactly the same as on Localizable.strings. Right click the resource, click "Make Localizable," and add the localizations you require. Just like before, Xcode will generate a new file for each language your resource needs to be in. In this case, that means we will wind up with several .xib files. It also means that our .xib files will be moved from the main directory in our app bundle to the appropriate .lproj directory within the application. Don't worry, Xcode does all this automatically.

    For the reason that localizations on xibs create several xibs, I recommend localizing them last. Once everything is set up exactly how you want it. Otherwise, you will need to reopen each xib and modify it, creating the possibility of error. So, we won't localize the xib yet.

    The first thing we must do is comment out the labels that we already added from the -loadView method. Next, open your LocalizeMeViewController.xib and recreate the labels. Once finished, compile. The finished product should look like it did when compiling via code.

    Please Register or Log in to view images



    Now that we have that all set and working, we are going to go back into Xcode and create a localized xib. Again, right click on LocalizeMeViewController.xib and select "Get Info." Click its "Make Localizable" button, and enter "es" for the localization. Open the newly created "es" file that appears when you expand "LocalizeMeViewController.xib" in Xcode and translate all the labels. Compile once more and switch the Simulator's language. Reopen your application, and it should be translated.

    Please Register or Log in to view images



  2. SkylarEC

    SkylarEC Super Moderator Emeritus Staff Member

    Joined:
    Sep 19, 2007
    Messages:
    6,642
    Likes Received:
    129
    Localizing a Settings bundle

    Localizing a Settings.bundle is more involved than it should be. To see how to do this, we must first create a Settings bundle. Go ahead and do so now. From the Xcode "File" menu, select "New File." In the "Resource" menu in the "iPhone OS" section, select "Settigns bundle." Leave this named "Settings.bundle."

    Please Register or Log in to view images


    Expand the Settings bundle and you'll see Root.plist and an en.lproj directory. Let's take everything our of the Root.plist except for the "group" and the "switch." Now, expand the en.lproj and open Root.strings. Leave only the "Group" and "Enabled" keys. Compile, and open Settings in the Simulator. Perfect : )

    Please Register or Log in to view images


    Uh-oh! Right clicking on either the Settings.bundle or the Root.plist in Xcode and clicking on "Get Info" shows us that the option to make either localizable is disabled. I don't know why this is, but it can be worked around. We will have to add the localizations manually.

    What you will need to do is open Finder and navigate to where you have your project saved. Right click on the Settings.bundle and select "Show package contents." Copy the en.lproj and rename the copy es.lproj.

    Please Register or Log in to view images


    Please Register or Log in to view images


    Please Register or Log in to view images


    Go back into Xcode and close and re-expand your Settings bundle. You should now see the es.lproj. Translate the Root.strings, recompile, and enojoy!

    Please Register or Log in to view images


    Please Register or Log in to view images



    Calling Different Resources

    All this is well and good so far. But, what about if you need to call a different image based on the localization? If you are designing your interface in a xib, just substitute images there. If you are using code, you will need to do a little bit of work.

    Let's go back and edit the LocalizeMeViewController's -loadView method. Knowing that the current language will always be at the beginning of the list of the user's prefered languages, we can figure out very easily which language is selected. Use NSLocale's preferredLanguages array to get the string contained in the first position. This is the two letter ISO 6901 Language Code Simply check that against the values that you will be localizing for and load the correct image.
    [OBJC] UIImageView *languageImage;

    if ([[[NSLocale preferredLanguages] objectAtIndex:0] isEqualToString

    Please Register or Log in to view images

    "en"]) {
    languageImage = [[UIImageView alloc] initWithImage:[UIImage imageNamed

    Please Register or Log in to view images

    "English.png"]];
    } else if ([[[NSLocale preferredLanguages] objectAtIndex:0] isEqualToString

    Please Register or Log in to view images

    "es"]) {
    languageImage = [[UIImageView alloc] initWithImage:[UIImage imageNamed

    Please Register or Log in to view images

    "Espanol.png"]];
    } else {
    languageImage = [[UIImageView alloc] initWithImage:[UIImage imageNamed

    Please Register or Log in to view images

    "English.png"]];
    }

    languageImage.center = CGPointMake(320/2, 480 - 20 - (languageImage.bounds.size.height / 2));

    [self.view addSubview:languageImage];
    [languageImage release]; [/OBJC]

    Please Register or Log in to view images


    Please Register or Log in to view images



    Original post at: skylarcantu.com
  3. Pelaez-1

    Pelaez-1 New Member

    Joined:
    May 5, 2008
    Messages:
    822
    Likes Received:
    0
    Device:
    iPhone
    Thanks, quite useful.

    Just to point a couple of things I noted.

    [objc]NSLocalizedString(@"Key", "Comment"); //Missing '@' on "Comment" string[/objc]

    and then use like this:
    [objc]case 0:
    label.text = NSLocalizedString(@"ONE", "One"); //Missed '@' too
    break;[/objc]

    They are supposed to be NSStrings, so I assume the @ is missing
  4. Steaps

    Steaps New Member

    Joined:
    Oct 24, 2007
    Messages:
    5,074
    Likes Received:
    41
    Device:
    iPod touch
    Could be completely wrong with this (Minds a little out of it), but wouldn't label be undeclared outside the for loop?
    [OBJC]
    - (void)loadView {
    [super loadView];

    self.view.backgroundColor = [UIColor blueColor];

    CGRect labelFrame = CGRectMake(0, 0, 320, 40);
    CGPoint labelCenter = CGPointMake(320/2, 140);

    for (int i = 0; i < 5; i++) {
    UILabel *label = [[UILabel alloc] initWithFrame:labelFrame];
    label.backgroundColor = [UIColor clearColor];
    label.textAlignment = UITextAlignmentCenter;
    label.tag = i + 1;
    switch (i) {
    case 0:
    label.text = NSLocalizedString(@"ONE", "One");
    break;
    case 1:
    label.text = NSLocalizedString(@"TWO", @"Two");
    break;
    case 2:
    label.text = NSLocalizedString(@"THREE", @"Three");
    break;
    case 3:
    label.text = NSLocalizedString(@"FOUR", @"Four");
    break;
    case 4:
    label.text = NSLocalizedString(@"FIVE", @"Five");
    break;
    default:
    break;
    }

    label.center = labelCenter;
    labelCenter.y += label.frame.size.height;

    [self.view addSubview:label];
    [label release];
    }
    [/OBJC]
  5. SkylarEC

    SkylarEC Super Moderator Emeritus Staff Member

    Joined:
    Sep 19, 2007
    Messages:
    6,642
    Likes Received:
    129

    Good catch! I will fix this now.

    It doesnt' matter, as we are not referencing the UILabels outside of the loop. If we need to, then we can refer to the tags that we have set on the labels.




    PS, I undeleted your post because it is a valid question.
  6. Steaps

    Steaps New Member

    Joined:
    Oct 24, 2007
    Messages:
    5,074
    Likes Received:
    41
    Device:
    iPod touch
    Yeah no worries, I tested it and felt like an idiot

    Please Register or Log in to view images

    .
  7. SkylarEC

    SkylarEC Super Moderator Emeritus Staff Member

    Joined:
    Sep 19, 2007
    Messages:
    6,642
    Likes Received:
    129
    If you click the link to the original posting, you can doanload a copy of the Xcode project.
  8. Steaps

    Steaps New Member

    Joined:
    Oct 24, 2007
    Messages:
    5,074
    Likes Received:
    41
    Device:
    iPod touch
    Favourited. Will they're be tutorials on there that aren't on here?
  9. SkylarEC

    SkylarEC Super Moderator Emeritus Staff Member

    Joined:
    Sep 19, 2007
    Messages:
    6,642
    Likes Received:
    129
    Possibly. They are a lot of work to write up, then convert over. It's easier to take the WP format and make it fit this forum's format, as opposed to the otherway around. My last tutorual and this one were written in Wordpress first, and I think it shows with a better quality of post.

    It just depends on whether or not I have time to do both versions in one sitting; and if in case I don't, whether I forget to come back later.
  10. Andrew Bukowski

    Andrew Bukowski New Member

    Joined:
    Feb 13, 2013
    Messages:
    1
    Likes Received:
    0
    Device:
    iPhone 3GS (White)
    I suggest https://poeditor.com/ as an alternative to Xcode. It works with po, strings files and many others and it's also interactive and time-saving.

Share This Page