My question:

我的iPhone应用程序如何告诉iOS,用户确实在应用程序首选项中 Select 了与常规设置中设置的语言不同的语言?

Other formulation of the same question:

我如何才能告诉系统,NSLocalizedString (@"text", @"comment");不应该访问系统范围内 Select 的语言,而应该访问应用程序内 Select 的语言?

background, example:

请以这种情况为例: 一位德国移民的儿子住在法国东北部,毗邻卢森堡和德国.他的母语是法语,所以他确实将苹果手机的用户界面语言设置为法语(Settings→General→International→Language→Français).但由于他的文化背景,以及他居住的地区是双语的,他的德语也说得很好.但是他不会说十个英语单词.在iPhone(以及iPad)上,他没有机会 Select 第二种语言,所以手机只知道他会说法语.它对其他语言的用户技能一无所知.

现在我的应用程序来了:我确实用英语和德语开发了它(德语是我的母语,英语是其中的标准语言).我确实根据多语言iOS应用的所有规则和最佳实践开发了它.我的应用程序的"第一"语言(默认语言)是英语.

This means:

如果有人在设置中 Select 了英语或德语,应用程序用户界面将自动使用所选语言.用户甚至不会注意到还有其他可用语言.

但如果他在常规设置中 Select 了任何其他语言(如汉语、波兰语或法语),他将获得应用程序的默认语言,在我的情况下,是英语.但对我的法德朋友来说,这不是最好的 Select .他希望使用现有的德语版本,但似乎没有办法让用户 Select 这个版本.

添加法语翻译可以解决我们的法德朋友的问题,但对于说另外两种语言(如意大利语和德语)的人来说就解决不了了,而且我的应用程序不能支持这个星球上所有的语言. 将默认语言设置为德语也不是最佳的,因为这会给使用法语(作为母语)和英语(作为第二语言)的人带来同样的问题.

因此,我认为我的应用程序必须能够手动 Select 与预先 Select 的语言不同的语言.将语言 Select 添加到应用程序设置面板不是问题.但是,我如何才能告诉系统,NSLocalizedString (@"text", @"comment");不应该访问系统范围内 Select 的语言,而应该访问应用程序内 Select 的语言呢?

推荐答案

与此同时,我确实为我自己的问题找到了解决方案:

我创建了一个新类"LocalizeHelper":


Header LocalizeHelper.h

//LocalizeHelper.h

#import <Foundation/Foundation.h>

// some macros (optional, but makes life easy)

// Use "LocalizedString(key)" the same way you would use "NSLocalizedString(key,comment)"
#define LocalizedString(key) [[LocalizeHelper sharedLocalSystem] localizedStringForKey:(key)]

// "language" can be (for american english): "en", "en-US", "english". Analogous for other languages.
#define LocalizationSetLanguage(language) [[LocalizeHelper sharedLocalSystem] setLanguage:(language)]

@interface LocalizeHelper : NSObject

// a singleton:
+ (LocalizeHelper*) sharedLocalSystem;

// this gets the string localized:
- (NSString*) localizedStringForKey:(NSString*) key;

//set a new language:
- (void) setLanguage:(NSString*) lang;              

@end

iMplementation LocalizeHelper.m

// LocalizeHelper.m
#import "LocalizeHelper.h"

// Singleton
static LocalizeHelper* SingleLocalSystem = nil;

// my Bundle (not the main bundle!)
static NSBundle* myBundle = nil;


@implementation LocalizeHelper


//-------------------------------------------------------------
// allways return the same singleton
//-------------------------------------------------------------
+ (LocalizeHelper*) sharedLocalSystem {
    // lazy instantiation
    if (SingleLocalSystem == nil) {
        SingleLocalSystem = [[LocalizeHelper alloc] init];
    }
    return SingleLocalSystem;
}


//-------------------------------------------------------------
// initiating
//-------------------------------------------------------------
- (id) init {
    self = [super init];
    if (self) {
        // use systems main bundle as default bundle
        myBundle = [NSBundle mainBundle];
    }
    return self;
}


//-------------------------------------------------------------
// translate a string
//-------------------------------------------------------------
// you can use this macro:
// LocalizedString(@"Text");
- (NSString*) localizedStringForKey:(NSString*) key {
    // this is almost exactly what is done when calling the macro NSLocalizedString(@"Text",@"comment")
    // the difference is: here we do not use the systems main bundle, but a bundle
    // we selected manually before (see "setLanguage")
    return [myBundle localizedStringForKey:key value:@"" table:nil];
}


//-------------------------------------------------------------
// set a new language
//-------------------------------------------------------------
// you can use this macro:
// LocalizationSetLanguage(@"German") or LocalizationSetLanguage(@"de");
- (void) setLanguage:(NSString*) lang {

    // path to this languages bundle
    NSString *path = [[NSBundle mainBundle] pathForResource:lang ofType:@"lproj" ];
    if (path == nil) {
        // there is no bundle for that language
        // use main bundle instead
        myBundle = [NSBundle mainBundle];
    } else {

        // use this bundle as my bundle from now on:
        myBundle = [NSBundle bundleWithPath:path];

        // to be absolutely shure (this is probably unnecessary):
        if (myBundle == nil) {
            myBundle = [NSBundle mainBundle];
        }
    }
}


@end

对于您想要支持的每种语言,您都需要一个名为Localizable.strings的文件.这与Apple本地化文档中描述的完全一样.唯一的区别是:现在你甚至可以使用苹果不支持的印地语或世界语等语言.

举个例子,下面是我的英语和德语版本的Localizable.string的前几行:

English

/* English - English */

/* for debugging */
"languageOfBundle" = "English - English";

/* Header-Title of the Table displaying all lists and projects */
"summary" = "Summary";

/* Section-Titles in table "summary" */
"help" = "Help";
"lists" = "Lists";
"projects" = "Projects";
"listTemplates" = "List Templates";
"projectTemplates" = "Project Templates";

German

/* German - Deutsch */

/* for debugging */
"languageOfBundle" = "German - Deutsch";

/* Header-Title of the Table displaying all lists and projects */
"summary" = "Überblick";

/* Section-Titles in table "summary" */
"help" = "Hilfe";
"lists" = "Listen";
"projects" = "Projekte";
"listTemplates" = "Vorlagen für Listen";
"projectTemplates" = "Vorlagen für Projekte";

要使用本地化,必须在应用程序中设置一些 routine ,并在语言 Select 中调用宏:

LocalizationSetLanguage(selectedLanguage);

在此之后,您必须确保所有用旧语言显示的内容现在都会用新语言重新绘制(隐藏文本必须在再次可见时立即重新绘制).

要使本地化文本适用于各种情况,您永远不必将修复文本写入对象标题.始终使用宏LocalizedString(keyword).

don't:

cell.textLabel.text = @"nice title";

do:

cell.textLabel.text = LocalizedString(@"nice title");

在每个版本的Localizable中都有一个"好标题"条目.串!

Ios相关问答推荐

如何在iPhone 15上消除.NET Maui中状态栏和页面之间的差距

withTaskGroup不适用于CLGeocoder

Xcode 15模拟器用x86_64编译

BezierPath 中绘制图像形状轮廓的算法(Canny 边缘检测器)

iOS 16.4,SwiftUI 底部工作表有时会忽略presentationDetents

Swift locationManager.requestWhenInUseAuthorization() 不提示用户

如何将 Info.plist 文件添加到 Xcode for admob,错误 添加后会产生多个命令

UIControl 子类 - 按下时显示 UIMenu

如何擦除 Swift 中的 Core Graphics Context 绘图?

.onChange(of: ) 一次用于多个 @State 属性?

缺少推送通知权利

NSFetchedResultsController 由字符串的第一个字母创建的部分

在 Swift 中按下返回键时在文本字段之间切换

动画 UILabel 字体大小更改

如何在导航栏右侧添加多个 UIBarButtonItem?

针对 Xcode 中的 iPad 选项

如何缩小 UIImage 并使其同时变得清晰/锐利而不是模糊?

@IBDesignable 崩溃代理

两个数字之间的动画UILabel文本?

我可以在 UIScrollView 中使用 UIRefreshControl 吗?