지난 번 포스팅에서 String File과 String Catalog를 활용해서 Localization을 세팅하는 법을 알아보았다. 이번에는 SwiftUI에 실제로 적용해보자.
일단 시뮬레이터의 언어를 한국어와 일본어로 각각 세팅을 하고 아래 코드를 실행해보자. Text (혹은 Text Field에) 직접 String을 넣는 경우에는 자동으로 Localization 처리가 된 것을 볼 수 있다.
import SwiftUI
struct LocalizedView: View {
@State var user: String = ""
var body: some View {
VStack {
Text("Hello \(user)")
Text("Good to see you!")
TextField("your name", text: $user)
}
.padding(.horizontal, 20)
}
}
그렇다면 Text를 다른 View로 한번 감싸고 parameter로 넣는 아래와 같은 뷰를 생각해보자. 하나는 같은 구조체 내부에서 다른 하나는 외부에서 View를 만들고 진행해보자. 이를 실행해보면 parameter로 String을 넣으면 Localization이 되지 않는 것을 볼 수 있다. 또한 String Catalog에서 자동으로 Localization이 필요한 문자열을 불러올 때도 불러오지 못하는 것을 볼 수 있다.
import SwiftUI
struct LocalizedView: View {
@State var user: String = ""
var body: some View {
VStack {
Text("Hello \(user)")
textView("Hello \(user)")
SubTextView("Hello \(user)")
Text("Good to see you!")
TextField("your name", text: $user)
}
.padding(.horizontal, 20)
}
}
extension LocalizedView {
func textView(_ text: String) -> some View {
Text(text)
}
}
struct SubTextView: View {
let text: String
init(_ text: String) {
self.text = text
}
var body: some View {
Text(text)
}
}
다른 케이스로 아래와 같은 케이스도 생각해볼 수 있다. Text를 다른 View로 감싸지 않고 그대로 사용하는 대신 String만 변수에 할당하는 케이스이다.
마찬가지로 Localization 되지 않는다. 생각해보면 이는 SwiftUI입장에서는 당연한 것이다. Localization의 대상은 불변의 String이어야 한다. 하지만 String을 변수로 할당하게 되면 SwiftUI 입장에서는 이 String이 불변하는 상수인지 변할 수 있는 변수인지 알 수가 없다. 만약에 변수로 할당을 해도 Localization이 된다면 사용자가 키보드로 입력한 문자열이 갑자기 Localization이 된다던가 하는 버그가 발생할 수 있다.
import SwiftUI
enum Greeting {
case firstMet
var message: String {
switch self {
case .firstMet: "Good to see you!"
}
}
}
struct LocalizedView: View {
@State var user: String = ""
var body: some View {
VStack {
Text("Hello \(user)")
Text("Good to see you!")
Text(Greeting.firstMet.message)
TextField("your name", text: $user)
}
.padding(.horizontal, 20)
}
}
그렇다면 위와 같은 케이스는 어떻게 Localization을 적용할 수 있을까? 가장 간단한 방법은 NSLocalizedString을 사용하는 것이다. NSLocalizedString을 활용하면 self (String)을 Key로 하는 Localized String을 구할 수 있다.
extension String {
func localize() -> String {
NSLocalizedString(self, comment: "")
}
}
위 메소드는 아래와 같이 활용할 수 있다.
extension LocalizedView {
func textView(_ text: String) -> some View {
// ✅ localize 적용
Text(text.localize())
}
}
struct SubTextView: View {
let text: String
init(_ text: String) {
self.text = text
}
var body: some View {
// ✅ localize 적용
Text(text.localize())
}
}
enum Greeting {
case firstMet
var message: String {
switch self {
// ✅ localize 적용
case .firstMet: "Good to see you!".localize()
}
}
}