Chapter 18. Localization

Localization is pretty simple in GNUstep. Strings in the source code and in the Gorm interface use different methods to localize. Here, I write an useless application to demonstrate both localization methods.

Open Gorm, make an interface like this:

Figure 18.1. Interface of Localization example

Interface of Localization example

Make a subclass of NSObject called "AppDelegate" as application delegate. Add an outlet "window", connect this outlet to the window. I don't not plan to use this Gorm as main interface. There, I set the NSOwner to AppDelegate. I'll load this interface manually.

Save the Gorm file as "Localization.gorm". Here is the code of AppDelegate.

AppDelegate.h

#ifndef _AppDelegate_
#define _AppDelegate_

#include <Foundation/NSObject.h>

@interface AppDelegate: NSObject
{
  id window;
}
@end

#endif /* _AppDelegate */

AppDelegate.m

#include "AppDelegate.h"
#include <AppKit/AppKit.h>

@implementation AppDelegate

- (void) applicationWillFinishLaunching: (NSNotification *) not
{
  NSMenu *menu;

The way to localize string in source code is to use bundle. But GNUstep offer a macro to make thing more easy. By use _() around the strings, they are ready to be localized later.

  menu = [[NSMenu alloc] initWithTitle: _(@"Main Menu")];

  [menu addItemWithTitle: _(@"Hide")
                  action: @selector(hide:)
           keyEquivalent: @"h"];
  [menu addItemWithTitle: _(@"Quit")
                  action: @selector(terminate:)
           keyEquivalent: @"q"];

  [NSApp setMainMenu: menu];

  RELEASE(menu);
}

- (void) applicationDidFinishLaunching: (NSNotification *) not
{

The Gorm file is loaded manually

  [NSBundle loadNibNamed: @"Localization.gorm" owner: self];
  [window makeKeyAndOrderFront: self];
}

@end

Since the main() is so simple, I write it in the same file

int main(int argc, const char **argv)
{
   NSAutoreleasePool *pool = [NSAutoreleasePool new];

   [NSApplication sharedApplication];

   [NSApp setDelegate: [AppDelegate new]];

   NSApplicationMain(argc, argv);

   RELEASE(pool);

   return 0;
}

GNUmakefile

include $(GNUSTEP_MAKEFILES)/common.make

APP_NAME = Localization

Localization_OBJC_FILES = AppDelegate.m

Localization_HEADERS = AppDelegate.h

Localization_LANGUAGES = English TraditionalChinese

Localization_LOCALIZED_RESOURCE_FILES = \
        Localizable.strings \
        Localization.gorm

include $(GNUSTEP_MAKEFILES)/application.make

In GNUmakefile, the most important is the Localization_LANGUAGES and Localization_LOCALIZED_RESOURCE_FILES. _LANGUAGES tell gmake which language to support. Here are English and TraditionalChinese, which correspond to the English.lproj/ and TraditionalChinese.lproj/ directories. _LOCALIZED_RESOURCE_FILES are the files in these language directory. Localizable.strings are the translated string. Localization.gorm is the interface I just saved from Gorm.

Now, let's look at the English.lproj/Localizable.strings

Localizable.strings

"Main Menu" = "Main Menu";

"Hide" = "Hide";

"Quit" = "Quit";

Left side are the strings in the source code and surrounded by _(). Right side are the translated strings. Since it is English translation, they are the same. But you can still change the string at right side to see what will happen.

For the traditional Chinese, I just copy Localizable.strings and Localization.gorm into TraditionalChinese.lproj/ directory. Change the right side of Localizable.strings into traditional Chinese. And use Gorm to change every string in the Localization.gorm into Chinese. Then this application is localized for English and traditional Chinese.

The way an application know which language to use is the NSLanguages in the user defaults. You can check out the chapter "Languages Setup" in this tutorial.

Here is the source code: Localization-src.tar.gz. It contains translation in English and traditional Chinese. You can play around it and add the support of your native language.

Some people think it is troublesome to make Gorm interfaces for each languages. The reason for that is that length of strings in each language may not be the same. A custom-designed interface for each language would give the best result. That's also the reason why Gorm use absolute position for graphic interface component. If you would rather want to use relative position interface system, you should try Renaissance.

To sum up, use _() in the source code for every string you want to localized. Make language.lproj/ directory for each language and specify the language in GNUmakefile. Put the translation named "Localizable.strings" in each language.lproj/ directory. Put all translated Gorm interface in each language.lproj/ directory. That's all.