8

I have an XCode project, with the XIB interface files built using Interface Builder. I'm building localized XIB files by using ibtool to extract strings, translating them, and using ibtool again to build localized XIB files.

However, doing this means I have to translate all items in the application menus, including those that are completely standard (File, Save, Open, Minimize, etc.). Is there a way to avoid that?

F'x
  • 12,105
  • 7
  • 71
  • 123

4 Answers4

2

i've developed a solution to this problem.

https://www.corecode.io/index_opensource.html

look for "Translator", it will translate your MainMenu.strings file into a dozen languages with the standard Apple translations for the standard menu item strings.

if you find some strings or languages missing that Aapple has included in their base apps, please send a patch over.

user1259710
  • 868
  • 2
  • 9
  • 12
  • note that all 32 languages that Mac OS X comes in are now supported. its main "database" is here, patches welcome: https://github.com/core-code/MiscApps/blob/master/Translator/Translator/MainMenuTranslations.plist – user1259710 Jan 20 '14 at 19:04
  • Very handy, thanks user1259710! Let’s hope Xcode 6 makes all this easier by default for non-English developers… – wdyp Jul 24 '14 at 00:02
  • "Window" is missing for multiple languages (not all). – Leo Sep 28 '14 at 02:42
  • @user1259710 Unfortunately not translating any string. Any known issues currently? – Julian F. Weinert Oct 29 '16 at 00:51
  • @julian-f-weinert no known issues, please open a ticket with your failing strings file at the github page or send it to us directly at feedback@corecode.io – user1259710 Dec 04 '16 at 18:37
  • Links above are now dead. Has this moved somewhere else or is it RIP? – RehcsifMit Sep 21 '17 at 19:02
  • Nevermind, found it: https://github.com/core-code/MiscApps/tree/master/Translator – RehcsifMit Sep 21 '17 at 19:04
1

So, apparently no way around this.

F'x
  • 12,105
  • 7
  • 71
  • 123
0

Translator by https://github.com/core-code/MiscApps/blob/master/Translator/Translator/MainMenuTranslations.plist is cool but if you do not want to deal with 30 MainMenu.string files in your build (I personally don't) - you can just add MainMenuTranslations.plist to your resources (230KB uncompressed is tiny) and do it on the fly like this:

- (void) processMenu: (NSString*) app {
    NSDictionary* d = [self loadMenuTranslations: app];
    NSMenu* mm = NSApplication.sharedApplication.mainMenu;
    for (int i = 0; i < mm.numberOfItems; i++) {
        NSMenuItem* mi = [mm itemAtIndex: i];
        mi.title = [self translateMenu: mi.title withDictionary: d];
        NSMenu* sm = [[mm itemAtIndex: i] submenu];
        sm.title = [self translateMenu: sm.title withDictionary: d];
        for (int j = 0; j < sm.numberOfItems; j++) {
            NSMenuItem* mi = [sm itemAtIndex: j];
            mi.title = [self translateMenu: mi.title withDictionary: d];
        }
    }
}

- (NSString*) translateMenu: (NSString*) key withDictionary: (NSDictionary*) dictionary {
    for (NSString* lang in dictionary) {
        NSDictionary* translation = dictionary[lang];
        NSString* t = translation[key];
        if (t != null) {
            return t;
        }
    }
    return key;
}

- (NSDictionary*) loadMenuTranslations: (NSString*) app {
    NSArray* langs = [NSUserDefaults.standardUserDefaults objectForKey: @"AppleLanguages"];
    NSURL* url = [NSBundle.mainBundle URLForResource:@"MainMenuTranslations.plist" withExtension: null];
    NSMutableDictionary* r = NSMutableDictionary.new;
    NSDictionary* translations = [NSDictionary dictionaryWithContentsOfURL: url];
    for (NSString* lang in langs) {
        NSString* locale = [NSString stringWithFormat:@"%@.lproj", lang];
        NSDictionary* translation = translations[locale];
        NSMutableDictionary* d = [NSMutableDictionary.alloc initWithCapacity: translations.count * 3 / 2];
        for (NSString* k in translation) {
            NSString* v = translation[k];
            NSString* key = k;
            if ([k indexOf: @"APPLICATIONNAME"] >= 0) {
                key = [k stringByReplacingOccurrencesOfString: @"APPLICATIONNAME" withString: app];
            }
            if ([v indexOf: @"APPLICATIONNAME"] >= 0) {
                v = [v stringByReplacingOccurrencesOfString: @"APPLICATIONNAME" withString: app];
            }
            d[key] = v;
        }
        if (d.count > 0) {
            r[lang] = d;
        }
    }
    return r;
}

just call it from

- (void) applicationDidFinishLaunching: (NSNotification*) n {
    // ...
    [self processMenu: @"<your app name>"];
}

I wish there is a UniversalTranslation.plist somewhere (which could be probably collected automatically via creative use of translate.google.com)

Leo
  • 790
  • 8
  • 10
0

I have been looking for a similar solution for a while and I found this resource

http://www.bdunagan.com/2009/03/15/ibtool-localization-made-easy/

It quotes toward the end of the article:

ibtool will look through MainMenu.xib for every user-visible string and insert that string with an associated ObjectID into MainMenu.strings, essentially a dictionary of strings keyed by ObjectID. Even better, the tool sorts them by ObjectID, so versioned .strings files are nicely diff’able. I can easily see what strings are added, removed, or just changed. Let me repeat this because it’s so incredibly handy: .strings files diff well! Of course, these .strings files are unicode, so they are not grep’able. Below is an example of the output for a string:

Go ahead and take a look I really hope it helps you as much as it helped me!

austinbv
  • 9,297
  • 6
  • 50
  • 82
  • I'm afraid you misunderstand my issue: I already use ibtool to maintain translations. This does not, however, address the issue of not wanting to translate all the standard menu items of the app (Copy, Paste, etc.). – F'x Nov 27 '10 at 08:28
  • Ah, I wish I could have helped more. – austinbv Nov 27 '10 at 14:31