क्या NSLocalizedString स्विफ्ट में बराबर है?


228

वहाँ एक स्विफ्ट के बराबर है NSLocalizedString(...)? में Objective-C, हम आमतौर पर उपयोग करते हैं:

NSString *string = NSLocalizedString(@"key", @"comment");

मैं स्विफ्ट में समान कैसे प्राप्त कर सकता हूं? मुझे एक समारोह मिला:

func NSLocalizedString(
    key: String,
    tableName: String? = default,
    bundle: NSBundle = default,
    value: String = default,
    #comment: String) -> String

हालांकि, यह बहुत लंबा है और बिल्कुल भी सुविधाजनक नहीं है।


2
सबसे अच्छा कोड स्निपेट का छोटा संस्करण बनाना है: NSLocalizedString ("", टिप्पणी: "") ... मुझे एक्सटेंशन समाधान पसंद आया, लेकिन समस्या यह है कि जेनस्ट्रिंग्स इन स्ट्रिंग्स को अनुवाद फ़ाइल में कैप्चर नहीं करेंगे।
मतज उकमार

3
स्विफ्ट 3 में आप केवल NSLocalizedString("Cancel", comment: "Cancel button title")डिफ़ॉल्ट मानों का लाभ उठा सकते हैं। मुझे लगता है कि यह सुविधाजनक है।
एलएसआई

: यह स्थानीयकरण (स्ट्रिंग विस्तार, विभिन्न तार टेबल और भी pluralization) के बारे में एक बहुत अच्छा लेख है medium.com/@marcosantadev/...
Lightman

यह एक मजबूत वास्तुकला माध्यम के लिए स्विफ्ट में स्थानीयकरण के बारे में एक बहुत अच्छा लेख है.
मेंडी

जवाबों:


373

मैं अगले समाधान का उपयोग करता हूं:

1) विस्तार बनाएँ:

extension String {
    var localized: String {
        return NSLocalizedString(self, tableName: nil, bundle: Bundle.main, value: "", comment: "")
    }
}

2) Localizable.strings फ़ाइल में:

"Hi" = "Привет";

3) उपयोग का उदाहरण:

myLabel.text = "Hi".localized

का आनंद लें! ;)

--upd: -

टिप्पणियों के मामले के लिए आप इस समाधान का उपयोग कर सकते हैं:

1) विस्तार:

extension String {
    func localized(withComment:String) -> String {
        return NSLocalizedString(self, tableName: nil, bundle: Bundle.main, value: "", comment: withComment)
    }
}

2) इनस्ट्रिंग फ़ाइल:

/* with !!! */
"Hi" = "Привет!!!";

3) का उपयोग कर:

myLabel.text = "Hi".localized(withComment: "with !!!")

92
इसके साथ एकमात्र मुद्दा यह है कि आप genstringsअपनी .strings फ़ाइलों को बनाने के लिए उपयोगिता का उपयोग नहीं कर पाएंगे ।
नेड

9
यह एक बहुत अच्छा विचार है! मैंने इसे बदलकर इसे थोड़ा और स्मार्ट बना दिया func localized(comment: String = "") -> Stringताकि यह छोटा हो जाए और वैकल्पिक टिप्पणियों के साथ :)
गुई मौरा

2
किसी भी विचार कैसे genstringsइस के साथ उपयोग करने के लिए ?
क्रिस

48
इस उत्तर के बारे में हर कोई बहुत उत्साहित है, लेकिन BIG समस्या (कई भाषाओं के साथ किसी भी गंभीर परियोजना के लिए) यह है कि यह आपके अनुवादित संदेशों के प्रबंधन को पूरी तरह से गड़बड़ कर देता है, क्योंकि genstringsकेवल NSLocalizedString में पारित शाब्दिक तार पर काम करता है। इस चालाक वर्कअराउंड के साथ, आप genstringsटूल का उपयोग करके अपनी .strings फ़ाइलों को अपडेट करने की क्षमता खो देते हैं , और कम से कम मेरे लिए इसका मतलब है कि मैं इस सरलीकृत दृष्टिकोण का उपयोग नहीं कर पाऊंगा।
एरिक वैन डेर नीट

14
मुझे यह महान समाधान github.com/marmelroy/Localize-Swift में लागू मिला । लेखक द्वारा शामिल कस्टम पाइथन स्क्रिप्ट द्वारा जीनस्ट्रिंग की समस्या का भी समाधान किया जाता है। मैं कोई लेखक नहीं हूं।
टोमक सेजनेर

279

NSLocalizedStringस्विफ्ट की दुनिया में भी मौजूद है।

func NSLocalizedString(
    key: String,
    tableName: String? = default,
    bundle: NSBundle = default,
    value: String = default,
    #comment: String) -> String

tableName, bundle, और valueमानकों को एक साथ चिह्नित हैं defaultकीवर्ड जिसका अर्थ है कि हम इन पैरामीटर फ़ंक्शन को कॉल करते समय छोड़ सकते हैं। इस स्थिति में, उनके डिफ़ॉल्ट मानों का उपयोग किया जाएगा।

इससे यह निष्कर्ष निकलता है कि विधि कॉल को सरल बनाया जा सकता है:

NSLocalizedString("key", comment: "comment")

स्विफ्ट 5 - कोई बदलाव नहीं, अभी भी उसी तरह काम करता है।


44
यह केवल अंतर है कि टिप्पणी शून्य नहीं हो सकती है, और स्वतः पूर्णता लघु संस्करण के लिए सहज ज्ञान युक्त है।
मार्सिन

1
यह किसी भी अधिक काम नहीं कर रहा है मुझे यह कहते हुए त्रुटि मिलती है कि पर्याप्त तर्क का उपयोग नहीं किया जाता है।
एप्स 4 U

2
ऐसा नहीं है कि उपरोक्त Xcode 6.3 में सही है, उद्देश्य- c से विशिष्ट परिवर्तन के साथ स्विफ्ट 1.2, टिप्पणी (जैसा कि मार्सिन ने कहा है) शून्य नहीं हो सकती है, लेकिन यह "" (खाली) हो सकती है।
नील

2
एक शून्य / खाली टिप्पणी स्ट्रिंग को बाद में स्ट्रिंग फ़ाइल में स्थानांतरित करना कठिन बना देती है; यदि कुछ और नहीं है तो कक्षा / फ़ाइल का नाम जहां टिप्पणी के रूप में उपयोग किया जाता है।
जोहान

यह सही जवाब है। एक बार जब Apple इसे Swift के लिए अपडेट कर देता है, तो Xcode इस API को केवल अपनी नई Swift API में ऑटो-कन्वर्ट करने में सक्षम होगा और कुछ और नहीं टूटेगा। वर्तमान में Xcode के रेफ्रेक्टर मेनू में भी (v 11.4.1) एक Wrap in NSLocalizedStringविकल्प है जो केवल टेक्स्ट को हाइलाइट करने, राइट-क्लिक करने और मेनू आइटम का चयन करके चीजों को वास्तव में आसान बनाता है।
एथन एलन

28

मौजूदा उत्तरों की एक भिन्नता:

स्विफ्ट 5.1:

extension String {

    func localized(withComment comment: String? = nil) -> String {
        return NSLocalizedString(self, comment: comment ?? "")
    }

}

तब आप इसे टिप्पणी के साथ या बिना उपयोग कर सकते हैं:

"Goodbye".localized()
"Hello".localized(withComment: "Simple greeting")

कृपया ध्यान दें कि genstringsइस समाधान के साथ काम नहीं करेगा।


14

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

genstrings MyCoolApp/Views/SomeView.swift -s localize -o .

विस्तार:

import UIKit

extension String {
    public static func localize(key: String, comment: String) -> String {
        return NSLocalizedString(key, comment: comment)
    }
}

उपयोग:

String.localize("foo.bar", comment: "Foo Bar Comment :)")

यह उत्तर आश्चर्यजनक है और इसे और अधिक उत्कीर्ण किया जाना चाहिए! यदि आपने अभी तक किसी अन्य पुस्तकालय में लाने से बचना चाह रहे हैं तो यह अब तक का सबसे सरल उपाय है। यह एक अच्छा देशी उपाय है।
cgossain

6

स्विफ्ट 3 संस्करण:) ...

import Foundation

extension String {
    var localized: String {
        return NSLocalizedString(self, tableName: nil, bundle: Bundle.main, value: "", comment: "")
    }
}

6

वास्तव में, आप स्विफ्ट परियोजनाओं में अपने ग्रंथों का अनुवाद करने के लिए दो चरणों का उपयोग कर सकते हैं:

1) पहला चरण अपने सभी अनुवाद योग्य तार बनाने के लिए पुराने तरीके का उपयोग कर रहा है:

NSLocalisedString("Text to translate", comment: "Comment to comment")

१.१) तब आपको स्थानीयकरण उत्पन्न करने के लिए जीनस्ट्रिंग का उपयोग करना चाहिए।

$ genstrings *swift

2) बाद में, आपको इस उत्तर का उपयोग करना चाहिए

२.१) नियमित एक्सप्रेशन के आधार पर अपने एक्सकोड "फाइंड एंड रिप्लेस" विकल्प का उपयोग करें। दिए गए उदाहरण के लिए (यदि आपके पास कोई टिप्पणी नहीं है) नियमित अभिव्यक्ति होगी:

NSLocalizedString\((.*)\, comment:\ \"\"\) 

और इसके साथ बदलें

$1.localized

या (यदि आपकी टिप्पणी है)

NSLocalizedString\((.*)\, comment:\ (.*)\)

और इसके साथ बदलें

$1.localizedWithComment(comment: $2)

आप अपनी इच्छानुसार रेगेक्स और विभिन्न एक्सटेंशन संयोजनों के साथ खेलने के लिए स्वतंत्र हैं। सामान्य तरीका पूरी प्रक्रिया को दो चरणों में विभाजित कर रहा है। उम्मीद है की वो मदद करदे।


1
क्षमा करें, मुझे यहाँ कई उत्तरों की बात नहीं मिली। उपयोग करने की विधि का क्या लाभ है NSLocalizedString("Cancel", comment: "Cancel button title")?
LShi

1
@ लशी कुछ लोग शिकायत कर रहे थे, कि NSLocalizedStringकम स्विफ्टियर दिख रहा है, जितना दिखना चाहिए था। String.localizedदूसरी ओर अधिक Swifty दिखता है लेकिन आप इसके gesntringsसाथ उपयोगिता का उपयोग करने में असमर्थ हैं जो आमतौर पर अंतर्राष्ट्रीयकरण के साथ आपके काम को आसान बनाने के लिए उपयोग किया जाता है। मेरा कहना है कि दोनों दृष्टिकोणों को मिलाना बहुत आसान है। तो मुख्य रूप से यह पठनीयता का सवाल है।
GYFK

यदि आपको एक और दौर करने की आवश्यकता है तो क्या होगा genstrings? क्या आप सभी .localizedको वापस बदल देते हैं NSLocalizedString?
क्रिश्चिक

5

मामलों के लिए एक छोटा सहायक तरीका बनाया गया, जहां "टिप्पणी" को हमेशा अनदेखा किया जाता है। कम कोड पढ़ना आसान है:

public func NSLocalizedString(key: String) -> String {
    return NSLocalizedString(key, comment: "")
}

बस इसे कहीं भी रख दें (एक वर्ग के बाहर) और Xcode को यह वैश्विक तरीका मिल जाएगा।


12
यह बुरा अभ्यास है। जब तक आप सभी अनुवाद स्वयं नहीं कर रहे हैं, तब तक टिप्पणियों की सिफारिश और मदद की जाती है।
यिर्मयाह

यहां तक ​​कि अगर आप खुद का अनुवाद कर रहे हैं, तो भी टिप्पणियां मददगार होंगी, खासकर एक बड़ी परियोजना में।
शिम

4

शायद सबसे अच्छा तरीका यह एक है

fileprivate func NSLocalizedString(_ key: String) -> String {
    return NSLocalizedString(key, comment: "")
}

तथा

import Foundation
extension String {
    static let Hello = NSLocalizedString("Hello")
    static let ThisApplicationIsCreated = NSLocalizedString("This application is created by the swifting.io team")
    static let OpsNoFeature = NSLocalizedString("Ops! It looks like this feature haven't been implemented yet :(!")
}

फिर आप इसे इस तरह से उपयोग कर सकते हैं

let message: String = .ThisApplicationIsCreated
print(message)

मेरे लिए यह सबसे अच्छा है क्योंकि

  • हार्डकोड स्ट्रिंग्स एक विशिष्ट फ़ाइल में हैं, इसलिए जिस दिन आप इसे बदलना चाहते हैं यह वास्तव में आसान है
  • हर बार अपनी फ़ाइल में स्ट्रिंग्स को मैन्युअल रूप से टाइप करने की तुलना में आसान
  • genstrings अभी भी काम करेंगे
  • चीजों को साफ-सुथरा रखने के लिए आप प्रति व्यू कंट्रोलर की तरह अधिक एक्सटेंशन जोड़ सकते हैं

3
ध्यान देने वाली बात यह है कि वर्णित तरीके से परिभाषित स्ट्रिंग्स स्थैतिक स्ट्रिंग्स हैं। IOS सेटिंग्स ऐप में भाषा बदलने के बाद ऐप को फिर से लॉन्च किया जाना चाहिए। यदि नहीं, तो परिवर्तनों को देखने के लिए इसे अपने आप से पुनः चलाएँ। इसमें एक मेमोरी ओवरहेड भी हो सकता है, क्योंकि हम एक बार में सभी स्ट्रिंग्स को इनिशियलाइज़ कर लेते हैं, उस समय नहीं जब उन्हें ज़रूरत होती है।
iDevAmit

2
मुझे लगता है कि यहाँ गणना की गई संपत्तियों का उपयोग करना बेहतर है, इस तरहstatic var Hello: String = { return NSLocalizedString("Hello") }
कला-सपने-सपने

डाउनवोटेड क्योंकि यह स्विफ्ट के नामकरण दिशानिर्देशों
क्रिस्टिक

3

जब आप एक एसडीके विकसित कर रहे हैं। आपको कुछ अतिरिक्त ऑपरेशन की आवश्यकता है।

1) YourLocalizeDemoSDK में हमेशा की तरह Localizable.strings बनाएँ ।

2) YourLocalizeDemo में एक ही Localizable.strings बनाएँ।

3) YourLocalizeDemoSDK के अपने बंडल पथ को खोजें।

स्विफ्ट 4 :

// if you use NSLocalizeString in NSObject, you can use it like this
let value = NSLocalizedString("key", tableName: nil, bundle: Bundle(for: type(of: self)), value: "", comment: "")

Bundle(for: type(of: self))YourLocalizeDemoSDK में बंडल खोजने में आपकी सहायता करता है। यदि आप Bundle.mainइसके बजाय उपयोग करते हैं, तो आपको एक गलत मान मिलेगा (वास्तव में यह कुंजी के साथ समान स्ट्रिंग होगा)।

लेकिन अगर आप ड्रिक एक्सएक्सएक्स द्वारा उल्लिखित स्ट्रिंग एक्सटेंशन का उपयोग करना चाहते हैं । आपको कुछ और करने की जरूरत है। मूल विस्तार इस तरह दिखता है।

extension String {
    var localized: String {
        return NSLocalizedString(self, tableName: nil, bundle: Bundle.main, value: "", comment: "")
    }
}

जैसा कि हम जानते हैं, हम एक एसडीके विकसित कर रहे हैं, Bundle.main YourLocalizeDemo के बंडल का बंडल मिलेगा। यही हम नहीं चाहते। हमें YourLocalizeDemoSDK में बंडल की आवश्यकता है। यह जल्दी से खोजने की एक चाल है।

YourLocalizeDemoSDK में एक NSObject उदाहरण में नीचे दिए गए कोड को चलाएं। और आपको YourLocalizeDemoSDK का URL मिल जाएगा।

let bundleURLOfSDK = Bundle(for: type(of: self)).bundleURL
let mainBundleURL = Bundle.main.bundleURL

दोनों दो url का प्रिंट लें, आप पाएंगे कि हम mainBundleURL पर बंडललेरोफोकसके आधार बना सकते हैं। इस मामले में, यह होगा:

let bundle = Bundle(url: Bundle.main.bundleURL.appendingPathComponent("Frameworks").appendingPathComponent("YourLocalizeDemoSDK.framework")) ?? Bundle.main

और स्ट्रिंग एक्सटेंशन होगा:

extension String {
    var localized: String {
        let bundle = Bundle(url: Bundle.main.bundleURL.appendingPathComponent("Frameworks").appendingPathComponent("YourLocalizeDemoSDK.framework")) ?? Bundle.main
        return NSLocalizedString(self, tableName: nil, bundle: bundle, value: "", comment: "")
    }
}

आशा करता हूँ की ये काम करेगा।


2

मैंने एक कस्टम ट्रांसलेशन फ़ंक्शन का उपयोग करके स्ट्रिंग्स निकालने के लिए अपने स्वयं के जीनस्ट्रिंग्स प्रकार का उपकरण बनाया है

extension String {

    func localizedWith(comment:String) -> String {
        return NSLocalizedString(self, tableName: nil, bundle: Bundle.main, value: "", comment: comment)
    }

}

https://gist.github.com/Maxdw/e9e89af731ae6c6b8d85f5fa60ba848c

यह आपकी सभी स्विफ्ट फ़ाइलों को पार्स करेगा और आपके कोड में स्ट्रिंग्स और टिप्पणियों को एक .strings फ़ाइल में निर्यात करेगा।

शायद ऐसा करने का सबसे आसान तरीका नहीं है, लेकिन यह संभव है।


1

हालांकि यह छोटी समस्या का जवाब नहीं देता है, लेकिन इससे मुझे संदेशों को व्यवस्थित करने में मदद मिली, मैंने नीचे जैसे त्रुटि संदेशों के लिए एक संरचना बनाई

struct Constants {
    // Error Messages
    struct ErrorMessages {
        static let unKnownError = NSLocalizedString("Unknown Error", comment: "Unknown Error Occured")
        static let downloadError = NSLocalizedString("Error in Download", comment: "Error in Download")
    }
}

let error = Constants.ErrorMessages.unKnownError

इस तरह आप संदेशों को व्यवस्थित कर सकते हैं और genstrings काम कर सकते हैं।

और यह जीनस्ट्रिंग्स कमांड का उपयोग किया जाता है

find ./ -name \*.swift -print0 | xargs -0 genstrings -o .en.lproj

1

यूनिट परीक्षणों में उपयोग के लिए हेल्पफुल:

यह एक सरल संस्करण है जिसे विभिन्न उपयोग मामलों (जैसे टेबलनेम के उपयोग के साथ) तक बढ़ाया जा सकता है।

public func NSLocalizedString(key: String, referenceClass: AnyClass, comment: String = "") -> String 
{
    let bundle = NSBundle(forClass: referenceClass)
    return NSLocalizedString(key, tableName:nil, bundle: bundle, comment: comment)
}

इसे इस तरह उपयोग करें:

NSLocalizedString("YOUR-KEY", referenceClass: self)

या एक टिप्पणी के साथ इस तरह:

NSLocalizedString("YOUR-KEY", referenceClass: self, comment: "usage description")

1
टिप्पणियों को छोड़ना बुरा है।
जोस

@ जोस आपकी टिप्पणी के लिए धन्यवाद। कोड एक विचार के रूप में था, कॉपी और पेस्ट के लिए टेम्पलेट के रूप में नहीं। लेकिन मैंने अगर आप चाहें तो टिप्पणियाँ जोड़ने का विकल्प जोड़ा;)
GatoCurioso

1

यह ".localized" दृष्टिकोण पर एक सुधार है। वर्ग विस्तार को जोड़ने के साथ शुरू करें क्योंकि यह आपके द्वारा प्रोग्राम किए गए किसी भी तार के साथ मदद करेगा:

extension String {
    func localized (bundle: Bundle = .main, tableName: String = "Localizable") -> String {
        return NSLocalizedString(self, tableName: tableName, value: "\(self)", comment: "")
    }
}

प्रोग्राम द्वारा आपके द्वारा सेट किए गए स्ट्रिंग्स के लिए उदाहरण का उपयोग करें:

  override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)

अब Xcode की स्टोरीबोर्ड अनुवाद फाइलें फाइल मैनेजर को गड़बड़ कर देती हैं और स्टोरीबोर्ड के अपडेट को अच्छी तरह से हैंडल नहीं करती हैं। एक बेहतर तरीका यह है कि आप एक नया बेसिक लेबल क्लास बनाएं और इसे अपने सभी स्टोरीबोर्ड लेबल पर असाइन करें:

class BasicLabel: UILabel {
    //initWithFrame to init view from code
    override init(frame: CGRect) {
      super.init(frame: frame)
      setupView()
    }

    //initWithCode to init view from xib or storyboard
    required init?(coder aDecoder: NSCoder) {
      super.init(coder: aDecoder)
      setupView()
    }

    //common func to init our view
    private func setupView() {
        let storyboardText = self.text
        text = storyboardText?.localized()
    }
}

अब आपके द्वारा जोड़ा गया हर लेबल और स्टोरीबोर्ड के लिए डिफ़ॉल्ट डिफ़ॉल्ट प्रदान करेगा स्वचालित रूप से अनुवादित हो जाएगा, यह मानते हुए कि आपने इसके लिए अनुवाद प्रदान किया है।

आप UIButton के लिए भी ऐसा ही कर सकते हैं:

class BasicBtn: UIButton {
    //initWithFrame to init view from code
    override init(frame: CGRect) {
      super.init(frame: frame)
      setupView()
    }

    //initWithCode to init view from xib or storyboard
    required init?(coder aDecoder: NSCoder) {
      super.init(coder: aDecoder)
      setupView()
    }

    //common func to init our view
    private func setupView() {
        let storyboardText = self.titleLabel?.text
        let lclTxt = storyboardText?.localized()
        setTitle(lclTxt, for: .normal)
    }
}

0

जब आप अनुवाद करना चाहते हैं, तो अंग्रेजी से कहें, जहां एक वाक्यांश एक ही है, दूसरी भाषा में जहां यह अलग है (लिंग, क्रिया संयुग्मन या अवनति के कारण) स्विफ्ट में सबसे सरल NSString फॉर्म है जो सभी मामलों में काम करता है तीन तर्क एक है । उदाहरण के लिए, अंग्रेजी वाक्यांश "पिछले था", "वजन" ( "предыдущ के मामले के लिए रूस के लिए अलग तरह अनुवाद किया है ий был") और "कमर" ( "предыдущ के लिए ая был देख के ")।

इस मामले में आपको एक स्रोत के लिए दो अलग-अलग अनुवाद की आवश्यकता है (WWDC 2018 में अनुशंसित XLIFF उपकरण के संदर्भ में)। आप इसे दो तर्क NSLocalizedString के साथ प्राप्त नहीं कर सकते हैं, जहां "पिछले" "कुंजी" और अंग्रेजी अनुवाद (अर्थात मूल्य के लिए) दोनों के लिए समान होगा। एकमात्र तरीका तीन तर्क रूप का उपयोग करना है

NSLocalizedString("previousWasFeminine", value: "previous was", comment: "previousWasFeminine")

NSLocalizedString("previousWasMasculine", value: "previous was", comment: "previousWasMasculine")

जहाँ कुंजियाँ ("पिछलीWasFeminine" और "पिछलाWasMasculine") भिन्न होती हैं।

मुझे पता है कि सामान्य सलाह है कि वाक्यांश को पूरे के रूप में अनुवादित किया जाए, हालांकि, कभी-कभी यह बहुत अधिक समय लगता है और असुविधाजनक होता है।


-1

डिफ़ॉल्ट भाषा के साथ स्थानीयकरण:

extension String {
func localized() -> String {
       let defaultLanguage = "en"
       let path = Bundle.main.path(forResource: defaultLanguage, ofType: "lproj")
       let bundle = Bundle(path: path!)

       return NSLocalizedString(self, tableName: nil, bundle: bundle!, value: "", comment: "")
    }
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.