如何创建格式化的本地化字符串?

发布于 2024-09-01 20:34:00 字数 341 浏览 3 评论 0原文

我有一个本地化字符串,需要使用一些变量。然而,在本地化中,变量的顺序可以根据语言的不同而变化,这一点很重要。

所以这不是一个好主意:

NSString *text = NSLocalizedString(@"My birthday is at %@ %@ in %@", nil);

在某些语言中,某些单词出现在其他单词之前,而在其他语言中则相反。我目前缺乏一个好的例子。

如何在格式化字符串中提供 NAMED 变量?有没有什么方法可以做到这一点,而不需要一些沉重的自制字符串替换?即使是一些编号变量,例如 {%@1}、{%@2} 等也足够了......有解决方案吗?

I have a localized string which needs to take a few variables. However, in localization it is important that the order of the variables can change from language to language.

So this is not a good idea:

NSString *text = NSLocalizedString(@"My birthday is at %@ %@ in %@", nil);

In some languages some words come before others, while in others it's reverse. I lack of an good example at the moment.

How would I provide NAMED variables in a formatted string? Is there any way to do it without some heavy self-made string replacements? Even some numbered variables like {%@1}, {%@2}, and so on would be sufficient... is there a solution?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

你另情深 2024-09-08 20:34:00

这就是为什么 NSLocalizedString 采用两个参数。使用第二个参数包含描述变量的本机语言含义的注释。然后,翻译人员可以使用 $ + 数字结构对它们重新排序。请参阅 Apple 的本地化人员说明

但是,您不能跳过一种语言的参数。例如,如果您有 3 个英语参数和 4 个法语参数,并且不需要第三个英语参数,则无法采用 %1$@ %2$@ 和 %4$@ 等格式。您只能跳过最后一项。

This is why NSLocalizedString takes two parameters. Use the second parameter to include a comment describing the native language meaning of the variables. Then, translators can reorder them using the $ + number construct. See Apple's Notes for Localizers.

However you cannot skip parameters in one language. For example, if you have 3 parameters in English and 4 in French and you don't need the third in English, you cannot format like %1$@ %2$@ and %4$@. You can only skip the last one.

夜空下最亮的亮点 2024-09-08 20:34:00

格式化本地化字符串示例:

NSString *today = [MyHandWatch today];
NSString *msg = [NSString stringWithFormat:NSLocalizedString(@"Today is %@", @""), today];

genstrings 将在您的 Localized.strings 文件中生成此行:

"Today is %@" = "Today is %@";

Formatted localized string example:

NSString *today = [MyHandWatch today];
NSString *msg = [NSString stringWithFormat:NSLocalizedString(@"Today is %@", @""), today];

genstrings will generate this line in your Localizable.strings file:

"Today is %@" = "Today is %@";
我的奇迹 2024-09-08 20:34:00

几周前,我在一个项目中通过使用 NSScanner 构建自己的简单模板系统解决了这个问题。该方法使用模板系统来查找具有语法 ${name} 的变量。变量通过 NSDictionary 提供给该方法。

- (NSString *)localizedStringFromTemplateString:(NSString *)string variables:(NSDictionary *)variables {
    NSMutableString *result = [NSMutableString string];
    // Create scanner with the localized string
    NSScanner *scanner = [[NSScanner alloc] initWithString:NSLocalizedString(string, nil)];
    [scanner setCharactersToBeSkipped:nil];

    NSString *output;

    while (![scanner isAtEnd]) {
        output = NULL;
        // Find ${variable} templates
        if ([scanner scanUpToString:@"${" intoString:&output]) {
            [result appendString:output];

            // Skip syntax
            [scanner scanString:@"${" intoString:NULL];

            output = NULL;

            if ([scanner scanUpToString:@"}" intoString:&output]) {
                id variable = nil;
                // Check for the variable
                if ((variable = [variables objectForKey:output])) {
                    if ([variable isKindOfClass:[NSString class]]) {
                        // NSString, append
                        [result appendString:variable];
                    } else if ([variable respondsToSelector:@selector(description)]) {
                        // Not a NSString, but can handle description, append
                        [result appendString:[variable description]];
                    }
                } else {
                    // Not found, localize the template key and append
                    [result appendString:NSLocalizedString(output, nil)];
                }
                // Skip syntax
                [scanner scanString:@"}" intoString:NULL];
            }
        }
    }

    [scanner release];

    return result;
}

使用如下所示的本地化文件:

"born message"  = "I was born in ${birthYear} on a ${birthWeekDay}. ${byebye}";
"byebye"        = "Cheers!";

我们可以实现以下结果...

NSDictionary *variables = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithInt:1986], @"birthYear", @"monday", @"birthWeekDay", nil];
NSString *finalString [self localizedStringFromTemplateString:@"born message" variables:variables];
NSLog(@"%@", finalString); // "I was born in 1986 on a monday. Cheers!"

如您所见,我也添加了一些额外的功能。首先,任何未找到的变量(在我的示例中为 ${byebye})都将被本地化并附加到结果中。我这样做是因为我从应用程序包中加载 HTML 文件并通过 localize 方法运行它们(这样做时,我在创建扫描仪时不会本地化输入字符串)。此外,我还添加了发送 NSString 对象之外的其他内容的功能,以获得额外的灵活性。

这段代码可能不是性能最好或写得最漂亮的,但它完成了工作,没有任何明显的性能影响:)

I solved this in a project a few weeks back by building my own simple template system with NSScanner. The method uses a template system that finds variables with the syntax ${name}. Variables are supplied to the method through an NSDictionary.

- (NSString *)localizedStringFromTemplateString:(NSString *)string variables:(NSDictionary *)variables {
    NSMutableString *result = [NSMutableString string];
    // Create scanner with the localized string
    NSScanner *scanner = [[NSScanner alloc] initWithString:NSLocalizedString(string, nil)];
    [scanner setCharactersToBeSkipped:nil];

    NSString *output;

    while (![scanner isAtEnd]) {
        output = NULL;
        // Find ${variable} templates
        if ([scanner scanUpToString:@"${" intoString:&output]) {
            [result appendString:output];

            // Skip syntax
            [scanner scanString:@"${" intoString:NULL];

            output = NULL;

            if ([scanner scanUpToString:@"}" intoString:&output]) {
                id variable = nil;
                // Check for the variable
                if ((variable = [variables objectForKey:output])) {
                    if ([variable isKindOfClass:[NSString class]]) {
                        // NSString, append
                        [result appendString:variable];
                    } else if ([variable respondsToSelector:@selector(description)]) {
                        // Not a NSString, but can handle description, append
                        [result appendString:[variable description]];
                    }
                } else {
                    // Not found, localize the template key and append
                    [result appendString:NSLocalizedString(output, nil)];
                }
                // Skip syntax
                [scanner scanString:@"}" intoString:NULL];
            }
        }
    }

    [scanner release];

    return result;
}

With a localize file looking like this:

"born message"  = "I was born in ${birthYear} on a ${birthWeekDay}. ${byebye}";
"byebye"        = "Cheers!";

We can accomplish the following results...

NSDictionary *variables = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithInt:1986], @"birthYear", @"monday", @"birthWeekDay", nil];
NSString *finalString [self localizedStringFromTemplateString:@"born message" variables:variables];
NSLog(@"%@", finalString); // "I was born in 1986 on a monday. Cheers!"

As you can see, I've added some extra functionality too. Firstly, any variables that aren't found (${byebye} in my example) will be localized and appended to the results. I did this because i load in HTML-files from my application bundle and run them through the localize method (when doing that, I don't localize the input string when creating the scanner though). Also, I added the ability to send in other things than just NSString objects, for some extra flexibility.

This code maybe isn't the best performing or prettiest written, but it does the job without any noticeable performance impacts :)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文