Objective-C helper classes for Apple iOS strings

The Respresso generates Objective-C helper classes, so you can reference localizations from Objective-C source code in a typo-safe way with auto-completion support in Xcode. For this, Respresso generates 2 helper classes:

  • RespressoStringKeys: Contains all localizations keys as readonly properties.
  • RespressoLanguages: Contains all localization languages as readonly properties. It also provides a getter property for defaultLanguage and the languages array.
  • RespressoStrings: Contains a readonly property for each localization key that returns locale specific translation. In case the key has localization variables, a function will be generated with them as arguments. It also provides language switching capabilities for localizations accessed through this class.

This format can't be imported to Respresso, it's output only.

How Respresso generates it?

This format is language independent, thus you will get the same files regardless of the added languages.

You can expect to get the following files:

  • RespressoStringKeys.h
  • RespressoStringKeys.m
  • RespressoLanguages.h
  • RespressoLanguages.m
  • RespressoStrings.h
  • RespressoStrings.m

Let's assume you have a single localization with two registered variables in Respresso:
mainScreen.accountBalance:

  • English (en): Balance: {{ currency }} {{ balance }}
  • English (en-GB): Unspecified
  • Hungarian (hu): Egyenleg: {{ balance }} {{ currency }}

It will output 6 files like these in the objc sync group:

RespressoStringKeys.h
#import <Foundation/Foundation.h>
@interface RespressoStringKeys : NSObject
- (nonnull instancetype)init NS_UNAVAILABLE;
@property(class, nonnull, nonatomic, readonly) NSString* mainScreenAccountBalance;
@end
RespressoStringKeys.m
#import "RespressoStringKeys.h"
@implementation RespressoStringKeys
+ (nonnull NSString*)mainScreenAccountBalance {
    return @"mainScreen.accountBalance";
}
@end
RespressoLanguages.h
#import <Foundation/Foundation.h>
@interface RespressoLanguages : NSObject
- (nonnull instancetype)init NS_UNAVAILABLE;
@property(class, nonnull, nonatomic, readonly) NSString* en;
@property(class, nonnull, nonatomic, readonly) NSString* enGB;
@property(class, nonnull, nonatomic, readonly) NSString* hu;

@property(class, nonnull, nonatomic, readonly) NSString* defaultLanguage;
@property(class, nonnull, nonatomic, readonly) NSArray* languages;
@end
RespressoLanguages.m
#import "RespressoLanguages.h"
@implementation RespressoLanguages
+ (nonnull NSString*)en { return @"en"; }
+ (nonnull NSString*)enGB { return @"en-GB"; }
+ (nonnull NSString*)hu { return @"hu"; }
+ (nonnull NSString*)defaultLanguage { return @"en"; }
+ (nonnull NSArray*)languages {
    return @[@"en", @"en-GB", @"hu"];
}
@end
RespressoStrings.h
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@interface RespressoStrings : NSObject
- (nonnull instancetype)init NS_UNAVAILABLE;
 + (nullable NSString *)localizedStringWithKey:(nullable NSString *)key;
@property (class, nullable, nonatomic) NSString* language;

@property(class, nonnull, nonatomic, readonly) NSString* mainScreenAccountBalance;
+ (nonnull NSString*)mainScreenAccountBalanceCurrency:(nonnull NSString*)currency balance:(CGFloat)balance;
@end
RespressoStrings.m
#import "RespressoStrings.h"
// There will be an internal interface not shown here

@implementation RespressoStrings
// There will be some internal functions not shown here

// Force a specific language to be used when accessed localizations through RespressoStrings
+ (void)setLanguage:(nullable NSString *)language { /* implementation */ }
+ (NSString*)language { /* implementation */ }

// Dynamically access localizations
// Calls NSLocalizedString(...) with RespressoStrings.language specific bundle
+ (nullable NSString*)localizedStringWithKey:(nullable NSString *)key { /* implementation */ }

+ (nonnull NSString*)mainScreenAccountBalance {
    return [RespressoStrings localizedStringWithKey:@"mainScreen.accountBalance"];
}
+ (nonnull NSString*)mainScreenAccountBalanceCurrency:(nonnull NSString*)currency balance:(CGFloat)balance {
    return [NSString stringWithFormat: [RespressoStrings mainScreenAccountBalance], currency, balance];
}
@end

Usage

Respresso's localization helper classes brings typo safe support to access localizations form code, even with parameters. You can easily force a specific language instead of the system default.

Access localized text

Each time you want to use a localized text from Respresso, you should access it through the RespressoStrings class. This is no magic, it uses the standard NSLocalizedString(...) and String(format: ...) but you will get auto-completion support in Xcode to boost your productivity. This will guarantee that the key is always matching the key in the .strings file, there is no more place for typos or missing localizations. For localizations with variables, you will also get a function with the proper parameter list with the proper types based on variable formatting set in Respresso.

How to access localizations:

#import "RespressoStrings.h"

NSString* localized = RespressoStrings.mainScreenAccountBalance;
//        localized = "Balance: %1$@ %2$.2f" on English devices

NSString* formattedWithParams = [RespressoStrings mainScreenAccountBalanceCurrency:@"USD" balance: 143.1268]; 
//        formattedWithParams = "Balance: USD 143.13" on English devices

NSString* dynamicKey = [RespressoStrings localizedStringWithKey:@"mainScreen.accountBalance"];
//        dynamicKey = "Balance: %1$@ %2$.2f" on English devices - same as localized

Force a specific language

Many apps provide language settings within the app that is a tedious task to implement in iOS as language switching is not available. Thus, we decided to bring you that feature out of the box if you use these helper classes to access localizations. For this, you get the RespressoLanguages class with the defaultLanguage and languages properties.

Switch language:

#import "RespressoStrings.h"
#import "RespressoLanguages.h"

RespressoStrings.language = RespressoLanguages.hu; // Force Hungarian language
NSString* localized = RespressoStrings.mainScreenAccountBalance; // "Egyenleg: %2$.2f %1$@"
RespressoStrings.language = nil; // Return to system default language (English)
localized = RespressoStrings.mainScreenAccountBalance; // "Balance: %1$@ %2$.2f"

Available languages:
To build a dynamic language selector, you will need to iterate over all the languages, therefore the RespressoLanguages class has a languages array. In addition to this, it provides the defaultLanguage property that will contain the language code that corresponds to the language marked as default in Respresso. Let's see an example:

#import "RespressoLanguages.h"

NSArrray* languages = RespressoLanguages.languages;
//        languages = ["en", "en-GB", "hu"]
NSString* defaultLanguage = RespressoLanguages.defaultLanguage;
//        defaultLanguage = "en"

Access localization keys

If you want to access the localization key that is present in the RespressoStrings.strings files, you have to use the RespressoStringKeys class:

#import "RespressoStringKeys.h"

NSString* key = RespressoStringKeys.mainScreenAccountBalance;
//        key = "mainScreen.accountBalance"

This can be used to access localizations using the standard NSLocalizedString(key, ...) or to look up localizations from a dynamically downloaded json from your backend.

Migration from legacy (v1) class

When we introduced the new Respresso CLI, this format also changed. We have a migration guide to help you transition to the new CLI and the new format.

Open migration guide