지역화Localization

샘플 다운로드 샘플 다운로드Download Sample Download the sample

.NET 리소스 파일을 사용하여 Xamarin.Forms 앱을 지역화할 수 있습니다.Xamarin.Forms apps can be localized using .NET resources files.

개요Overview

.NET 애플리케이션 지역화를 위해 기본 제공되는 메커니즘에서는 RESX 파일System.ResourcesSystem.Globalization 네임스페이스의 클래스를 사용합니다.The built-in mechanism for localizing .NET applications uses RESX files and the classes in the System.Resources and System.Globalization namespaces. 변환된 문자열이 포함된 RESX 파일이 변환에 대한 강력한 형식의 액세스 권한을 제공하는 컴파일러 생성 클래스와 함께 Xamarin.Forms 어셈블리에 포함됩니다.The RESX files containing translated strings are embedded in the Xamarin.Forms assembly, along with a compiler-generated class that provides strongly-typed access to the translations. 그러면 변환된 텍스트를 코드에서 검색할 수 있습니다.The translated text can then be retrieved in code.

샘플 코드Sample Code

이 문서와 연결된 두 개의 샘플이 있습니다.There are two samples associated with this document:

  • UsingResxLocalization은 설명된 개념의 매우 간단한 데모입니다.UsingResxLocalization is a very simple demonstration of the concepts explained. 아래에 표시된 코드 조각은 이 샘플의 모든 것입니다.The code snippets shown below are all from this sample.
  • TodoLocalized은 이러한 지역화 기술을 사용하는 기본 작업 앱입니다.TodoLocalized is a basic working app that uses these localization techniques.

빌드 시스템의 제한으로 인해 리소스 파일이 코드에서 강력한 형식의 변환된 문자열에 액세스할 수 없게 만드는 .designer.cs 파일을 생성하지 못한다 해도 TodoLocalized 샘플에는 공유 프로젝트 데모가 포함됩니다.The TodoLocalized sample includes a Shared Project demo however due to limitations of the build system the resource files do not get a .designer.cs file generated which breaks the ability to access translated strings strongly-typed in code.

이 문서의 나머지 부분은 Xamarin.Forms .NET Standard 라이브러리 템플릿을 사용하는 프로젝트와 관련이 있습니다.The remainder of this document relates to projects using the Xamarin.Forms .NET Standard library template.

Xamarin.Forms 코드 글로벌화Globalizing Xamarin.Forms Code

애플리케이션의 글로벌화는 "세계를 준비"시키는 프로세스로서Globalizing an application is the process of making it "world ready." 다양한 언어를 표시할 수 있는 코드를 작성합니다.This means writing code that is capable of displaying different languages.

애플리케이션 글로벌화의 주요 부분 중 하나는 하드 코딩된 텍스트가 없도록 사용자 인터페이스를 빌드하는 것입니다.One of the key parts of globalizing an application is building the user-interface so that there is no hard-coded text. 대신 사용자에게 표시된 모든 항목을 선택한 언어로 변환된 문자열 세트에서 검색해야 합니다.Instead, anything displayed to the user should be retrieved from a set of strings that have been translated into their chosen language.

이 문서에서는 RESX 파일을 사용하여 해당 문자열을 저장하고 사용자의 기본 설정에 따라 표시용 문자열을 검색하는 방법을 살펴봅니다.In this document we'll examine how to use RESX files to store those strings and retrieve them for display depending on the user's preference.

샘플의 대상은 영어, 프랑스어, 스페인어, 독일어, 중국어, 일본어, 러시아어 및 브라질 포르투갈어입니다.The samples target English, French, Spanish, German, Chinese, Japanese, Russian, and Brazilian Portuguese languages. 애플리케이션은 필요한 경우 적거나 많은 언어로 변환될 수 있습니다.Applications can be translated into as few or as many languages as required.

참고

유니버설 Windows 플랫폼에서 RESX 파일보다는 RESW 파일이 푸시 알림 지역화에 사용되어야 합니다.On the Universal Windows Platform, RESW files should be used for push notification localization, rather than RESX files. 자세한 내용은 UWP 지역화를 참조하세요.For more information, see UWP Localization.

리소스 추가Adding Resources

Xamarin.Forms. NET Standard 라이브러리 애플리케이션 글로벌화의 첫 번째 단계는 앱에서 사용하는 모든 텍스트를 저장하는 데 사용할 RESX 리소스 파일을 추가하는 것입니다.The first step in globalizing a Xamarin.Forms .NET Standard library application is adding the RESX resource files that will be used to store all the text used in the app. 기본 텍스트를 포함하는 RESX 파일을 추가한 다음, 지원하려는 각 언어에 대한 추가적인 RESX 파일을 추가해야 합니다.We need to add a RESX file that contains the default text, and then add additional RESX files for each language we wish to support.

기본 언어 리소스Base Language Resource

기본 리소스(RESX) 파일에는 기본 언어 문자열이 포함됩니다(샘플에서는 영어를 기본 언어로 가정합니다).The base resources (RESX) file will contain the default language strings (the samples assume English is the default language). 프로젝트를 마우스 오른쪽 단추로 클릭하고 추가 > 새 파일... 을 선택하여 Xamarin.Forms 공용 코드 프로젝트에 파일을 추가합니다.Add the file to the Xamarin.Forms common code project by right-clicking on the project and choosing Add > New File....

AppResources와 같은 의미 있는 이름을 선택하고 확인을 누릅니다.Choose a meaningful name such as AppResources and press OK.

리소스 파일 추가Add Resource File

프로젝트에 두 파일을 추가합니다.Two files will be added to the project:

  • 변환 가능한 문자열이 XML 형식으로 저장되는 AppResources.resx 파일입니다.AppResources.resx file where translatable strings are stored in an XML format.
  • partial 클래스를 선언하여 RESX XML 파일에서 생성된 모든 요소에 대한 참조를 포함하는 AppResources.designer.cs 파일입니다.AppResources.designer.cs file that declares a partial class to contain references to all the elements created in the RESX XML file.

솔루션 트리에서는 관련 파일을 보여줍니다.The solution tree will show the files as related. 새 변환 가능한 문자열을 추가하려면 RESX 파일을 편집해야 하며, .designer.cs 파일은 편집하지 말아야 합니다.The RESX file should be edited to add new translatable strings; the .designer.cs file should not be edited.

문자열 표시 유형String Visibility

기본적으로 문자열에 대한 강력한 형식의 참조를 생성할 경우 어셈블리에 대한 internal이 됩니다.By default when strongly-typed references to strings are generated, they will be internal to the assembly. 이는 RESX 파일에 대한 기본 빌드 도구에서 internal 속성을 사용하여 .designer.cs 파일을 생성하기 때문입니다.This is because the default build tool for RESX files generates the .designer.cs file with internal properties.

이 빌드 도구가 구성되는 위치를 확인하려면 AppResources.resx 파일을 선택하고 속성 패드를 표시합니다.Select the AppResources.resx file and show the Properties pad to see where this build tool is configure. 아래 스크린샷에서는 사용자 지정 도구: ResXFileCodeGenerator를 보여 줍니다.The screenshot below shows the Custom Tool: ResXFileCodeGenerator.

강력한 형식의 문자열 속성을 public으로 만들려면 아래 스크린샷에 표시된 것처럼 수동으로 구성을 사용자 지정 도구: PublicResXFileCodeGenerator로 변경해야 합니다.To make the strongly-typed string properties public, you must manually change the configuration to Custom Tool: PublicResXFileCodeGenerator, as shown in the screenshot below:

이 변경은 선택 사항이며, 다양한 어셈블리에서 지역화된 문자열을 참조하려는 경우(예: 다양한 어셈블리의 RESX 파일을 코드에 저장하는 경우)에만 필요합니다.This change is optional, and is only required if you wish to reference localized strings across different assemblies (for example, if you put the RESX files in a different assembly to your code). 이 항목에 대한 샘플은 internal 문자열이 사용되는 경우 동일한 Xamarin.Forms. NET Standard 라이브러리 어셈블리에서 정의되므로 해당 문자열을 유지합니다.The sample for this topic leaves the strings internal because they are defined in the same Xamarin.Forms .NET Standard library assembly where they are used.

위에 표시된 것과 같이 기본 RESX 파일에서 사용자 지정 도구만 설정해야 합니다. 다음 섹션에 설명된 언어별 RESX 파일에서 모든 빌드 도구를 설정할 필요는 없습니다.You only need to set the custom tool on the base RESX file as shown above; you do not need to set any build tool on the language-specific RESX files discussed in the following sections.

RESX 파일 편집Editing the RESX file

안타깝게도 Mac용 Visual Studio에는 기본 제공 RESX 편집기가 없습니다.Unfortunately there is no built-in RESX editor in Visual Studio for Mac. 변환 가능한 문자열을 추가하면 각 문자열에 대한 새 XML data 요소의 추가가 필요합니다.Adding new translatable strings requires the addition of a new XML data element for each string. data 요소에는 다음이 포함될 수 있습니다.Each data element can contain the following:

  • name 특성(필수)는 이 변환 가능한 문자열의 핵심입니다.name attribute (required) is the key for this translatable string. 공백이나 특수 문자가 허용되지 않도록 올바른 C# 속성 이름이어야 합니다.It must be a valid C# property name - so no spaces or special characters are allowed.
  • 실제 문자열인 value 요소(필수)는 애플리케이션에 표시됩니다.value element (required), which is the actual string that is displayed in the application.
  • comment 요소(선택 사항)에는 문자열을 사용하는 방법을 설명하는 변환기에 대한 지침이 포함될 수 있습니다.comment element (optional) can contain instructions for the translator that explains how this string is used.
  • 문자열의 공백을 유지하는 방법을 제어하기 위한 xml:space 특성(선택 사항)입니다.xml:space attribute (optional) to control how spacing in the string is preserved.

몇 가지 예제 data 요소가 여기에 표시됩니다.Some example data elements are shown here:

<data name="NotesLabel" xml:space="preserve">
    <value>Notes:</value>
    <comment>label for input field</comment>
</data>
<data name="NotesPlaceholder" xml:space="preserve">
    <value>eg. buy milk</value>
    <comment>example input for notes field</comment>
</data>
<data name="AddButton" xml:space="preserve">
    <value>Add new item</value>
</data>

애플리케이션이 작성되므로 사용자에 게 표시되는 텍스트의 모든 부분을 새 data 요소의 기본 RESX 리소스 파일에 추가해야 합니다.As the application is written, every piece of text displayed to the user should be added to the base RESX resources file in a new data element. 변환의 고품질을 확보하려면 가급적 comment가 포함되는 것이 좋습니다.It is recommended that you include comments as much as possible to ensure a high-quality translation.

참고

Visual Studio(평가판 Community 버전을 포함하여)에는 기본 RESX 편집기가 포함됩니다.Visual Studio (including the free Community edition) contains a basic RESX editor. Windows 컴퓨터에 대한 액세스 권한이 있는 경우 RESX 파일에 문자열을 추가 및 편집하는 것이 간편한 방법일 수 있습니다.If you have access to a Windows computer, that can be a convenient way to add and edit strings in RESX files.

언어별 리소스Language-Specific Resources

일반적으로 기본 텍스트 문자열은 애플리케이션의 대규모 청크가 작성되기까지(기본 RESX 파일에 많은 문자열이 포함된 경우) 실제로 변환되지 않습니다.Typically, the actual translation of the default text strings won't happen until large chunks of the application have been written (in which case the default RESX file will contain lots of strings). 지역화 코드를 테스트할 수 있으려면 기계로 변환된 텍스트로 채우면서 개발 주기 초반에 언어별 리소스를 추가하는 것이 좋습니다.It is still a good idea to add the language-specific resources early in the development cycle, optionally populating with machine-translated text to help test the localization code.

지원하려는 각 언어에 대한 추가적인 RESX 파일 하나를 추가합니다.One additional RESX file is added for each language we wish to support. 언어별 리소스 파일은 특정 명명 규칙을 따라야 합니다. 즉, 기본 리소스 파일과 동일한 파일 이름을 사용하고(예:Language-specific resource files must follow a specific naming convention: use the same filename as the base resources file (eg. AppResources).AppResources) followed by a period (.) and then the language code. 간단한 예제는 다음과 같습니다.Simple examples include:

  • AppResources.fr.resx - 프랑스어 번역입니다.AppResources.fr.resx - French language translations.
  • AppResources.es.resx - 스페인어 번역입니다.AppResources.es.resx - Spanish language translations.
  • AppResources.de.resx - 독일어 번역입니다.AppResources.de.resx - German language translations.
  • AppResources.ja.resx - 일본어 번역입니다.AppResources.ja.resx - Japanese language translations.
  • AppResources.zh-Hans.resx - 중국어(간체) 번역입니다.AppResources.zh-Hans.resx - Chinese (Simplified) language translations.
  • AppResources.zh-Hant.resx - 중국어(번체) 번역입니다.AppResources.zh-Hant.resx - Chinese (Traditional) language translations.
  • AppResources.pt.resx - 포르투갈어 번역입니다.AppResources.pt.resx - Portuguese language translations.
  • AppResources.pt-BR.resx - 브라질 포르투갈어 번역입니다.AppResources.pt-BR.resx - Brazilian Portuguese language translations.

일반적인 패턴은 2글자 언어 코드를 사용하는 것이지만 다른 형식을 사용하는 일부 예제(예: 중국어) 및 4글자 로캘 식별자가 필요한 다른 예제(예: 브라질 포르투갈어)도 있습니다.The general pattern is to use two-letter language codes, but there are some examples (such as Chinese) where a different format is used, and other examples (such as Brazilian Portuguese) where a four character locale identifier is required.

이러한 언어별 리소스 파일은 .designer.cs partial 클래스가 필요’하지 않기’ 때문에 해당 리소스 파일을 빌드 작업: EmbeddedResource이 설정된 일반 XML 파일로 추가할 수 있습니다.These language-specific resources files do not require a .designer.cs partial class so they can be added as regular XML files, with the Build Action: EmbeddedResource set. 이 스크린샷은 언어별 리소스 파일이 포함된 솔루션을 보여줍니다.This screenshot shows a solution containing language-specific resource files:

애플리케이션을 개발하고 기본 RESX 파일이 텍스트를 추가했으므로 각 data 요소를 변환하고 앱에 포함되도록 언어별 리소스 파일을 반환할(표시된 명명 규칙을 사용하여) 변환기에 텍스트를 전송해야 합니다.As an application is developed and the base RESX file has text added, you should send it out to translators who will translate each data element and return a language-specific resource file (using the naming convention shown) to be included in the app. 일부 '기계 번역' 예제는 다음과 같습니다.Some 'machine translated' examples are shown below:

AppResources.es.resx(스페인어)AppResources.es.resx (Spanish)

<data name="AddButton" xml:space="preserve">
    <value>Escribir un artículo</value>
    <comment>this string appears on a button to add a new item to the list</comment>
</data>

AppResources.ja.resx(일본어)AppResources.ja.resx (Japanese)

<data name="AddButton" xml:space="preserve">
    <value>新しい項目を追加</value>
    <comment>this string appears on a button to add a new item to the list</comment>
</data>

AppResources.pt-BR.resx(브라질 포르투갈어)AppResources.pt-BR.resx (Brazilian Portuguese)

<data name="AddButton" xml:space="preserve">
    <value>adicionar novo item</value>
    <comment>this string appears on a button to add a new item to the list</comment>
</data>

value 요소만 변환기에서 업데이트되어야 합니다. comment는 변환되지 않습니다.Only the value element needs to be updated by the translator - the comment is not intended to be translated. 유의: &lt;, &gt;&amp;가 포함된 <, >, &과 같이 예약된 문자를 이스케이프하기 위해 XML 파일을 편집하는 경우 및 value 또는 해당 문자가 comment에 표시되는 경우입니다.Remember: when editing XML files to escape reserved characters like <, >, & with &lt;, &gt;, and &amp; if they appear in the value or comment.

코드의 리소스 사용Using Resources in Code

RESX 리소스 파일의 문자열은 AppResources 클래스를 사용하여 사용자 인터페이스 코드에서 사용할 수 있습니다.Strings in the RESX resource files will be available to use in your user interface code using the AppResources class. RESX 파일에서 각 문자열에 할당된 name은 아래에 표시된 대로 Xamarin.Forms 코드에서 참조할 수 있는 해당 클래스의 속성이 됩니다.The name assigned to each string in the RESX file becomes a property on that class which can be referenced in Xamarin.Forms code as shown below:

var myLabel = new Label ();
var myEntry = new Entry ();
var myButton = new Button ();
// populate UI with translated text values from resources
myLabel.Text = AppResources.NotesLabel;
myEntry.Placeholder = AppResources.NotesPlaceholder;
myButton.Text = AppResources.AddButton;

텍스트가 하드 코딩되기보다는 리소스에서 로드되기 때문에 앱을 여러 언어로 변환할 수 있는 것을 제외하고 iOS, Android 및 UWP(유니버설 Windows 플랫폼)의 사용자 인터페이스가 예상대로 렌더링됩니다.The user interface on iOS, Android, and the Universal Windows Platform (UWP) renders as you'd expect, except now it's possible to translate the app into multiple languages because the text is being loaded from a resource rather than being hard-coded. 변환에 앞서 각 플랫폼에서 UI를 보여주는 스크린샷은 다음과 같습니다.Here is a screenshot showing the UI on each platform prior to translation:

문제 해결Troubleshooting

특정 언어 테스트Testing a Specific Language

다른 문화권을 신속하게 테스트하려는 경우 특히 개발 중에 다른 언어로 시뮬레이터 또는 디바이스를 전환하는 것은 까다로울 수 있습니다.It can be tricky to switch the simulator or a device to different languages, particularly during development when you want to test different cultures quickly.

이 코드 조각에 표시된 것처럼 Culture를 설정하여 특정 언어를 강제로 로드할 수 있습니다.You can force a specific language to be loaded by setting the Culture as shown in this code snippet:

// force a specific culture, useful for quick testing
AppResources.Culture =  new CultureInfo("fr-FR");

이 방법(AppResources 클래스에서 직접 문화권 설정)은 앱 내부에서(디바이스의 로캘을 사용하지 않고) 언어 선택기를 구현하는 데 사용될 수 있습니다.This approach – setting the culture directly on the AppResources class – can also be used to implement a language-selector inside your app (rather than using the device's locale).

포함 리소스 로드Loading Embedded Resources

다음 코드 조각은 포함된 리소스(예: RESX 파일)를 사용하여 문제를 디버깅 하려 할 때 유용합니다.The following code snippet is useful when trying to debug issues with embedded resources (such as RESX files). 앱(앱 수명 주기 초반)에 이 코드를 추가하면 전체 리소스 식별자가 표시되며 어셈블리에 포함된 모든 리소스가 나열됩니다.Add this code to your app (early in the app lifecycle) and it will list all the resources embedded in the assembly, showing the full resource identifier:

using System.Reflection;
// ...
// NOTE: use for debugging, not in released app code!
var assembly = typeof(EmbeddedImages).GetTypeInfo().Assembly; // "EmbeddedImages" should be a class in your app
foreach (var res in assembly.GetManifestResourceNames())
{
    System.Diagnostics.Debug.WriteLine("found resource: " + res);
}

AppResources.Designer.cs 파일(약 33번 줄)에서 전체 리소스 관리자 이름이 아래 코드와 비슷하게In the AppResources.Designer.cs file (around line 33), the full resource manager name is specified (eg. 지정됩니다(예: "UsingResxLocalization.Resx.AppResources")."UsingResxLocalization.Resx.AppResources") similar to the code below:

System.Resources.ResourceManager temp =
        new System.Resources.ResourceManager(
                "UsingResxLocalization.Resx.AppResources",
                typeof(AppResources).GetTypeInfo().Assembly);

위에 표시된 디버그 코드의 결과에 대한 애플리케이션 출력을 검사하여 리소스가 올바로 나열됐는지 확인합니다(예: "UsingResxLocalization.Resx.AppResources").Check the Application Output for the results of the debug code shown above, to confirm the correct resources are listed (ie. "UsingResxLocalization.Resx.AppResources").

그렇지 않은 경우, AppResources 클래스는 해당 리소스를 로드할 수 없습니다.If not, the AppResources class will be unable to load its resources. 리소스를 찾을 수 없는 문제를 해결하려면 다음을 확인합니다.Check the following to resolve issues where the resources cannot be found:

  • 프로젝트에 대한 기본 네임스페이스는 AppResources.Designer.cs 파일의 루트 네임스페이스와 일치합니다.The default namespace for the project matches the root namespace in the AppResources.Designer.cs file.
  • AppResources.resx 파일이 하위 디렉터리에 있는 경우 하위 디렉터리 이름은 네임스페이스 리소스 식별자에 속해야 합니다.If the AppResources.resx file is located in a subdirectory, the subdirectory name should be part of the namespace and part of the resource identifier.
  • AppResources.resx 파일에는 빌드 작업: EmbeddedResource가 있습니다.The AppResources.resx file has Build Action: EmbeddedResource.
  • 프로젝트 옵션 > 소스 코드 > .NET 명명 정책 > Visual Studio 스타일 리소스 이름 사용을 선택합니다.The Project Options > Source Code > .NET Naming Policies > Use Visual Studio-style resources names is ticked. 그러나 앱 전체에서 업데이트되어야 할 RESX 리소스를 참조할 때 사용된 네임스페이스를 선호하는 경우 선택을 취소할 수 있습니다.You can untick this if you prefer, however the namespaces used when referencing your RESX resources will need to updated throughout the app.

DEBUG 모드(Android 전용)에서 작동하지 않습니다.Doesn't work in DEBUG mode (Android only)

변환된 문자열이 Android가 빌드한 RELEASE에서는 작동하지만 디버깅 중에는 작동하지 않는 경우 Android 프로젝트를 마우스 오른쪽 단추로 클릭하고 옵션 > 빌드 > Android 빌드를 선택하고 빠른 어셈블리 배포가 선택되지 않도록 해야 합니다.If the translated strings are working in your RELEASE Android builds but not while debugging, right-click on the Android Project and select Options > Build > Android Build and ensure that the Fast assembly deployment is NOT ticked. 이 옵션은 리소스를 로드할 때 문제가 발생하므로 지역화된 애플리케이션을 테스트하는 경우 사용해서는 안 됩니다.This option causes problems with loading resources and should not be used if you are testing localized apps.

올바른 언어 표시Displaying the Correct Language

지금까지 실제로 번역이 나타나게 하는 방법이 아닌, 번역을 제공할 수 있도록 코드를 작성하는 방법을 살펴봤습니다.So far we've examined how to write code so that translations can be provided, but not how to actually make them appear. Xamarin.Forms 코드는 .NET의 리소스를 활용하여 올바른 언어 번역을 로드할 수 있습니다. 그러나 사용자가 선택한 언어를 확인하려면 각 플랫폼에서 운영 체제를 쿼리해야 합니다.Xamarin.Forms code can take advantage of .NET's resources to load the correct language translations, but we need to query the operating system on each platform to determine which language the user has selected.

일부 플랫폼별 코드는 사용자의 언어 기본 설정을 가져와야 하므로 종속성 서비스를 사용하여 해당 정보를 Xamarin.Forms 앱에서 노출하고 각 플랫폼에서 구현합니다.Because some platform-specific code is required to obtain the user's language preference, use a dependency service to expose that information in the Xamarin.Forms app and implement it for each platform.

먼저 아래 코드와 비슷한 사용자의 기본 설정된 문화권을 노출하려면 인터페이스를 정의합니다.First, define an interface to expose the user's preferred culture, similar to the code below:

public interface ILocalize
{
    CultureInfo GetCurrentCultureInfo ();
    void SetLocale (CultureInfo ci);
}

다음으로 Xamarin.Forms App 클래스에서 DependencyService를 사용하여 인터페이스를 호출하고 RESX 리소스 문화권을 올바른 값으로 설정합니다.Second, use the DependencyService in the Xamarin.Forms App class to call the interface and set our RESX resources culture to the correct value. 리소스 프레임워크가 해당 플랫폼에서 선택한 언어를 자동으로 인식하므로 유니버설 Windows 플랫폼의 값을 수동으로 설정할 필요가 없습니다.Notice that we don't need to manually set this value for the Universal Windows Platform, since the resources framework automatically recognizes the selected language on those platforms.

if (Device.RuntimePlatform == Device.iOS || Device.RuntimePlatform == Device.Android)
{
    var ci = DependencyService.Get<ILocalize>().GetCurrentCultureInfo();
    Resx.AppResources.Culture = ci; // set the RESX for resource localization
    DependencyService.Get<ILocalize>().SetLocale(ci); // set the Thread for locale-aware methods
}

Culture 리소스는 올바른 언어 문자열을 사용하도록 애플리케이션이 처음 로드될 때 설정해야 합니다.The resource Culture needs to be set when the application first loads so that the correct language strings are used. 사용자가 앱이 실행되는 동안 해당 언어 기본 설정을 업데이트하는 경우 iOS 또는 Android에서 발생하는 플랫폼별 이벤트에 따라 이 값을 선택적으로 업데이트할 수 있습니다.You may optionally update this value according to platform-specific events that may be raised on iOS or Android if the user updates their language preferences while the app is running.

ILocalize 인터페이스에 대한 구현이 아래의 플랫폼별 코드 섹션에 표시됩니다.The implementations for the ILocalize interface are shown in the Platform-specific Code section below. 이러한 구현은 이 PlatformCulture 도우미 클래스를 활용합니다.These implementations take advantage of this PlatformCulture helper class:

public class PlatformCulture
{
    public PlatformCulture (string platformCultureString)
    {
        if (String.IsNullOrEmpty(platformCultureString))
        {
            throw new ArgumentException("Expected culture identifier", "platformCultureString"); // in C# 6 use nameof(platformCultureString)
        }
        PlatformString = platformCultureString.Replace("_", "-"); // .NET expects dash, not underscore
        var dashIndex = PlatformString.IndexOf("-", StringComparison.Ordinal);
        if (dashIndex > 0)
        {
            var parts = PlatformString.Split('-');
            LanguageCode = parts[0];
            LocaleCode = parts[1];
        }
        else
        {
            LanguageCode = PlatformString;
            LocaleCode = "";
        }
    }
    public string PlatformString { get; private set; }
    public string LanguageCode { get; private set; }
    public string LocaleCode { get; private set; }
    public override string ToString()
    {
        return PlatformString;
    }
}

플랫폼별 코드Platform-Specific Code

iOS, Android 및 UWP 모두가 조금 다르게 이 정보를 노출하므로 표시할 언어를 검색하는 코드는 플랫폼 특정적이어야 합니다.The code to detect which language to display must be platform-specific because iOS, Android, and UWP all expose this information in slightly different ways. ILocalize 종속성 서비스에 대한 코드는 추가 플랫폼별 요구 사항과 함께 플랫폼에 대해 다음과 같이 제공되어 지역화된 텍스트가 올바로 렌더링되었는지 확인합니다.The code for the ILocalize dependency service is provided below for each platform, along with additional platform-specific requirements to ensure localized text is rendered correctly.

플랫폼별 코드는 사용자가 .NET의 CultureInfo 클래스에서 지원되지 않는 로캘 식별자를 구성하도록 운영 체제에서 허용하는 사례도 처리해야 합니다.The platform-specific code must also handle cases where the operating system allows the user to configure a locale identifier that is not supported by .NET's CultureInfo class. 이러한 경우 사용자 지정 코드가 작성되어 지원되지 않는 로캘을 검색하고 최상의 .NET 호환 가능한 로캘을 대체해야 합니다.In these cases custom code must be written to detect unsupported locales and substitute the best .NET-compatible locale.

iOS 애플리케이션 프로젝트iOS Application Project

iOS 사용자는 날짜 및 시간 형식의 문화권에서 개별적으로 자신의 기본 설정 언어를 선택합니다.iOS users select their preferred language separately from date and time formatting culture. Xamarin.Forms 앱을 지역화하는 올바른 리소스를 로드하려면 첫 번째 요소에 대한 NSLocale.PreferredLanguages 배열을 쿼리해야 합니다.To load the correct resources to localize a Xamarin.Forms app we just need to query the NSLocale.PreferredLanguages array for the first element.

ILocalize 종속성 서비스의 다음 구현을 iOS 애플리케이션 프로젝트에 배치해야 합니다.The following implementation of the ILocalize dependency service should be placed in the iOS application project. iOS는 대시(.NET 표준 표현) 대신 밑줄을 사용하므로 코드는 CultureInfo 클래스를 인스턴스화하기 전에 해당 밑줄을 교체합니다.Because iOS uses underscores instead of dashes (which is the .NET standard representation) the code replaces the underscore before instantiating the CultureInfo class:

[assembly:Dependency(typeof(UsingResxLocalization.iOS.Localize))]

namespace UsingResxLocalization.iOS
{
    public class Localize : UsingResxLocalization.ILocalize
    {
        public void SetLocale (CultureInfo ci)
        {
            Thread.CurrentThread.CurrentCulture = ci;
            Thread.CurrentThread.CurrentUICulture = ci;
        }

        public CultureInfo GetCurrentCultureInfo ()
        {
            var netLanguage = "en";
            if (NSLocale.PreferredLanguages.Length > 0)
            {
                var pref = NSLocale.PreferredLanguages [0];
                netLanguage = iOSToDotnetLanguage(pref);
            }
            // this gets called a lot - try/catch can be expensive so consider caching or something
            System.Globalization.CultureInfo ci = null;
            try
            {
                ci = new System.Globalization.CultureInfo(netLanguage);
            }
            catch (CultureNotFoundException e1)
            {
                // iOS locale not valid .NET culture (eg. "en-ES" : English in Spain)
                // fallback to first characters, in this case "en"
                try
                {
                    var fallback = ToDotnetFallbackLanguage(new PlatformCulture(netLanguage));
                    ci = new System.Globalization.CultureInfo(fallback);
                }
                catch (CultureNotFoundException e2)
                {
                    // iOS language not valid .NET culture, falling back to English
                    ci = new System.Globalization.CultureInfo("en");
                }
            }
            return ci;
        }

        string iOSToDotnetLanguage(string iOSLanguage)
        {
            // .NET cultures don't support underscores
            string netLanguage = iOSLanguage.Replace("_", "-");

            //certain languages need to be converted to CultureInfo equivalent
            switch (iOSLanguage)
            {
                case "ms-MY":   // "Malaysian (Malaysia)" not supported .NET culture
                case "ms-SG":    // "Malaysian (Singapore)" not supported .NET culture
                    netLanguage = "ms"; // closest supported
                    break;
                case "gsw-CH":  // "Schwiizertüütsch (Swiss German)" not supported .NET culture
                    netLanguage = "de-CH"; // closest supported
                    break;
                // add more application-specific cases here (if required)
                // ONLY use cultures that have been tested and known to work
            }
            return netLanguage;
        }

        string ToDotnetFallbackLanguage (PlatformCulture platCulture)
        {
            var netLanguage = platCulture.LanguageCode; // use the first part of the identifier (two chars, usually);
            switch (platCulture.LanguageCode)
            {
                case "pt":
                    netLanguage = "pt-PT"; // fallback to Portuguese (Portugal)
                    break;
                case "gsw":
                    netLanguage = "de-CH"; // equivalent to German (Switzerland) for this app
                    break;
                // add more application-specific cases here (if required)
                // ONLY use cultures that have been tested and known to work
            }
            return netLanguage;
        }
    }
}

참고

GetCurrentCultureInfo 메서드의 try/catch 블록은 일반적으로 로캘 식별자에서 사용된 대체(fallback) 동작을 모방하며(정확한 일치가 발견되지 않는 경우), 언어를 기반으로 근접한 일치(로캘에서 첫 번째 블록의 문자)를 찾습니다.The try/catch blocks in the GetCurrentCultureInfo method mimic the fallback behavior typically used with locale specifiers – if the exact match is not found, look for a close match based just on the language (first block of characters in the locale).

Xamarin.Forms의 경우 일부 로캘은 iOS에서 유효하지만 .NET의 유효한 CultureInfo 값과 일치하지 않으며 위의 코드는 이 값을 처리하려고 합니다.In the case of Xamarin.Forms, some locales are valid in iOS but do not correspond to a valid CultureInfo in .NET, and the code above attempts to handle this.

예를 들어 iOS 설정 > 일반 언어 & 지역 화면을 선택하면 사용자는 휴대폰 언어영어로, 지역스페인으로 설정할 수 있습니다. 그 결과로 "en-ES"의 로캘 문자열이 됩니다.For example, the iOS Settings > General Language & Region screen allows you to set your phone Language to English but the Region to Spain, which results in a locale string of "en-ES". CultureInfo 생성이 실패하는 경우 표시 언어를 선택하려면 코드는 처음 두 글자만 사용하는 것으로 대체할 수 있습니다.When the CultureInfo creation fails, the code falls back to using just the first two letters to select the display language.

개발자는 지원되는 해당 언어에 필요한 특정 사례를 처리하려면 iOSToDotnetLanguageToDotnetFallbackLanguage 메서드를 수정해야 합니다.Developers should modify the iOSToDotnetLanguage and ToDotnetFallbackLanguage methods to handle specific cases required for their supported languages.

Picker 컨트롤의 완료 단추와 같이 iOS에서 자동으로 변환되는 일부 시스템에서 정의된 사용자 인터페이스 요소가 있습니다.There are some system-defined user-interface elements that are automatically translated by iOS, such as the Done button on the Picker control. iOS에서 이러한 요소를 강제로 변환하려면 Info.plist 파일에서 지원하는 언어를 표시해야 합니다.To force iOS to translate these elements we need to indicate which languages we support in the Info.plist file. 여기에 표시된 것처럼 Info.plist > 소스를 통해 이러한 값을 추가할 수 있습니다.You can add these values via Info.plist > Source as shown here:

Info.plist의 지역화 키Localization keys in Info.plist

또는 XML 편집기에서 Info.plist 파일을 열고 값을 직접 편집합니다.Alternatively, open the Info.plist file in an XML editor and edit the values directly:

<key>CFBundleLocalizations</key>
<array>
    <string>de</string>
    <string>es</string>
    <string>fr</string>
    <string>ja</string>
    <string>pt</string> <!-- Brazil -->
    <string>pt-PT</string> <!-- Portugal -->
    <string>ru</string>
    <string>zh-Hans</string>
    <string>zh-Hant</string>
</array>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>

종속성 서비스를 구현하고 Info.plist를 업데이트하면 iOS 앱은 지역화된 텍스트를 표시할 수 있습니다.Once you've implemented the dependency service and updated Info.plist, the iOS app will be able to display localized text.

참고

Apple에서는 기대했던 것과 약간 다르게 포르투갈어를 처리합니다.Note that Apple treats Portuguese slightly differently than you'd expect. 해당 docs: "브라질에서 사용되는 포르투갈어에 대한 언어 ID로 pt를 사용하고 포르투갈에서 사용되는 포르투갈어에 대한 언어 ID로 pt-PT를 사용합니다".From their docs: "use pt as the language ID for Portuguese as it is used in Brazil and pt-PT as the language ID for Portuguese as it is used in Portugal". 즉 포르투갈어가 비표준 로캘에서 선택되는 경우 iOS에서 대체 언어는 코드가 이 동작(예: 위의 ToDotnetFallbackLanguage)을 변경하도록 작성되지 않는 경우 브라질 포르투갈어입니다.This means when Portuguese language is chosen in a non-standard locale, the fallback language will be Brazilian Portuguese on iOS, unless code is written to change this behavior (such as the ToDotnetFallbackLanguage above).

iOS 지역화에 대한 자세한 내용은 iOS 지역화를 참조하세요.For more information about iOS Localization, see iOS Localization.

Android 애플리케이션 프로젝트Android Application Project

Android는 Java.Util.Locale.Default를 통해 현재 선택된 로캘을 노출하고 다음 코드로 교체되는 대시 대신 밑줄 구분 기호를 사용합니다.Android exposes the currently selected locale via Java.Util.Locale.Default, and also uses an underscore separator instead of a dash (which is replaced by the following code). Android 애플리케이션 프로젝트에 이 종속성 서비스 구현을 추가합니다.Add this dependency service implementation to the Android application project:

[assembly:Dependency(typeof(UsingResxLocalization.Android.Localize))]

namespace UsingResxLocalization.Android
{
    public class Localize : UsingResxLocalization.ILocalize
    {
        public void SetLocale(CultureInfo ci)
        {
            Thread.CurrentThread.CurrentCulture = ci;
            Thread.CurrentThread.CurrentUICulture = ci;
        }
        public CultureInfo GetCurrentCultureInfo()
        {
            var netLanguage = "en";
            var androidLocale = Java.Util.Locale.Default;
            netLanguage = AndroidToDotnetLanguage(androidLocale.ToString().Replace("_", "-"));
            // this gets called a lot - try/catch can be expensive so consider caching or something
            System.Globalization.CultureInfo ci = null;
            try
            {
                ci = new System.Globalization.CultureInfo(netLanguage);
            }
            catch (CultureNotFoundException e1)
            {
                // iOS locale not valid .NET culture (eg. "en-ES" : English in Spain)
                // fallback to first characters, in this case "en"
                try
                {
                    var fallback = ToDotnetFallbackLanguage(new PlatformCulture(netLanguage));
                    ci = new System.Globalization.CultureInfo(fallback);
                }
                catch (CultureNotFoundException e2)
                {
                    // iOS language not valid .NET culture, falling back to English
                    ci = new System.Globalization.CultureInfo("en");
                }
            }
            return ci;
        }
        string AndroidToDotnetLanguage(string androidLanguage)
        {
            var netLanguage = androidLanguage;
            //certain languages need to be converted to CultureInfo equivalent
            switch (androidLanguage)
            {
                case "ms-BN":   // "Malaysian (Brunei)" not supported .NET culture
                case "ms-MY":   // "Malaysian (Malaysia)" not supported .NET culture
                case "ms-SG":   // "Malaysian (Singapore)" not supported .NET culture
                    netLanguage = "ms"; // closest supported
                    break;
                case "in-ID":  // "Indonesian (Indonesia)" has different code in  .NET
                    netLanguage = "id-ID"; // correct code for .NET
                    break;
                case "gsw-CH":  // "Schwiizertüütsch (Swiss German)" not supported .NET culture
                    netLanguage = "de-CH"; // closest supported
                    break;
                    // add more application-specific cases here (if required)
                    // ONLY use cultures that have been tested and known to work
            }
            return netLanguage;
        }
        string ToDotnetFallbackLanguage(PlatformCulture platCulture)
        {
            var netLanguage = platCulture.LanguageCode; // use the first part of the identifier (two chars, usually);
            switch (platCulture.LanguageCode)
            {
                case "gsw":
                    netLanguage = "de-CH"; // equivalent to German (Switzerland) for this app
                    break;
                    // add more application-specific cases here (if required)
                    // ONLY use cultures that have been tested and known to work
            }
            return netLanguage;
        }
    }
}

참고

GetCurrentCultureInfo 메서드의 try/catch 블록은 일반적으로 로캘 식별자에서 사용된 대체(fallback) 동작을 모방하며(정확한 일치가 발견되지 않는 경우), 언어를 기반으로 근접한 일치(로캘에서 첫 번째 블록의 문자)를 찾습니다.The try/catch blocks in the GetCurrentCultureInfo method mimic the fallback behavior typically used with locale specifiers – if the exact match is not found, look for a close match based just on the language (first block of characters in the locale).

Xamarin.Forms의 경우 일부 로캘은 Android에서 유효하지만 .NET의 유효한 CultureInfo 값과 일치하지 않으며 위의 코드는 이 값을 처리하려고 합니다.In the case of Xamarin.Forms, some locales are valid in Android but do not correspond to a valid CultureInfo in .NET, and the code above attempts to handle this.

개발자는 지원되는 해당 언어에 필요한 특정 사례를 처리하려면 iOSToDotnetLanguageToDotnetFallbackLanguage 메서드를 수정해야 합니다.Developers should modify the iOSToDotnetLanguage and ToDotnetFallbackLanguage methods to handle specific cases required for their supported languages.

이 코드가 Android 애플리케이션 프로젝트에 추가되면 변환된 문자열이 자동으로 표시됩니다.Once this code has been added to the Android application project, it will be able to automatically display translated strings.

참고

경고: 변환된 문자열이 Android가 빌드한 RELEASE에서는 작동하지만 디버깅 중에는 작동하지 않는 경우 Android 프로젝트를 마우스 오른쪽 단추로 클릭하고 옵션 > 빌드 > Android 빌드를 선택하고 빠른 어셈블리 배포가 선택되지 않도록 해야 합니다.WARNING: If the translated strings are working in your RELEASE Android builds but not while debugging, right-click on the Android Project and select Options > Build > Android Build and ensure that the Fast assembly deployment is NOT ticked. 이 옵션은 리소스를 로드할 때 문제가 발생하므로 지역화된 애플리케이션을 테스트하는 경우 사용해서는 안 됩니다.This option causes problems with loading resources and should not be used if you are testing localized apps.

Android 지역화에 대한 자세한 내용은 Android 지역화를 참조하세요.For more information about Android localization, see Android Localization.

UWPUniversal Windows Platform

UWP(유니버설 Windows 플랫폼) 프로젝트에는 종속 서비스가 필요하지 않습니다.Universal Windows Platform (UWP) projects do not require the dependency service. 대신 이 플랫폼에서 자동으로 리소스의 문화권을 올바르게 설정합니다.Instead, this platform automatically sets the resource's culture correctly.

AssemblyInfo.csAssemblyInfo.cs

.NET Standard 라이브러리 프로젝트에서 속성 노드를 확장하고 AssemblyInfo.cs 파일을 두 번 클릭합니다.Expand the Properties node in the .NET Standard library project and double-click on the AssemblyInfo.cs file. 중립 리소스 어셈블리 언어를 영어로 설정하려면 파일에 다음 줄을 추가합니다.Add the following line to the file to set the neutral resources assembly language to English:

[assembly: NeutralResourcesLanguage("en")]

이러면 앱의 기본 문화권에 대해 리소스 관리자에게 알리므로, 하나의 영어 로캘에서 앱을 실행하는 경우 언어 중립 RESX 파일(AppResources.resx)에서 정의된 문자열이 표시되는지 확인합니다.This informs the resource manager of the app's default culture, therefore ensuring that the strings defined in the language neutral RESX file (AppResources.resx) will be displayed when the app is running in one the English locales.

예제Example

위에 표시된 대로 플랫폼별 프로젝트를 업데이트하고 변환된 RESX 파일을 사용하여 앱을 다시 컴파일한 후 각 앱에서 업데이트된 변환을 사용할 수 있습니다.After updating the platform-specific projects as shown above and recompiling the app with translated RESX files, updated translations will be available in each app. 중국어(간체)로 번역된 샘플 코드의 스크린샷은 다음과 같습니다.Here is a screenshot from the sample code translated into Simplified Chinese:

UWP 지역화에 대한 자세한 내용은 UWP 지역화를 참조하세요.For more information about UWP localization, see UWP Localization.

XAML 지역화Localizing XAML

XAML에서 Xamarin.Forms 사용자 인터페이스를 빌드하는 경우 태그는 XML에 문자열이 직접 포함된 이 인터페이스와 비슷해 보입니다.When building a Xamarin.Forms user interface in XAML the markup would look similar to this, with strings embedded directly in the XML:

<Label Text="Notes:" />
<Entry Placeholder="eg. buy milk" />
<Button Text="Add to list" />

이상적으로 XAML에서 직접 사용자 인터페이스 컨트롤을 변환할 수 있으며, 태그 확장을 만들어 수행할 수 있습니다.Ideally, we could translate user interface controls directly in the XAML, which we can do by creating a markup extension. XAML에 RESX 리소스를 노출하는 태그 확장에 대한 코드는 다음과 같습니다.The code for a markup extension that exposes the RESX resources to XAML is shown below. 이 클래스는 Xamarin.Forms 공용 코드 (XAML 페이지와 함께)에 추가해야 합니다.This class should be added to the Xamarin.Forms common code (along with the XAML pages):

using System;
using System.Globalization;
using System.Reflection;
using System.Resources;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;

namespace UsingResxLocalization
{
    // You exclude the 'Extension' suffix when using in XAML
    [ContentProperty("Text")]
    public class TranslateExtension : IMarkupExtension
    {
        readonly CultureInfo ci = null;
        const string ResourceId = "UsingResxLocalization.Resx.AppResources";

        static readonly Lazy<ResourceManager> ResMgr = new Lazy<ResourceManager>(
            () => new ResourceManager(ResourceId, IntrospectionExtensions.GetTypeInfo(typeof(TranslateExtension)).Assembly));

        public string Text { get; set; }

        public TranslateExtension()
        {
            if (Device.RuntimePlatform == Device.iOS || Device.RuntimePlatform == Device.Android)
            {
                ci = DependencyService.Get<ILocalize>().GetCurrentCultureInfo();
            }
        }

        public object ProvideValue(IServiceProvider serviceProvider)
        {
            if (Text == null)
                return string.Empty;

            var translation = ResMgr.Value.GetString(Text, ci);
            if (translation == null)
            {
#if DEBUG
                throw new ArgumentException(
                    string.Format("Key '{0}' was not found in resources '{1}' for culture '{2}'.", Text, ResourceId, ci.Name),
                    "Text");
#else
                translation = Text; // HACK: returns the key, which GETS DISPLAYED TO THE USER
#endif
            }
            return translation;
        }
    }
}

다음 글머리 기호는 위의 코드의 중요한 요소를 설명합니다.The following bullets explain the important elements in the code above:

  • 클래스 이름은 TranslateExtension이라고 할 수 있지만 참조할 수 있는 규칙에 따라 태그의 변환으로 명명됩니다.The class is named TranslateExtension, but by convention we can refer to is as Translate in our markup.
  • 클래스는 작동하려면 Xamarin.Forms에서 필요한 IMarkupExtension을 구현합니다.The class implements IMarkupExtension, which is required by Xamarin.Forms for it to work.
  • "UsingResxLocalization.Resx.AppResources"는 RESX 리소스에 대한 리소스 식별자입니다."UsingResxLocalization.Resx.AppResources" is the resource identifier for our RESX resources. 이 식별자는 기본 네임스페이스, 리소스 파일이 있는 폴더 및 기본 RESX 파일로 구성되어 있습니다.It is comprised of our default namespace, the folder where the resource files are located and the default RESX filename.
  • 리소스를 로드하고 정적 ResMgr 필드에서 캐시될 현재 어셈블리를 확인하려면 IntrospectionExtensions.GetTypeInfo(typeof(TranslateExtension)).Assembly)를 사용하여 ResourceManager 클래스를 만듭니다.The ResourceManager class is created using IntrospectionExtensions.GetTypeInfo(typeof(TranslateExtension)).Assembly) to determine the current assembly to load resources from, and cached in the static ResMgr field. ProvideValue 메서드에서 처음 사용될 때까지 해당 생성을 지연하도록 해당 클래스를 Lazy 형식으로 만듭니다.It's created as a Lazy type so that its creation is deferred until it's first used in the ProvideValue method.
  • ci는 종속성 서비스를 사용하여 기본 운영 체제에서 사용자가 선택한 언어를 가져옵니다.ci uses the dependency service to get the user's chosen language from the native operating system.
  • GetString은 리소스 파일에서 실제 변환된 문자열을 검색하는 메서드입니다.GetString is the method that retrieves the actual translated string from the resources files. ILocalize 인터페이스가 해당 플랫폼에서 구현되지 않으므로 유니버설 Windows 플랫폼에서 ci는 null입니다.On the Universal Windows Platform, ci will be null because the ILocalize interface isn't implemented on those platforms. 이 방법은 첫 번째 매개 변수만 사용하여 GetString 메서드를 호출하는 것과 동일합니다.This is equivalent to calling the GetString method with only the first parameter. 대신 리소스 프레임 워크는 로캘을 자동으로 인식하고 적절한 RESX 파일에서 변환된 문자열을 검색합니다.Instead, the resources framework will automatically recognize the locale and will retrieve the translated string from the appropriate RESX file.
  • 예외(DEBUG 모드 전용에서)를 throw하여 누락된 리소스를 디버깅하도록 오류 처리가 포함되었습니다.Error handling has been included to help debug missing resources by throwing an exception (in DEBUG mode only).

다음 XAML 코드 조각에서는 태그 확장을 사용하는 방법을 보여줍니다.The following XAML snippet shows how to use the markup extension. 작동하게 하려면 두 단계가 있습니다.There are two steps to make it work:

  1. 루트 노드에서 사용자 지정 xmlns:i18n 네임스페이스를 선언합니다.Declare the custom xmlns:i18n namespace in the root node. namespaceassembly는 동일하지만 사용자 프로젝트에서 다를 수 있는 예제의 경우 프로젝트 설정과 정확히 일치해야 합니다.The namespace and assembly must match the project settings exactly - in this example they are identical but could be different in your project.
  2. 일반적으로 Translate 태그 확장을 호출하는 텍스트가 포함되는 특성에서 {Binding} 구문을 사용합니다.Use {Binding} syntax on attributes that would normally contain text to call the Translate markup extension. 리소스 키는 유일한 필수 매개 변수입니다.The resource key is the only required parameter.
<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
        xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
        x:Class="UsingResxLocalization.FirstPageXaml"
        xmlns:i18n="clr-namespace:UsingResxLocalization;assembly=UsingResxLocalization">
    <StackLayout Padding="0, 20, 0, 0">
        <Label Text="{i18n:Translate NotesLabel}" />
        <Entry Placeholder="{i18n:Translate NotesPlaceholder}" />
        <Button Text="{i18n:Translate AddButton}" />
    </StackLayout>
</ContentPage>

다음과 같은 보다 자세한 정보 표시 구문은 태그 확장에도 유효합니다.The following more verbose syntax is also valid for the markup extension:

<Button Text="{i18n:TranslateExtension Text=AddButton}" />

플랫폼별 요소 지역화Localizing Platform-Specific Elements

Xamarin.Forms 코드로 사용자 인터페이스의 변환을 처리할 수 있지만 각 플랫폼별 프로젝트에서 수행해야 하는 몇 가지 요소가 있습니다.Although we can handle the translation of the user interface in Xamarin.Forms code, there are some elements that must be done in each platform-specific project. 이 섹션에서는 지역화 방법을 살펴봅니다.This section will cover how to localize:

  • Application NameApplication Name
  • 이미지Images

샘플 프로젝트에는 다음과 같이 C#에서 참조하는 flag.png라는 지역화된 이미지가 포함됩니다.The sample project includes a localized image called flag.png, which is referenced in C# as follows:

var flag = new Image();
switch (Device.RuntimePlatform)
{
    case Device.iOS:
    case Device.Android:
        flag.Source = ImageSource.FromFile("flag.png");
        break;
    case Device.UWP:
        flag.Source = ImageSource.FromFile("Assets/Images/flag.png");
        break;
}

플래그 이미지도 다음과 같이 XAML에서 참조됩니다.The flag image is also referenced in the XAML like this:

<Image>
  <Image.Source>
    <OnPlatform x:TypeArguments="ImageSource">
        <On Platform="iOS, Android" Value="flag.png" />
        <On Platform="UWP" Value="Assets/Images/flag.png" />
    </OnPlatform>
  </Image.Source>
</Image>

아래에 설명된 프로젝트 구조가 구현되는 한 모든 플랫폼은 지역화된 버전의 이미지에 다음과 같은 이미지 참조를 자동으로 확인합니다.All platforms will automatically resolve image references like these to localized versions of the images, as long as the project structures explained below are implemented.

iOS 애플리케이션 프로젝트iOS Application Project

iOS는 지역화 프로젝트 또는 .lproj 디렉터리라는 명명 표준을 사용하여 이미지 및 문자열 리소스를 포함합니다.iOS uses a naming standard called Localization Projects or .lproj directories to contain image and string resources. 이러한 디렉터리에는 앱에서 사용되는 지역화된 버전의 이미지 및 앱 이름을 지역화하는 데 사용할 수 있는 InfoPlist.strings 파일도 포함될 수 있습니다.These directories can contain localized versions of images used in the app, and also the InfoPlist.strings file that can be used to localize the app name. iOS 지역화에 대한 자세한 내용은 iOS 지역화를 참조하세요.For more information about iOS Localization, see iOS Localization.

이미지Images

이 스크린샷에서는 언어별 .lproj 디렉터리가 포함된 iOS 샘플 앱을 보여줍니다.This screenshot shows the iOS sample app with language-specific .lproj directories. es.lproj라는 스페인어 디렉터리에는 flag.png뿐만 아니라 지역화된 버전의 기본 이미지도 포함됩니다.The Spanish directory called es.lproj, contains localized versions of the default image, as well as flag.png:

각 언어 디렉터리에는 해당 언어에 맞게 지역화된 flag.png의 복사본이 포함됩니다.Each language directory contains a copy of flag.png, localized for that language. 이미지가 제공되지 않으면 운영 체제의 기본값은 기본 언어 디렉터리의 이미지가 됩니다.If no image is supplied, the operating system will default to the image in the default language directory. Retina 지원의 경우 각 이미지의 @2x@3x 복사본을 제공해야 합니다.For full Retina support, you should supply @2x and @3x copies of each image.

앱 이름App Name

InfoPlist.strings의 내용은 단일 키 값으로서 앱 이름을 구성합니다.The contents of the InfoPlist.strings is just a single key-value to configure the app name:

"CFBundleDisplayName" = "ResxEspañol";

애플리케이션을 실행하는 경우 앱 이름 및 이미지 모두 지역화됩니다.When the application is run, the app name and the image are both localized:

Android 애플리케이션 프로젝트Android Application Project

Android는 언어 코드 접미사가 있는 다양한 드로어블문자열 디렉터리를 사용하여 지역화된 이미지를 저장하기 위한 다른 체계를 따릅니다.Android follows a different scheme for storing localized images using different drawable and strings directories with a language code suffix. 4글자 로캘 코드가 필요한 경우(예: zh-TW 또는 pt-BR) Android에서는 대시 뒤에/로캘 코드 앞에 r을 추가해야 합니다(예:When a four-letter locale code is required (such as zh-TW or pt-BR), note that Android requires an additional r following the dash/preceding the locale code (eg. zh-rTW 또는 pt-rBR).zh-rTW or pt-rBR). Android 지역화에 대한 자세한 내용은 Android 지역화를 참조하세요.For more information about Android localization, see Android Localization.

이미지Images

이 스크린샷은 일부 지역화된 드로어블 및 문자열을 통해 Android 샘플을 보여줍니다.This screenshot shows the Android sample with a some localized drawables and strings:

Android에서는 중국어 간체 및 번체에 대해 zh-Hans 및 zh-Hant를 사용하지 않고 대신 zh-CN 및 zh-TW와 같은 국가별 코드를 지원합니다.Note that Android does not use zh-Hans and zh-Hant codes for Simplified and Traditional Chinese; instead, it only supports country-specific codes zh-CN and zh-TW.

고밀도 화면에 대한 다른 해상도 이미지를 지원하려면 drawables-es-mdpi, drawables-es-xdpi, drawables-es-xxdpi 등의 -*dpi 접미사가 있는 언어 폴더를 추가로 만듭니다. 자세한 내용은 대체 Android 리소스 제공을 참조하세요.To support different resolution images for high-density screens, create additional language folders with -*dpi suffixes, such as drawables-es-mdpi, drawables-es-xdpi, drawables-es-xxdpi, etc. See Providing Alternative Android Resources for more information.

앱 이름App Name

strings.xml의 내용은 단일 키 값으로서 앱 이름을 구성합니다.The contents of the strings.xml is just a single key-value to configure the app name:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="app_name">ResxEspañol</string>
</resources>

Label이 XML 문자열을 참조하도록 Android 앱 프로젝트에서 MainActivity.cs를 업데이트합니다.Update the MainActivity.cs in the Android app project so that the Label references the strings XML.

[Activity (Label = "@string/app_name", MainLauncher = true,
        ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]

이제 앱은 앱 이름 및 이미지를 지역화합니다.The app now localizes the app name and image. 결과(스페인어)의 스크린샷은 다음과 같습니다.Here's a screenshot of the result (in Spanish):

유니버설 Windows 플랫폼 애플리케이션 프로젝트Universal Windows Platform Application Projects

유니버설 Windows 플랫폼은 이미지 및 앱 이름의 지역화를 간소화하는 리소스 인프라를 소유합니다.The Universal Windows Platform possesses a resource infrastructure that simplifies the localization of images and the app name. UWP 지역화에 대한 자세한 내용은 UWP 지역화를 참조하세요.For more information about UWP localization, see UWP Localization.

이미지Images

다음 스크린샷에 표시된 것과 같이 리소스별 폴더에 배치하여 이미지를 지역화할 수 있습니다.Images can be localized by placing them in a resource-specific folder, as demonstrated in the following screenshot:

런타임 시 Windows 리소스 인프라는 사용자의 로캘에 따라 적절한 이미지를 선택합니다.At runtime the Windows resource infrastructure will select the appropriate image based on the user's locale.

요약Summary

RESX 파일 및 .NET 글로벌화 클래스를 사용하여 Xamarin.Forms 애플리케이션을 지역화할 수 있습니다.Xamarin.Forms applications can be localized using RESX files and .NET globalization classes. 사용자가 선호하는 언어를 검색하기 위한 약간의 플랫폼별 코드를 제외하고는 지역화 작업의 대부분은 공용 코드로 중앙 집중화되어 있습니다.Apart from a small amount of platform-specific code to detect what language the user prefers, most of the localization effort is centralized in the common code.

이미지는 일반적으로 iOS 및 Android 모두에서 제공하는 다중 해상도 지원을 활용하기 위해 플랫폼 특정 방식으로 처리됩니다.Images are generally handled in a platform-specific way to take advantage of the multi-resolution support provided in both iOS and Android.