Swiftで同等のNSLocalizedStringとは何ですか?


228

Swiftに相当するものはありNSLocalizedString(...)ますか?ではObjective-C、通常次のものを使用します。

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

Swiftで同じことをするにはどうすればよいですか?私は関数を見つけました:

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

しかし、それは非常に長く、まったく便利ではありません。


2
最善の方法は、短いコードスニペットを作成することです。
Matej Ukmar

3
Swift 3ではNSLocalizedString("Cancel", comment: "Cancel button title")、デフォルト値を利用するだけで使用できます。便利だと思います。
LShi 2017

これはローカリゼーション(文字列の拡張、さまざまな文字列テーブル、さらには複数化)に関する非常に優れた記事です。medium.com
@ marcosantadev

これは、堅牢なアーキテクチャのためスウィフトにおけるローカライズについては非常に良い記事ですmedium.com/@mendibarouk/...
メンディ

回答:


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).stringsファイル:

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

3)使用:

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

92
これに関する唯一の問題は、genstringsユーティリティを使用して.stringsファイルを生成できないことです。
2015年

9
それはとても良い考えです!また、に変更するfunc localized(comment: String = "") -> Stringことで少しスマートになり、より小さくなり、オプションのコメントが付けられました:)
Gui Moura

2
genstringsこれをどのように使用するか考えていますか?
Chris

48
誰もがこの回答に非常に興奮していますが、大きな問題(複数の言語を使用する深刻なプロジェクトの場合)は、genstringsNSLocalizedStringに渡されたリテラル文字列でのみ機能するため、翻訳されたメッセージの管理を完全に混乱させることです。この巧妙な回避策を使用すると、genstringsツールを使用して.stringsファイルを更新できなくなります。少なくとも私にとっては、この単純化されたアプローチを使用できないことを意味します。
Erik van der Neut

14
この素晴らしいソリューションがgithub.com/marmelroy/Localize-Swiftに実装されていることがわかりました。genstringsの問題は、作成者が組み込んだカスタムPythonスクリプトによっても解決されます。私は著者ではありません。
Tomek Cejner 16

279

NSLocalizedStringスウィフトの世界にも存在します。

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

tableNamebundle、およびvalueパラメータがでマークされているdefault関数を呼び出している間、我々は、これらのパラメータを省略することができることを意味するキーワード。この場合、デフォルト値が使用されます。

これは、メソッド呼び出しを次のように簡略化できるという結論につながります。

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

Swift 5-変更なし、それでもそのように機能します。


44
コメントをnilにできないのは唯一の違いであり、オートコンプリートはショートバージョンでは直感的とはほど遠いものです。
Marcin、2014

1
これはもう機能していません。十分な引数が使用されていないというエラーが表示されます。
アプリ4 U

2
Xcode 6.3、Swift 1.2では、objective-cからの特定の変更を加えた上で上記が正しいわけではありません。コメント(Marcinによる)はnilにすることはできませんが、 ""(空)にすることもできます。
Neil

2
nil / emptyコメントを使用すると、文字列ファイルの後半で文字列を再配置することが難しくなります。他に何もない場合は、コメントとして使用される場所にクラス/ファイル名を追加します。
ヨハン

これが正解です。AppleがSwift用にアップデートすると、XcodeはこのAPIを新しいSwift APIに自動変換できるようになり、それ以外は何も壊れません。XcodeのRefractorメニュー(v 11.4.1)でも、Wrap in NSLocalizedStringテキストを強調表示し、右クリックしてメニュー項目を選択するだけで、非常に簡単に操作できるオプションがあります。
イーサンアレン

28

既存の回答のバリエーション:

Swift 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

この方法を使用することにより、さまざまなタイプ(つまり、IntまたはCurrencyUnitなどのカスタムクラス)の異なる実装を作成することが可能になります。genstringsユーティリティを使用して、このメソッド呼び出しをスキャンすることもできます。コマンドにルーチンフラグを追加するだけです

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

Swift 3バージョン:)...

import Foundation

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

6

実際、Swiftプロジェクトでは2つのフェーズを使用してテキストを翻訳できます。

1)最初のフェーズでは、古い方法を使用してすべての翻訳可能な文字列を作成します。

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

1.1)次に、genstringsを使用してLocalizable.stringsを生成する必要があります。

$ genstrings *swift

2)その後、この回答を使用する必要があります。

2.1)正規表現に基づいてXCodeの「検索と置換」オプションを使用します。与えられた例(コメントがない場合)の場合、正規表現は次のようになります。

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

そしてそれを

$1.localized

または(コメントがある場合)

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

そしてそれを

$1.localizedWithComment(comment: $2)

必要に応じて、正規表現やさまざまな拡張機能の組み合わせを自由に使用できます。一般的な方法は、プロセス全体を2つのフェーズに分割することです。お役に立てば幸いです。


1
申し訳ありませんが、ここでは多くの回答の要点を理解できません。を使用するよりもこの方法の利点は何NSLocalizedString("Cancel", comment: "Cancel button title")ですか?
LShi 2017

1
@LShi一部の人々は不満を言っNSLocalizedStringていました。String.localized一方、Swiftの方が見栄えgesntringsはよくなりますが、国際化の作業を容易にするために一般的に使用されているユーティリティを使用することはできません。私のポイントは、両方のアプローチを組み合わせるのはかなり簡単だということです。つまり、主に読みやすさの問題です。
GYFK 2017

次のラウンドを行う必要がある場合はどうなりますgenstringsか?あなたはすべてのバック交換するか.localizedによってNSLocalizedString
クリスティク

5

「コメント」が常に無視される場合のための小さなヘルパーメソッドを作成しました。コードが少ないほど読みやすくなります。

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

(クラスの外の)どこかに置くだけで、Xcodeはこのグローバルメソッドを見つけます。


12
これは悪い習慣です。自分ですべての翻訳を行っている場合を除き、コメントはお勧めです。
エレミヤ2016

自分で翻訳している場合でも、特に大規模なプロジェクトではコメントが役に立ちます。
シム、

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)

私にはこれが一番です

  • ハードコードされた文字列は1つの特定のファイルにあるため、変更したい日はとても簡単です
  • 毎回ファイルに文字列を手動で入力するよりも使いやすい
  • genstringsは引き続き機能します
  • ビューコントローラーごとに1つなど、拡張機能を追加して、物事をきちんと保つことができます

3
注意すべきことは、上記の方法で定義された文字列は静的文字列であることです。iOS設定アプリで言語を変更した後、アプリを再起動する必要があります。そうでない場合は、変更を確認するために自分で再起動してください。また、必要なときにではなく、一度にすべての文字列を初期化するため、メモリのオーバーヘッドも発生する可能性があります。
iDevAmit 2017年

2
私はこのように、それはここで計算されたプロパティを使用する方が良いと思うstatic var Hello: String = { return NSLocalizedString("Hello") }
夢見るアート・オブ・


3

SDKを開発しているとき。追加の操作が必要です。

1)YourLocalizeDemoSDKで通常どおりLocalizable.stringsを作成します。

2)YourLocalizeDemoに同じLocalizable.stringsを作成します。

3)YourLocalizeDemoSDKのバンドルパスを見つけます。

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))YourLocalizeDemoSDKでバンドルを見つけるのに役立ちます。Bundle.main代わりに使用すると、誤った値が返されます(実際には、キーと同じ文字列になります)。

しかし、dr OXによって言及された文字列拡張を使用したい場合。あなたはもう少しする必要があります。元の拡張子は次のようになります。

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

ご存知のように、私たちはSDKを開発しておりBundle.main、YourLocalizeDemoのバンドルのバンドルを取得します。それは私たちが望んでいることではありません。YourLocalizeDemoSDKにバンドルが必要です。これはそれを素早く見つけるためのトリックです。

YourLocalizeDemoSDKのNSObjectインスタンスで以下のコードを実行します。そして、YourLocalizeDemoSDKのURLを取得します。

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

2つのURLの両方を出力すると、mainBundleURLに基​​づいてbundleURLofSDKを構築できることがわかります。この場合は、次のようになります。

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

カスタム翻訳機能を使用して文字列を抽出するための独自のgenstringsのようなツールを作成しました

extension String {

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

}

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

すべてのSwiftファイルを解析し、コード内の文字列とコメントを.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

このようにして、メッセージを整理し、genstringを機能させることができます。

そして、これは使用されるgenstringsコマンドです

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

1

単体テストでの使用に役立つ:

これは、さまざまなユースケース(tableNamesの使用など)に拡張できるシンプルなバージョンです。

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
コメントを省略するのは悪い習慣です。
ホセ

@Joséコメントありがとうございます。コードは、コピーアンドペーストのテンプレートとしてではなく、アイデアとして意図されたものです。しかし、必要に応じてコメントを追加するオプションを追加しました;)
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

フレーズが同じである英語から、別の言語に翻訳する場合(性別、動詞の活用または格下げのため)すべての場合に機能するSwiftの最も単純な NSStringフォームは、3つの引数1つです。 。例えば、英語のフレーズ、「体重」の場合のために、異なるロシア語に翻訳され、「以前だった」(「предыдущ ий был」)と「腰」(「предыдущためая был а」)。

この場合、1つのソースに対して2つの異なる翻訳が必要です(WWDC 2018で推奨されるXLIFFツールに関して)。2つの引数NSLocalizedStringでこれを達成することはできません。「以前の」は「キー」と英語の翻訳(つまり値)の両方で同じになります。唯一の方法は、3つの引数形式を使用することです

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

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

ここで、キー( "previousWasFeminine"と "previousWasMasculine")は異なります。

一般的なアドバイスはフレーズ全体を翻訳することですが、時間がかかりすぎて不便な場合もあります。


-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: "")
    }
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.