[iPhone] - 시작하세요! 아이폰 3 프로그래밍 - Part 17. 애플리케이션 지역화

iPhone/[위키북스]시작하세요! 아이폰3 프로그래밍 2010. 10. 8. 16:17
* 애플리케이션 지역화
- 아이폰의 아키텍처는 지역화를 적용하기에 적합하도록 설계되었기 때문에 애플리케이션의 리소스를 다양한 언어로 쉽게 변경할 수 있을 뿐만 아니라, 한 언어의 여러 방언으로 쉽게 변경할 수 있다.
- 하지만, 일반적인 경우에는 이미 만들어진 애플리케이션에 다국어 기능을 추가하는 것은 처음부터 애플리케이션을 다시 만드는 것보다 더 어려운 일이다.

* 지역화 아키텍처
- 다국어를 지원하지 않는 애플리케이션을 실행하면 애플리케이션의 텍스트들은 기본 언어로 설정된 개발자의 모둑어가 적용되어 있을 것이다.
- 개발자가 애플리케이션에 다국어 기능을 추가하려고 할 때 각각의 언어를 표시하는 데 사용할 파일들을 저장하기 위해 애플리케이션 번들 디렉터리에 언어별로 하위 디렉터리를 생성할 것이다. 이와 같이 생성된 각각의 하위 디렉터리를 '지역화 프로젝트(localization project)' 또는 '지역화 폴더(localization folder)'라고 부른다. 지역화 폴더 이름의 맨 마지막에는 항상 .lproj라는 확장자가 붙는다.
- 사용자는 설정Settings 애플리케이션에서 언어와 지역을 설정할 수 있다.
- 다국어를 지원하는 애플리케이션이 이미지, 프로퍼티 리스트, nib와 같은 리소스 파일들을 로딩하려 할때 애플리케이션은 사용자가 설정한 언어와 지역을 확인하고 설정에 맞는 지역화 폴더를 찾는다. 만일 폴더를 찾았다면 기본으로 설정된 언어 대신에 현재 설정된 언어에 필요한 리소스 파일들을 로딩할 것이다.
- 사용자가 언어와 지역을 프랑스어와 프랑스로 선택했다면 애플리케이션은 fr_FR.lproj라는 이름의 지역화 폴더를 찾을 것이다. fr_FR에서 앞의 두 글자는 프랑스어의 ISO 국가 코드를 의미한다. 밑줄 뒤에 따라오는 두 글자는 프랑스의 2자리 ISO코드를 의미한다.
- 애플리케이션이 fr_FR.lproj라는 이름의 지역화 폴더를 찾을 수 없다면, fre_FR이나 fra_FR이라는 이름의 지역화 폴더를 찾을 것이다.
- 만일 애플리케이션이 지역화 폴더를 찾지 못하면 지역 코드를 무시하고 언어 코드로만 일치하는 지역화 폴더를 찾으려 할 것이다. 예를 들어, 프랑스와 프랑스어로 설정되어 있을 경우 애플리케이션은 fr.lproj라는 이름의 지역화 폴더를 찾을 것이다.
- 애플리케이션이 언어/지역으로 구성된 지역화 폴더나 언어로만 구성된 지역화 폴더를 찾지 못했다면, 개발 시에 기본으로 설정된 언어의 리소스 파일들을 사용할 것이다. 반대로 설정된 언어에 적합한 지역화 폴더를 찾았다면, 필요한 리소스 파일들을 지역화 폴더에서 먼저 찾을 것이다. 예를 들어 여러분이 imageNamed:를 사용하여 UIImage객체에 이미지를 로딩한다면, 애플리케이션은 먼저 지역화 프로젝트 안에서 명시된 이름의 이미지 파일을 찾을 것이다. 이미지 파일을 찾으면 그 이미지를 사용할 것이고, 찾지 못한다면 기본 언어 폴더의 이미지 파일을 사용할 것이다.
- 만일 애플리케이션이 fr_FR.lproj와 fr.lproj라는 이름을 사용하는 2개의 지역화 폴더를 가지고 있다면, 좀 더 구체적인 이름을 사용하는 지역화 폴더의 리소스 파일들을 먼저 사용할 것이다. 이 경우에는 fr_FR.lproj가 이에 해당된다.
- 애플리케이션이 fr_FR.lproj폴더에서 리소스 파일들을 찾지 못하면 fr.lproj폴더에서 리소스 파일들을 찾으려고 할 것이다. 이러한 특징을 활용하면 특정 언어에서 지역에 관계없이 공통적으로 사용되는 표현들은 fr.lproj와 같은 형식의 폴더에 저장하고, 지역에 따라 표현이 다른 텍스트나 이미지 파일들은 fr_FR.lproj와 같은 형식을 사용하는 지역화 폴더에 저장하면된다.

* 문자열 파일 사용하기
- 만일 다국어 지원하는 애플리케이션을 만들 계획이라면 애플리케이션의 경고창이나 메시지 전달에 사용될 텍스트들을 소스코드 안에 직접 작성해서는 안 된다.
- 가장 좋은 방법은 이러한 문자열들을 '문자열파일'이라고 부르는 텍스트 파일에 저장하는 것이다. 문자열 파일은 주석이 달려 있는 한 쌍의 문자열의 리스트를 저장하고 있는 유니코드(UTF-16)텍스트 파일이다.
/* Used to ask the user his/her first name */
"First Name" = "First Name";

/* Used to get the user's last name */
"Last Name" = "Last Name";

/* Used to ask the user's birth date */
"Birthday" = "Birthday"

- /* 와 */ 사이의 글자들은 주석이며 애플리케이션에서 사용되지 않고 안전하게 제외될 것이다.
- 문자열 리스트의 각 라인에 같은 문자열이 두 번씩 표기된 것에 주목하자. 이퀄 기호(=)의 왼쪽 문자열은 키를 나타내며, 설정된 언어에 상관없이 동일한 값을 유지한다. 이퀄 기호의 오른쪽 문자열은 특정 언어로 번역된 문자열이다. 만일 프랑스어로 지역화된 문자열 파일을 열어보면 아래와 같을 것이다.
/* Used to ask the user his/her first name */
"First Name" = "Prenom";

/* Used to get the user's last name */
"Last Name" = "Nom de famille";

/* Used to ask the user's birth date */
"Birthday" = "anniversaire"

* 문자열 파일 만들기
- 실제로 여러분이 문자열 파일을 직접 만들 필요는 없다. 대신 코드 안에 지역화해야 할 모든 텍스트 문자열을 특정 매크로로 감싸는 작업을 해야 한다. 코드를 작성하고 지역화 할 준비가 끝나면 genstrings라는 콘솔 프로그램을 실행할 것이다. 이 프로그램은 매크로를 찾기 위해 모든 코드 파일들을 검색하고, 그 중 필욯나 문자열들을 추출하여 지역화하는 데 사용할 문자열 파일에 저장한다.
- 일반적인 문자열 선언문은 아래와 같이 사용된다.
NSString *myString = @"First Name";

- 이 문자열을 추출하려면 아래와 같이 수정해야 한다.
NSString *myString = NSLocalizedString(@"First Name", @"Used to ask the user his/her first name");

- NSLocalizedString 매크로는 2개의 인자를 사용한다. 첫 번째 인자는 기본 언어로 사용할 문자열 변수이다. 만약 다국어를 지원하지 않는다면 애플리케이션은 이 문자열을 사용할 것이다. 또 다른 인자는 문자열 파일 안의 주석으로 사용된다.
- NSLocalizedString 매크로는 애플리케이션 번들 디렉토리의 지역화 폴더에서 Localizable.strings라는 문자열 파일을 찾는다. 만일 이 파일을 찾지 못하면 자신의 첫 번째 인자로 전달받은 문자열을 반환하고 애플리케이션에는 반환된 문자열이 보여질 것이다.
- NSLocalizedString 매크로가 문자열 파일을 찾으면 첫 번째 인자와 일치하는 문자열 쌍을 찾기 위해 파일의 내용을 검색할 것이다. 안에서 설명했던 예제의 경우에 NSLocalizedString매크로는 "First Name"을 찾기 위해 문자열 파일을 검색할 것이다. 만일 지역화 폴더에서 일치하는 문자열을 찾지 못했다면, 기본 언어 폴더 안의 문자열 파일을 검색할 것이고, 문자열 파일 안의 문자열을 사용할 것이다. 기본 언어 폴더의 문자열 파일에서도 찾지 못하면 NSLocalizedString 매크로의 첫 번째 인자로 전달된 문자열을 화면 상에 보여줄 것이다.

* 실생활에서의 아이폰 : 애플리케이션 지역화히기
- 애플리케이션의 NSLocale 인스턴스는 사용자의 언어와 지역 정보를 가지고 있다. NSLocale 인스턴스는 애플리케이션의 화면에 표시되는 언어,날짜,통화,시간 정보에 대한 기준으로 사용될 것이다.
- 애플리케이션 상단에 위치한 언어와 지역 정보는 사용자의 로케일로부터 가져온 것이다. 화면의 왼쪽에 배치된 글자들은 nib 파일 안에 설정된 텍스트를 보여주는 정적인 문자열이다. 오른쪽에는 배치된 글자들은 아웃렛을 사용하여 프로그램이 실행될 때 동적으로 변경될 정보들이다. 화면 하단의 기발 이미지는 정적인 UIImageView 객체이다.
- Xcode에서 뷰 기반의 애플리케이션 템플릿을 이용하여 새 프로젝트를 생성하고, LocalizeMe라고 입력한다.  기존 폴더에서 Base Language라는 이름의 폴더가 있으며, 이 폴더에서 icon.png와 flah.png라는 이믈의 파일을 Resources 폴더로 옮긴다.
- Info.plist를 클릭하고 Icon file의 값을 icon.png로 설정한다.

#### LocalizeMeViewController.h ####
#import 

@interface LocalizeMeViewController : UIViewController 
{
	UILabel *localeLabel;
	UILabel *label1;
	UILabel *label2;
	UILabel *label3;
	UILabel *label4;
	UILabel *label5;
}

@property (nonatomic, retain) IBOutlet UILabel *localeLabel;
@property (nonatomic, retain) IBOutlet UILabel *label1;
@property (nonatomic, retain) IBOutlet UILabel *label2;
@property (nonatomic, retain) IBOutlet UILabel *label3;
@property (nonatomic, retain) IBOutlet UILabel *label4;
@property (nonatomic, retain) IBOutlet UILabel *label5;

@end

- LocalizeMeViewController.xib 파일을 더블클릭하여 인터페이스 빌더를 실행한다.
- 라이브러리 창에서 레이블(Label) 하나를 드래그하여 뷰 윈도우의 상단에 배치한다. 왼쪽 블루 가이드 라인에서 오른쪽 블루 가이드 라인까지 뷰의 전체 너비를 차지할 수 있도록 레이블의 크기를 조절한다. 레이블을 선택하고 레이블의 글자를 진하게 만들고 텍스트를 가운데 정렬한다. 텍스트 색상을 밝은 파랑으로 변경한다. 속성 인스펙터 창의 Adjust to fit 옵션이 설정되었다면, 텍스트 크기가 너무 크더라도 크기는 자동으로 저절될 것이다.
- File's Owner 아이콘에서 컨트롤-드래그하여 레이블 위로 끌어온 뒤에 localeLabel 아웃렛을 선택한다.
- 라이브러리 창에서 레이블 5개를 드래그하고, 레이블들을 블루 가이드 라인을 사용하여 왼쪽 가장자리에 나란히 붙인다.
- 맨 위의 레이블을 더블클릭하고, Label에서 Onw으로 변경하다. 다음으로 마지막 Five까지 순서대로 변경한다.
- 라이브러리 창에서 5개의 레이블을 드래그하여 오른쪽 측면에 나란히 배치한다. 텍스트 정렬을 오른쪽으로 변경하고 여유롭게 크기를 조절한다. 그런다음 File's Owner아이콘을 각각의 5개의 레이블로 컨트롤 드래그하여 레이블의 아웃렛으로 연결한다. 해당 레이블에 텍스트는 삭제한다.
- 라이브러리 창에서 이미지 뷰(Image View)를 드래그하여 뷰의 하단에 배치한다. 속성 인스펙터창에서 View의 Image항목을 flag.png로 변경하고, 이미지의 너비가 왼쪽 블루 가이드 라인과 오른쪽 블루 가이드 라인에 맞춰질 수 있도록 이미지 뷰의 크기를 조절한다. 다음으로 Mode를 Center에서 Aspect Fit으로 변경한다. 이 옵션을 설정하면 이미지 뷰에 붙여진 이미지의 크기를 자동으로 조절해서 이미지 뷰의 크기에 맞게 해주며 이미지의 크기가 조절되어도 이미지의 비율은 그대로 유지될 것이다.

#### LocalizeMeViewController.m ####
#import "LocalizeMeViewController.h"

@implementation LocalizeMeViewController
@synthesize localeLabel;
@synthesize label1;
@synthesize label2;
@synthesize label3;
@synthesize label4;
@synthesize label5;

-(void)viewDidLoad
{
	// 현재 로케일 정보를 얻기 위해 NSLoale인스턴스를 생성
	// NSLocale의 인스턴스 객체를 사용하면 설정 애플리케이션에 설정된 언어와 지역에 대한 정보를 얻을수 있다.
	// NSLocale 클래스는 딕셔너리처럼 키-밸류 형태로 사용할수 있다.
	// NSLocale에는 현재 사용자가 설정한 언어/지역 정보와 통화,날짜 포맷 등의 정보가 들어 있다.
	NSLocale *locale = [NSLocale currentLocale];
	
	// locale인스턴스를 통해 식별자를 가져오는 코드.
	// 이 식별자는 현재 로케일에 대한 언어/지역을 나타낸다.
	// localeIdentifier의 자료형은 NSString* 이므로 식별자는 문자열의 형태로 사용된다.
	// ex : [locale localeIdentifier] = @"fr_FR"
	// displayNameForKey:value: 메서드는 요청된 키에 대한 밸류를 반환하며 설정된 언어에 따라 반환값이 다르다.
	NSString *displayNameString = [locale displayNameForKey:NSLocaleIdentifier value:[locale localeIdentifier]];
	localeLabel.text = displayNameString;
	
	
	label1.text = NSLocalizedString(@"One", @"The Number 1");
	label2.text = NSLocalizedString(@"Two", @"The Number 2");
	label3.text = NSLocalizedString(@"Three", @"The Number 3");
	label4.text = NSLocalizedString(@"Four", @"The Number 4");
	label5.text = NSLocalizedString(@"Five", @"The Number 5");
	
	[super viewDidLoad];
	
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
}

- (void)viewDidUnload {
	self.localeLabel = nil;
	self.label1 = nil;
	self.label2 = nil;
	self.label3 = nil;
	self.label4 = nil;
	self.label5 = nil;
	[super viewDidUnload];
}


- (void)dealloc {
	[localeLabel release];
	[label1 release];
	[label2 release];
	[label3 release];
	[label4 release];
	[label5 release];
    [super dealloc];
}

@end

* Nib 파일 지역화하기
- 이제 nib 파일을 지역화해보자. 어떤 파일이든 지역화하는 과정은 동일하다.
- Xcode에서 LocalizeMeViewController.xib 파일을 클릭하고, Func+ I 을 눌러서 Info 윈도우를 실행한다. General탭을 클릭하고 이동한다. 그런 다음 윈도우의 왼쪽 아라에 위치한 Make File Localizable 버튼을 클릭한다.
- Make File Localizable 버튼을 클릭하면 윈도우는 Targets탭으로 변경될 것이다. Info 윈도우를 닫고 Xcode의 Group & Files창을 살펴보자 LocalizeMeViewController.xib 파일의 왼쪽에는 삼각형 모양의 아이콘이 있따. 이것을 클릭하면 리스트가 펼쳐지고 하위 목록들이 나타날것이다.

* 지역화된 프로젝트 구조 살펴보기
- 프로젝트의 LocalizeMeViewControoler.xib는 English라는 하위 항목 하나를 가지고 있다. 이것은 기본 언어이며 자동으로 생성되었다.
- Groups & File창의 LocalizeMeViewController.xib를 클릭하고 Func + I 을 눌러서 Info 윈도우가 나타나도록만든다. General탭의 Add Localization 버튼을 클릭한다. 지역화를 폴더의 이름을 입력받는 창이 나타날것이다. 프랑스어에 대한 지역화를 추가하기 위해 fr이라고 입력한다. 드롭다운 메뉴의 French를 선택해서는 않된다.
- 로케일 처리할 때 언어 코드는 소문자를 사용하지만, 국가 코드는 대문자를 사용한다.
- fr을 입력하고 리턴 키를 누르면 프로젝트 폴더 안에 fr.lproj라는 이름의 새로운 지역화 폴더가 생성될 것이다. 이제 LocalizeMeViewController.xib의 하위 항목으로 English와 fr이 보일 것이다. fr을 더블클릭하여 nib파일이 열리도록 만든다.
- 인터페이스 빌더에 로딩된 nib 파일은 앞에서 만들었던 nib 파일의 복사본이기 때문에 모든 내용이 동일 할 것이다. 이 파일에 수정한 내용들은 프랑스어로 설정한 사용자들에게 보여질 것이다. 왼편에 위치한 레이블들을 더블클릭하고 그것들을 각각 Un,Deux, Trois, Quatre, Cinq로 변경한다. 변경이 끝나면 nib을 저장하고 Xcode로 이동한다.
- 아이폰은 설정 내용을 캐시하여 사용하므로 지금 애플리케이션을 컴파일하고 실행하면 옛날과 동일한 모습만 보일것이다.
- 시뮬레이터에서의 iPhone Simulator 메뉴의 밑에 Reset Content and Settings... 메뉴가 있다. 이 메뉴를 지금 선택해 보자. 설정 애플리케이션을 실행하고 일반을 클릭한다. 그런 다음 다국어(International)메뉴를 클릭한다. 여기에서 언어와 지역에 대한 설정을 변경할 수 있다.
- 지역 포맷(Region Format)을 미국(United States)에서 프랑스(France,프랑스어 French의 하위 항목이다.)로 변경하고, 언어(Language)를 영어(English)에서 프랑스어(Francais)로 변경한다.
- Xcode로 이동하여 Build 메뉴의 Clean을 선택한다.
- Clean을 실행하고 나서 다시 LocalizeMe 애플리케이션을 빌드하고 실행한다. 이번에는 왼쪽에 위치한 글자들이 프랑스어로 보일 것이다.

* 이미지 지역화 하기
: