다음을 통해 공유


ASP.NET Core Blazor 세계화 및 지역화

참고 항목

이 문서의 최신 버전은 아닙니다. 현재 릴리스는 이 문서의 .NET 9 버전을 참조 하세요.

Warning

이 버전의 ASP.NET Core는 더 이상 지원되지 않습니다. 자세한 내용은 .NET 및 .NET Core 지원 정책을 참조 하세요. 현재 릴리스는 이 문서의 .NET 9 버전을 참조 하세요.

Important

이 정보는 상업적으로 출시되기 전에 실질적으로 수정될 수 있는 시험판 제품과 관련이 있습니다. Microsoft는 여기에 제공된 정보에 대해 어떠한 명시적, 또는 묵시적인 보증을 하지 않습니다.

현재 릴리스는 이 문서의 .NET 9 버전을 참조 하세요.

이 문서에서는 다양한 문화권 및 언어의 사용자를 위해 세계화되고 지역화된 콘텐츠를 렌더링하는 방법을 설명합니다.

세계화 및 지역화

세계화를 위해 Blazor는 숫자 및 날짜 서식을 제공합니다. 지역화를 위해 Blazor는 .NET 리소스 시스템을 사용하여 콘텐츠를 렌더링합니다.

제한된 ASP.NET Core 지역화 기능 모음이 지원됩니다.

IStringLocalizerIStringLocalizer<T> 앱에서 Blazor 지원됩니다.

지원되지 않음:IHtmlLocalizerIViewLocalizer데이터 주석 지역화는 핵심 MVC 기능을 Blazor되지 않습니다.

이 문서에서는 다음을 기준으로 Blazor의 세계화 및 지역화 기능을 사용하는 방법을 설명합니다.

  • Accept-Language 헤더 - 브라우저 설정에서 사용자의 언어 기본 설정에 따라 브라우저에 의해 설정됩니다.
  • Accept-Language 헤더의 값을 기준으로 하지 않는 앱에서 설정한 문화권. 이러한 설정은 모든 사용자에 대해 정적이거나 앱 논리에 따라 동적일 수 있습니다. 설정이 사용자의 기본 설정을 기준으로 하는 경우 일반적으로 나중에 방문할 때 다시 로드할 수 있게 저장됩니다.

추가 일반 정보는 다음 리소스를 참조하세요.

‘언어’와 ‘문화권’이라는 용어는 세계화와 지역화 개념을 처리할 때 서로 바꿔서 사용되는 경우가 많습니다.

이 문서에서 언어는 브라우저 설정에서 사용자가 선택한 항목을 나타냅니다. 사용자의 언어 선택은 브라우저 요청의 Accept-Language 헤더로 제출됩니다. 브라우저 설정은 일반적으로 UI에서 "언어"라는 단어를 사용합니다.

문화권은 .NET 및 Blazor API의 멤버와 관련이 있습니다. 예를 들어, 사용자의 요청에는 사용자의 관점에서 Accept-Language를 지정하는 헤더가 포함될 수 있지만, 앱은 궁극적으로 사용자가 요청한 언어의 CurrentCulture("culture") 속성을 설정합니다. API는 일반적으로 멤버 이름에 "culture"라는 단어를 사용합니다.

이 문서의 지침에서는 접근성 도구에서 사용하는 페이지의 HTML 언어 특성()<html lang="...">을 설정하지 않습니다. 태그 특성 lang 또는 <html> JavaScript에 언어 document.documentElement.lang 를 할당하여 값을 정적으로 설정할 수 있습니다. interop을 사용하여 값을document.documentElement.langJS동적으로 설정할 수 있습니다.

참고 항목

이 문서의 코드 예제에서는 NRT(nullable 참조 형식) 및 .NET 컴파일러 null 상태 정적 분석을 채택합니다. 이 분석은 .NET 6 이상의 ASP.NET Core에서 지원됩니다. ASP.NET Core 5.0 이하를 대상으로 하는 경우 문서의 예제에서 null 형식 지정(?)을 제거합니다.

세계화

@bind 특성 지시문은 형식을 적용하고 앱에서 지원하는 사용자의 첫 번째 기본 설정 언어를 기준으로 표시 값을 구문 분석합니다. @bind@bind:culture 매개 변수를 지원하여 값을 구문 분석하고 서식을 지정하기 위한 System.Globalization.CultureInfo을 제공합니다.

현재 문화권은 System.Globalization.CultureInfo.CurrentCulture 속성에서 액세스할 수 있습니다.

CultureInfo.InvariantCulture는 다음 필드 형식(<input type="{TYPE}" />)에 사용됩니다. 여기서 {TYPE} 자리 표시자는 형식입니다.

  • date
  • number

이전 필드 형식:

  • 적절한 브라우저 기반 서식 지정 규칙을 사용하여 표시됩니다.
  • 자유 형식 텍스트를 포함할 수 없습니다.
  • 브라우저의 구현에 따라 사용자 상호 작용 특성을 제공합니다.

Blazor 는 현재 문화권에서 값을 렌더링하는 기본 제공 지원을 제공합니다. 따라서 문화권과 @bind:culture 필드 형식을 사용할 때는 문화권을 datenumber 지정하지 않는 것이 좋습니다.

다음 필드 형식에는 특정 서식 요구 사항이 있으며 모든 주요 브라우저에서 지원되지 않으므로 다음에서 지원 Blazor되지 않습니다.

  • datetime-local
  • month
  • week

이전 형식의 현재 브라우저 지원에 대한 자세한 내용은 Can I use를 참조하세요.

.NET 세계화 및 ICU(유니코드용 국제 구성 요소) 지원(Blazor WebAssembly)

Blazor WebAssembly 에서는 축소된 세계화 API와 ICU(International Components for Unicode) 로캘 집합을 사용합니다. 자세한 내용은 .NET 세계화 및 ICU: WebAssembly의 ICU를 참조하세요.

앱의 로캘을 제어하기 위해 사용자 지정 ICU 데이터 파일을 로드하려면 WASM 세계화 Icu를 참조하세요. 현재 사용자 지정 ICU 데이터 파일을 수동으로 빌드해야 합니다. 파일을 만드는 프로세스를 용이하게 하는 .NET 도구는 2025년 11월에 .NET 10에 대해 계획되어 있습니다.

Blazor WebAssembly 에서는 축소된 세계화 API와 ICU(International Components for Unicode) 로캘 집합을 사용합니다. 자세한 내용은 .NET 세계화 및 ICU: WebAssembly의 ICU를 참조하세요.

앱에서 로캘의 사용자 지정 하위 집합을 Blazor WebAssembly 로드하는 것은 .NET 8 이상에서 지원됩니다. 자세한 내용은 이 문서의 8.0 이상 버전에 대한 이 섹션에 액세스하세요.

고정 세계화

이 섹션은 클라이언트 쪽 Blazor 시나리오에만 적용됩니다.

앱에 지역화가 필요하지 않은 경우 일반적으로 미국 영어(en-US)를 기준으로 하는 고정 문화권을 지원하도록 앱을 구성합니다. 고정 세계화를 사용하면 앱의 다운로드 크기가 줄어들고 앱 시작 속도가 빨라집니다. 앱의 프로젝트 파일(InvariantGlobalization)에서 true 속성을 .csproj로 설정합니다.

<PropertyGroup>
  <InvariantGlobalization>true</InvariantGlobalization>
</PropertyGroup>

또는 다음 방식으로 고정 세계화를 구성합니다.

  • runtimeconfig.json의 경우

    {
      "runtimeOptions": {
        "configProperties": {
          "System.Globalization.Invariant": true
        }
      }
    }
    
  • 환경 변수 사용:

    • 키: DOTNET_SYSTEM_GLOBALIZATION_INVARIANT
    • 값: true 또는 1

자세한 내용은 세계화를 위한 런타임 구성 옵션(.NET 설명서)을 참조하세요.

표준 시간대 정보

이 섹션은 클라이언트 쪽 Blazor 시나리오에만 적용됩니다.

고정 세계화를 채택하면 지역화되지 않은 표준 시간대 이름만 사용됩니다. 앱의 다운로드 크기를 줄이고 앱 시작 속도를 단축하는 표준 시간대 코드 및 데이터를 트리밍하려면 앱의 프로젝트 파일에 값 <InvariantTimezone> 이 포함된 MSBuild 속성을 적용 true 합니다.

<PropertyGroup>
  <InvariantTimezone>true</InvariantTimezone>
</PropertyGroup>

참고 항목

<BlazorEnableTimeZoneSupport> 이전 <InvariantTimezone> 설정을 재정의합니다. 설정을 제거하는 <BlazorEnableTimeZoneSupport> 것이 좋습니다.

정확한 표준 시간대 정보를 위해 데이터 파일이 포함되어 있습니다. 앱에 이 기능이 필요하지 않은 경우 MSBuild 속성을 앱의 프로젝트 파일로 설정 <BlazorEnableTimeZoneSupport> 하여 사용하지 않도록 설정하는 것이 false 좋습니다.

<PropertyGroup>
  <BlazorEnableTimeZoneSupport>false</BlazorEnableTimeZoneSupport>
</PropertyGroup>

데모 구성 요소

다음 CultureExample1 구성 요소는 이 문서에서 다루는 Blazor 세계화 및 지역화 개념을 보여 주는 데 사용할 수 있습니다.

CultureExample1.razor:

@page "/culture-example-1"
@using System.Globalization

<h1>Culture Example 1</h1>

<ul>
    <li><b>CurrentCulture</b>: @CultureInfo.CurrentCulture</li>
    <li><b>CurrentUICulture</b>: @CultureInfo.CurrentUICulture</li>
</ul>

<h2>Rendered values</h2>

<ul>
    <li><b>Date</b>: @dt</li>
    <li><b>Number</b>: @number.ToString("N2")</li>
</ul>

<h2><code>&lt;input&gt;</code> elements that don't set a <code>type</code></h2>

<p>
    The following <code>&lt;input&gt;</code> elements use
    <code>CultureInfo.CurrentCulture</code>.
</p>

<ul>
    <li><label><b>Date:</b> <input @bind="dt" /></label></li>
    <li><label><b>Number:</b> <input @bind="number" /></label></li>
</ul>

<h2><code>&lt;input&gt;</code> elements that set a <code>type</code></h2>

<p>
    The following <code>&lt;input&gt;</code> elements use
    <code>CultureInfo.InvariantCulture</code>.
</p>

<ul>
    <li><label><b>Date:</b> <input type="date" @bind="dt" /></label></li>
    <li><label><b>Number:</b> <input type="number" @bind="number" /></label></li>
</ul>

@code {
    private DateTime dt = DateTime.Now;
    private double number = 1999.69;
}

앞의 예제(N2)에 나오는 숫자 문자열 형식(.ToString("N2"))은 표준 .NET 숫자 형식 지정자입니다. N2 형식은 모든 숫자 형식에 대해 지원되며, 그룹 구분 기호를 포함하고, 소수점 이하 두 자리까지 렌더링됩니다.

필요에 따라 구성 요소에 대한 구성 요소(NavMenu)의 탐색에 NavMenu.razor 메뉴 항목을 추가합니다CultureExample1.

Accept-Language 헤더에서 문화권을 동적으로 설정

앱에 Microsoft.Extensions.Localization 패키지를 추가합니다.

Accept-Language 헤더는 브라우저에서 설정되며 브라우저 설정의 사용자 언어 기본 설정에 의해 제어됩니다. 브라우저 설정에서 사용자는 기본 설정 순서대로 하나 이상의 기본 설정 언어를 지정합니다. 기본 설정 순서는 브라우저에서 헤더의 각 언어에 대한 품질 값(q, 0-1)을 설정하는 데 사용됩니다. 다음 예제에서는 영어 또는 영어 미국 기본 설정으로 영어, 영어 및 코스타리카 스페인어를 미국 지정합니다.

Accept-Language: en-US,en; q=0.9,es-CR; q=0.8

앱의 문화권은 앱의 지원되는 문화권과 일치하는 첫 번째로 요청된 언어를 일치시켜 설정됩니다.

클라이언트 쪽 개발에서 클라이언트 쪽 앱의 프로젝트 파일(BlazorWebAssemblyLoadAllGlobalizationData)에 속성을 true 설정합니다.csproj.

<PropertyGroup>
  <BlazorWebAssemblyLoadAllGlobalizationData>true</BlazorWebAssemblyLoadAllGlobalizationData>
</PropertyGroup>

클라이언트 쪽 개발에서는 헤더에서 Accept-Language 문화권을 동적으로 설정하는 것은 지원되지 않습니다.

참고 항목

앱 사양에서 지원되는 문화권을 명시적 목록 으로 제한해야 하는 경우 이 문서의 사용자 기본 설정 섹션을 통해 클라이언트 쪽 문화권을 동적으로 설정합니다.

앱은 지역화 미들웨어를 사용하여 지역화됩니다. AddLocalization을 사용하여 앱에 지역화 서비스를 추가합니다.

서비스가 등록된 파일에 다음 줄을 Program 추가합니다.

builder.Services.AddLocalization();

서버 쪽 개발에서 요청 문화권을 확인할 수 있는 미들웨어 앞에 앱의 지원되는 문화권을 지정합니다. 일반적으로 요청 지역화 미들웨어를 호출 MapRazorComponents하기 직전에 배치합니다. 다음 예제에서는 영어 및 코스타리카 스페인어를 미국 지원되는 문화권을 구성합니다.

서버 쪽 개발에서 라우팅 미들웨어(UseRouting)가 처리 파이프라인에 추가된 직후 앱의 지원되는 문화권을 지정합니다. 다음 예제에서는 영어 및 코스타리카 스페인어를 미국 지원되는 문화권을 구성합니다.

app.UseRequestLocalization(new RequestLocalizationOptions()
    .AddSupportedCultures(new[] { "en-US", "es-CR" })
    .AddSupportedUICultures(new[] { "en-US", "es-CR" }));

파일의 Program 미들웨어 파이프라인에서 지역화 미들웨어를 정렬하는 방법에 대한 자세한 내용은 ASP.NET Core 미들웨어를 참조하세요.

CultureExample1 섹션에 표시되는 구성 요소를 사용하여 세계화의 작동 방식을 알아봅니다. 미국 영어(en-US)를 사용하여 요청을 실행합니다. 브라우저의 언어 설정에서 코스타리카 스페인어(es-CR)로 전환합니다. 웹 페이지를 다시 요청합니다.

참고 항목

일부 브라우저에서는 요청 및 브라우저의 자체 UI 설정 모두에 대해 강제로 기본 언어 설정을 사용하도록 합니다. 이렇게 하면 모든 설정 UI 화면이 읽을 수 없는 언어로 표시될 수 있으므로 언어를 이해할 수 있는 언어로 변경하는 것이 어려울 수 있습니다. Opera와 같은 브라우저에서는 웹 페이지 요청에 대한 기본 언어를 설정할 수 있지만 브라우저의 설정 UI를 사용 중인 언어로 그대로 둘 수 있으므로 테스트에 적합합니다.

문화권이 미국 영어(en-US)인 경우 렌더링된 구성 요소는 월/일 날짜 서식(6/7), 12시간 형식(AM/PM), 쉼표를 숫자 구분 기호로, 점을 소숫점으로 사용합니다(1,999.69).

  • 날짜: 6/7/2021 6:45:22 AM
  • 숫자: 1,999.69

문화권이 코스타리카 스페인어(es-CR)인 경우 렌더링된 구성 요소는 일/월 날짜 서식(7/6), 24시간 시간 및 10진수 값(1.999,69)에 대한 쉼표가 있는 숫자의 마침표 구분 기호를 사용합니다.

  • 날짜: 7/6/2021 6:49:38
  • 숫자: 1.999,69

정적으로 클라이언트 쪽 문화권 설정

앱의 프로젝트 파일(BlazorWebAssemblyLoadAllGlobalizationData)에서 true 속성을 .csproj로 설정합니다.

<PropertyGroup>
  <BlazorWebAssemblyLoadAllGlobalizationData>true</BlazorWebAssemblyLoadAllGlobalizationData>
</PropertyGroup>

클라이언트 쪽 렌더링에 대한 IL(중간 언어) 링커 구성은 명시적으로 요청된 로캘을 제외하고 국제화 정보를 제거합니다. 자세한 내용은 ASP.NET Core Blazor용 링커 구성을 참조하세요.

Blazor가 applicationCultureBlazor 시작 옵션으로 시작될 때 JavaScript에서 앱의 문화권을 설정할 수 있습니다. 다음 예제에서는 미국 영어(en-US) 문화권을 사용하여 앱을 시작하도록 구성합니다.

's 태그Blazor자동 시작을 방지 <script> 합니다.

<script src="{BLAZOR SCRIPT}" autostart="false"></script>

앞의 예제 {BLAZOR SCRIPT} 에서 자리 표시자는 스크립트 경로 및 파일 이름입니다 Blazor . 스크립트의 위치는 ASP.NET Core Blazor 프로젝트 구조를 참조하세요.

'의 <script> 태그 뒤Blazor와 닫는 <script> 태그 앞에 다음 </body> 블록을 추가합니다.

Blazor Web App:

<script>
  Blazor.start({
    webAssembly: {
      applicationCulture: 'en-US'
    }
  });
</script>

독립 실행형 Blazor WebAssembly:

<script>
  Blazor.start({
    applicationCulture: 'en-US'
  });
</script>

applicationCulture의 값은 BCP-47 언어 태그 형식을 준수해야 합니다. Blazor 시작에 대한 자세한 내용은 ASP.NET Core Blazor 시작을 참조하세요.

문화권 Blazor의 시작 옵션을 설정하는 또 다른 방법은 C# 코드에서 문화권을 설정하는 것입니다. CultureInfo.DefaultThreadCurrentCulture 파일에서 CultureInfo.DefaultThreadCurrentUICulture 동일한 문화권으로 설정합니다Program.

System.Globalization 파일에 네임스페이스를 추가합니다.Program

using System.Globalization;

WebAssemblyHostBuilder을 빌드하고 실행하는 줄 앞에 문화권 설정을 추가합니다(await builder.Build().RunAsync();).

CultureInfo.DefaultThreadCurrentCulture = new CultureInfo("en-US");
CultureInfo.DefaultThreadCurrentUICulture = new CultureInfo("en-US");

참고 항목

현재 앱은 Blazor WebAssembly 에 따라 리소스만 로드합니다 DefaultThreadCurrentCulture. 자세한 내용은 WASM이 현재 문화권에만 의존(현재 UI 문화권은 존중되지 않음)(Blazor#56824)dotnet/aspnetcore 하세요.

CultureExample1 섹션에 표시되는 구성 요소를 사용하여 세계화의 작동 방식을 알아봅니다. 미국 영어(en-US)를 사용하여 요청을 실행합니다. 브라우저의 언어 설정에서 코스타리카 스페인어(es-CR)로 전환합니다. 웹 페이지를 다시 요청합니다. 요청된 언어가 코스타리카 스페인어인 경우 앱의 문화는 영어(en-US)미국 유지됩니다.

정적으로 서버 쪽 문화권 설정

서버 쪽 앱은 지역화 미들웨어를 사용하여 지역화됩니다. AddLocalization을 사용하여 앱에 지역화 서비스를 추가합니다.

Program 파일에서:

builder.Services.AddLocalization();

요청 문화권을 확인할 수 있는 Program 미들웨어 앞에 파일의 정적 문화권을 지정합니다. 일반적으로 요청 지역화 미들웨어를 바로 앞에 MapRazorComponents배치합니다. 다음 예제에서는 미국 영어를 구성합니다.

라우팅 미들웨어(Program)가 처리 파이프라인에 UseRouting 추가된 직후 파일에 정적 문화권을 지정합니다. 다음 예제에서는 미국 영어를 구성합니다.

app.UseRequestLocalization("en-US");

UseRequestLocalization의 문화권 값은 BCP-47 언어 태그 형식을 준수해야 합니다.

파일의 Program 미들웨어 파이프라인에서 지역화 미들웨어를 정렬하는 방법에 대한 자세한 내용은 ASP.NET Core 미들웨어를 참조하세요.

서버 쪽 앱은 지역화 미들웨어를 사용하여 지역화됩니다. AddLocalization을 사용하여 앱에 지역화 서비스를 추가합니다.

Startup.ConfigureServices(Startup.cs)에서:

services.AddLocalization();

라우팅 미들웨어가 처리 파이프라인에 추가된 직후에 Startup.Configure(Startup.cs)에서 정적 문화권을 지정합니다. 다음 예제에서는 미국 영어를 구성합니다.

app.UseRequestLocalization("en-US");

UseRequestLocalization의 문화권 값은 BCP-47 언어 태그 형식을 준수해야 합니다.

Startup.Configure의 미들웨어 파이프라인에서 지역화 미들웨어를 정렬하는 방법에 대한 내용은 ASP.NET Core 미들웨어를 참조하세요.

CultureExample1 섹션에 표시되는 구성 요소를 사용하여 세계화의 작동 방식을 알아봅니다. 미국 영어(en-US)를 사용하여 요청을 실행합니다. 브라우저의 언어 설정에서 코스타리카 스페인어(es-CR)로 전환합니다. 웹 페이지를 다시 요청합니다. 요청된 언어가 코스타리카 스페인어인 경우 앱의 문화는 영어(en-US)미국 유지됩니다.

사용자 기본 설정에 따라 클라이언트 쪽 문화권을 동적으로 설정

앱이 사용자의 기본 설정을 저장할 수 있는 위치의 예로는 브라우저 로컬 스토리지(클라이언트 쪽 시나리오에 공통), 지역화 또는 데이터베이스(서버 쪽 시나리오에 공통) 또는 외부 데이터베이스에 연결되고 웹 APIcookie됩니다. 다음 예제에서는 브라우저 로컬 스토리지를 사용하는 방법을 보여 줍니다.

앱에 Microsoft.Extensions.Localization 패키지를 추가합니다.

참고 항목

.NET 앱에 패키지를 추가하는 방법에 대한 지침은 패키지 사용 워크플로에서 패키지 설치 및 관리의 문서(NuGet 설명서)를 참조하세요. NuGet.org에서 올바른 패키지 버전을 확인합니다.

프로젝트 파일에서 BlazorWebAssemblyLoadAllGlobalizationData 속성을 true로 설정합니다.

<PropertyGroup>
  <BlazorWebAssemblyLoadAllGlobalizationData>true</BlazorWebAssemblyLoadAllGlobalizationData>
</PropertyGroup>

클라이언트 쪽 렌더링에 대한 앱의 문화권은 프레임워크의 API를 Blazor 사용하여 설정됩니다. 사용자의 문화권 선택은 브라우저 로컬 스토리지에 유지할 수 있습니다.

태그 뒤<script> 함수를 제공하여 브라우저 로컬 스토리지를 사용하여 사용자의 문화권 선택을 가져와서 설정합니다.

<script>
  window.blazorCulture = {
    get: () => window.localStorage['BlazorCulture'],
    set: (value) => window.localStorage['BlazorCulture'] = value
  };
</script>

참고 항목

앞의 예제에서는 전역 함수를 사용하여 클라이언트를 오염합니다. 프로덕션 앱에서의 더 나은 접근 방식은 JavaScript 모듈에서의 JavaScript 격리를 참조하세요.

파일의 맨 위에 네임스페이스를 System.Globalization 추가합니다Microsoft.JSInterop.Program

using System.Globalization;
using Microsoft.JSInterop;

다음 줄을 제거합니다.

- await builder.Build().RunAsync();

앞의 줄을 다음 코드로 바꿉니다. 이 코드는 Blazor을(를) 사용하여 AddLocalization의 지역화 서비스를 앱의 서비스 컬렉션에 추가하고 JSinterop을 사용하여 JS으(로) 호출하고 로컬 스토리지에서 사용자의 문화권 선택을 검색합니다. 로컬 스토리지에 사용자에 대한 문화권이 없는 경우 코드는 기본값인 미국 영어(en-US)를 설정합니다.

builder.Services.AddLocalization();

var host = builder.Build();

const string defaultCulture = "en-US";

var js = host.Services.GetRequiredService<IJSRuntime>();
var result = await js.InvokeAsync<string>("blazorCulture.get");
var culture = CultureInfo.GetCultureInfo(result ?? defaultCulture);

if (result == null)
{
    await js.InvokeVoidAsync("blazorCulture.set", defaultCulture);
}

CultureInfo.DefaultThreadCurrentCulture = culture;
CultureInfo.DefaultThreadCurrentUICulture = culture;

await host.RunAsync();

참고 항목

현재 앱은 Blazor WebAssembly 에 따라 리소스만 로드합니다 DefaultThreadCurrentCulture. 자세한 내용은 WASM이 현재 문화권에만 의존(현재 UI 문화권은 존중되지 않음)(Blazor#56824)dotnet/aspnetcore 하세요.

다음 CultureSelector 구성 요소는 다음 작업을 수행하는 방법을 보여줍니다.

  • JS interop을 통해 사용자의 문화권 선택을 브라우저 로컬 스토리지로 설정합니다.
  • 요청한(forceLoad: true) 구성 요소를 다시 로드합니다. 이 구성 요소는 업데이트된 문화권을 사용합니다.

CultureSelector.razor:

@using System.Globalization
@inject IJSRuntime JS
@inject NavigationManager Navigation

<p>
    <label>
        Select your locale:
        <select @bind="selectedCulture" @bind:after="ApplySelectedCultureAsync">
            @foreach (var culture in supportedCultures)
            {
                <option value="@culture">@culture.DisplayName</option>
            }
        </select>
    </label>
</p>

@code
{
    private CultureInfo[] supportedCultures = new[]
    {
        new CultureInfo("en-US"),
        new CultureInfo("es-CR"),
    };

    private CultureInfo? selectedCulture;

    protected override void OnInitialized()
    {
        selectedCulture = CultureInfo.CurrentCulture;
    }

    private async Task ApplySelectedCultureAsync()
    {
        if (CultureInfo.CurrentCulture != selectedCulture)
        {
            await JS.InvokeVoidAsync("blazorCulture.set", selectedCulture!.Name);

            Navigation.NavigateTo(Navigation.Uri, forceLoad: true);
        }
    }
}
@using System.Globalization
@inject IJSRuntime JS
@inject NavigationManager Navigation

<p>
    <label>
        Select your locale:
        <select value="@selectedCulture" @onchange="HandleSelectedCultureChanged">
            @foreach (var culture in supportedCultures)
            {
                <option value="@culture">@culture.DisplayName</option>
            }
        </select>
    </label>
</p>

@code
{
    private CultureInfo[] supportedCultures = new[]
    {
        new CultureInfo("en-US"),
        new CultureInfo("es-CR"),
    };

    private CultureInfo? selectedCulture;

    protected override void OnInitialized()
    {
        selectedCulture = CultureInfo.CurrentCulture;
    }

    private async Task HandleSelectedCultureChanged(ChangeEventArgs args)
    {
        selectedCulture = CultureInfo.GetCultureInfo((string)args.Value!);

        if (CultureInfo.CurrentCulture != selectedCulture)
        {
            await JS.InvokeVoidAsync("blazorCulture.set", selectedCulture!.Name);

            Navigation.NavigateTo(Navigation.Uri, forceLoad: true);
        }
    }
}

참고 항목

IJSInProcessRuntime에 대한 자세한 내용은 ASP.NET Core의 .NET 메서드에서 JavaScript 함수 호출Blazor을 참조하세요.

구성 요소의 닫는 </main> 태그(MainLayout)에 MainLayout.razor 구성 요소를 추가합니다CultureSelector.

<article class="bottom-row px-4">
    <CultureSelector />
</article>

CultureExample1 섹션에 표시되는 구성 요소를 사용하여 이전 예제의 작동 방식을 알아봅니다.

사용자 기본 설정에 따라 서버 쪽 문화권을 동적으로 설정

앱이 사용자의 기본 설정을 저장할 수 있는 위치의 예로는 브라우저 로컬 스토리지(클라이언트 쪽 시나리오에 공통), 지역화 또는 데이터베이스(서버 쪽 시나리오에 공통) 또는 외부 데이터베이스에 연결되고 웹 APIcookie됩니다. 다음 예제에서는 지역화 cookie를 사용하는 방법을 보여 줍니다.

참고 항목

다음 예제에서는 앱이 구성 요소의 구성 요소 에 대화형 SSR(대화형 서버 쪽 렌더링)을 지정하여 전역App한다고 가정합니다(Components/App.razor).

<Routes @rendermode="InteractiveServer" />

앱이 페이지별/구성 요소 대화형 작업을 채택하는 경우 이 섹션의 끝에 있는 설명에 따라 예제 구성 요소의 렌더링 모드를 수정합니다.

앱에 Microsoft.Extensions.Localization 패키지를 추가합니다.

참고 항목

.NET 앱에 패키지를 추가하는 방법에 대한 지침은 패키지 사용 워크플로에서 패키지 설치 및 관리의 문서(NuGet 설명서)를 참조하세요. NuGet.org에서 올바른 패키지 버전을 확인합니다.

서버 쪽 앱은 지역화 미들웨어를 사용하여 지역화됩니다. AddLocalization을 사용하여 앱에 지역화 서비스를 추가합니다.

Program 파일에서:

builder.Services.AddLocalization();

RequestLocalizationOptions을 통해 앱의 기본 문화권 및 지원되는 문화권을 설정합니다.

요청 처리 파이프라인에서 호출하기 MapRazorComponents 전에 다음 코드를 배치합니다.

라우팅 미들웨어(UseRouting)가 요청 처리 파이프라인에 추가된 후 다음 코드를 배치합니다.

var supportedCultures = new[] { "en-US", "es-CR" };
var localizationOptions = new RequestLocalizationOptions()
    .SetDefaultCulture(supportedCultures[0])
    .AddSupportedCultures(supportedCultures)
    .AddSupportedUICultures(supportedCultures);

app.UseRequestLocalization(localizationOptions);

미들웨어 파이프라인에서 지역화 미들웨어를 정렬하는 방법에 대한 자세한 내용은 ASP.NET Core 미들웨어를 참조하세요.

다음 예제에서는 지역화 미들웨어에서 읽을 수 있는 cookie의 현재 문화권을 설정하는 방법을 보여 줍니다.

구성 요소에는 다음 네임스페이 App 스가 필요합니다.

구성 요소 파일의 맨 위에 다음을 App 추가합니다(Components/App.razor).

@using System.Globalization
@using Microsoft.AspNetCore.Localization

구성 요소 파일의 @code 맨 아래에 다음 App 블록을 추가합니다.

@code {
    [CascadingParameter]
    public HttpContext? HttpContext { get; set; }

    protected override void OnInitialized()
    {
        HttpContext?.Response.Cookies.Append(
            CookieRequestCultureProvider.DefaultCookieName,
            CookieRequestCultureProvider.MakeCookieValue(
                new RequestCulture(
                    CultureInfo.CurrentCulture,
                    CultureInfo.CurrentUICulture)));
    }
}

Pages/_Host.cshtml 파일을 수정하려면 다음 네임스페이스가 필요합니다.

파일에 다음을 추가합니다.

@using System.Globalization
@using Microsoft.AspNetCore.Localization
@{
    this.HttpContext.Response.Cookies.Append(
        CookieRequestCultureProvider.DefaultCookieName,
        CookieRequestCultureProvider.MakeCookieValue(
            new RequestCulture(
                CultureInfo.CurrentCulture,
                CultureInfo.CurrentUICulture)));
}

미들웨어 파이프라인에서 지역화 미들웨어를 정렬하는 방법에 대한 자세한 내용은 ASP.NET Core 미들웨어를 참조하세요.

앱이 컨트롤러 작업을 처리하도록 구성되지 않은 경우 다음과 같습니다.

  • 파일의 서비스 컬렉션을 AddControllers 호출 Program 하여 MVC 서비스를 추가합니다.

    builder.Services.AddControllers();
    
  • (Program)를 MapControllers 호출 IEndpointRouteBuilder 하여 파일에 컨트롤러 엔드포인트 라우팅을 app 추가합니다.

    app.MapControllers();
    

사용자가 문화권을 선택하기 위한 UI를 제공하려면 지역화 에서 cookie을 사용합니다. 앱은 컨트롤러에 대한 리디렉션을 통해 사용자가 선택한 문화권을 유지합니다. 컨트롤러는 사용자가 선택한 문화권을 cookie로 설정하고 사용자를 원래 URI로 다시 리디렉션합니다. 이 프로세스는 사용자가 보안 리소스에 액세스하려고 할 때 웹앱에서 발생하는 작업과 비슷합니다. 즉, 사용자는 로그인 페이지로 리디렉션되고 다시 원래 리소스로 리디렉션됩니다.

Controllers/CultureController.cs:

using Microsoft.AspNetCore.Localization;
using Microsoft.AspNetCore.Mvc;

[Route("[controller]/[action]")]
public class CultureController : Controller
{
    public IActionResult Set(string culture, string redirectUri)
    {
        if (culture != null)
        {
            HttpContext.Response.Cookies.Append(
                CookieRequestCultureProvider.DefaultCookieName,
                CookieRequestCultureProvider.MakeCookieValue(
                    new RequestCulture(culture, culture)));
        }

        return LocalRedirect(redirectUri);
    }
}

Warning

LocalRedirect 이전 예제와 같이 작업 결과를 사용하여 열린 리디렉션 공격을 방지합니다. 자세한 내용은 ASP.NET Core에서 오픈 리디렉션 공격 방지를 참조하세요.

다음 CultureSelector 구성 요소는 새 문화권으로 SetCultureController 메서드를 호출하는 방법을 보여줍니다. 구성 요소는 앱 전체에서 사용할 수 있게 Shared 폴더에 배치됩니다.

CultureSelector.razor:

@using System.Globalization
@inject IJSRuntime JS
@inject NavigationManager Navigation

<p>
    <label>
        Select your locale:
        <select @bind="selectedCulture" @bind:after="ApplySelectedCultureAsync">
            @foreach (var culture in supportedCultures)
            {
                <option value="@culture">@culture.DisplayName</option>
            }
        </select>
    </label>
</p>

@code
{
    private CultureInfo[] supportedCultures = new[]
    {
        new CultureInfo("en-US"),
        new CultureInfo("es-CR"),
    };

    private CultureInfo? selectedCulture;

    protected override void OnInitialized()
    {
        selectedCulture = CultureInfo.CurrentCulture;
    }

    private async Task ApplySelectedCultureAsync()
    {
        if (CultureInfo.CurrentCulture != selectedCulture)
        {
            var uri = new Uri(Navigation.Uri)
                .GetComponents(UriComponents.PathAndQuery, UriFormat.Unescaped);
            var cultureEscaped = Uri.EscapeDataString(selectedCulture.Name);
            var uriEscaped = Uri.EscapeDataString(uri);

            Navigation.NavigateTo(
                $"Culture/Set?culture={cultureEscaped}&redirectUri={uriEscaped}",
                forceLoad: true);
        }
    }
}
@using System.Globalization
@inject IJSRuntime JS
@inject NavigationManager Navigation

<p>
    <label>
        Select your locale:
        <select value="@selectedCulture" @onchange="HandleSelectedCultureChanged">
            @foreach (var culture in supportedCultures)
            {
                <option value="@culture">@culture.DisplayName</option>
            }
        </select>
    </label>
</p>

@code
{
    private CultureInfo[] supportedCultures = new[]
    {
        new CultureInfo("en-US"),
        new CultureInfo("es-CR"),
    };

    private CultureInfo? selectedCulture;

    protected override void OnInitialized()
    {
        selectedCulture = CultureInfo.CurrentCulture;
    }

    private async Task HandleSelectedCultureChanged(ChangeEventArgs args)
    {
        selectedCulture = CultureInfo.GetCultureInfo((string)args.Value!);

        if (CultureInfo.CurrentCulture != selectedCulture)
        {
            var uri = new Uri(Navigation.Uri)
                .GetComponents(UriComponents.PathAndQuery, UriFormat.Unescaped);
            var cultureEscaped = Uri.EscapeDataString(selectedCulture.Name);
            var uriEscaped = Uri.EscapeDataString(uri);

            Navigation.NavigateTo(
                $"Culture/Set?culture={cultureEscaped}&redirectUri={uriEscaped}",
                forceLoad: true);
        }
    }
}

구성 요소에 CultureSelector 구성 요소를 추가합니다 MainLayout . 파일의 닫 </main> 는 태그 안에 다음 태그를 배치합니다 Components/Layout/MainLayout.razor .

구성 요소에 CultureSelector 구성 요소를 추가합니다 MainLayout . 파일의 닫 </main> 는 태그 안에 다음 태그를 배치합니다 Shared/MainLayout.razor .

<article class="bottom-row px-4">
    <CultureSelector />
</article>

CultureExample1 섹션에 표시되는 구성 요소를 사용하여 이전 예제의 작동 방식을 알아봅니다.

앞의 예제에서는 앱이 구성 요소의 구성 요소 에 대화형 서버 렌더링 모드를 지정하여 전역Routes한다고 가정합니다(AppComponents/App.razor).

<Routes @rendermode="InteractiveServer" />

앱이 페이지별/구성 요소 대화형 작업을 채택하는 경우 다음을 변경합니다.

  • 구성 요소 파일의 맨 위에 대화형 서버 렌더링 모드를 CultureExample1 추가합니다(Components/Pages/CultureExample1.razor).

    @rendermode InteractiveServer
    
  • 앱의 기본 레이아웃(Components/Layout/MainLayout.razor)에서 대화형 서버 렌더링 모드를 구성 요소에 CultureSelector 적용합니다.

    <CultureSelector @rendermode="InteractiveServer" />
    

사용자 기본 설정에 따라 문화권을 동적으로 Blazor Web App 설정

이 섹션은 Blazor Web AppAuto(Server 및 WebAssembly) 대화형 작업을 채택하는 s에 적용됩니다.

앱이 사용자의 기본 설정을 저장할 수 있는 위치의 예로는 브라우저 로컬 스토리지(클라이언트 쪽 시나리오에 공통), 지역화 또는 데이터베이스(서버 쪽 시나리오에 공통), 로컬 스토리지 및 지역화 cookie (cookie서버 및 WebAssembly 구성 요소 포함) 또는 외부 데이터베이스에 연결되고 웹 APIBlazor Web App됩니다. 다음 예제에서는 CSR(클라이언트 쪽 렌더링) 구성 요소에 브라우저 로컬 스토리지를 사용하고 SSR(서버 쪽 렌더링) 구성 요소에 대한 지역화를 cookie 사용하는 방법을 보여 줍니다.

.Client 프로젝트 업데이트

Microsoft.Extensions.Localization 프로젝트에 패키지를 추가합니다.Client.

참고 항목

.NET 앱에 패키지를 추가하는 방법에 대한 지침은 패키지 사용 워크플로에서 패키지 설치 및 관리의 문서(NuGet 설명서)를 참조하세요. NuGet.org에서 올바른 패키지 버전을 확인합니다.

BlazorWebAssemblyLoadAllGlobalizationData 프로젝트 파일에서 속성을 true 설정합니다..Client

<PropertyGroup>
  <BlazorWebAssemblyLoadAllGlobalizationData>true</BlazorWebAssemblyLoadAllGlobalizationData>
</PropertyGroup>

프로젝트 System.Globalization 파일의 맨 위에 네임스페이 Microsoft.JSInterop 스를 .Client 추가합니다Program.

using System.Globalization;
using Microsoft.JSInterop;

다음 줄을 제거합니다.

- await builder.Build().RunAsync();

앞의 줄을 다음 코드로 바꿉니다. 이 코드는 Blazor을(를) 사용하여 AddLocalization의 지역화 서비스를 앱의 서비스 컬렉션에 추가하고 JSinterop을 사용하여 JS으(로) 호출하고 로컬 스토리지에서 사용자의 문화권 선택을 검색합니다. 로컬 스토리지에 사용자에 대한 문화권이 없는 경우 코드는 기본값인 미국 영어(en-US)를 설정합니다.

builder.Services.AddLocalization();

var host = builder.Build();

const string defaultCulture = "en-US";

var js = host.Services.GetRequiredService<IJSRuntime>();
var result = await js.InvokeAsync<string>("blazorCulture.get");
var culture = CultureInfo.GetCultureInfo(result ?? defaultCulture);

if (result == null)
{
    await js.InvokeVoidAsync("blazorCulture.set", defaultCulture);
}

CultureInfo.DefaultThreadCurrentCulture = culture;
CultureInfo.DefaultThreadCurrentUICulture = culture;

await host.RunAsync();

참고 항목

현재 앱은 Blazor WebAssembly 에 따라 리소스만 로드합니다 DefaultThreadCurrentCulture. 자세한 내용은 WASM이 현재 문화권에만 의존(현재 UI 문화권은 존중되지 않음)(Blazor#56824)dotnet/aspnetcore 하세요.

프로젝트에 다음 CultureSelector 구성 요소를 추가합니다 .Client .

구성 요소는 SSR 또는 CSR 구성 요소에 대해 작동하기 위해 다음 방법을 채택합니다.

  • 클라이언트 쪽 세계화 데이터에는 서버 쪽 세계화 데이터가 제공하는 문화권 표시 이름의 지역화된 텍스트가 포함되어 있으므로 드롭다운 목록에서 사용 가능한 각 문화권의 표시 이름은 사전에서 제공됩니다. 예를 들어 서버 쪽 지역화는 문화권 English (United States) 이 언제 en-US 이고 Ingles () 다른 문화권이 사용되는 경우를 표시합니다. 문화권 표시 이름의 지역화는 세계화와 함께 Blazor WebAssembly 사용할 수 없으므로 로드된 문화권에 대한 클라이언트의 미국 영어 표시 이름만 en-US사용할 수 있습니다. 사용자 지정 사전을 사용하면 구성 요소가 적어도 전체 영어 문화권 이름을 표시할 수 있습니다.
  • 사용자가 문화 JS 권을 변경하면 interop은 로컬 브라우저 스토리지에서 문화권을 설정하고 컨트롤러 작업은 문화권으로 지역화를 cookie 업데이트합니다. 컨트롤러는 서버 프로젝트 업데이트 섹션의 뒷부분에서 앱에 추가됩니다 .

Pages/CultureSelector.razor:

@using System.Globalization
@inject IJSRuntime JS
@inject NavigationManager Navigation

<p>
    <label>
        Select your locale:
        <select @bind="@selectedCulture" @bind:after="ApplySelectedCultureAsync">
            @foreach (var culture in supportedCultures)
            {
                <option value="@culture">@cultureDict[culture.Name]</option>
            }
        </select>
    </label>
</p>

@code
{
    private Dictionary<string, string> cultureDict = 
        new()
        {
            { "en-US", "English (United States)" },
            { "es-CR", "Spanish (Costa Rica)" }
        };

    private CultureInfo[] supportedCultures = new[]
    {
        new CultureInfo("en-US"),
        new CultureInfo("es-CR"),
    };

    private CultureInfo? selectedCulture;

    protected override void OnInitialized()
    {
        selectedCulture = CultureInfo.CurrentCulture;
    }

    private async Task ApplySelectedCultureAsync()
    {
        if (CultureInfo.CurrentCulture != selectedCulture)
        {
            await JS.InvokeVoidAsync("blazorCulture.set", selectedCulture!.Name);

            var uri = new Uri(Navigation.Uri)
                .GetComponents(UriComponents.PathAndQuery, UriFormat.Unescaped);
            var cultureEscaped = Uri.EscapeDataString(selectedCulture.Name);
            var uriEscaped = Uri.EscapeDataString(uri);

            Navigation.NavigateTo(
                $"Culture/Set?culture={cultureEscaped}&redirectUri={uriEscaped}",
                forceLoad: true);
        }
    }
}

참고 항목

IJSInProcessRuntime에 대한 자세한 내용은 ASP.NET Core의 .NET 메서드에서 JavaScript 함수 호출Blazor을 참조하세요.

.Client 프로젝트에서 다음 CultureClient 구성 요소를 배치하여 CSR 구성 요소에 대해 세계화가 작동하는 방식을 연구합니다.

Pages/CultureClient.razor:

@page "/culture-client"
@rendermode InteractiveWebAssembly
@using System.Globalization

<PageTitle>Culture Client</PageTitle>

<h1>Culture Client</h1>

<ul>
    <li><b>CurrentCulture</b>: @CultureInfo.CurrentCulture</li>
    <li><b>CurrentUICulture</b>: @CultureInfo.CurrentUICulture</li>
</ul>

<h2>Rendered values</h2>

<ul>
    <li><b>Date</b>: @dt</li>
    <li><b>Number</b>: @number.ToString("N2")</li>
</ul>

<h2><code>&lt;input&gt;</code> elements that don't set a <code>type</code></h2>

<p>
    The following <code>&lt;input&gt;</code> elements use
    <code>CultureInfo.CurrentCulture</code>.
</p>

<ul>
    <li><label><b>Date:</b> <input @bind="dt" /></label></li>
    <li><label><b>Number:</b> <input @bind="number" /></label></li>
</ul>

<h2><code>&lt;input&gt;</code> elements that set a <code>type</code></h2>

<p>
    The following <code>&lt;input&gt;</code> elements use
    <code>CultureInfo.InvariantCulture</code>.
</p>

<ul>
    <li><label><b>Date:</b> <input type="date" @bind="dt" /></label></li>
    <li><label><b>Number:</b> <input type="number" @bind="number" /></label></li>
</ul>

@code {
    private DateTime dt = DateTime.Now;
    private double number = 1999.69;
}

서버 프로젝트 업데이트

Microsoft.Extensions.Localization 서버 프로젝트에 패키지를 추가합니다.

참고 항목

.NET 앱에 패키지를 추가하는 방법에 대한 지침은 패키지 사용 워크플로에서 패키지 설치 및 관리의 문서(NuGet 설명서)를 참조하세요. NuGet.org에서 올바른 패키지 버전을 확인합니다.

서버 쪽 앱은 지역화 미들웨어를 사용하여 지역화됩니다. AddLocalization을 사용하여 앱에 지역화 서비스를 추가합니다.

서비스가 등록된 서버 프로젝트의 Program 파일에서 다음을 수행합니다.

builder.Services.AddLocalization();

RequestLocalizationOptions을 통해 앱의 기본 문화권 및 지원되는 문화권을 설정합니다.

요청 처리 파이프라인에서 호출하기 MapRazorComponents 전에 다음 코드를 배치합니다.

var supportedCultures = new[] { "en-US", "es-CR" };
var localizationOptions = new RequestLocalizationOptions()
    .SetDefaultCulture(supportedCultures[0])
    .AddSupportedCultures(supportedCultures)
    .AddSupportedUICultures(supportedCultures);

app.UseRequestLocalization(localizationOptions);

다음 예제에서는 지역화 미들웨어에서 읽을 수 있는 cookie의 현재 문화권을 설정하는 방법을 보여 줍니다.

구성 요소에는 다음 네임스페이 App 스가 필요합니다.

구성 요소 파일의 맨 위에 다음을 App 추가합니다(Components/App.razor).

@using System.Globalization
@using Microsoft.AspNetCore.Localization

클라이언트 쪽 렌더링에 대한 앱의 문화권은 프레임워크의 API를 Blazor 사용하여 설정됩니다. 사용자의 문화권 선택은 CSR 구성 요소에 대한 브라우저 로컬 스토리지에 유지할 수 있습니다.

'의 Blazor 태그<script>브라우저 로컬 스토리지를 사용하여 사용자의 문화권 선택을 가져와서 설정하는 함수를 제공합니다JS.

<script>
  window.blazorCulture = {
    get: () => window.localStorage['BlazorCulture'],
    set: (value) => window.localStorage['BlazorCulture'] = value
  };
</script>

참고 항목

앞의 예제에서는 전역 함수를 사용하여 클라이언트를 오염합니다. 프로덕션 앱에서의 더 나은 접근 방식은 JavaScript 모듈에서의 JavaScript 격리를 참조하세요.

구성 요소 파일의 @code 맨 아래에 다음 App 블록을 추가합니다.

@code {
    [CascadingParameter]
    public HttpContext? HttpContext { get; set; }

    protected override void OnInitialized()
    {
        HttpContext?.Response.Cookies.Append(
            CookieRequestCultureProvider.DefaultCookieName,
            CookieRequestCultureProvider.MakeCookieValue(
                new RequestCulture(
                    CultureInfo.CurrentCulture,
                    CultureInfo.CurrentUICulture)));
    }
}

서버 프로젝트가 컨트롤러 작업을 처리하도록 구성되지 않은 경우:

  • 파일의 서비스 컬렉션을 AddControllers 호출 Program 하여 MVC 서비스를 추가합니다.

    builder.Services.AddControllers();
    
  • (Program)를 MapControllers 호출 IEndpointRouteBuilder 하여 파일에 컨트롤러 엔드포인트 라우팅을 app 추가합니다.

    app.MapControllers();
    

사용자가 SSR 구성 요소에 대한 문화권을 선택할 수 있도록 하려면 지역화와 cookie 사용합니다. 앱은 컨트롤러에 대한 리디렉션을 통해 사용자가 선택한 문화권을 유지합니다. 컨트롤러는 사용자가 선택한 문화권을 cookie로 설정하고 사용자를 원래 URI로 다시 리디렉션합니다. 이 프로세스는 사용자가 보안 리소스에 액세스하려고 할 때 웹앱에서 발생하는 작업과 비슷합니다. 즉, 사용자는 로그인 페이지로 리디렉션되고 다시 원래 리소스로 리디렉션됩니다.

Controllers/CultureController.cs:

using Microsoft.AspNetCore.Localization;
using Microsoft.AspNetCore.Mvc;

[Route("[controller]/[action]")]
public class CultureController : Controller
{
    public IActionResult Set(string culture, string redirectUri)
    {
        if (culture != null)
        {
            HttpContext.Response.Cookies.Append(
                CookieRequestCultureProvider.DefaultCookieName,
                CookieRequestCultureProvider.MakeCookieValue(
                    new RequestCulture(culture, culture)));
        }

        return LocalRedirect(redirectUri);
    }
}

Warning

LocalRedirect 이전 예제와 같이 작업 결과를 사용하여 열린 리디렉션 공격을 방지합니다. 자세한 내용은 ASP.NET Core에서 오픈 리디렉션 공격 방지를 참조하세요.

구성 요소에 CultureSelector 구성 요소를 추가합니다 MainLayout . 파일의 닫 </main> 는 태그 안에 다음 태그를 배치합니다 Components/Layout/MainLayout.razor .

<article class="bottom-row px-4">
    <CultureSelector @rendermode="InteractiveAuto" />
</article>

CultureExample1 섹션에 표시되는 구성 요소를 사용하여 이전 예제의 작동 방식을 알아봅니다.

서버 프로젝트에서 다음 CultureServer 구성 요소를 배치하여 SSR 구성 요소에 대해 세계화가 작동하는 방식을 연구합니다.

Components/Pages/CultureServer.razor:

@page "/culture-server"
@rendermode InteractiveServer
@using System.Globalization

<PageTitle>Culture Server</PageTitle>

<h1>Culture Server</h1>

<ul>
    <li><b>CurrentCulture</b>: @CultureInfo.CurrentCulture</li>
    <li><b>CurrentUICulture</b>: @CultureInfo.CurrentUICulture</li>
</ul>

<h2>Rendered values</h2>

<ul>
    <li><b>Date</b>: @dt</li>
    <li><b>Number</b>: @number.ToString("N2")</li>
</ul>

<h2><code>&lt;input&gt;</code> elements that don't set a <code>type</code></h2>

<p>
    The following <code>&lt;input&gt;</code> elements use
    <code>CultureInfo.CurrentCulture</code>.
</p>

<ul>
    <li><label><b>Date:</b> <input @bind="dt" /></label></li>
    <li><label><b>Number:</b> <input @bind="number" /></label></li>
</ul>

<h2><code>&lt;input&gt;</code> elements that set a <code>type</code></h2>

<p>
    The following <code>&lt;input&gt;</code> elements use
    <code>CultureInfo.InvariantCulture</code>.
</p>

<ul>
    <li><label><b>Date:</b> <input type="date" @bind="dt" /></label></li>
    <li><label><b>Number:</b> <input type="number" @bind="number" /></label></li>
</ul>

@code {
    private DateTime dt = DateTime.Now;
    private double number = 1999.69;
}

다음의 CultureClient 사이드바 탐색에 구성 요소와 CultureServer 구성 요소를 모두 추가합니다.Components/Layout/NavMenu.razor

<div class="nav-item px-3">
    <NavLink class="nav-link" href="culture-server">
        <span class="bi bi-list-nested-nav-menu" aria-hidden="true"></span> Culture (Server)
    </NavLink>
</div>
<div class="nav-item px-3">
    <NavLink class="nav-link" href="culture-client">
        <span class="bi bi-list-nested-nav-menu" aria-hidden="true"></span> Culture (Client)
    </NavLink>
</div>

대화형 자동 구성 요소

이 섹션의 지침은 대화형 자동 렌더링 모드를 채택하는 구성 요소에도 작동합니다.

@rendermode InteractiveAuto

지역화

앱에서 동적 문화권 선택을 아직 지원하지 않는 경우 앱에 Microsoft.Extensions.Localization 패키지를 추가합니다.

참고 항목

.NET 앱에 패키지를 추가하는 방법에 대한 지침은 패키지 사용 워크플로에서 패키지 설치 및 관리의 문서(NuGet 설명서)를 참조하세요. NuGet.org에서 올바른 패키지 버전을 확인합니다.

클라이언트 쪽 지역화

앱의 프로젝트 파일(BlazorWebAssemblyLoadAllGlobalizationData)에서 true 속성을 .csproj로 설정합니다.

<PropertyGroup>
  <BlazorWebAssemblyLoadAllGlobalizationData>true</BlazorWebAssemblyLoadAllGlobalizationData>
</PropertyGroup>

파일에서 Program 네임스페이 System.Globalization 스를 파일 맨 위에 추가합니다.

using System.Globalization;

다음을 사용하여 앱의 서비스 컬렉션Blazor에 '의 지역화 서비스를 추가AddLocalization합니다.

builder.Services.AddLocalization();

서버 쪽 지역화

지역화 미들웨어를 사용하여 앱의 문화권을 설정합니다.

앱에서 동적 문화권 선택을 아직 지원하지 않는 경우:

  • AddLocalization을 사용하여 앱에 지역화 서비스를 추가합니다.
  • 파일에서 앱의 기본 문화권과 지원되는 문화권을 Program 지정합니다. 다음 예제에서는 영어 및 코스타리카 스페인어를 미국 지원되는 문화권을 구성합니다.
builder.Services.AddLocalization();

요청 문화권을 확인할 수 있는 미들웨어 앞에 요청 지역화 미들웨어를 배치합니다. 일반적으로 다음을 호출 MapRazorComponents하기 직전에 미들웨어를 배치합니다.

라우팅 미들웨어(UseRouting)가 처리 파이프라인에 추가된 직후:

var supportedCultures = new[] { "en-US", "es-CR" };
var localizationOptions = new RequestLocalizationOptions()
    .SetDefaultCulture(supportedCultures[0])
    .AddSupportedCultures(supportedCultures)
    .AddSupportedUICultures(supportedCultures);

app.UseRequestLocalization(localizationOptions);

미들웨어 파이프라인에서 지역화 미들웨어를 정렬하는 방법에 대한 자세한 내용은 ASP.NET Core 미들웨어를 참조하세요.

  • AddLocalization을 사용하여 앱에 지역화 서비스를 추가합니다.
  • Startup.Configure(Startup.cs)에서 앱의 기본 문화권 및 지원되는 문화권을 설정합니다. 다음 예제에서는 영어 및 코스타리카 스페인어를 미국 지원되는 문화권을 구성합니다.

Startup.ConfigureServices(Startup.cs)에서:

services.AddLocalization();

Startup.Configure 라우팅 미들웨어(UseRouting)가 처리 파이프라인에 추가된 직후:

var supportedCultures = new[] { "en-US", "es-CR" };
var localizationOptions = new RequestLocalizationOptions()
    .SetDefaultCulture(supportedCultures[0])
    .AddSupportedCultures(supportedCultures)
    .AddSupportedUICultures(supportedCultures);

app.UseRequestLocalization(localizationOptions);

Startup.Configure의 미들웨어 파이프라인에서 지역화 미들웨어를 정렬하는 방법에 대한 내용은 ASP.NET Core 미들웨어를 참조하세요.

앱이 사용자의 문화권 설정 저장에 따라 리소스를 지역화해야 하는 경우 지역화 문화권 cookie를 사용합니다. cookie를 사용하면 WebSocket 연결이 문화권을 올바르게 전파할 수 있게 됩니다. 지역화 체계가 URL 경로 또는 쿼리 문자열을 기준으로 하는 경우 스키마는 WebSocket을 사용하지 못할 수 있으므로 문화권이 유지되지 않습니다. 따라서 지역화 문화권 cookie를 사용하는 것이 좋습니다. Razor 섹션을 통해 서버 쪽 문화권을 동적으로 설정합니다.

지역화된 리소스의 예

이 섹션의 지역화된 리소스 예제는 이 문서의 이전 예제에서 작동합니다. 여기서 앱의 지원되는 문화권은 영어(en)를 기본 로케일로 사용하고 스페인어(es)를 사용자가 선택할 수 있거나 브라우저에서 지정되는 대체 로케일로 사용합니다.

각 로캘에 대한 리소스 파일을 만듭니다. 다음 예제에서는 영어와 스페인어로 된 문자열에 대한 리소스를 Greeting 만듭니다.

  • 영어(en): Hello, World!
  • 스페인어(es): ¡Hola, Mundo!

참고 항목

폴더를 마우스 오른쪽 단추로 클릭하고 새 항목Pages리소스 파일 추가를 선택하여 > 추가할>수 있습니다. 파일 이름을 CultureExample2.resx로 지정합니다. 편집기가 나타나면 새 항목에 대한 데이터를 제공합니다. 이름Greeting으로 설정하고 Hello, World!로 설정합니다. 파일을 저장합니다.

Visual Studio Code를 사용하는 경우 Tim Heuer의 ResX Viewer 및 Editor를 설치하는 것이 좋습니다. 폴더에 빈 CultureExample2.resx 파일을 추가합니다 Pages . 확장은 UI에서 파일 관리를 자동으로 수행합니다. 새 리소스 추가 단추를 선택합니다. 지침에 따라 (키), (값) GreetingHello, World! (주석)에 대한 None 항목을 추가합니다. 파일을 저장합니다. 파일을 닫고 다시 열면 리소스를 Greeting 볼 수 있습니다.

Tim Heuer의 ResX Viewer 및 Editor는 Microsoft가 소유하거나 유지 관리하지 않으며 Microsoft 지원 계약 또는 라이선스가 적용되지 않습니다.

다음은 일반적인 리소스 파일을 보여 줍니다. Visual Studio의 Pages 기본 제공 리소스 파일 편집기 또는 리소스 파일을 만들고 편집하기 위한 확장이 있는 Visual Studio Code와 같은 IDE(통합 개발 환경)와 함께 기본 제공 도구를 사용하지 않으려는 경우 리소스 파일을 앱의 폴더에 수동으로 배치할 수 있습니다.

Pages/CultureExample2.resx:

<?xml version="1.0" encoding="utf-8"?>
<root>
  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
    <xsd:element name="root" msdata:IsDataSet="true">
      <xsd:complexType>
        <xsd:choice maxOccurs="unbounded">
          <xsd:element name="metadata">
            <xsd:complexType>
              <xsd:sequence>
                <xsd:element name="value" type="xsd:string" minOccurs="0" />
              </xsd:sequence>
              <xsd:attribute name="name" use="required" type="xsd:string" />
              <xsd:attribute name="type" type="xsd:string" />
              <xsd:attribute name="mimetype" type="xsd:string" />
              <xsd:attribute ref="xml:space" />
            </xsd:complexType>
          </xsd:element>
          <xsd:element name="assembly">
            <xsd:complexType>
              <xsd:attribute name="alias" type="xsd:string" />
              <xsd:attribute name="name" type="xsd:string" />
            </xsd:complexType>
          </xsd:element>
          <xsd:element name="data">
            <xsd:complexType>
              <xsd:sequence>
                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
              </xsd:sequence>
              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
              <xsd:attribute ref="xml:space" />
            </xsd:complexType>
          </xsd:element>
          <xsd:element name="resheader">
            <xsd:complexType>
              <xsd:sequence>
                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
              </xsd:sequence>
              <xsd:attribute name="name" type="xsd:string" use="required" />
            </xsd:complexType>
          </xsd:element>
        </xsd:choice>
      </xsd:complexType>
    </xsd:element>
  </xsd:schema>
  <resheader name="resmimetype">
    <value>text/microsoft-resx</value>
  </resheader>
  <resheader name="version">
    <value>2.0</value>
  </resheader>
  <resheader name="reader">
    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
  </resheader>
  <resheader name="writer">
    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
  </resheader>
  <data name="Greeting" xml:space="preserve">
    <value>Hello, World!</value>
  </data>
</root>

참고 항목

폴더를 마우스 오른쪽 단추로 클릭하고 새 항목Pages리소스 파일 추가를 선택하여 > 추가할>수 있습니다. 파일 이름을 CultureExample2.es.resx로 지정합니다. 편집기가 나타나면 새 항목에 대한 데이터를 제공합니다. 이름Greeting으로 설정하고 ¡Hola, Mundo!로 설정합니다. 파일을 저장합니다.

Visual Studio Code를 사용하는 경우 Tim Heuer의 ResX Viewer 및 Editor를 설치하는 것이 좋습니다. 폴더에 빈 CultureExample2.resx 파일을 추가합니다 Pages . 확장은 UI에서 파일 관리를 자동으로 수행합니다. 새 리소스 추가 단추를 선택합니다. 지침에 따라 (키), (값) Greeting¡Hola, Mundo! (주석)에 대한 None 항목을 추가합니다. 파일을 저장합니다. 파일을 닫고 다시 열면 리소스를 Greeting 볼 수 있습니다.

다음은 일반적인 리소스 파일을 보여 줍니다. Visual Studio의 Pages 기본 제공 리소스 파일 편집기 또는 리소스 파일을 만들고 편집하기 위한 확장이 있는 Visual Studio Code와 같은 IDE(통합 개발 환경)와 함께 기본 제공 도구를 사용하지 않으려는 경우 리소스 파일을 앱의 폴더에 수동으로 배치할 수 있습니다.

Pages/CultureExample2.es.resx:

<?xml version="1.0" encoding="utf-8"?>
<root>
  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
    <xsd:element name="root" msdata:IsDataSet="true">
      <xsd:complexType>
        <xsd:choice maxOccurs="unbounded">
          <xsd:element name="metadata">
            <xsd:complexType>
              <xsd:sequence>
                <xsd:element name="value" type="xsd:string" minOccurs="0" />
              </xsd:sequence>
              <xsd:attribute name="name" use="required" type="xsd:string" />
              <xsd:attribute name="type" type="xsd:string" />
              <xsd:attribute name="mimetype" type="xsd:string" />
              <xsd:attribute ref="xml:space" />
            </xsd:complexType>
          </xsd:element>
          <xsd:element name="assembly">
            <xsd:complexType>
              <xsd:attribute name="alias" type="xsd:string" />
              <xsd:attribute name="name" type="xsd:string" />
            </xsd:complexType>
          </xsd:element>
          <xsd:element name="data">
            <xsd:complexType>
              <xsd:sequence>
                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
              </xsd:sequence>
              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
              <xsd:attribute ref="xml:space" />
            </xsd:complexType>
          </xsd:element>
          <xsd:element name="resheader">
            <xsd:complexType>
              <xsd:sequence>
                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
              </xsd:sequence>
              <xsd:attribute name="name" type="xsd:string" use="required" />
            </xsd:complexType>
          </xsd:element>
        </xsd:choice>
      </xsd:complexType>
    </xsd:element>
  </xsd:schema>
  <resheader name="resmimetype">
    <value>text/microsoft-resx</value>
  </resheader>
  <resheader name="version">
    <value>2.0</value>
  </resheader>
  <resheader name="reader">
    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
  </resheader>
  <resheader name="writer">
    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
  </resheader>
  <data name="Greeting" xml:space="preserve">
    <value>¡Hola, Mundo!</value>
  </data>
</root>

다음 구성 요소는 Greeting와 함께 지역화된 IStringLocalizer<T> 문자열을 사용하는 방법을 보여 줍니다. 다음 예제의 Razor 태그 @Loc["Greeting"]은 이전 리소스 파일에 설정된 Greeting 값으로 키가 지정된 문자열을 지역화합니다.

Microsoft.Extensions.Localization에 대한 네임스페이스를 앱의 _Imports.razor 파일에 추가합니다.

@using Microsoft.Extensions.Localization

CultureExample2.razor:

@page "/culture-example-2"
@using System.Globalization
@inject IStringLocalizer<CultureExample2> Loc

<h1>Culture Example 2</h1>

<ul>
    <li><b>CurrentCulture</b>: @CultureInfo.CurrentCulture</li>
    <li><b>CurrentUICulture</b>: @CultureInfo.CurrentUICulture</li>
</ul>

<h2>Greeting</h2>

<p>
    @Loc["Greeting"]
</p>

<p>
    @greeting
</p>

@code {
    private string? greeting;

    protected override void OnInitialized()
    {
        greeting = Loc["Greeting"];
    }
}

필요에 따라 구성 요소의 CultureExample2 메뉴 항목을 구성 요소(NavMenu)의 탐색에 NavMenu.razor 추가합니다.

WebAssembly 문화권 공급자 참조 원본

Blazor 프레임워크가 지역화를 처리하는 방법을 자세히 이해하려면 ASP.NET Core 참조 원본의 WebAssemblyCultureProvider 클래스를 참조하세요.

참고 항목

.NET 참조 원본의 설명서 링크는 일반적으로 다음 릴리스의 .NET을 위한 현재 개발을 나타내는 리포지토리의 기본 분기를 로드합니다. 특정 릴리스를 위한 태그를 선택하려면 Switch branches or tags(분기 또는 태그 전환) 드롭다운 목록을 사용합니다. 자세한 내용은 ASP.NET Core 소스 코드(dotnet/AspNetCore.Docs #26205)의 버전 태그를 선택하는 방법을 참조하세요.

공유 리소스

지역화 공유 리소스를 만들려면 다음 방법을 채택합니다.

  • Microsoft.Extensions.Localization 패키지가 프로젝트에서 참조되고 있는지 확인합니다.

    참고 항목

    .NET 앱에 패키지를 추가하는 방법에 대한 지침은 패키지 사용 워크플로에서 패키지 설치 및 관리의 문서(NuGet 설명서)를 참조하세요. NuGet.org에서 올바른 패키지 버전을 확인합니다.

  • 프로젝트의 _Imports 파일에 있는 항목을 통해 프로젝트의 Razor 구성 요소에서 Microsoft.Extensions.Localization 네임스페이스를 사용할 수 있는지 확인합니다.

    @using Microsoft.Extensions.Localization
    
  • 임의의 클래스 이름을 사용하여 더미 클래스를 만듭니다. 다음 예제에서

    • 앱은 BlazorSample 네임스페이스를 사용하고 지역화 자산은 BlazorSample.Localization 네임스페이스를 사용합니다.
    • 더미 클래스의 이름은 SharedResource입니다.
    • 클래스 파일은 앱의 루트에 있는 Localization 폴더에 배치됩니다.

    참고 항목

    자동 생성된 디자이너 파일(예: SharedResources.Designer.cs)을 사용하지 마세요. 더미 클래스는 공유 리소스 클래스 역할을 하기 위한 것입니다. 디자이너 파일이 있으면 네임스페이스 충돌이 발생합니다.

    Localization/SharedResource.cs:

    namespace BlazorSample.Localization;
    
    public class SharedResource
    {
    }
    
  • Embedded resource을 사용하여 공유 리소스 파일을 만듭니다. 다음 예제에서

    • 파일은 더미 Localization 클래스(SharedResource)가 있는 Localization/SharedResource.cs 폴더에 배치됩니다.

    • 더미 클래스의 이름과 일치하도록 리소스 파일의 이름을 지정합니다. 다음 예제 파일에는 기본 지역화 파일과 스페인어(es) 지역화를 위한 파일이 포함됩니다.

    • Localization/SharedResource.resx

    • Localization/SharedResource.es.resx

    Warning

    이 섹션의 접근 방식을 따르면 리소스를 동시에 설정하고 LocalizationOptions.ResourcesPath 로드하는 데 사용할 IStringLocalizerFactory.Create 수 없습니다.

  • IStringLocalizer<T>구성 요소에 삽입된 Razor에 대한 더미 클래스를 참조하려면, 지역화 네임스페이스에 대한 @using 지시문을 배치하거나 더미 클래스 참조에 지역화 네임스페이스를 포함합니다. 아래 예제에서 다음을 수행합니다.

    • 첫 번째 예제에서는 Localization 지시문을 사용하여 SharedResource 더미 클래스의 @using 네임스페이스를 나타냅니다.
    • 두 번째 예제에서는 SharedResource 더미 클래스의 네임스페이스를 명시적으로 설명합니다.

    Razor 구성요소에서 다음 접근 방식 중 하나를 사용합니다.

    @using Localization
    @inject IStringLocalizer<SharedResource> Loc
    
    @inject IStringLocalizer<Localization.SharedResource> Loc
    

추가적인 지침에 대해서는 ASP.NET Core의 전역화 및 지역화를 참조하세요.

개발자 도구에서 "센서" 창을 사용하여 위치 재정의

Google Chrome 또는 Microsoft Edge 개발자 도구에서 센서 창을 사용하여 위치 재정의를 사용하는 경우 미리 렌더링한 후 대체 언어가 다시 설정됩니다. 테스트할 때 센서 창을 사용하여 언어를 설정하지 마세요. 브라우저의 언어 설정을 사용하여 언어를 설정합니다.

자세한 내용은 InteractiveServer(Blazor#53707)dotnet/aspnetcore 하세요.

추가 리소스