51

UIBarButtonItem have identifiers like Cancel, Done and some others. They are shown as text to user. If user changes language then for example Cancel button will be translated automatically. And as developer you do not need to provide localization string for this buttons. It means that Cancel, Done and other strings already localized and comes together with OS.

Is here a way to get this strings programmatically?

I do not want to add additional strings to localization files. And if it is possible to access then it would be very good.

Ramis
  • 13,985
  • 7
  • 81
  • 100
  • can't you get access to your string through the title property? – tiguero Aug 30 '12 at 13:09
  • 2
    I can get title of the UIBarButtonItem if this button is placed in UI. But I want to get this translations not using work around. – Ramis Aug 30 '12 at 13:50
  • yourUIBarButtonItem.title let you retrieve the string that is displayed - is that what u want? – tiguero Aug 30 '12 at 13:54
  • 2
    I know that I can get title of this button. As I wrote before Cancel, Done and other strings already comes together with OS with all localizations. What I want is to access this strings for OS. – Ramis Aug 31 '12 at 11:04
  • @tiguero The question is valid: You might want to get the localized string without creating the button. – Nikolai Ruhe Aug 31 '12 at 11:11
  • @Ramis, did you find the way of getting these kinds of strings programmatically? Any success? – Stanislav Pankevich Sep 17 '12 at 22:48
  • @Stanislaw I did not find solution for it. – Ramis Sep 25 '12 at 11:16

8 Answers8

33

Here's a little macro I created to get the System UIKit Strings:

#define UIKitLocalizedString(key) [[NSBundle bundleWithIdentifier:@"com.apple.UIKit"] localizedStringForKey:key value:@"" table:nil]

Use it like this:

UIKitLocalizedString(@"Search");
UIKitLocalizedString(@"Done");
UIKitLocalizedString(@"Cancel");
...
Stephan Heilner
  • 888
  • 7
  • 10
  • 2
    Is there any way to get all keys? – kelin Jan 03 '17 at 23:53
  • 1
    I changed my tests to XCUI in Swift now and it doesn't work anymore :( – Bruno Muniz Jan 16 '18 at 09:45
  • 4
    This no longer works, right? The UIKit bundle no longer has the Localized.string file. In fact, after searching through the runtime simulator files, I couldn't even identify where these strings are located at all. – androidguy Jul 05 '20 at 02:22
  • No longer works because of the bundleWithIdentifier call. Swap it out for bundleForClass and it works again. See my answer for example. – scosman May 11 '23 at 15:25
13

One (admittedly questionable) way of accomplishing this easily is use Apple's framework bundle localizations directly:

To see what they have to offer, open the following directory via the Finder:

/Applications/Xcode/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator6.1.sdk/System/Library/Frameworks

And in your case, you'll subsequently open ./UIKit.framework/English.lproj/Localizable.strings (in TextMate). Here you see a wide variety of translations that Apple uses for things like "Print", "OK", "On", "Off", etc. The real magic is that there are about 35 different language translations that you can copy into your own Localizable.strings files, for free.

If you are incredibly brazen and don't mind putting your app's future stability in question, you could skip the whole "copy into your own Localizable.strings" process and go straight to the source programmatically:

NSBundle *uiKitBundle = [NSBundle bundleWithIdentifier:@"com.apple.UIKit"];
NSString *onText = uiKitBundle ? [uiKitBundle localizedStringForKey:@"Yes" value:nil table:nil] : @"YES";
NSString *offText = uiKitBundle ? [uiKitBundle localizedStringForKey:@"No" value:nil table:nil] : @"NO";

Caveat: In no way do I recommend that you actually access these localized resources programmatically in an app that you intend to submit to the App Store. I'm merely illustrating a particular implementation that I've seen which addresses your original question.

Greg Combs
  • 4,252
  • 3
  • 33
  • 47
  • Anyone know where these localized .strings files live now with Xcode 11? It seems like all the Frameworks paths inside the SDKs have only headers no strings files. – androidguy Jun 01 '20 at 05:29
9

Encouraged by Answer to this Question (by Stephan Heilner) and Answer (by bdunagan) for iPhone/iOS: How can I get a list of localized strings in all the languages my app is localized in?

Objective-C

NSString * LocalizedString(NSString *key) {
    return [[NSBundle mainBundle] localizedStringForKey:key];
}

@interface NSBundle(Localization)
- (NSString *)localizedStringForKey:(NSString *)key;
- (NSDictionary<NSString *, NSString *> *)localizationTable;
@end

@implementation NSBundle(Localization)
- (NSDictionary<NSString *, NSString *> *)localizationTable {
    NSString *path = [self pathForResource:@"Localizable" ofType:@"strings"];
    NSData *data = [NSData dataWithContentsOfFile:path];
    NSError *error = nil;
    id obj = [NSPropertyListSerialization propertyListWithData:data options:NSPropertyListImmutable format:NULL error:&error];
    if (error && obj == nil) {
        @throw error;
        return nil;
    }
    if ([obj isKindOfClass:NSDictionary.class]) {
        return obj;
    }    
    @throw NSInternalInconsistencyException;
    return nil;
}

- (NSString *)localizedStringForKey:(NSString *)key {
    return [self localizedStringForKey:key value:nil table:nil];
}
@end

Swift 5

public extension String {
    func localized(_ bundle: Bundle = .main) -> String {
        bundle.localize(self)
    }        
    var localized: String {
        return localized()
    }
}

extension Bundle {
    static var UIKit: Bundle {
        Self(for: UIApplication.self)
    }
    func localize(_ key: String, table: String? = nil) -> String {
        self.localizedString(forKey: key, value: nil, table: nil)
    }
    var localizableStrings: [String: String]? {
        guard let fileURL = url(forResource: "Localizable", withExtension: "strings") else {
            return nil
        }
        do {
            let data = try Data(contentsOf: fileURL)
            let plist = try PropertyListSerialization.propertyList(from: data, format: .none)
            return plist as? [String: String]
        } catch {
            print(error)
        }
        return nil
    }
}

Usage:

"Photo Library".localized(.UIKit)

To get all keys of localized strings of UIKit:

Bundle.UIKit.localizableStrings?.keys//.map { $0 }
Stanislav P.
  • 145
  • 1
  • 7
4

While perhaps not exactly what you were seeking, there is a commercial app in the Mac App Store called "System Strings" claiming that it provides a collection of more than 53000 standard localized strings. It was released November 2, 2012. I am in no way affiliated with this app or the author. The URL is https://itunes.apple.com/us/app/systemstrings/id570467776.

Daniel Zhang
  • 5,778
  • 2
  • 23
  • 28
1

Sounds like what you are asking is if Apple provides a way to access a dictionary of pre-translated strings. I would think that anything provided by Apple for something like this would be located in their Docs: Internationalization Programming Topics

To answer your question I do not believe they provide a dictionary/list of known translations. Either you will have to define them in your Localizable.strings resource file or do as others have stated in the comments and pull the title from the UIBarButtonItem (I would go with the resource file personally).

Joe
  • 2,987
  • 15
  • 24
0

Why not use base localization with your storyboard? It will localize it for you.

ullstrm
  • 9,812
  • 7
  • 52
  • 83
0

Working version in iOS 16. The earlier ones don't seem to work any longer

+(NSString*) uiKitLocalizedStringForKey:(NSString*)key {
    NSBundle* uikitBundle = [NSBundle bundleForClass:[UIButton class]];
    if (!uikitBundle) {
        // Never seen this happen, but might as well guard for it
        return key;
    }
    return [uikitBundle localizedStringForKey:key value:key table:nil];
}
scosman
  • 2,343
  • 18
  • 34
-6

You could use

NSLocalizedString(@"Cancel", @"Cancel")