NSLocalizedString tương đương trong Swift là gì?


228

Có một Swift tương đương NSLocalizedString(...)? Trong Objective-C, chúng tôi thường sử dụng:

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

Làm thế nào tôi có thể đạt được điều tương tự trong Swift? Tôi tìm thấy một chức năng:

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

Tuy nhiên, nó rất dài và không thuận tiện chút nào.


2
Tốt nhất là tạo phiên bản ngắn hơn của đoạn mã: NSLocalizedString ("", bình luận: "") ... Tôi thích giải pháp mở rộng, nhưng vấn đề là genstrings sẽ không bắt được các chuỗi này vào tệp dịch.
Matej Ukmar

3
Trong Swift 3, bạn chỉ có thể sử dụng NSLocalizedString("Cancel", comment: "Cancel button title")lợi dụng các giá trị mặc định. Đó là thuận tiện tôi nghĩ.
LShi

Đây là một bài viết rất hay về nội địa hóa (mở rộng chuỗi, các bảng chuỗi khác nhau và thậm chí số nhiều): Medium.com/@marcosantadev/ trộm
LightMan

Đây là một bài viết rất hay về nội địa hóa trong Swift cho một phương tiện kiến ​​trúc mạnh mẽ.com /@mendibarouk / Khăn
Mendy

Câu trả lời:


373

Tôi sử dụng giải pháp tiếp theo:

1) tạo phần mở rộng:

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

2) trong tệp Localizable.strings :

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

3) ví dụ về việc sử dụng:

myLabel.text = "Hi".localized

thưởng thức! ;)

--upd: -

đối với trường hợp có ý kiến ​​bạn có thể sử dụng giải pháp này:

1) Gia hạn:

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

2) trong tệp .strings:

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

3) sử dụng:

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

92
Vấn đề duy nhất với điều này là bạn sẽ không thể sử dụng genstringstiện ích để tạo các tệp .strings của mình.
Ned

9
Đó là một ý tưởng rất tốt! Tôi cũng làm cho nó thông minh hơn một chút bằng cách thay đổi để func localized(comment: String = "") -> Stringnó trở nên nhỏ hơn và với các nhận xét tùy chọn :)
Gui Moura

2
Bất kỳ ý tưởng làm thế nào để sử dụng genstringsvới điều này?
Chris

48
Mọi người đều rất hào hứng với câu trả lời này, nhưng vấn đề LỚN (đối với bất kỳ dự án nghiêm túc nào với một số ngôn ngữ) là điều này hoàn toàn làm rối việc quản lý các tin nhắn đã dịch của bạn, bởi vì genstringschỉ hoạt động trên các chuỗi chữ được chuyển đến NSLocalizedString. Với cách giải quyết thông minh này, bạn sẽ mất khả năng cập nhật các tệp .strings của mình bằng genstringscông cụ và ít nhất với tôi điều đó có nghĩa là tôi sẽ không thể sử dụng phương pháp đơn giản hóa này.
Erik van der Neut

14
Tôi tìm thấy giải pháp tuyệt vời này được triển khai trong github.com/marmelroy/Localize-Swift . Vấn đề về genstrings cũng được giải quyết bằng kịch bản python tùy chỉnh được bao gồm bởi tác giả. Tôi không phải là một tác giả.
Tomek Cejner

279

Sự NSLocalizedStringtồn tại cũng trong thế giới của Swift.

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

Các tableName, bundlevaluecác thông số được đánh dấu bằng một defaulttừ khóa mà phương tiện chúng ta có thể bỏ qua các tham số khi gọi hàm. Trong trường hợp này, các giá trị mặc định của chúng sẽ được sử dụng.

Điều này dẫn đến một kết luận rằng cuộc gọi phương thức có thể được đơn giản hóa thành:

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

Swift 5 - không thay đổi, vẫn hoạt động như vậy.


44
Chỉ có sự khác biệt là nhận xét không thể là con số không và tính năng tự động hoàn thành không trực quan cho phiên bản ngắn.
Marcin

1
điều này không còn hiệu quả nữa. Tôi gặp lỗi khi nói rằng không đủ đối số được sử dụng.
Ứng dụng 4 U

2
Không phải những điều trên là đúng trong Xcode 6.3, Swift 1.2 với sự thay đổi cụ thể từ object-c, nhận xét (như Marcin đã nêu) không thể là con số không, nhưng nó có thể là "" (trống).
Neil

2
Một bình luận nil / trống làm cho khó có thể di chuyển chuỗi sau trong tệp chuỗi; nếu không có gì khác thêm tên lớp / tên tệp trong đó nó được sử dụng làm bình luận.
Johan

Đây là câu trả lời chính xác. Khi Apple cập nhật nó cho Swift, Xcode sẽ có thể tự động chuyển đổi API này sang API Swift mới và không có gì khác bị phá vỡ. Ngay cả trong menu Refractor của Xcode hiện tại (v 11.4.1), có một Wrap in NSLocalizedStringtùy chọn giúp mọi thứ thực sự dễ dàng bằng cách chỉ cần tô sáng văn bản, nhấp chuột phải và chọn mục menu.
Ethan Allen

28

Một biến thể của các câu trả lời hiện có:

Swift 5.1:

extension String {

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

}

Sau đó, bạn có thể chỉ cần sử dụng nó có hoặc không có nhận xét:

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

Xin lưu ý rằng genstringssẽ không làm việc với giải pháp này.


14

Bằng cách sử dụng theo cách này, có thể tạo ra một triển khai khác nhau cho các loại khác nhau (ví dụ: các lớp Int hoặc tùy chỉnh như MoneyUnit, ...). Cũng có thể quét phương thức này bằng cách sử dụng tiện ích genstrings. Đơn giản chỉ cần thêm cờ thường trình vào lệnh

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

sự mở rộng:

import UIKit

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

sử dụng:

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

Câu trả lời này là tuyệt vời và nên được nâng cao hơn nữa! Đây là giải pháp đơn giản nhất mà tôi đã tìm thấy cho đến nay nếu bạn đang tìm cách tránh mang vào một thư viện khác. Đây là một giải pháp bản địa tốt.
cgossain

6

Phiên bản Swift 3 :) ...

import Foundation

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

6

Trên thực tế, bạn có thể sử dụng hai giai đoạn để dịch văn bản của mình trong các dự án Swift:

1) Giai đoạn đầu tiên là sử dụng cách cũ để tạo tất cả các chuỗi có thể dịch của bạn:

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

1.1) Sau đó, bạn nên sử dụng genstrings để tạo Localizable.strings:

$ genstrings *swift

2) Sau đó, bạn nên sử dụng câu trả lời này .

2.1) Sử dụng tùy chọn "Tìm và thay thế" XCode của bạn dựa trên biểu thức thông thường. Đối với ví dụ đã cho (nếu bạn không có ý kiến), biểu thức chính quy sẽ là:

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

và thay thế nó bằng

$1.localized

hoặc (nếu bạn có ý kiến)

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

và thay thế nó bằng

$1.localizedWithComment(comment: $2)

Bạn có thể tự do chơi với regex và các kết hợp mở rộng khác nhau theo ý muốn. Cách chung là chia toàn bộ quá trình theo hai giai đoạn. Mong rằng sẽ giúp.


1
Xin lỗi tôi không nhận được điểm của nhiều câu trả lời ở đây. Lợi ích của phương pháp này khi sử dụng là NSLocalizedString("Cancel", comment: "Cancel button title")gì?
LShi

1
@LShi một số người đã phàn nàn, rằng nó NSLocalizedStringtrông Swiftier ít hơn so với vẻ ngoài của nó. String.localizedmặt khác trông Swifty hơn nhưng bạn không thể sử dụng gesntringstiện ích với nó thường được sử dụng để giảm bớt công việc của bạn với quốc tế hóa. Quan điểm của tôi là khá dễ dàng để kết hợp cả hai cách tiếp cận. Vì vậy, chủ yếu nó là một câu hỏi về khả năng đọc.
GYFK

Điều gì xảy ra nếu bạn cần phải làm một vòng khác genstrings? Bạn có thay thế tất cả .localizedbằng cách NSLocalizedString?
Cristik

5

Tạo một phương thức trợ giúp nhỏ cho các trường hợp, trong đó "bình luận" luôn bị bỏ qua. Ít mã dễ đọc hơn:

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

Chỉ cần đặt nó ở bất cứ đâu (bên ngoài một lớp) và Xcode sẽ tìm thấy phương thức toàn cầu này.


12
Đây là thực hành xấu. Nhận xét được khuyến nghị và hữu ích trừ khi bạn tự thực hiện tất cả các bản dịch.
Giê-rê-mi

Ngay cả khi bạn tự dịch, các ý kiến ​​sẽ hữu ích, đặc biệt là trong một dự án lớn.
Shim

4

Có lẽ cách tốt nhất là cái này ở đây .

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

sau đó bạn có thể sử dụng nó như thế này

let message: String = .ThisApplicationIsCreated
print(message)

với tôi đây là điều tốt nhất bởi vì

  • Các chuỗi được mã hóa cứng nằm trong một tệp cụ thể, vì vậy ngày bạn muốn thay đổi nó thực sự dễ dàng
  • Sử dụng dễ dàng hơn so với việc nhập thủ công các chuỗi trong tệp của bạn mỗi lần
  • genstrings vẫn sẽ làm việc
  • bạn có thể thêm nhiều tiện ích mở rộng, như một bộ điều khiển cho mỗi chế độ xem để giữ mọi thứ gọn gàng

3
Điều cần lưu ý là các Chuỗi được xác định theo cách được mô tả là các chuỗi tĩnh. Ứng dụng nên được khởi chạy lại sau khi thay đổi ngôn ngữ trong ứng dụng Cài đặt iOS. Nếu không, hãy tự khởi động lại để xem các thay đổi. Nó cũng có thể có phí bộ nhớ, vì chúng tôi khởi tạo tất cả các chuỗi cùng một lúc, không phải lúc chúng cần.
iDevAmit

2
Tôi nghĩ rằng tốt hơn là sử dụng các thuộc tính được tính toán ở đây, như thế nàystatic var Hello: String = { return NSLocalizedString("Hello") }
nghệ thuật của những giấc mơ


3

Khi bạn đang phát triển SDK. Bạn cần một số hoạt động thêm.

1) tạo Localizable.strings như bình thường trong YourLocalizeDemoSDK.

2) tạo cùng Localizable.strings trong YourLocalizeDemo.

3) tìm đường dẫn Bundle của bạn của bạn về 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))giúp bạn tìm gói trong YourLocalizeDemoSDK. Nếu bạn dùngBundle.main thay thế, bạn sẽ nhận được một giá trị sai (thực tế nó sẽ là cùng một chuỗi với khóa).

Nhưng nếu bạn muốn sử dụng phần mở rộng String được đề cập bởi dr OX . Bạn cần phải làm thêm một số. Phần mở rộng nguồn gốc trông như thế này.

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

Như chúng ta biết, chúng tôi đang phát triển SDK, Bundle.main sẽ nhận được gói của YourLocalizeDemo. Đó không phải là những gì chúng ta muốn. Chúng tôi cần gói trong YourLocalizeDemoSDK. Đây là một mẹo để tìm thấy nó một cách nhanh chóng.

Chạy mã dưới đây trong một phiên bản NSObject trong YourLocalizeDemoSDK. Và bạn sẽ nhận được URL của YourLocalizeDemoSDK.

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

In cả hai url, bạn sẽ thấy rằng chúng tôi có thể xây dựng cơ sở bundleURLofSDK trên mainBundleURL. Trong trường hợp này, nó sẽ là:

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

Và phần mở rộng String sẽ là:

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

Hy vọng nó giúp.


2

Tôi đã tạo công cụ sắp xếp kiểu genstrings của riêng mình để trích xuất chuỗi bằng chức năng dịch tùy chỉnh

extension String {

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

}

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

Nó sẽ phân tích tất cả các tệp nhanh chóng của bạn và xuất các chuỗi và nhận xét trong mã của bạn sang tệp .strings.

Có lẽ không phải là cách dễ nhất để làm điều đó, nhưng nó có thể.


1

Mặc dù điều này không trả lời cho vấn đề rút ngắn, nhưng điều này giúp tôi tổ chức các thông báo, tôi đã tạo một cấu trúc cho các thông báo lỗi như bên dưới

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

Bằng cách này, bạn có thể sắp xếp các tin nhắn và làm cho genstrings hoạt động.

Và đây là lệnh genstrings được sử dụng

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

1

Hữu ích cho việc sử dụng trong các bài kiểm tra đơn vị:

Đây là một phiên bản đơn giản có thể được mở rộng cho các trường hợp sử dụng khác nhau (ví dụ: với việc sử dụng tên bảng).

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

Sử dụng nó như thế này:

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

Hoặc thích điều này với một bình luận:

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

1
Đó là thực tế xấu để bỏ qua các ý kiến.
José

@ José Cảm ơn bình luận của bạn. Mã này có ý nghĩa như một ý tưởng, không phải là mẫu để sao chép và dán. Nhưng tôi đã thêm tùy chọn để thêm nhận xét nếu bạn muốn;)
GatoCurioso

1

Đây là một cải tiến về phương pháp ".localized". Bắt đầu với việc thêm phần mở rộng lớp vì điều này sẽ giúp với bất kỳ chuỗi nào bạn đang thiết lập theo chương trình:

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

Ví dụ sử dụng cho các chuỗi bạn đặt theo chương trình:

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

Bây giờ các tệp dịch bảng phân cảnh của Xcode làm cho trình quản lý tệp lộn xộn và cũng không xử lý các bản cập nhật cho bảng phân cảnh. Cách tiếp cận tốt hơn là tạo một lớp nhãn cơ bản mới và gán nó cho tất cả các nhãn bảng phân cảnh của bạn:

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

Giờ đây, mọi nhãn bạn thêm và cung cấp mặc định mặc định trong bảng phân cảnh sẽ tự động được dịch, giả sử bạn đã cung cấp bản dịch cho nó.

Bạn có thể làm tương tự cho 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

Khi bạn dịch, hãy nói từ tiếng Anh, trong đó một cụm từ giống nhau, sang một ngôn ngữ khác, nơi đó khác biệt (vì giới tính, cách chia động từ hoặc từ chối) , hình thức NSString đơn giản nhất trong Swift hoạt động trong mọi trường hợp là ba đối số một . Ví dụ, cụm từ tiếng Anh "trước đây là", được dịch khác nhau sang tiếng Nga đối với trường hợp "cân" ( "предыдущ ий был") và cho "eo" ( "предыдущ ая был а ").

Trong trường hợp này, bạn cần hai bản dịch khác nhau cho một Nguồn (về công cụ XLIFF được đề xuất trong WWDC 2018). Bạn không thể đạt được nó với hai đối số NSLocalizedString, trong đó "trước đó" sẽ giống nhau cho cả "khóa" và bản dịch tiếng Anh (nghĩa là cho giá trị). Cách duy nhất là sử dụng ba mẫu đối số

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

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

trong đó các khóa ("trướcWasFeminine" và "trướcWasMasculine") khác nhau.

Tôi biết rằng lời khuyên chung là dịch toàn bộ cụm từ, tuy nhiên, đôi khi nó quá tốn thời gian và bất tiện.


-1

Bản địa hóa với ngôn ngữ mặc định:

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: "")
    }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.