-
Localization in iOSiOS 2022. 12. 14. 04:06
아래 세 가지로 나눠서 현지화에 대해 알아보겠습니다.
- 기기의 언어 및 지역 정보를 가져와서 소스 코드 내에서 사용하여 사용자 맞춤 데이터를 제공
- 앱 이름을 언어에 따라 변환하여 현지화를 수행
- UI 컴포넌트의 문자열을 변환하여 현지화를 수행
기기 Locale 정보 가져와서 사용하기
기기의 언어 및 지역 정보는 Locale 타입을 이용해서 가져올 수 있습니다. Locale은 사용자에게 보여주기 위한 데이터의 형식을 지정하는 데 사용하기 위한 언어, 문화 및 기술 규칙에 대한 정보를 가지고 있습니다. 다음과 같이 설정 > 일반 > 언어 및 지역의 값을 확인할 수 있습니다.
func printLocale() { let identifier = Locale.current.identifier let regionCode = Locale.current.regionCode! let languageCode = Locale.current.languageCode! print("identifier: \(identifier)\nregionCode: \(regionCode)\nlanguageCode: \(languageCode)") }
저는 이 정보를 이용해서 분기하여 어떤 데이터를 사용자에게 보여줄지 결정하였습니다. Date 타입에 대해서 dateFormatter와 timeZone을 사용할 때 기기의 언어에는 포맷이 영향을 받지만, 지역에는 영향을 받지 않는 것을 보고 languageCode에 따라 처리해줬습니다. 참고로 regionCode 및 languageCode는 iOS 16 이상부터 deprecated 예정입니다. 이상부터는 Locale.current.language.languageCode.identifier를 사용하라고 하네요. regionCode 또한 마찬가지입니다.
그리고 XCode의 Project > Info > Localization에 등록되어 있지 않은 언어 선택 시 선호하는 언어의 순서, 즉 우선순위에 따라 Locale 프로퍼티의 값이 정해집니다. XCode에서 영어와 한국어를 localizations에 추가했을 때, 시뮬레이터나 기기에 아래 사진과 같이 '선호하는 언어'가 설정되어 있다면, 일본어는 추가되어있지 않으니 밀려나고 다음 순위인 영어가 선택되어, 다음과 같이 출력됩니다.
선호하는 언어 및 그에 따른 출력
출력:
identifier: en_KR
regionCode: KR
languageCode: en
일본어만 남기고 모두 제거해도 똑같이 출력되는 것을 보았을 때, 기본값으로 영어가 들어가있는 것을 확인할 수 있었습니다.
다음은 연산 프로퍼티를 통해 Locale을 사용하는 예시입니다.
// return String을 사용해서 URLQueryItem을 채움. var language: String { if Locale.current.languageCode == "ko" { return "kr" } else { return "en" } }
애플리케이션 이름 localization
앱 이름을 현지화하기 위해서 Strings File을 사용할 수 있습니다. new file.
파일명은 임의의 이름이 아닌 InfoPlist.strings로 생성합니다.
Inspector 창에서 Localize를 눌러줍니다.
이때, Project > Info > Localization에서 언어를 추가해주지 않았다면, 기본값으로 English가 뜰 겁니다. Localize 눌러주면 됩니다.
이제 Project > Info > Localizations 로 가서, 언어를 추가해줍니다.
프로젝트에 추가할 언어를 선택하고, 적용할 파일을 선택하면 됩니다. 이전에 만들어준 InfoPlist.strings를 선택해줍니다.
그러면 다음과 같이 선택한 언어가 InfoPlist.strings에 추가됩니다.
이제 InfoPlist의 각 파일에 다음과 같이 키 = 값 형식으로 앱 이름을 작성하시면 됩니다.
InfoPlist(English)
// 세미콜론을 빠뜨리면 경고가 뜹니다. "CFBundleDisplayName" = "Localization";
InfoPlist(Korean)
"CFBundleDisplayName" = "현지화";
결과
언어를 영어로 선택한 경우
언어를 한국어로 선택한 경우
참고
첫 번째로, 순서는 중요하지 않습니다. Project > Info > Localization에서 먼저 언어를 추가하였을 때 InfoPlist.strings를 추가하고, 다음과 같이 inspector에서 추가해주시면 됩니다. 삭제할 때는 반대로 체크를 해제하시면 됩니다.
두 번째로, InfoPlist라는 파일 이름과 CFBundleDisplayName이라는 키를 임의로 변경하시면 의도대로 작동하지 않습니다. 그 이유는 아래의 사진을 보면 알 수 있듯이, 직접 Info.plist에 접근하여 쓰지 않고 간접적으로 접근하는 방법이기 때문입니다. 추가적으로 Bundle Display Name에 값을 넣어주면, 현지화를 적용하지 않은 언어를 사용할 때, 넣어준 값을 앱 이름으로 볼 수 있습니다.
UI localization
여러 UI 컴포넌트의 문자열을 사용자(의 언어)에게 맞게 바꿔줘야겠죠? 다음 문자열들에 적용해보겠습니다.
앱 이름과 마찬가지로 Strings 파일을 사용할 수 있습니다. 이름은 Localizable.strings로 생성합니다. 파일 생성과 기본적인 설정은 앱 이름 설정할 때와 똑같습니다.
똑같이 키 = 값 형식으로 작성해줍니다.
Localizable (English)
"Weather" = "Weather"; "City" = "City"; "Forecast" = "Forecast"; ...
Localizable (Korean)
"Weather" = "날씨"; "City" = "도시"; "Forecast" = "예보"; ...
이제 NSLocalizedString(_:tableName:bundle:value:comment:) 함수를 사용하여 각 문자열을 현지화해주면 됩니다.
func NSLocalizedString( _ key: String, tableName: String? = nil, bundle: Bundle = Bundle.main, value: String = "", comment: String ) -> String
tableName은 strings 파일의 이름을 입력해주면 됩니다. tableName이 nil이거나 빈 문자열일 경우, 기본값은 Localizable입니다. 따라서 strings 파일을 나누어서 사용하지 않고, Localizable.strings만을 사용할 경우 적어주지 않아도 됩니다. 물론, 다른 이름으로 strings 파일을 생성하고 tableName으로 그 이름을 넘겨준다면 상관없습니다. value는 테이블에서 키를 찾을 수 없으면 반환하는 문자열입니다. comment는 strings 파일에서 키-값 쌍 위에 배치할 설명입니다. 단어는 사용되는 문맥에 따라 여러 가지 다른 의미를 가질 수 있습니다. 현지화를 수행하는 만큼, 혼란을 야기할 수 있는 단어에 comment를 추가하여 문자열에 대한 문맥을 제공할 수 있습니다.
다음과 같이 String의 연산 프로퍼티로 추가하여 간단하게 사용할 수 있습니다.
extension String { var localized: String { return NSLocalizedString(self, comment: "") } } // 현지화 적용 private let titleLabel: UILabel = { // ... label.text = "Forecast".localized // ... }()
Objective-C 예시
NSString *errorMessage = @""; ... errorMessage = NSLocalizedString(@"UndefinedError", nil);
언어를 영어로 바꿨을 때의 결과
'iOS' 카테고리의 다른 글
Actor in Swift concurrency (0) 2022.12.31 Diffable DataSource (2) 2022.12.29 Operator, Combine Framework in Swift (0) 2022.12.11 Publisher와 Subscriber, Combine Framework in Swift (0) 2022.12.09 Async/await in Swift (0) 2022.12.03