Swift'te NSLocalizedString eşdeğeri nedir?


228

Swift eşdeğeri var NSLocalizedString(...)mı? İçinde Objective-C, genellikle kullanırız:

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

Aynı şeyi Swift'te nasıl başarabilirim? Bir işlev buldum:

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

Ancak, çok uzun ve hiç uygun değil.


2
En iyi kod snippet'in daha kısa sürümünü oluşturmaktır: NSLocalizedString ("", comment: "") ... Uzantı çözümünü beğendim, ancak sorun genstrings bu dizeleri çeviri dosyasına yakalamayacak.
Matej Ukmar

3
Swift 3'te sadece NSLocalizedString("Cancel", comment: "Cancel button title")varsayılan değerlerden faydalanmayı kullanabilirsiniz . Bence uygun.
LShi

Bu, yerelleştirme hakkında çok iyi bir makaledir (dize uzantısı, farklı dizgi tabloları ve hatta çoğullaştırma): medium.com/@marcosantadev/…
LightMan

Bu, sağlam bir mimari araç
Mendy

Yanıtlar:


373

Bir sonraki çözümü kullanıyorum:

1) uzantı oluşturmak:

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

2) Localizable.strings dosyasında:

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

3) kullanım örneği:

myLabel.text = "Hi".localized

zevk almak! ;)

--upd: -

yorum içeren durumlar için bu çözümü kullanabilirsiniz:

1) Uzatma:

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

2) .strings dosyasında:

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

3) kullanarak:

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

92
Bununla ilgili tek sorun genstrings, .strings dosyalarınızı oluşturmak için yardımcı programı kullanamayacağınızdır .
Ned

9
Bu çok iyi bir fikir! Ben de bunu değiştirerek biraz daha akıllı yaptım, func localized(comment: String = "") -> Stringböylece daha küçük olur ve isteğe bağlı yorumlarla :)
Gui Moura

2
Bununla nasıl kullanılacağı hakkında bir fikrin var genstringsmı?
Chris

48
Herkes bu cevap için çok heyecanlı, ancak BÜYÜK problem (çeşitli dillere sahip herhangi bir ciddi proje için), çevirilen mesajlarınızın yönetimini tamamen genstringsbozmasıdır , çünkü sadece NSLocalizedString'e aktarılan gerçek dizelerde çalışır. Bu akıllı geçici çözümle, genstringsaracı kullanarak .strings dosyalarınızı güncelleme yeteneğini kaybedersiniz ve en azından benim için bu basitleştirilmiş yaklaşımı kullanamayacağım anlamına gelir.
Erik van der Neut

14
Bu harika çözümü github.com/marmelroy/Localize-Swift uygulamasında buldum . Genstrings sorunu, yazar tarafından dahil edilen özel python betiği ile de çözülür. Ben yazar değilim.
Tomek Cejner

279

NSLocalizedStringSwift'in dünyasında da mevcut.

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

tableName, bundleVe valueparametreler ile işaretlenmiştir defaultişlevini çağırarak ederken bu parametreleri atlayabilirsiniz araçlar anahtar kelime. Bu durumda, varsayılan değerleri kullanılır.

Bu, yöntem çağrısının basitleştirilebileceği sonucuna yol açar:

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

Swift 5 - değişiklik yok, hala böyle çalışıyor.


44
tek yorumun sıfır olamaz olması ve otomatik tamamlamanın kısa sürüm için sezgisel olmaktan uzak olması.
Marcin

1
Bu artık çalışmıyor yeterli argüman kullanılmadığını söyleyerek hata alıyorum.
Uygulamalar 4 U

2
Yukarıdaki Xcode 6.3, Swift 1.2'de obj-c'den belirli bir değişiklikle doğru değil, yorum (Marcin'nin belirttiği gibi) sıfır olamaz, ancak "" (boş) olabilir.
Neil

2
Nil / boş bir yorum, dizeyi daha sonra dize dosyasında yeniden konumlandırmayı zorlaştırır; başka hiçbir şey yorum olarak kullanıldığı yere sınıf / dosya adı eklemez.
Johan

Bu doğru cevap. Apple Swift için güncelledikten sonra, Xcode bu API'yi yeni Swift API'sine otomatik olarak dönüştürebilir ve başka hiçbir şey kırılmaz. Xcode'un Refraktör menüsünde (v 11.4.1) bile, Wrap in NSLocalizedStringsadece metni vurgulayarak, sağ tıklayarak ve menü öğesini seçerek işleri gerçekten kolaylaştıran bir seçenek var .
Ethan Allen

28

Mevcut cevapların bir varyasyonu:

Hızlı 5.1:

extension String {

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

}

Daha sonra yorum yaparak veya yorum yapmadan kullanabilirsiniz:

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

Not edingenstrings bu çözüm ile çalışmaz.


14

Bu şekilde farklı türler için farklı bir uygulama oluşturmak mümkündür (örneğin Int veya CurrencyUnit, ... gibi özel sınıflar). Genstrings yardımcı programını kullanarak bu yöntemi çağırmak da mümkündür. Sadece rutin bayrağı komuta ekleyin

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

uzantı:

import UIKit

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

kullanımı:

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

Bu cevap şaşırtıcı ve daha fazla oy verilmeli! Bu, başka bir kütüphane getirmekten kaçınmak istiyorsanız, şimdiye kadar bulduğum en basit çözüm. Bu iyi bir yerel çözümdür.
cgossain

6

Swift 3 sürümü:) ...

import Foundation

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

6

Aslında, Swift projelerinde metinlerinizi çevirmek için iki aşama kullanabilirsiniz:

1) İlk aşama tüm çevrilebilir dizelerinizi oluşturmak için eski yolu kullanmaktır:

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

1.1) Daha sonra Localizable.strings oluşturmak için genstrings kullanmalısınız:

$ genstrings *swift

2) Daha sonra bu cevabı kullanmalısınız .

2.1) Normal ifadeye dayalı olarak XCode "Bul ve Değiştir" seçeneğini kullanın. Verilen örneğe gelince (yorumunuz yoksa) normal ifade şöyle olacaktır:

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

ve yerine

$1.localized

veya (yorumlarınız varsa)

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

ve yerine

$1.localizedWithComment(comment: $2)

İstediğiniz gibi normal ifade ve farklı uzantı kombinasyonlarıyla oynamakta özgürsünüz. Genel yol, tüm süreci iki aşamaya ayırmaktır. Umarım yardımcı olur.


1
Üzgünüm, burada pek çok cevabın anlamını göremiyorum. Yöntemin kullanımına göre faydası nedir NSLocalizedString("Cancel", comment: "Cancel button title")?
LShi

1
@LShi bazı insanlar şikayet ediyordu, bu NSLocalizedStringgöründüğünden daha az Swiftier görünüyor. String.localizedÖte yandan daha Swifty görünüyor, ancak gesntringsuluslararasılaşma ile çalışmanızı kolaylaştırmak için yaygın olarak kullanılan yardımcı programı kullanamazsınız . Demek istediğim, her iki yaklaşımı da karıştırmak oldukça kolay. Yani esas olarak okunabilirlik meselesi.
GYFK

Başka bir tur yapmanız gerekiyorsa ne olur genstrings? Hepsini geri yerine sen mi .localizedtarafından NSLocalizedString?
Cristik

5

"Yorum" un her zaman göz ardı edildiği durumlar için küçük bir yardımcı yöntem oluşturuldu. Daha az kodun okunması daha kolaydır:

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

Sadece herhangi bir yere (bir sınıfın dışında) koyun ve Xcode bu global yöntemi bulacaktır.


12
Bu kötü bir uygulamadır. Tüm çeviriyi kendiniz yapmadığınız sürece yorumlar önerilir ve yararlıdır.
Jeremiah

Kendinizi tercüme etseniz bile, yorumlar özellikle büyük bir projede yardımcı olacaktır.
şim

4

Muhtemelen en iyi yolu bu biridir burada .

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

ve

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 :(!")
}

daha sonra böyle kullanabilirsiniz

let message: String = .ThisApplicationIsCreated
print(message)

bence bu en iyisi çünkü

  • Sabit kodlu dizeler belirli bir dosyadadır, bu yüzden değiştirmek istediğiniz gün gerçekten kolaydır
  • Her seferinde dosyanızdaki dizeleri manuel olarak yazmaktan daha kolay
  • genstrings hala çalışacak
  • işleri düzenli tutmak için görünüm denetleyicisi başına bir tane gibi daha fazla uzantı ekleyebilirsiniz

3
Unutulmaması gereken, açıklanan şekilde tanımlanan Dizelerin statik dizeler olmasıdır. İOS Ayarları uygulamasında dil değiştirildikten sonra uygulama yeniden başlatılmalıdır. Değilse, değişiklikleri görmek için kendiniz yeniden başlatın. Aynı zamanda bir bellek yükü de olabilir, çünkü tüm dizeleri ihtiyaç duydukları anda değil, aynı anda başlatırız.
iDevAmit

2
Bence buradaki bilgisayarlı özellikleri kullanmak daha iyistatic var Hello: String = { return NSLocalizedString("Hello") }
hayalinizdeki sanat


3

Bir SDK geliştirirken. Ekstra bir operasyona ihtiyacınız var.

1) YourLocalizeDemoSDK içinde her zamanki gibi Localizable.strings oluşturun .

2) YourLocalizeDemo'da aynı Localizable.strings dosyasını oluşturun.

3) YourLocalizeDemoSDK Paket Yolunuzu bulun.

Swift4 :

// 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))paketinizi YourLocalizeDemoSDK içinde bulmanıza yardımcı olur. Eğer kullanırsanız Bundle.mainyerine, yanlış bir değer (aslında anahtarla aynı dize olacaktır) alacak.

Ancak dr OX tarafından belirtilen String uzantısını kullanmak istiyorsanız . Biraz daha yapmalısın. Orijin uzantısı buna benzer.

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

Bildiğimiz gibi, bir SDK geliştiriyoruz Bundle.main, YourLocalizeDemo'nun paketini alacaksınız. İstediğimiz bu değil. Paketinize YourLocalizeDemoSDK içinde ihtiyacımız var. Bu onu hızlı bir şekilde bulmak için bir numara.

Aşağıdaki kodu YourLocalizeDemoSDK bir NSObject örneğinde çalıştırın. Ve YourLocalizeDemoSDK URL'sini alacaksınız.

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

Her iki url'yi de yazdırın, mainBundleURL üzerinde bundleURLofSDK tabanı oluşturabileceğimizi göreceksiniz. Bu durumda, olacak:

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

Ve String uzantısı:

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: "")
    }
}

Umarım yardımcı olur.


2

Özel bir çeviri işlevi kullanarak dizeleri ayıklamak için kendi genstrings tür aracımı oluşturdum

extension String {

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

}

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

Tüm hızlı dosyalarınızı ayrıştırır ve kodunuzdaki dizeleri ve yorumları bir .strings dosyasına aktarır.

Muhtemelen bunu yapmanın en kolay yolu değil, ama mümkündür.


1

Bu, kısaltma sorununa cevap vermese de, bu mesajları düzenlememe yardımcı oldu, aşağıdaki gibi hata mesajları için bir yapı oluşturdum

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

Bu şekilde mesajları düzenleyebilir ve genstring'leri çalıştırabilirsiniz.

Ve bu kullanılan genstrings komutu

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

1

Birim testlerinde kullanım için yararlı:

Bu, farklı kullanım durumlarına genişletilebilecek basit bir sürümdür (örneğin, tableNames kullanımı ile).

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

Şöyle kullanın:

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

Ya da bir yorumla böyle:

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

1
Yorumları bırakmak kötü bir uygulamadır.
José

@ José Yorumunuz için teşekkürler. Kod, kopyalama ve yapıştırma için şablon olarak değil, bir fikir anlamına geliyordu. Ama isterseniz yorum ekleme seçeneğini ekledim;)
GatoCurioso

1

Bu ".localized" yaklaşımında bir gelişmedir. Sınıf uzantısını eklemeyle başlayın, çünkü bu, programlı olarak ayarladığınız herhangi bir dizeye yardımcı olacaktır:

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

Programlı olarak ayarladığınız dizeler için örnek kullanım:

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

Şimdi Xcode'un film şeridi çeviri dosyaları dosya yöneticisini dağınık hale getiriyor ve film şeridindeki güncellemeleri iyi işlemiyor. Daha iyi bir yaklaşım, yeni bir temel etiket sınıfı oluşturmak ve bunu tüm film şeridi etiketlerinize atamaktır:

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()
    }
}

Artık film şeridinde eklediğiniz ve varsayılan varsayılanı sağladığınız her etiket, bunun için bir çeviri sağladığınız varsayılarak otomatik olarak çevrilecektir.

Aynı şeyi UIButton için de yapabilirsiniz:

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

Bir ifadenin aynı olduğu İngilizce'den, farklı olduğu başka bir dile (cinsiyet, fiil çekimleri veya çöküş nedeniyle) çevirdiğinizde, Swift'te her durumda çalışan en basit NSString formu üç argümandır . Örneğin, "önceki" ifadesi olan İngilizce ifade, "ağırlık" ("предыдущ ий был") ve "bel" ("предыдущ ая был а ") için Rusça'ya farklı bir şekilde çevrilmiştir .

Bu durumda, bir Kaynak için iki farklı çeviriye ihtiyacınız vardır (WWDC 2018'de önerilen XLIFF aracı açısından). Bunu, "öncekinin" hem "anahtar" hem de İngilizce çeviri (yani değer için) için aynı olacağı iki NSLocalizedString argümanı ile gerçekleştiremezsiniz. Tek yol üç argüman formunu kullanmaktır

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

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

burada anahtarlar ("previousWasFeminine" ve "previousWasMasculine") farklıdır.

Genel tavsiyenin ifadeyi bir bütün olarak çevirmek olduğunu biliyorum, ancak bazen çok zaman alıcı ve rahatsız edici.


-1

Varsayılan dilde yerelleştirme:

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: "")
    }
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.