다음을 통해 공유


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

비고

이 기사는 최신 버전이 아닙니다. 현재 릴리스에 대해서는 본 기사의 .NET 9 버전을 참조하십시오.

경고

이 버전의 ASP.NET Core는 더 이상 지원되지 않습니다. 자세한 내용은 .NET 및 .NET Core 지원 정책을 참조하세요. 현재 릴리스에 대해서는 본 기사의 .NET 9 버전을 참조하십시오.

중요합니다

이 정보는 사전 출시 제품과 관련이 있으며, 상업적으로 출시되기 전에 상당히 수정될 수 있습니다. Microsoft는 여기에 제공된 정보에 대해 어떠한 명시적이거나 묵시적인 보증도 하지 않습니다.

현재 릴리스에 대해서는 본 기사의 .NET 9 버전을 참조하십시오.

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

세계화 및 지역화

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

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

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

지원되지 않음: ASP.NET Core MVC의IHtmlLocalizerIViewLocalizer 기능은 Blazor 앱에서 지원되지 않습니다.

앱의 경우, 데이터 주석를 사용하여 양식의 유효성 검사를 위한 지역화된 유효성 검사 메시지가 지원되며, 이는 가 구현된 경우에 가능합니다.

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

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

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

종종 언어문화 권이라는 용어는 세계화 및 지역화 개념을 다룰 때 서로 바꿔서 사용됩니다.

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

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

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

비고

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

세계화

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

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

CultureInfo.InvariantCulture 는 다음 필드 형식(<input type="{TYPE}" />자리 표시자가 형식인 경우 {TYPE} )에 사용됩니다.

  • date
  • number

앞의 필드 형식은 다음과 같습니다.

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

Blazor는 현재 문화권에 맞춰 값을 표시할 수 있는 기본 제공 기능을 제공합니다. 따라서 @bind:culturedate 필드 형식을 사용할 때는 number로 문화권을 지정하지 않는 것이 좋습니다.

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

  • datetime-local
  • month
  • week

이전 형식의 현재 브라우저 지원은 사용 가능을 참조하세요.

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

Blazor WebAssembly에서는 축소된 국제화 API와 Unicode 로캘의 기본 International Components 세트를 사용합니다. 자세한 내용은 .NET 세계화 및 ICU: WebAssembly의 ICU를 참조하세요.

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

Blazor WebAssembly에서는 축소된 국제화 API와 Unicode 로캘의 기본 International Components 세트를 사용합니다. 자세한 내용은 .NET 세계화 및 ICU: WebAssembly의 ICU를 참조하세요.

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

고정 세계화

이 섹션은 클라이언트 쪽 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> 값을 사용하여 true MSBuild 속성을 적용하십시오. 표준 시간대 코드 및 데이터를 줄이려면, 다음 방법을 따르세요.

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

비고

<BlazorEnableTimeZoneSupport> 이전 <InvariantTimezone> 설정을 재정의합니다. 설정 <BlazorEnableTimeZoneSupport>을(를) 제거할 것을 권장합니다.

정확한 표준 시간대 정보를 위해 데이터 파일이 포함되어 있습니다. 앱에서 이 기능이 필요하지 않은 경우, 앱의 프로젝트 파일에서 <BlazorEnableTimeZoneSupport> MSBuild 속성을 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 모든 숫자 형식에 대해 지원되며 그룹 구분 기호를 포함하며 최대 2개의 소수 자릿수를 렌더링합니다.

선택적으로 NavMenu 구성 요소를 위해 NavMenu.razor 구성 요소의 탐색에 메뉴 항목을 추가합니다 (CultureExample1).

Accept-Language 헤더에서 컬처를 동적으로 설정

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

헤더는 Accept-Language 브라우저에 의해 설정되고 브라우저 설정에서 사용자의 언어 기본 설정에 의해 제어됩니다. 브라우저 설정에서 사용자는 기본 설정 순서대로 하나 이상의 기본 설정 언어를 설정합니다. 기본 설정 순서는 브라우저에서 헤더의 각 언어에 대한 품질 값(q0-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)로 전환합니다. 웹 페이지를 다시 요청합니다.

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

  • 날짜: 2021년 6월 7일 오전 6:45:22
  • 번호: 1,999.69

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

  • 날짜: 2021년 7월 6일 6:49:38
  • 번호: 1.999,69

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

앱의 BlazorWebAssemblyLoadAllGlobalizationData 프로젝트 파일(true)에서 속성을 .csproj로 설정하십시오.

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

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

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

Blazor 자동 시작을 방지하려면 autostart="false"의 Blazor 태그에 <script>를 추가하십시오.

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

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

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

Blazor Web App:

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

독립형 Blazor WebAssembly:

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

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

문화 Blazor권의 시작 옵션을 설정하는 대신 C# 코드에서 문화권을 설정하는 것이 좋습니다. 설정 파일 CultureInfo.DefaultThreadCurrentCulture에서 CultureInfo.DefaultThreadCurrentUICultureProgram을 동일한 문화로 설정합니다.

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

using System.Globalization;

WebAssemblyHostBuilder를 빌드하고 실행하는 줄 앞에 문화 설정을 추가합니다.

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에 지역화 서비스를 추가합니다.

In 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)로 유지됩니다.

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

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

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

비고

.NET 앱에 패키지를 추가하는 방법에 대한 지침은 패키지 사용 작업 흐름(NuGet 문서)패키지 설치 및 관리 섹션에서 확인할 수 있습니다. 올바른 패키지 버전을 NuGet.org에서 확인하세요.

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

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

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

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

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

비고

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

파일의 맨 위에 System.Globalization 파일에 Microsoft.JSInteropProgram 네임스페이스를 추가하세요.

using System.Globalization;
using Microsoft.JSInterop;

다음 줄을 제거합니다.

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

앞의 줄을 다음 코드로 바꿉다. 이 코드는 앱의 서비스 컬렉션 Blazor 에 '의 지역화 서비스를 추가하고 AddLocalizationinterop을 사용하여 JS 로컬 스토리지에서 사용자의 문화권 선택을 호출 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 구성 요소는 다음 작업을 수행하는 방법을 보여 줍니다.

  • 사용자의 문화권 선택을 인터롭을 통해 브라우저 로컬 스토리지에 설정하세요.
  • 업데이트된 문화권을 사용하는 요청된 구성 요소(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);
        }
    }
}

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

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

CultureExample1 데모 구성 요소 섹션에 표시된 구성 요소를 사용하여 이전 예제의 작동 방식을 연구합니다.

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

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

비고

다음 예제에서는 앱이 전역 대화형 작업을 채택한다고 가정합니다. 이를 위해 Routes 구성 요소의 App 구성 요소에 대화형 SSR(대화형 서버 쪽 렌더링)을 지정합니다(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 사용합니다. 앱은 컨트롤러로의 리디렉션을 통해 사용자가 선택한 문화권을 유지합니다. 컨트롤러는 사용자의 선택한 문화권을 a 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);
    }
}

경고

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 대화형 작업을 채택한다고 가정합니다(App).

<Routes @rendermode="InteractiveServer" />

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

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

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

    <CultureSelector @rendermode="InteractiveServer" />
    

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

이 섹션은 Auto(서버 및 WebAssembly) 상호작용을 채택하는 Blazor Web App에 적용됩니다.

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

.Client 프로젝트 업데이트

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

비고

.NET 앱에 패키지를 추가하는 방법에 대한 지침은 패키지 사용 작업 흐름(NuGet 문서)패키지 설치 및 관리 섹션에서 확인할 수 있습니다. 올바른 패키지 버전을 NuGet.org에서 확인하세요.

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

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

프로젝트 System.GlobalizationMicrosoft.JSInterop 파일 맨 위에 .ClientProgram 네임스페이스를 추가하십시오.

using System.Globalization;
using Microsoft.JSInterop;

다음 줄을 제거합니다.

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

앞의 줄을 다음 코드로 바꿉다. 이 코드는 앱의 서비스 컬렉션 Blazor 에 '의 지역화 서비스를 추가하고 AddLocalizationinterop을 사용하여 JS 로컬 스토리지에서 사용자의 문화권 선택을 호출 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 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);
        }
    }
}

.Client 프로젝트의 _Imports 파일(_Imports.razor)에서 Pages 폴더의 구성 요소에 대한 네임스페이스를 추가하고 .Client 프로젝트의 네임스페이스에 맞게 네임스페이스를 업데이트합니다.

@using BlazorSample.Client.Pages

.Client 프로젝트에서 CultureSelector 구성 요소에 MainLayout 구성 요소를 추가합니다. </main> 파일의 닫힘 Layout/MainLayout.razor 태그 안에 다음 마크업을 배치합니다.

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

.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;
}

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

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;
}

CultureExample1 섹션에 표시된 구성 요소를 사용하여 전역 자동 렌더링 모드를 상속하는 구성 요소에 대해 세계화가 작동하는 방식을 연구합니다. CultureExample1 프로젝트의 .Client 폴더에 Pages 구성 요소를 추가합니다.

CultureClient사이드바 탐색에 CultureServer, CultureExample1Layout/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>
<div class="nav-item px-3">
    <NavLink class="nav-link" href="culture-example-1">
        <span class="bi bi-list-nested-nav-menu" aria-hidden="true"></span> Culture (Auto)
    </NavLink>
</div>

서버 프로젝트 업데이트

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 사용합니다. 앱은 컨트롤러로의 리디렉션을 통해 사용자가 선택한 문화권을 유지합니다. 컨트롤러는 사용자의 선택한 문화권을 a 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);
    }
}

경고

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

대화형 자동 구성 요소

이 섹션의 지침은 페이지별/구성 요소 렌더링을 채택하고 대화형 자동 렌더링 모드를 지정하는 앱의 구성 요소에도 적용됩니다.

@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 앱의 기본 문화권과 지원되는 문화권을 지정합니다. 다음 예제에서는 미국 영어 및 코스타리카 스페인어에 지원되는 문화권을 구성합니다.

In 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 경로 또는 쿼리 문자열을 기반으로 하는 경우 스키마가 WebSockets에서 작동하지 않아 문화권을 유지하지 못할 수 있습니다. 따라서 지역화 문화 설정 cookie을 사용하는 것이 좋습니다. 사용자의 문화권 선택을 유지하는 예제 식을 보려면 이 문서의 Razor.

지역화된 리소스의 예

이 섹션의 지역화된 리소스 예제는 앱의 지원 문화권이 기본 로캘로 영어()이고 스페인어(enes)가 사용자 선택 가능 또는 브라우저 지정 대체 로캘인 이 문서의 이전 예제와 함께 작동합니다.

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

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

비고

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

Visual Studio Code를 사용하는 경우 Tim Heuer의 ResX Viewer 및 Editor를 설치하는 것이 좋습니다. 폴더에 빈 CultureExample2.resx 파일을 추가합니다 Pages . 확장은 UI에서 파일 관리를 자동으로 수행합니다. 새 리소스 추가 단추를 선택합니다. Greeting (키), Hello, 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 리소스 파일 추가를 > 선택하여 Visual Studio에서 다음리소스 파일을> 수 있습니다. 파일 이름을 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에서 확인하세요.

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

    @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

    경고

    동시에 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하세요.

추가 리소스