NSLocalizedString का उपयोग करते हुए सबसे अच्छा अभ्यास


140

मैं (सभी अन्य लोगों की तरह) NSLocalizedStringअपने ऐप को स्थानीय बनाने के लिए उपयोग कर रहा हूं ।

दुर्भाग्य से, कई "कमियां" हैं (जरूरी नहीं कि NSLocalizedString का दोष ही हो), सहित

  • Xcode में तार के लिए कोई स्वतः पूर्णता नहीं। यह न केवल त्रुटि-प्रवण, बल्कि थकाऊ भी काम करता है।
  • आप एक स्ट्रिंग को फिर से परिभाषित कर सकते हैं क्योंकि आप पहले से मौजूद एक समतुल्य स्ट्रिंग को नहीं जानते थे (यानी "कृपया पासवर्ड दर्ज करें" बनाम "पासवर्ड दर्ज करें")
  • स्वतः पूर्णता-मुद्दे के समान, आपको "याद रखने" की आवश्यकता है / टिप्पणी स्ट्रिंग को कॉपी करें, या फिर genstringएक स्ट्रिंग के लिए कई टिप्पणियों के साथ समाप्त हो जाएगा
  • यदि आप genstringपहले से ही कुछ तारों को स्थानीयकृत करने के बाद उपयोग करना चाहते हैं, तो आपको अपने पुराने स्थानीयकरणों को न खोने के लिए सावधान रहना होगा।
  • वही तार आपके पूरे प्रोजेक्ट को चौपट कर देते हैं। उदाहरण के लिए, आपने NSLocalizedString(@"Abort", @"Cancel action")हर जगह उपयोग किया , और फिर कोड की समीक्षा ने आपको NSLocalizedString(@"Cancel", @"Cancel action")कोड को अधिक सुसंगत बनाने के लिए स्ट्रिंग का नाम बदलने के लिए कहा ।

मैं क्या करता हूं (और SO पर कुछ खोजों के बाद मुझे लगा कि बहुत से लोग ऐसा करते हैं) एक अलग strings.hफ़ाइल है जहाँ मैं #defineसभी स्थानीयकरण-कोड रखता हूँ । उदाहरण के लिए

// In strings.h
#define NSLS_COMMON_CANCEL NSLocalizedString(@"Cancel", nil)
// Somewhere else
NSLog(@"%@", NSLS_COMMON_CANCEL);

यह अनिवार्य रूप से कोड-पूर्णता प्रदान करता है, चर नामों को बदलने के लिए एक एकल स्थान (ताकि अब जेनस्ट्रिंग की कोई आवश्यकता नहीं है), और ऑटो-रिफ्लेक्टर के लिए एक अनूठा कीवर्ड। हालांकि, यह उन #defineबयानों की एक पूरी गुच्छा के साथ समाप्त होने की लागत पर आता है जो स्वाभाविक रूप से संरचित नहीं होते हैं (जैसे कि लोकेस्ट्रिंग.कोमोन.कैंसेल या ऐसा कुछ)।

इसलिए, जब यह कुछ हद तक ठीक है, तो मैं सोच रहा था कि आप लोग इसे अपनी परियोजनाओं में कैसे करेंगे। क्या NSLocalizedString के उपयोग को आसान बनाने के लिए अन्य तरीके हैं? क्या शायद कोई ऐसा ढांचा भी है जो इसे घेरता है?


मैं बस इसे लगभग आपकी तरह ही करता हूं। लेकिन मैं NSLocalizedStringWithDefaultValue makro का उपयोग विभिन्न स्थानीयकरण मुद्दों (जैसे नियंत्रकों, मॉडल, आदि) के लिए अलग तार फ़ाइलों को बनाने और प्रारंभिक डिफ़ॉल्ट मान बनाने के लिए कर रहा हूं।
उर्फ

ऐसा लगता है कि स्थानीयकरण के लिए xcode6 का निर्यात शीर्ष लेख फ़ाइल में मैक्रोज़ के रूप में परिभाषित किए गए तार को नहीं पकड़ता है। क्या कोई पुष्टि कर सकता है या मुझे बता सकता है कि मुझे क्या याद आ रहा है? धन्यवाद...!
12 अक्टूबर को ज्यूडस्टर

@Jsterster, नए फंड एडिटर के साथ भी पुष्टि कर सकता है-> स्थानीयकरण के लिए निर्यात यह हेडर फ़ाइल में नहीं मिलता है
Red

जवाबों:


100

NSLocalizedStringकुछ सीमाएँ हैं, लेकिन कोको के लिए यह इतना केंद्रीय है कि स्थानीयकरण को संभालने के लिए कस्टम कोड लिखना अनुचित है, जिसका अर्थ है कि आपको इसका उपयोग करना होगा। उस ने कहा, थोड़ा टूलिंग मदद कर सकता है, यहां बताया गया है कि मैं कैसे आगे बढ़ता हूं:

स्ट्रिंग्स फ़ाइल को अपडेट करना

genstringsआपकी स्ट्रिंग फ़ाइलों को ओवरराइट करता है, आपके सभी पिछले अनुवादों को छोड़ देता है। मैंने पुराने स्ट्रिंग्स फ़ाइल को पार्स करने, रिक्त स्थान को चलाने और भरने के लिए update_strings.py लिखा है genstringsताकि आपको अपने मौजूदा अनुवादों को मैन्युअल रूप से पुनर्स्थापित न करना पड़े। स्क्रिप्ट मौजूदा स्ट्रिंग फ़ाइलों को यथासंभव अपडेट करने से बचने के लिए यथासंभव बारीकी से मिलान करने का प्रयास करती है।

अपने तार नामकरण

यदि आप NSLocalizedStringविज्ञापन के रूप में उपयोग करते हैं:

NSLocalizedString(@"Cancel or continue?", @"Cancel notice message when a download takes too long to proceed");

आप अपने कोड के दूसरे भाग में उसी स्ट्रिंग को परिभाषित कर सकते हैं, जो एक ही अंग्रेजी शब्द के रूप में संघर्ष कर सकता है, अलग-अलग संदर्भों में अलग-अलग अर्थ हो सकता है ( OKऔर Cancelमन में आता है)। यही कारण है कि मैं हमेशा एक मॉड्यूल-विशिष्ट उपसर्ग के साथ एक अर्थहीन ऑल-कैप स्ट्रिंग का उपयोग करता हूं, और बहुत सटीक विवरण:

NSLocalizedString(@"DOWNLOAD_CANCEL_OR_CONTINUE", @"Cancel notice window title when a download takes too long to proceed");

विभिन्न स्थानों में एक ही स्ट्रिंग का उपयोग करना

यदि आप एक ही स्ट्रिंग का कई बार उपयोग करते हैं, तो आप या तो एक मैक्रो का उपयोग कर सकते हैं, या इसे अपने व्यू कंट्रोलर या अपने डेटा स्रोत में एक उदाहरण चर के रूप में कैश कर सकते हैं। इस तरह आपको उस विवरण को दोहराना नहीं पड़ेगा जो बासी हो सकता है और उसी स्थानीयकरण के उदाहरणों के बीच असंगत हो सकता है, जो हमेशा भ्रमित होता है। उदाहरण के रूप में चर प्रतीक हैं, आप इन सबसे आम अनुवादों पर ऑटो-समापन का उपयोग करने में सक्षम होंगे, और विशिष्ट लोगों के लिए "मैनुअल" स्ट्रिंग्स का उपयोग करेंगे, जो केवल एक बार भी होगा।

मुझे आशा है कि आप इन युक्तियों के साथ कोको स्थानीयकरण के साथ अधिक उत्पादक होंगे!


आपके उत्तर के लिए धन्यवाद, मैं निश्चित रूप से आपके अजगर-फ़ाइल पर एक नज़र डालूंगा। मैं आपके नामकरण सम्मेलनों से सहमत हूं। मैंने हाल ही में कुछ अन्य iOS देवों के साथ बात की है, और उन्होंने मैक्रोज़ के बजाय स्थैतिक स्ट्रिंग्स के उपयोग की सिफारिश की है, जो समझ में आता है। मैंने आपके उत्तर को बदल दिया है, लेकिन मैं इसे स्वीकार करने से पहले थोड़ा इंतजार करूंगा, क्योंकि समाधान अभी भी थोड़ा अनाड़ी है। शायद कुछ बेहतर साथ आए। एक बार फिर धन्यवाद!
जियाओउ

आपका स्वागत है। स्थानीयकरण एक थकाऊ प्रक्रिया है, सही उपकरण और वर्कफ़्लो अंतर की दुनिया बनाते हैं।
ndfred 7

17
मुझे समझ में नहीं आया है कि गेटटेक्स्ट-स्टाइल स्थानीयकरण फ़ंक्शंस कुंजी में से किसी एक अनुवाद का उपयोग क्यों करते हैं। यदि आपका मूल पाठ बदलता है तो क्या होगा? आपकी कुंजी बदल जाती है और आपकी सभी स्थानीय फ़ाइलें उनकी कुंजी के लिए पुराने पाठ का उपयोग कर रही हैं। इससे मुझे कभी कोई मतलब नहीं है। मैंने हमेशा "home_button_text" जैसी कुंजियों का उपयोग किया है, इसलिए वे अद्वितीय हैं और कभी नहीं बदलते हैं। मैंने अपनी सभी Localizable.strings फ़ाइलों को पार्स करने के लिए एक बैश स्क्रिप्ट भी लिखी है और स्टैटिक विधियों के साथ एक क्लास फाइल जेनरेट की है जो उपयुक्त स्ट्रिंग को लोड करेगी। यह मुझे कोड पूरा करने देता है। एक दिन मैं यह स्रोत खोल सकता हूं।
माइक वेलर

2
मुझे लगता है कि आपका मतलब genstringsनहीं है gestring
हिरोशी

1
@ndfred संकलन समय जाँचता है कि आपने स्ट्रिंग गलत टाइप नहीं की है, यह सबसे बड़ी जीत है। यह वैसे भी जोड़ने के लिए थोड़ा और अधिक कोड है। इसके अलावा रिफैक्टरिंग, स्थैतिक विश्लेषण के मामले में, एक प्रतीक होने से चीजें आसान हो जाती हैं।
एलन ज़ेंग

31

के रूप में Xcode में तार के लिए autocompletition के लिए, आप https://github.com/questbeat/Lin की कोशिश कर सकते हैं ।


3
यह वास्तव में काफी आश्चर्यजनक है। मैक्रोज़ बनाने की आवश्यकता नहीं है।
ब्यू नौवेल्ले

1
पृष्ठ नहीं मिला_
जुआनमी

1
@ जुआनमी मृत लिंक का उल्लेख करने के लिए धन्यवाद। मैंने लिंक को गीथब यूआरएल के साथ बदल दिया।
हिरोशी

24

Ndfred से सहमत हैं, लेकिन मैं इसे जोड़ना चाहूंगा:

दूसरा पैरामीटर ... डिफ़ॉल्ट मान के रूप में उपयोग किया जा सकता है !!

(NSLocalizedStringWithDefaultValue जीनस्ट्रिंग के साथ ठीक से काम नहीं करता है, इसीलिए मैंने यह समाधान प्रस्तावित किया है)

यहां मेरा कस्टम कार्यान्वयन है जो NSLocalizedString का उपयोग करता है जो डिफ़ॉल्ट मान के रूप में टिप्पणी का उपयोग करता है:

1 है। अपने पूर्व संकलित हेडर (.pch फ़ाइल) में, 'NSLocalizedString' मैक्रो को फिर से परिभाषित करें:

// 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. स्थानीयकरण हैंडलर को लागू करने के लिए एक वर्ग बनाएं

#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. इसका उपयोग करें!

सुनिश्चित करें कि आप अपने ऐप बिल्ड चरणों में एक रन स्क्रिप्ट जोड़ते हैं, ताकि आप प्रत्येक बिल्ड पर Localizable.strings फ़ाइल अपडेट हो जाए, अर्थात, आपके Localized.strings फ़ाइल में नई स्थानीयकृत स्ट्रिंग जोड़ दी जाएगी:

मेरी बिल्ड फेज स्क्रिप्ट एक शेल स्क्रिप्ट है:

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

इसलिए जब आप इस नई लाइन को अपने कोड में जोड़ते हैं:

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

फिर एक बिल्ड करें, आपकी ./Localizable.scripts फ़ाइल में यह नई लाइन होगी:

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

और जब से कुंजी == मान 'view_settings_title' के लिए आया है, तो कस्टम स्थानीयकृत StringHandler टिप्पणी लौटाएगा, अर्थात 'सेटिंग'

Voilà :-)


एआरसी त्रुटियां हो रही हैं, चयनकर्ता के लिए कोई ज्ञात उदाहरण विधि नहीं: स्थानीयकृत स्ट्रिंग: टिप्पणी::
मंगेश

मुझे लगता है कि यह इसलिए है क्योंकि LocalizationHandlerUtil.h गायब है। मुझे कोड वापस नहीं मिल रहा है ... बस हेडर फ़ाइल बनाने की कोशिश करें स्थानीयकरणहैंडलर यूटीआईएल.एच और यह ठीक होना चाहिए
पास्कल

मैंने फाइलें बनाई हैं। मुझे लगता है कि यह फ़ोल्डर पथ समस्या के कारण है।
मंगेश

3

स्विफ्ट में मैं निम्नलिखित का उपयोग कर रहा हूं, उदाहरण के लिए इस मामले में "हां" बटन के लिए:

NSLocalizedString("btn_yes", value: "Yes", comment: "Yes button")

value:डिफ़ॉल्ट पाठ मान के लिए उपयोग पर ध्यान दें । पहला पैरामीटर अनुवाद आईडी के रूप में कार्य करता है। value:पैरामीटर का उपयोग करने का लाभ यह है कि डिफ़ॉल्ट पाठ को बाद में बदला जा सकता है लेकिन अनुवाद आईडी एक ही रहता है। इसमें Localizable.strings फ़ाइल होगी"btn_yes" = "Yes";

यदि value:पैरामीटर का उपयोग नहीं किया गया था, तो पहले पैरामीटर का उपयोग दोनों के लिए किया जाएगा: अनुवाद आईडी के लिए और डिफ़ॉल्ट पाठ मान के लिए भी। इसमें Localizable.strings फ़ाइल शामिल होगी "Yes" = "Yes";। स्थानीयकरण फ़ाइलों के प्रबंधन के इस तरह अजीब लगता है। खासकर अगर अनुवादित पाठ लंबा है तो आईडी भी लंबी है। जब भी डिफॉल्ट टेक्स्ट वैल्यू का कोई कैरेक्टर बदला जाता है, तो ट्रांसलेशन आईडी भी बदल जाती है। यह उन मुद्दों की ओर जाता है जब बाहरी अनुवाद प्रणालियों का उपयोग किया जाता है। अनुवाद आईडी को बदलना नए अनुवाद पाठ को जोड़ने के रूप में समझा जाता है, जो हमेशा वांछित नहीं हो सकता है।


2

मैंने कई भाषाओं में Localizable.strings को बनाए रखने में मदद करने के लिए एक स्क्रिप्ट लिखी। हालांकि यह स्वतः पूर्णता में मदद नहीं करता है, यह कमांड का उपयोग करके .strings फ़ाइलों को मर्ज करने में मदद करता है:

merge_strings.rb ja.lproj/Localizable.strings en.lproj/Localizable.strings

अधिक जानकारी के लिए देखें: https://github.com/hiroshi/merge_strings

आपमें से कुछ लोग इसे उपयोगी मानते हैं।


2

अगर कोई स्विफ्ट के समाधान की तलाश में है। आप मेरे समाधान की जाँच कर सकते हैं जो मैंने यहाँ एक साथ रखा है: SwiftyLocalization

सेटअप के कुछ चरणों के साथ, आपके पास Google स्प्रेडशीट (टिप्पणी, कस्टम रंग, हाइलाइट, फ़ॉन्ट, कई शीट, और बहुत कुछ) में एक बहुत ही लचीला स्थानीयकरण होगा।

संक्षेप में, चरण हैं: Google स्प्रैडशीट -> CSV फ़ाइलें -> Localizable.strings

इसके अलावा, यह Localizables.swift, एक संरचना भी उत्पन्न करता है जो आपके लिए कुंजी पुनर्प्राप्ति और डिकोडिंग के लिए इंटरफेस की तरह काम करता है (आपको मैन्युअल रूप से कुंजी से स्ट्रिंग को डिकोड करने का एक तरीका निर्दिष्ट करना होगा)।

यह महान क्यों है?

  1. अब आपको सभी स्थानों पर एक सादे तार की कुंजी की आवश्यकता नहीं है।
  2. संकलित समय पर गलत कुंजियों का पता लगाया जाता है।
  3. Xcode स्वत: पूर्ण कर सकता है।

हालांकि ऐसे उपकरण हैं जो आपकी स्थानीय कुंजी को स्वतः पूर्ण कर सकते हैं। एक वास्तविक चर का संदर्भ यह सुनिश्चित करेगा कि यह हमेशा एक वैध कुंजी है, अन्यथा यह संकलन नहीं करेगा।

// It's defined as computed static var, so it's up-to-date every time you call. 
// You can also have your custom retrieval method there.

button.setTitle(Localizables.login.button_title_login, forState: .Normal)

परियोजना CSV फ़ाइलों को परिवर्तित करने के लिए शीट -> CSV, और पायथन स्क्रिप्ट को परिवर्तित करने के लिए Google ऐप स्क्रिप्ट का उपयोग करती है -> Localizable.strings आप यह जानने के लिए इस उदाहरण पत्र पर एक त्वरित नज़र डाल सकते हैं कि क्या संभव है।


1

iOS 7 और Xcode 5 के साथ, आपको 'Localization.strings' विधि का उपयोग करने से बचना चाहिए, और नए 'आधार स्थानीयकरण' विधि का उपयोग करना चाहिए। यदि आप 'आधार स्थानीयकरण' के लिए Google के आसपास कुछ ट्यूटोरियल देखते हैं

Apple डॉक: बेस लोकलाइज़ेशन


हाँ स्टीव जो सही है। इसके अलावा, आपको अभी भी किसी भी गतिशील रूप से उत्पन्न स्ट्रिंग के लिए .strings फ़ाइल विधि की आवश्यकता है। लेकिन केवल इन के लिए, Apple का पसंदीदा तरीका आधार स्थानीयकरण है।
रॉनी वेयर्स

नई विधि के लिए लिंक?
हाइपरबोले

1
Imo आधार स्थानीयकरण विधि बेकार है। आपको डायनामिक स्ट्रिंग्स के लिए अभी भी अन्य लोकेशन फाइल्स को रखना है, और यह आपके स्ट्रिंग्स को बहुत सारी फाइलों के माध्यम से फैलाता है। Nibs / स्टोरीबोर्ड के अंदर के स्ट्रिंग्स को स्थानीय रूप से चाबियों में स्वचालित रूप से स्थानीय किया जा सकता है। कुछ Libs जैसे github.com/AliSoftware/OHAutoNIBi18n
राफेल नोब्रे

0
#define PBLocalizedString(key, val) \

[[NSBundle mainBundle] localizedStringForKey:(key) value:(val) table:nil]

0

अपने आप को, मैं अक्सर कोडिंग के साथ दूर ले जाया जाता हूं, प्रविष्टियों को .strings फ़ाइलों में रखना भूल जाता हूं। इस प्रकार मेरे पास सहायक स्क्रिप्ट हैं जो यह पता लगाने के लिए हैं कि मैं .strings फ़ाइलों और अनुवाद में वापस डालने के लिए क्या देना चाहता हूं।

मैं NSLocalizedString से अधिक मेरे अपने मैक्रो का उपयोग के रूप में, की समीक्षा करने और उपयोग करने से पहले स्क्रिप्ट अपडेट कर लें के रूप में मैं सादगी के लिए मान लिया है कि शून्य NSLocalizedString के लिए एक दूसरी परम के रूप में प्रयोग किया जाता है। जिस भाग को आप बदलना चाहते हैं, वह है

NSLocalizedString\(@(".*?")\s*,\s*nil\) 

बस इसे किसी ऐसी चीज़ से बदलें जो आपके मैक्रो और NSLocalizedString उपयोग से मेल खाती है।

यहां स्क्रिप्ट आती है, आपको केवल भाग 3 वास्तव में चाहिए। बाकी को यह देखना आसान है कि यह सब कहां से आता है:

// Part 1. Get keys from one of the Localizable.strings
perl -ne 'print "$1\n" if /^\s*(".+")\s*=/' myapp/fr.lproj/Localizable.strings

// Part 2. Get keys from the source code
grep -n -h -Eo -r  'NSLocalizedString\(@(".*?")\s*,\s*nil\)' ./ | perl -ne 'print "$1\n" if /NSLocalizedString\(@(".+")\s*,\s*nil\)/'

// Part 3. Get Part 1 and 2 together.

comm -2 -3 <(grep -n -h -Eo -r  'NSLocalizedString\(@(".*?")\s*,\s*nil\)' ./ | perl -ne 'print "$1\n" if /NSLocalizedString\(@(".+")\s*,\s*nil\)/' | sort | uniq) <(perl -ne 'print "$1\n" if /^\s*(".+")\s*=/' myapp/fr.lproj/Localizable.strings | sort) | uniq >> fr-localization-delta.txt

आउटपुट फ़ाइल में कुंजियाँ होती हैं जो कोड में पाई गईं, लेकिन Localizable.strings फ़ाइल में नहीं। यहाँ एक नमूना है:

"MPH"
"Map Direction"
"Max duration of a detailed recording, hours"
"Moving ..."
"My Track"
"New Trip"

निश्चित रूप से अधिक पॉलिश किया जा सकता है, लेकिन मुझे लगा कि मैं साझा करूंगा।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.