it-swarm.dev

اختيار لغة يدوي في تطبيق iOS (iPhone و iPad)

سؤالي:

كيف يمكن لتطبيق iPhone الخاص بي إخبار دائرة الرقابة الداخلية ، أن المستخدم حدد لغة في تفضيلات التطبيقات ، وهذا يختلف عن اللغة المحددة في الإعدادات العامة؟

صياغة أخرى لنفس السؤال:

كيف يمكنني إخبار النظام ، أنه لا ينبغي لـ NSLocalizedString (@"text", @"comment"); الوصول إلى اللغة المحددة على مستوى النظام ، ولكن اللغة المحددة داخل التطبيق؟

الخلفية ، مثال:

يرجى أخذ هذا الموقف كمثال: ابن للمهاجرين الألمان يعيشون في شمال شرق فرنسا بجوار لوكسمبورغ وألمانيا. لغته الأم هي الفرنسية ، لذلك قام بتعيين لغة واجهات المستخدم الخاصة بهاتف iPhone على الفرنسية (الإعدادات -> عام -> دولي -> اللغة -> الفرنسية). ولكن نظرًا لخلفيته الثقافية ولأن المنطقة التي يعيش فيها ثنائية اللغة ، فإنه يتحدث الألمانية جيدًا. لكنه لا يتكلم عشر كلمات بالإنجليزية. على iPhone (و iPad أيضًا) ، ليس لديه فرصة لاختيار لغة ثانية ، لذلك يعلم الهاتف فقط أنه ينتشر باللغة الفرنسية. ليس لديه معرفة بمهارات المستخدمين بلغات أخرى.

الآن يأتي تطبيقي: لقد قمت بتطويره باللغتين الإنجليزية والألمانية (الألمانية هي لغتي الأم والإنجليزية هي لغة قياسية في تكنولوجيا المعلومات). قمت بتطويره وفقًا لجميع القواعد وأفضل الممارسات لتطبيقات iOS متعددة اللغات. اللغة "الأولى" (اللغة الافتراضية) في تطبيقي هي اللغة الإنجليزية.

هذا يعني:

إذا اختار شخص ما اللغة الإنجليزية أو الألمانية في إعداداته ، فستستخدم واجهة مستخدم التطبيقات تلقائيًا اللغة المحددة. لن يلاحظ المستخدم وجود لغات أخرى.

ولكن إذا قام بتحديد أي لغة أخرى (مثل الصينية أو البولندية أو الفرنسية) في الإعدادات العامة ، فسوف يحصل على اللغة الافتراضية للتطبيقات ، والتي هي ، في حالتي ، الإنجليزية. لكن بالنسبة لصديقي الفرنسي ، ليس هذا هو الخيار الأفضل. يرغب في استخدام الإصدار الألماني الحالي ، ولكن يبدو أنه لا توجد طريقة للسماح للمستخدم بتحديد هذا الإصدار.

ستؤدي إضافة ترجمة فرنسية إلى حل المشكلة بالنسبة إلى صديقنا الفرنسي-الألماني ، ولكن ليس للأشخاص الذين يتحدثون لغتين أخريين (مثل الإيطالية والألمانية) ، ولا يمكنني دعم تطبيقي بجميع اللغات التي يتم التحدث بها على هذا الكوكب. كما أن ضبط اللغة الافتراضية على اللغة الألمانية ليس هو الأمثل ، لأن هذا سيثير نفس المشكلة بالنسبة للأشخاص الذين يتحدثون الفرنسية (لغة أصلية) والإنجليزية (كلغة ثانية).

لذلك أعتقد أن تطبيقي يجب أن يكون لديه القدرة على تحديد لغة مختلفة يدويًا عن اللغة المحددة مسبقًا. لا تعد إضافة اختيار اللغة إلى لوحة إعدادات التطبيقات هي المشكلة. ولكن كيف يمكنني إخبار النظام ، أنه لا ينبغي لـ NSLocalizedString (@"text", @"comment"); الوصول إلى اللغة المحددة على مستوى النظام ، ولكن اللغة المحددة داخل التطبيق؟

67
Hubert Schölnast

في غضون ذلك ، وجدت حلاً لمشكلتي على نفسي:

لقد أنشأت فئة جديدة "LocalizeHelper":


رأس 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.strings:

الإنجليزية

/* 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 - 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";

لاستخدام الترجمة ، يجب أن يكون لديك بعض الإجراءات الروتينية في التطبيق الخاص بك ، وفي اختيار اللغة التي تتصل بها الماكرو:

LocalizationSetLanguage(selectedLanguage);

بعد ذلك يجب أن تتأكد من أن كل ما تم عرضه باللغة القديمة ، يتم إعادة رسمه باللغة الجديدة الآن (يجب إعادة رسم النصوص المخفية بمجرد ظهورها مرة أخرى).

للحصول على نصوص مترجمة لكل موقف ، يجب عليك أبدا كتابة نصوص الإصلاح على عناوين الكائنات. استخدم دائمًا الماكرو LocalizedString(keyword).

لا:

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

فعل:

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

ولديك إدخال "لقب جميل" في كل نسخة من Localizable.strings!

81
Hubert Schölnast

ما عليك سوى إضافة ما يلي إلى الشاشة مع اختيار اللغة:

    NSString *tempValue = //user chosen language. Can be picker view/button/segmented control/whatever. Just get the text out of it
    NSString *currentLanguage = @"";
    if ([tempValue rangeOfString:NSLocalizedString(@"English", nil)].location != NSNotFound) {
        currentLanguage = @"en";
    } else if ([tempValue rangeOfString:NSLocalizedString(@"German", nil)].location != NSNotFound) {
        currentLanguage = @"de";
    } else if ([tempValue rangeOfString:NSLocalizedString(@"Russian", nil)].location != NSNotFound) {
        currentLanguage = @"ru";
    }
    [[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObjects:currentLanguage, nil] forKey:@"AppleLanguages"];
    [[NSUserDefaults standardUserDefaults]synchronize];

ثم اطلب منهم إعادة تشغيل التطبيق وسيكون التطبيق بلغة أخرى.

آمل أن يساعد

38
Novarg

إليك جاهز للاستخدام و دليل خطوة بخطوة حول كيفية استخدام نهج Novarg في Swift 3 :


الخطوة رقم 1: تطبيق منتقي اللغة

إن أفضل طريقة للقيام بذلك أمر متروك لك وتعتمد على المشروع. لكن استخدم

Bundle.main.localizations.filter({ $0 != "Base" }) // => ["en", "de", "tr"]

للحصول على قائمة بجميع اللغات المدعومة رموز اللغة برمجياً. كما يمكنك استخدام

Locale.current.localizedString(forLanguageCode: "en") // replace "en" with your variable

لتقديم اسم اللغة في the apps اللغة الحالية .

كمثال كامل ، يمكنك تقديم ورقة عمل منبثقة بعد النقر على زر مثل هذا:

@IBOutlet var changeLanguageButton: UIButton!

@IBAction func didPressChangeLanguageButton() {
    let message = "Change language of this app including its content."
    let sheetCtrl = UIAlertController(title: "Choose language", message: message, preferredStyle: .actionSheet)

    for languageCode in Bundle.main.localizations.filter({ $0 != "Base" }) {
        let langName = Locale.current.localizedString(forLanguageCode: languageCode)
        let action = UIAlertAction(title: langName, style: .default) { _ in
            self.changeToLanguage(languageCode) // see step #2
        }
        sheetCtrl.addAction(action)
    }

    let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
    sheetCtrl.addAction(cancelAction)

    sheetCtrl.popoverPresentationController?.sourceView = self.view
    sheetCtrl.popoverPresentationController?.sourceRect = self.changeLanguageButton.frame
    present(sheetCtrl, animated: true, completion: nil)
}

الخطوة رقم 2: شرح المستخدم ما يجب القيام به + تغيير اللغة مع إعادة التشغيل

ربما لاحظت أن الكود في الخطوة رقم 1 يستدعي طريقة تسمى changeToLanguage(langCode:). هذا ما يجب عليك القيام به ، أيضًا عندما يختار المستخدم لغة جديدة لتغييرها ، بغض النظر عن كيفية تصميم منتقيك. إليك تنفيذه ، فقط انسخه إلى مشروعك:

private func changeToLanguage(_ langCode: String) {
    if Bundle.main.preferredLocalizations.first != langCode {
        let message = "In order to change the language, the App must be closed and reopened by you."
        let confirmAlertCtrl = UIAlertController(title: "App restart required", message: message, preferredStyle: .alert)

        let confirmAction = UIAlertAction(title: "Close now", style: .destructive) { _ in
            UserDefaults.standard.set([langCode], forKey: "AppleLanguages")
            UserDefaults.standard.synchronize()
            exit(EXIT_SUCCESS)
        }
        confirmAlertCtrl.addAction(confirmAction)

        let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
        confirmAlertCtrl.addAction(cancelAction)

        present(confirmAlertCtrl, animated: true, completion: nil)
    }
}

سيؤدي ذلك إلى سؤال المستخدم وإعلامه بما إذا كان يريد إجراء التغيير وكيفية القيام بذلك. كما أنه يحدد لغة التطبيقات في البداية التالية باستخدام:

UserDefaults.standard.set([langCode], forKey: "AppleLanguages")
UserDefaults.standard.synchronize() // required on real device

الخطوة رقم 3 (اختياري): توطين السلاسل

قد ترغب في ترجمة السلاسل مثل "إغلاق الآن" باستخدام الماكرو NSLocalizedString (أو أي طريقة محسّنة أخرى).


مثال على العالم الحقيقي

أنا أستخدم هذا التطبيق الدقيق في تطبيق مستهدف لنظام iOS 10 ، يمكنني التأكيد على أنه يعمل بالنسبة لي على جهاز محاكاة وجهاز. التطبيق هو في الواقع المصدر المفتوح ، حتى تتمكن من العثور على الكود أعلاه موزعة على فئات مختلفة هنا .

17
Dschee

قد تكون إجابتي مسألة تفضيل لأنني أعارض ازدواجية الاختيار اليدوي للغة في التطبيق: سيتعين عليك تجاوز جميع الأزرار التي يوفرها النظام والتأكد من عدم استخدامها. يضيف أيضًا طبقة أخرى من التعقيد وقد يؤدي إلى تشويش المستخدم.

ومع ذلك ، نظرًا لأن هذا يجب أن يكون جوابًا ، أعتقد أنه تم حل حالة الاستخدام الخاصة بك دون اختراق اختيار اللغة.

في تفضيلات iOS ، يمكنك تعيين لغات إضافية:

 iOS language selection preferences 

قد يكون ابنك المثال قد وضع اللغة الفرنسية كلغة رئيسية والألمانية كلغة إضافية.

بعد ذلك ، عندما يتم ترجمة التطبيق الخاص بك إلى الإنكليزية والألمانية ، فإن جهاز iPhone الخاص بهذا الشاب سيختار الموارد الألمانية.

هل سيؤدي ذلك إلى حل المشكلة؟

3
Tomek Cejner

توطين - سويفت - توطين سريع وسريع و i18n مع تبديل لغة داخل التطبيق

2
AlessandroDP

انها بسيطة جدا وسهلة لتغيير اللغة يدويا. بادئ ذي بدء ، تحتاج إلى ترجمة تطبيقك ، ثم يمكنك استخدام التعليمات البرمجية أدناه لتغيير اللغة يدويًا في تطبيقك.

UIAlertController *actionSheet = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"App restart required", @"App restart required") message:NSLocalizedString(@"In order to change the language, the App must be closed and reopened by you.", @"In order to change the language, the App must be closed and reopened by you.") preferredStyle:UIAlertControllerStyleActionSheet];

    [actionSheet addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"Cancel", @"Cancel") style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {


        [self dismissViewControllerAnimated:YES completion:^{


        }];
    }]];

    [actionSheet addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"Restart", @"Restart") style:UIAlertActionStyleDestructive handler:^(UIAlertAction *action) {

        [[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObjects:@"ar", nil] forKey:@"AppleLanguages"];
        [[NSUserDefaults standardUserDefaults]synchronize];

        exit(EXIT_SUCCESS);


    }]];


    [self presentViewController:actionSheet animated:YES completion:nil];
}
0
Spydy