开发者

Custom NSLocalizedString?

开发者 https://www.devze.com 2023-03-17 20:06 出处:网络
Is it possible to use the NSLocalizedString infrastructure (based on localizable.strings) with a custom-defined \"localization\"?

Is it possible to use the NSLocalizedString infrastructure (based on localizable.strings) with a custom-defined "localization"?

Th开发者_JAVA技巧e thing is, there are some languages that have different wordings for males and females. I want to ask the user's gender on first launch and then use the appropriate phrases. Of course, both are based on the same language. I can do it with my own code but I'd rather do it the easy way if possible.


Here is my Custom implementation that use NSLocalizedString that use comment as default value:

(NSLocalizedStringWithDefaultValue does not work properly with genstring, that's why I proposed this solution)

1 . In your pre compiled header (.pch file) , redefine the 'NSLocalizedString' macro:

// cutom NSLocalizedString that use macro comment as default value
#import "LocalizationHandlerUtil.h"

#undef NSLocalizedString
#define NSLocalizedString(key,_comment) [[LocalizationHandlerUtil singleton] localizedString:key  comment:_comment]

2. create a class to implement the localization handler

#import "LocalizationHandlerUtil.h"

@implementation LocalizationHandlerUtil

static LocalizationHandlerUtil * singleton = nil;

+ (LocalizationHandlerUtil *)singleton
{
    return singleton;
}

__attribute__((constructor))
static void staticInit_singleton()
{
    singleton = [[LocalizationHandlerUtil alloc] init];
}

- (NSString *)localizedString:(NSString *)key comment:(NSString *)comment
{
    // default localized string loading
    NSString * localizedString = [[NSBundle mainBundle] localizedStringForKey:key value:key table:nil];

    // if (value == key) and comment is not nil -> returns comment
    if([localizedString isEqualToString:key] && comment !=nil)
        return comment;

    return localizedString;
}

@end

3. Use it!

Make sure you add a Run script in your App Build Phases so you Localizable.strings file will be updated at each build, i.e., new localized string will be added in your Localized.strings file:

My build phase Script is a shell script:

Shell: /bin/sh
Shell script content: find . -name \*.m | xargs genstrings -o MyProjectFolder

So when you add this new line in your code:

self.title = NSLocalizedString(@"view_settings_title", @"Settings");

Then perform a build, your ./Localizable.scripts file will contain this new line:

/* Settings */
"view_settings_title" = "view_settings_title";

And since key == value for 'view_settings_title', the custom LocalizedStringHandler will returns the comment, i.e. 'Settings"

Voilà :-)


NSLocalizedString is just a macro defined in NSBundle.h
Redefine it or create a new one, for example NSGenderAwareLocalizedString to fit your needs.

With the new macro, you are free to do whatever you want: two strings files per language, one for male and one for female. Or you can define a convention to derivate the key for a localized string for a female from the key of the male localized string.


There is a special mechanism for this. From Apple reference: Searching for Custom Functions With genstrings

The genstrings tool searches for the Core Foundation and Foundation string macros by default. It uses the information in these macros to create the string entries in your project’s strings files. You can also direct genstrings to look for custom string-loading functions in your code and use those functions in addition to the standard macros. You might use custom functions to wrap the built-in string-loading routines and perform some extra processing or you might replace the default string handling behavior with your own custom model.

If you want to use genstrings with your own custom functions, your functions must use the naming and formatting conventions used by the Foundation macros. The parameters for your functions must match the parameters for the corresponding macros exactly. When you invoke genstrings, you specify the -s option followed by the name of the function that corresponds to the NSLocalizedString macro. Your other function names should then build from this base name. For example, if you specified the function name MyStringFunction, your other function names should be MyStringFunctionFromTable, MyStringFunctionFromTableInBundle, and MyStringFunctionWithDefaultValue. The genstrings tool looks for these functions and uses them to build the corresponding strings files.

To implement your own behaviour use NSBundle method localizedStringForKey:value:table:


Here is my Custom implementation that use NSLocalizedString that use comment as default value:

--> Here I convert in 2 Language (English and Italian)

--> Put this method in appdelegate class

- (NSString*)languageSelectedStringForKey:(NSString*) key {        

    NSString *path = nil;
    NSString *language = [[NSUserDefaults standardUserDefaults] valueForKey:@"AppLanguage"];

    if ([language isEqualToString:@"English"])
        path = [[NSBundle mainBundle] pathForResource:@"en" ofType:@"lproj"];
    else if ([language isEqualToString:@"Italian"])
        path = [[NSBundle mainBundle] pathForResource:@"it" ofType:@"lproj"];

    NSBundle* languageBundle = [NSBundle bundleWithPath:path];
    NSString* str=[languageBundle localizedStringForKey:key value:@"" table:nil];
    return str;
}

--> call this method by

 self.title = [appDelgate languageSelectedStringForKey:@"Back"];

that convert Back in selected language.


In the Xcode Project Navigator,

  1. click Project name (first item on list),
  2. then in opened tab click your project under PROJECT label
  3. Select Build Settings
  4. In Search in right corner enter LOCALIZED_STRING_MACRO_NAMES
  5. Add your custom function name to showed setting (divide by space from existing) Example: NSLocalizedString CFLocalizedString NSBundleLocalizedString

    Custom NSLocalizedString?

After this, option "export for localization" from Xcode will produce an XLIFF file that contains translatable strings mentioned in your custom function.


@Guillaume provides the best solution, without actually showing the implementation. Since the author of the question wasn't able to figure it out, I decided to include it for future people. I found the thread helpful, now it is more than helpful. :)

As mentioned by @Guillaume, the best solution is to create a custom macro with a lookup on the table . The 'table' is just the name of the other file that contains the variants. In this case, I am assuming you will name your file 'Female.strings'

This ensures the most flexibility and gives you a solution that doesn't require you to define entries for BOTH cases. This is actually really useful for your case as not all phrases may have feminine forms.

As a result, the following solution doesn't require duplicate entries, which is pretty cool!

First define your macro:

#define SXLocalizedString(key, comment) [Utility SXLocalizedString:key with:comment]

Then define the expanded function as such:

+ (NSString*)SXLocalizedString:(NSString*)str with:(NSString*)comment {
    NSString* feminine = NSLocalizedStringFromTable(str, @"Female", comment);
    NSString* value = NSLocalizedString(str, comment);
    if ([self userIsFemale] &&
        feminine) {
        // choose the feminine version of the string
        value = feminine;
    }
    return value;
}


For couple of years Xcode has LOCALIZED_STRING_MACRO_NAMES, so you can put your custom NSLocalizedString alternative macro names if they follow same parameters structure and Xcode will correctly export/import them, similar to genstrings answer

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号