NSLocalizedString을 사용하는 모범 사례


140

(다른 모든 사람들과 마찬가지로) NSLocalizedString내 앱을 현지화 하는 데 사용 하고 있습니다.

불행히도 다음을 포함하여 몇 가지 "결점"이 있습니다 (NSLocalizedString 자체의 결함 일 필요는 없음).

  • Xcode에서 문자열에 대한 자동 완성이 없습니다. 이로 인해 오류가 발생하기 쉬울뿐만 아니라 번거 롭습니다.
  • 이미 존재하는 동등한 문자열을 알지 못했기 때문에 단순히 문자열을 다시 정의하게 될 수 있습니다 (예 : "비밀번호를 입력하십시오"대 "비밀번호를 먼저 입력하십시오")
  • 자동 완성 문제와 마찬가지로 주석 문자열을 "기억"/ 복사해야합니다. 그렇지 않으면 genstring한 문자열에 대해 여러 주석이 생깁니다.
  • genstring이미 일부 문자열을 현지화 한 후 사용하려면 이전 현지화를 잃지 않도록주의해야합니다.
  • 전체 프로젝트에 동일한 문자열이 흩어져 있습니다. 예를 들어 NSLocalizedString(@"Abort", @"Cancel action")어디에서나 사용한 다음 코드 검토 NSLocalizedString(@"Cancel", @"Cancel action")에서 코드의 일관성을 높이기 위해 문자열의 이름을 바꾸도록 요청합니다 .

내가하는 일은 (그리고 많은 사람들이 이것을 찾은 후에 많은 사람들이 이것을하는 것으로 생각했습니다) 모든 현지화 코드 가있는 별도의 strings.h파일 을 갖는 것 #define입니다. 예를 들어

// In strings.h
#define NSLS_COMMON_CANCEL NSLocalizedString(@"Cancel", nil)
// Somewhere else
NSLog(@"%@", NSLS_COMMON_CANCEL);

이것은 본질적으로 코드 완성, 변수 이름을 변경하기위한 단일 위치 (더 이상 genstring 필요 없음) 및 자동 리팩터링을위한 고유 키워드를 제공합니다. 그러나 이것은 #define본질적으로 구조화되지 않은 (예를 들어 LocString.Common.Cancel 또는 이와 유사한) 명령문 으로 끝납니다 .

그래서, 이것은 다소 효과가 있지만 프로젝트에서 어떻게하는지 궁금합니다. NSLocalizedString의 사용을 단순화하는 다른 접근 방법이 있습니까? 캡슐화하는 프레임 워크가 있을까요?


난 그냥 당신처럼 거의 동일합니다. 그러나 NSLocalizedStringWithDefaultValue makro를 사용하여 다른 현지화 문제 (컨트롤러, 모델 등)에 대한 다른 문자열 파일을 만들고 초기 기본값을 만듭니다.
anka

xcode6의 현지화로 내보내기가 헤더 파일에서 매크로로 정의 된 문자열을 포착하지 못하는 것 같습니다. 누구든지 내가 누락 된 것을 확인하거나 말해 줄 수 있습니까? 감사...!
Juddster

@Juddster, 새로운 펀드 Editor-> Export for Localization으로도 헤더 파일에서 픽업되지 않음
Red

답변:


100

NSLocalizedString몇 가지 제한 사항이 있지만 Cocoa의 중심이기 때문에 현지화를 처리하기 위해 사용자 지정 코드를 작성하는 것은 부당합니다. 즉,이를 사용해야합니다. 약간의 툴링이 도움이 될 수 있습니다.

문자열 파일 업데이트

genstrings문자열 파일을 덮어 쓰고 이전의 모든 번역을 버립니다. 내가 쓴 update_strings.py를 이전 문자열 파일, 실행 구문 분석 할 수 genstrings있도록 수동으로 기존 번역을 복원 할 필요가 없다는 공백 및 채우기. 스크립트는 업데이트 할 때 너무 큰 차이를 피하기 위해 기존 문자열 파일을 가능한 한 가깝게 일치시킵니다.

문자열 이름 지정

NSLocalizedString광고 한대로 사용 하는 경우 :

NSLocalizedString(@"Cancel or continue?", @"Cancel notice message when a download takes too long to proceed");

서로 다른 상황에서 다른 의미를 가질 수 같은 영어 용어로 충돌 할 수있는 코드의 다른 부분에서 같은 문자열을 정의 결국 (수 OKCancel마음에 와서). 그렇기 때문에 항상 모듈 별 접두사와 매우 정확한 설명이있는 의미없는 올캡 문자열을 사용합니다.

NSLocalizedString(@"DOWNLOAD_CANCEL_OR_CONTINUE", @"Cancel notice window title when a download takes too long to proceed");

다른 장소에서 동일한 문자열 사용

동일한 문자열을 여러 번 사용하는 경우처럼 매크로를 사용하거나 View Controller 또는 데이터 소스에서 인스턴스 변수로 캐시 할 수 있습니다. 이 방법을 사용하면 설명이 반복되어 동일한 지역화 인스턴스 사이에서 오래되고 일관성이 없어 질 수 있습니다. 항상 혼란 스럽습니다. 인스턴스 변수는 기호이므로 가장 일반적인 번역에서 자동 완성 기능을 사용하고 특정 변수에 대해서는 "수동"문자열을 사용할 수 있습니다.이 문자열은 어쨌든 한 번만 발생합니다.

이 팁으로 Cocoa 현지화를 통해 생산성을 높이기를 바랍니다.


귀하의 답변에 감사드립니다, 나는 분명히 파이썬 파일을 살펴 보겠습니다. 나는 당신의 명명 규칙에 동의합니다. 최근에 다른 iOS 개발자들과 이야기를 나 macro으며 매크로 대신 정적 문자열을 사용하는 것이 좋습니다. 나는 당신의 대답을 upvoted했지만 해결책이 약간 어색하기 때문에 그것을 받아들이 기 전에 조금 기다릴 것입니다. 아마도 더 좋은 것이 나올 것입니다. 다시 감사합니다!
JiaYow

당신은 매우 환영합니다. 현지화는 지루한 과정으로, 올바른 도구와 워크 플로가 세상을 변화시킵니다.
ndfred

17
왜 gettext 스타일의 지역화 함수가 번역 중 하나를 키로 사용하는지 이해하지 못했습니다. 원본 텍스트가 변경되면 어떻게됩니까? 키 변경 사항 및 모든 현지화 된 파일이 이전 텍스트를 키로 사용하고 있습니다. 그것은 나에게 이해가되지 않았습니다. 나는 항상 "home_button_text"와 같은 키를 사용해 왔기 때문에 고유하고 절대 변하지 않습니다. 또한 모든 Localizable.strings 파일을 구문 분석하고 적절한 문자열을로드하는 정적 메소드로 클래스 파일을 생성하는 bash 스크립트를 작성했습니다. 이것은 코드 완성을 제공합니다. 언젠가 나는 이것을 오픈 소스로 할 수있다.
Mike Weller

2
나는 당신이 genstrings아니라고 생각합니다 gestring.
hiroshi

1
@ndfred 컴파일 타임은 문자열을 잘못 입력하지 않았는지 확인하는 것이 가장 큰 승리입니다. 어쨌든 추가 할 코드가 거의 없습니다. 또한 리팩토링, 정적 분석의 경우 기호를 사용하면 작업이 쉬워집니다.
Allen Zeng


24

ndfred와 동의하지만 다음을 추가하고 싶습니다.

두 번째 파라미터는 ... 기본값으로 사용할 수 있습니다 !!

(NSLocalizedStringWithDefaultValue는 genstring에서 제대로 작동하지 않으므로이 솔루션을 제안했습니다)

주석을 기본값으로 사용하는 NSLocalizedString을 사용하는 사용자 정의 구현은 다음과 같습니다.

1 . 사전 컴파일 된 헤더 (.pch 파일)에서 'NSLocalizedString'매크로를 재정의하십시오.

// cutom NSLocalizedString that use macro comment as default value
#import "LocalizationHandlerUtil.h"

#undef NSLocalizedString
#define NSLocalizedString(key,_comment) [[LocalizationHandlerUtil singleton] localizedString:key  comment:_comment]

2. 지역화 처리기를 구현할 클래스를 만듭니다.

#import "LocalizationHandlerUtil.h"

@implementation LocalizationHandlerUtil

static LocalizationHandlerUtil * singleton = nil;

+ (LocalizationHandlerUtil *)singleton
{
    return singleton;
}

__attribute__((constructor))
static void staticInit_singleton()
{
    singleton = [[LocalizationHandlerUtil alloc] init];
}

- (NSString *)localizedString:(NSString *)key comment:(NSString *)comment
{
    // default localized string loading
    NSString * localizedString = [[NSBundle mainBundle] localizedStringForKey:key value:key table:nil];

    // if (value == key) and comment is not nil -> returns comment
    if([localizedString isEqualToString:key] && comment !=nil)
        return comment;

    return localizedString;
}

@end

3. 그것을 사용하십시오!

앱 빌드 단계에서 실행 스크립트를 추가해야 각 빌드마다 Localizable.strings 파일이 업데이트됩니다. 즉, 현지화 된 새 문자열이 Localized.strings 파일에 추가됩니다.

내 빌드 단계 스크립트는 쉘 스크립트입니다.

Shell: /bin/sh
Shell script content: find . -name \*.m | xargs genstrings -o MyClassesFolder

따라서 코드에 다음 줄을 추가하면

self.title = NSLocalizedString(@"view_settings_title", @"Settings");

그런 다음 빌드를 수행하면 ./Localizable.scripts 파일에 다음 줄이 포함됩니다.

/* Settings */
"view_settings_title" = "view_settings_title";

그리고 'view_settings_title'의 키 == 값이므로 사용자 정의 LocalizedStringHandler는 주석, 즉 'Settings'를 반환합니다.

Voilà :-)


ARC 오류가 발생했습니다. 선택기 'localizedString : comment : :(
Mangesh

LocalizationHandlerUtil.h가 없기 때문이라고 생각합니다. 코드를 다시 찾을 수 없습니다 ... 헤더 파일 LocalizationHandlerUtil.h를 만들려고하면 정상입니다.
Pascal

파일을 만들었습니다. 폴더 경로 문제로 인한 것 같습니다.
Mangesh

3

스위프트에서는 다음과 같은 것을 사용하고 있습니다.

NSLocalizedString("btn_yes", value: "Yes", comment: "Yes button")

value:기본 텍스트 값의 사용법에 유의하십시오 . 첫 번째 매개 변수는 번역 ID 역할을합니다. 이 value:매개 변수 를 사용하면 나중에 기본 텍스트를 변경할 수 있지만 번역 ID는 동일하게 유지됩니다. Localizable.strings 파일에는"btn_yes" = "Yes";

경우 value:매개 변수가 다음 사용되지 않은 첫 번째 매개 변수는 모두를 위해 사용되는 : 번역 ID과도 기본 텍스트 값. Localizable.strings 파일에는가 포함 "Yes" = "Yes";됩니다. 이런 종류의 지역화 파일 관리는 이상하게 보입니다. 특히 번역 된 텍스트가 길면 ID도 길다. 기본 텍스트 값의 문자가 변경 될 때마다 번역 ID도 변경됩니다. 외부 번역 시스템을 사용할 때 문제가 발생합니다. 번역 ID를 변경하는 것은 항상 원치 않을 수있는 새로운 번역 텍스트를 추가하는 것으로 이해됩니다.


2

Localizable.strings를 여러 언어로 유지 관리하는 데 도움이되는 스크립트를 작성했습니다. 자동 완성에는 도움이되지 않지만 다음 명령을 사용하여 .strings 파일을 병합하는 데 도움이됩니다.

merge_strings.rb ja.lproj/Localizable.strings en.lproj/Localizable.strings

자세한 내용은 https://github.com/hiroshi/merge_strings를 참조하십시오.

당신 중 일부는 내가 희망하는 것이 유용하다고 생각합니다.


2

누군가 스위프트 솔루션을 찾고 있다면. 여기에 정리 한 솔루션을 확인하고 싶을 수도 있습니다. SwiftyLocalization

몇 단계 만 설정하면 Google 스프레드 시트에서 매우 유연한 현지화 (설명, 사용자 정의 색상, 강조 표시, 글꼴, 여러 시트 등)가 가능합니다.

간단히 말해 단계는 다음과 같습니다. Google 스프레드 시트-> CSV 파일-> Localizable.strings

또한 키 검색 및 디코딩에 대한 인터페이스처럼 작동하는 구조체 인 Localizables.swift도 생성합니다 (키에서 문자열을 디코딩하는 방법을 수동으로 지정해야 함).

왜 이것이 좋습니까?

  1. 더 이상 모든 장소에서 일반 문자열로 키를 가질 필요가 없습니다.
  2. 컴파일시 잘못된 키가 감지되었습니다.
  3. Xcode는 자동 완성을 수행 할 수 있습니다.

지역화 가능한 키를 자동 완성 할 수있는 도구가 있습니다. 실제 변수에 대한 참조는 항상 유효한 키인지 확인하고 그렇지 않으면 컴파일되지 않습니다.

// It's defined as computed static var, so it's up-to-date every time you call. 
// You can also have your custom retrieval method there.

button.setTitle(Localizables.login.button_title_login, forState: .Normal)

이 프로젝트는 Google 앱 스크립트를 사용하여 시트-> CSV를 변환하고 Python 스크립트는 CSV 파일을 변환합니다-> Localizable.strings이 예제 시트를 빠르게 살펴보고 가능한 것을 알 수 있습니다.


1

iOS 7 및 Xcode 5에서는 'Localization.strings'메소드를 사용하지 말고 새로운 '기본 현지화'메소드를 사용해야합니다. '기본 지역화'를 위해 Google을 사용하는 경우 몇 가지 자습서가 있습니다.

Apple Doc : 기본 현지화


네 스티브 맞습니다. 또한 동적으로 생성 된 문자열에 대해서는 .strings 파일 메소드가 여전히 필요합니다. 그러나 이것들에 대해서만 Apple이 선호하는 방법은 기본 현지화입니다.
Ronny Webers

새로운 방법에 연결 하시겠습니까?
Hyperbole

1
기본 현지화 방법은 쓸모가 없습니다. 여전히 동적 문자열에 대한 다른 위치 파일을 유지해야하며 문자열이 많은 파일에 분산되어 유지됩니다. 빻 내부 문자열은 / 스토리 보드는 다음과 같은 몇 가지 libs와 함께 Localizable.strings의 키에 자동으로 지역화 할 수 있습니다 github.com/AliSoftware/OHAutoNIBi18n
라파엘 노브레

0
#define PBLocalizedString(key, val) \

[[NSBundle mainBundle] localizedStringForKey:(key) value:(val) table:nil]

0

나 자신은 종종 항목을 .strings 파일에 넣는 것을 잊어 버리고 코딩을 수행하지 않습니다. 따라서 .strings 파일에 다시 넣고 번역해야 할 내용을 찾는 도우미 스크립트가 있습니다.

NSLocalizedString에서 고유 한 매크로를 사용 하므로 nil 이 NSLocalizedString의 두 번째 매개 변수로 사용 된다는 가정하에 사용하기 전에 스크립트를 검토하고 업데이트하십시오 . 변경하고 싶은 부분은

NSLocalizedString\(@(".*?")\s*,\s*nil\) 

매크로 및 NSLocalizedString 사용법과 일치하는 것으로 바꾸십시오.

여기에 스크립트가 제공되며 실제로 3 부만 있으면됩니다. 나머지는 모든 것이 어디서 나오는지를 더 쉽게 보는 것입니다.

// Part 1. Get keys from one of the Localizable.strings
perl -ne 'print "$1\n" if /^\s*(".+")\s*=/' myapp/fr.lproj/Localizable.strings

// Part 2. Get keys from the source code
grep -n -h -Eo -r  'NSLocalizedString\(@(".*?")\s*,\s*nil\)' ./ | perl -ne 'print "$1\n" if /NSLocalizedString\(@(".+")\s*,\s*nil\)/'

// Part 3. Get Part 1 and 2 together.

comm -2 -3 <(grep -n -h -Eo -r  'NSLocalizedString\(@(".*?")\s*,\s*nil\)' ./ | perl -ne 'print "$1\n" if /NSLocalizedString\(@(".+")\s*,\s*nil\)/' | sort | uniq) <(perl -ne 'print "$1\n" if /^\s*(".+")\s*=/' myapp/fr.lproj/Localizable.strings | sort) | uniq >> fr-localization-delta.txt

출력 파일에는 코드에는 있지만 Localizable.strings 파일에는없는 키가 포함되어 있습니다. 다음은 샘플입니다.

"MPH"
"Map Direction"
"Max duration of a detailed recording, hours"
"Moving ..."
"My Track"
"New Trip"

확실히 더 연마 될 수 있지만 공유 할 것이라고 생각했습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.