애플리케이션은 클래스가 나타내는 .NET Framework Resource Manager를 ResourceManager 사용하여 지역화된 리소스를 검색합니다. Resource Manager는 허브 및 스포크 모델을 사용하여 리소스를 패키지하고 배포한다고 가정합니다. 허브는 중립 또는 기본 문화권이라는 단일 문화권에 대한 리소스 및 로컬화할 수 없는 실행 코드가 포함된 주 어셈블리입니다. 기본 문화권은 애플리케이션에 대한 대체 문화권입니다. 지역화된 리소스를 찾을 수 없는 경우 리소스가 사용되는 문화권입니다. 각 스포크는 단일 문화권에 대한 리소스를 포함하지만 코드를 포함하지 않는 위성 어셈블리에 연결합니다.
이 모델에는 다음과 같은 몇 가지 이점이 있습니다.
- 애플리케이션을 배포한 후 새 문화권에 대한 리소스를 증분 방식으로 추가할 수 있습니다. 문화권별 리소스의 후속 개발에는 상당한 시간이 필요할 수 있으므로 주 애플리케이션을 먼저 릴리스하고 나중에 문화권별 리소스를 제공할 수 있습니다.
- 애플리케이션을 다시 컴파일하지 않고도 애플리케이션의 위성 어셈블리를 업데이트하고 변경할 수 있습니다.
- 애플리케이션은 특정 문화권에 필요한 리소스를 포함하는 위성 어셈블리만 로드해야 합니다. 이렇게 하면 시스템 리소스의 사용을 크게 줄일 수 있습니다.
그러나 이 모델에는 다음과 같은 단점도 있습니다.
- 여러 리소스 집합을 관리해야 합니다.
- 여러 구성을 테스트해야 하므로 애플리케이션을 테스트하는 초기 비용이 증가합니다. 장기적으로는 여러 병렬 국제 버전을 테스트하고 유지하는 것보다 여러 위성으로 하나의 핵심 애플리케이션을 테스트하는 것이 더 쉽고 저렴합니다.
리소스 명명 규칙
애플리케이션의 리소스를 패키지할 때 공용 언어 런타임에서 예상하는 리소스 명명 규칙을 사용하여 이름을 지정해야 합니다. 런타임은 해당 문화권 이름으로 리소스를 식별합니다. 각 문화권에는 고유한 이름이 지정되며, 이는 일반적으로 언어와 연결된 소문자 문화권 이름과 필요한 경우 국가 또는 지역과 연결된 대문자 하위 문화권 이름 2자로 된 조합입니다. 하위 문화권 이름은 대시(-)로 구분된 문화권 이름을 따릅니다. 예를 들어 일본어로는 일본어에 대한 ja-JP, 미국에서 사용되는 영어 en-US, 독일에서 사용되는 독일어 de-DE, 오스트리아어로 de-AT 등이 있습니다. Windows에서 지원하는 언어/지역 이름 목록에서 언어태그 열을 참조하세요. 문화권 이름은 BCP 47에 정의된 표준을 따릅니다.
비고
중국어(간체)와 같이 zh-Hans
두 글자 문화권 이름에 대한 몇 가지 예외가 있습니다.
자세한 내용은 리소스 파일 만들기 및 위성 어셈블리 만들기를 참조하세요.
리소스 대체 프로세스
리소스 패키징 및 배포를 위한 허브 및 스포크 모델은 대체 프로세스를 사용하여 적절한 리소스를 찾습니다. 애플리케이션에서 사용할 수 없는 지역화된 리소스를 요청하는 경우 공용 언어 런타임은 문화권 계층에서 사용자의 애플리케이션 요청과 가장 밀접하게 일치하는 적절한 대체 리소스를 검색하고, 예외를 최후의 수단으로만 throw합니다. 계층의 각 수준에서 적절한 리소스가 발견되면 런타임에서 사용합니다. 리소스를 찾을 수 없는 경우 검색은 다음 수준에서 계속됩니다.
조회 성능을 향상시키려면 주 어셈블리에 특성을 적용 NeutralResourcesLanguageAttribute 하고 주 어셈블리에서 작동하는 중립 언어의 이름을 전달합니다.
.NET Framework 리소스 대체 프로세스
.NET Framework 리소스 대체 프로세스에는 다음 단계가 포함됩니다.
팁 (조언)
relativeBindForResources< 구성 요소를 사용하여> 리소스 대체 프로세스 및 런타임이 리소스 어셈블리에 대해 프로브하는 프로세스를 최적화할 수 있습니다. 자세한 내용은 리소스 대체 프로세스 최적화를 참조하세요.
런타임은 먼저 애플리케이션에 대해 요청된 문화권과 일치하는 어셈블리에 대한 전역 어셈블리 캐시 를 확인합니다.
전역 어셈블리 캐시는 많은 애플리케이션에서 공유하는 리소스 어셈블리를 저장할 수 있습니다. 이렇게 하면 만드는 모든 애플리케이션의 디렉터리 구조에 특정 리소스 집합을 포함할 필요가 없습니다. 런타임이 어셈블리에 대한 참조를 찾으면 어셈블리에서 요청된 리소스를 검색합니다. 어셈블리에서 항목을 찾으면 요청된 리소스를 사용합니다. 항목을 찾지 못하면 검색을 계속합니다.
다음으로 런타임은 요청된 문화권과 일치하는 하위 디렉터리에 대해 현재 실행 중인 어셈블리의 디렉터리를 확인합니다. 하위 디렉터리를 찾으면 해당 하위 디렉터리에서 요청된 문화권에 대한 유효한 위성 어셈블리를 검색합니다. 그런 다음 런타임은 위성 어셈블리에서 요청된 리소스를 검색합니다. 어셈블리에서 리소스를 찾으면 해당 리소스를 사용합니다. 리소스를 찾지 못하면 검색을 계속합니다.
다음 런타임은 Windows Installer를 쿼리하여 요청 시 위성 어셈블리를 설치할지 여부를 확인합니다. 이 경우 설치를 처리하고, 어셈블리를 로드하고, 어셈블리 또는 요청된 리소스를 검색합니다. 어셈블리에서 리소스를 찾으면 해당 리소스를 사용합니다. 리소스를 찾지 못하면 검색을 계속합니다.
런타임은 위성 어셈블리를 AppDomain.AssemblyResolve 찾을 수 없음을 나타내기 위해 이벤트를 발생시킵니다. 이벤트를 처리하도록 선택하는 경우 이벤트 처리기는 리소스가 조회에 사용되는 위성 어셈블리에 대한 참조를 반환할 수 있습니다. 그렇지 않으면 이벤트 처리기가 반환
null
되고 검색이 계속됩니다.다음으로 런타임은 전역 어셈블리 캐시를 다시 검색합니다. 이번에는 요청된 문화권의 부모 어셈블리를 검색합니다. 부모 어셈블리가 전역 어셈블리 캐시에 있는 경우 런타임은 어셈블리에서 요청된 리소스를 검색합니다.
부모 문화권은 적절한 대체 문화권으로 정의됩니다. 리소스를 제공하는 것이 예외를 throw하는 것보다 낫기 때문에 부모를 백업 후보로 고려하세요. 이 프로세스를 통해 리소스를 다시 사용할 수도 있습니다. 자식 문화권이 요청된 리소스를 지역화할 필요가 없는 경우에만 부모 수준에서 특정 리소스를 포함해야 합니다. 예를 들어,
en
(중립 영어),en-GB
(영국에서 사용되는 영어),en-US
(미국에서 사용되는 영어) 위성 어셈블리를 제공하는 경우en
위성에는 공통 용어가 포함되고,en-GB
및en-US
위성은 다른 용어에 대해서만 재정의를 제공할 수 있습니다.다음으로 런타임은 현재 실행 중인 어셈블리의 디렉터리를 확인하여 부모 디렉터리가 포함되어 있는지 확인합니다. 부모 디렉터리가 있는 경우 런타임은 디렉터리에서 부모 문화권에 대한 유효한 위성 어셈블리를 검색합니다. 어셈블리를 찾으면 런타임은 어셈블리에서 요청된 리소스를 검색합니다. 리소스를 찾으면 해당 리소스를 사용합니다. 리소스를 찾지 못하면 검색을 계속합니다.
다음 런타임은 Windows Installer를 쿼리하여 요청 시 부모 위성 어셈블리를 설치할지 여부를 확인합니다. 이 경우 설치를 처리하고, 어셈블리를 로드하고, 어셈블리 또는 요청된 리소스를 검색합니다. 어셈블리에서 리소스를 찾으면 해당 리소스를 사용합니다. 리소스를 찾지 못하면 검색을 계속합니다.
런타임은 적절한 대체 리소스를 찾을 수 없음을 나타내기 위해 AppDomain.AssemblyResolve 이벤트를 발생합니다. 이벤트를 처리하도록 선택하는 경우 이벤트 처리기는 리소스가 조회에 사용되는 위성 어셈블리에 대한 참조를 반환할 수 있습니다. 그렇지 않으면 이벤트 처리기가 반환
null
되고 검색이 계속됩니다.다음 런타임은 이전 세 단계와 마찬가지로 여러 잠재적인 수준을 통해 부모 어셈블리를 검색합니다. 각 문화권에는 CultureInfo.Parent 속성에 의해 정의된 하나의 부모만 있습니다. 그러나 그 부모는 또 다른 부모를 가질 수도 있습니다. 문화권의 Parent 속성이 반환 CultureInfo.InvariantCulture되면 부모 문화권에 대한 검색이 중지됩니다. 리소스 대체의 경우 고정 문화권은 부모 문화권 또는 리소스를 가질 수 있는 문화권으로 간주되지 않습니다.
원래 지정된 문화권과 모든 부모를 검색했으며 리소스를 아직 찾을 수 없는 경우 기본(대체) 문화권에 대한 리소스가 사용됩니다. 일반적으로 기본 문화권에 대한 리소스는 주 애플리케이션 어셈블리에 포함됩니다. 그러나 리소스의 최종 폴백 위치가 주 어셈블리가 아닌 위성 어셈블리임을 나타내기 위해 Satellite 특성의 Location 속성에 NeutralResourcesLanguageAttribute 값을 지정할 수 있습니다.
비고
기본 리소스는 주 어셈블리를 사용하여 컴파일할 수 있는 유일한 리소스입니다. 위성 어셈블리를 NeutralResourcesLanguageAttribute 특성을 사용하여 지정하지 않으면 궁극적인 대체(최종 부모)가 됩니다. 따라서 기본 어셈블리에 항상 기본 리소스 집합을 포함하는 것이 좋습니다. 이렇게 하면 예외가 발생하는 것을 방지할 수 있습니다. 기본 리소스를 포함하면 모든 리소스에 대한 대체를 제공하여 문화적으로 특정되지 않은 경우에도 항상 사용자에게 하나 이상의 리소스를 제공합니다.
마지막으로 런타임에서 기본(대체) 문화권에 대한 리소스를 찾지 못하면 리소스를 찾을 수 없음을 나타내는 예외가 발생합니다 MissingManifestResourceExceptionMissingSatelliteAssemblyException.
예를 들어 애플리케이션이 스페인어(멕시코)(문화권)에 대해 지역화된 리소스를 es-MX
요청한다고 가정합니다. 런타임은 먼저 전역 어셈블리 캐시에서 일치하는 es-MX
어셈블리를 검색하지만 찾지 못합니다. 그런 다음 런타임은 현재 실행 중인 어셈블리의 디렉터리에서 es-MX
디렉터리를 검색합니다. 실패하면 런타임은 전역 어셈블리 캐시에서 적절한 대체 문화권을 반영하는 부모 어셈블리(이 경우 es
스페인어)를 다시 검색합니다. 부모 어셈블리를 찾을 수 없는 경우, 런타임은 해당 리소스를 찾을 때까지 모든 잠재적 수준의 문화권별로 부모 어셈블리를 검색합니다 es-MX
. 리소스를 찾을 수 없는 경우 런타임은 기본 문화권에 리소스를 사용합니다.
.NET Framework 리소스 대체 프로세스 최적화
다음 조건에서는 런타임이 위성 어셈블리에서 리소스를 검색하는 프로세스를 최적화할 수 있습니다.
위성 어셈블리는 코드 어셈블리와 동일한 위치에 배포됩니다. 코드 어셈블리가 전역 어셈블리 캐시에 설치되면 위성 어셈블리도 전역 어셈블리 캐시에 설치됩니다. 코드 어셈블리가 디렉터리에 설치된 경우 위성 어셈블리는 해당 디렉터리의 문화권별 폴더에 설치됩니다.
위성 어셈블리는 요청 시 설치되지 않습니다.
애플리케이션 코드는 이벤트를 처리 AppDomain.AssemblyResolve 하지 않습니다.
다음 예제와 같이 relativeBindForResources< 요소를 포함하고> 해당 enabled
특성을 true
애플리케이션 구성 파일에 설정하여 위성 어셈블리에 대한 프로브를 최적화합니다.
<configuration>
<runtime>
<relativeBindForResources enabled="true" />
</runtime>
</configuration>
위성 어셈블리에 최적화된 프로브는 옵트인 기능입니다. 즉, 런타임은 <에 설명된 단계를 따릅니다.> 이 경우 위성 어셈블리를 검색하는 프로세스는 다음과 같이 수정됩니다.
런타임은 부모 코드 어셈블리의 위치를 사용하여 위성 어셈블리를 검색합니다. 부모 어셈블리가 전역 어셈블리 캐시에 설치되어 있으면 런타임은 캐시에서 검색되지만 애플리케이션의 디렉터리에는 검색되지 않습니다. 부모 어셈블리가 애플리케이션 디렉터리에 설치된 경우 런타임은 전역 어셈블리 캐시가 아닌 애플리케이션 디렉터리에서 프로브합니다.
런타임은 Windows Installer에서 위성 어셈블리의 주문형 설치를 쿼리하지 않습니다.
특정 리소스 어셈블리에 대한 프로브가 실패하면 런타임에서 AppDomain.AssemblyResolve 이벤트를 발생시키지 않습니다.
.NET Core 리소스 대체 프로세스
.NET Core 리소스 대체 프로세스에는 다음 단계가 포함됩니다.
런타임은 요청된 문화권에 대한 위성 어셈블리를 로드하려고 시도합니다.
요청된 문화권과 일치하는 하위 디렉터리에 대해 현재 실행 중인 어셈블리의 디렉터리를 확인합니다. 하위 디렉터리를 찾으면 해당 하위 디렉터리에서 요청된 문화권에 대한 유효한 위성 어셈블리를 검색하고 로드합니다.
비고
대/소문자를 구분하는 파일 시스템(즉, Linux 및 macOS)이 있는 운영 체제에서 문화권 이름 하위 디렉터리 검색은 대/소문자를 구분합니다. 하위 디렉터리 이름은 CultureInfo.Name의 대소문자를 정확히 일치시켜야 합니다 (예:
es
,es-MX
).비고
프로그래머가 사용자 지정 어셈블리 로드 컨텍스트를 AssemblyLoadContext파생한 경우 상황은 복잡합니다. 실행 중인 어셈블리가 사용자 지정 컨텍스트에 로드된 경우 런타임은 위성 어셈블리를 사용자 지정 컨텍스트로 로드합니다. 세부 정보는 이 문서의 범위를 벗어났습니다. AssemblyLoadContext을(를) 참조하세요.
위성 어셈블리가 발견되지 않은 경우, AssemblyLoadContext가 위성 어셈블리를 찾을 수 없음을 나타내는 AssemblyLoadContext.Resolving 이벤트를 발생시킵니다. 이벤트를 처리하도록 선택하면 이벤트 처리기가 위성 어셈블리에 대한 참조를 로드하고 반환할 수 있습니다.
위성 어셈블리를 아직 찾을 수 없는 경우 AssemblyLoadContext는 AppDomain이 위성 어셈블리를 찾을 수 없음을 나타내는 이벤트를 트리거 AppDomain.AssemblyResolve 합니다. 이벤트를 처리하도록 선택하면 이벤트 처리기가 위성 어셈블리에 대한 참조를 로드하고 반환할 수 있습니다.
위성 어셈블리가 발견되면 런타임은 요청된 리소스를 검색합니다. 어셈블리에서 리소스를 찾으면 해당 리소스를 사용합니다. 리소스를 찾지 못하면 검색을 계속합니다.
비고
위성 어셈블리 내에서 리소스를 찾기 위해 런타임은 현재ResourceManager에 대해 요청된 CultureInfo.Name 리소스 파일을 검색합니다. 리소스 파일 내에서 요청된 리소스 이름을 검색합니다. 둘 중 하나를 찾을 수 없으면 리소스를 찾을 수 없는 것으로 처리됩니다.
런타임은 다음으로 1단계와 2단계를 반복할 때마다 여러 잠재적인 수준을 통해 부모 문화권 어셈블리를 검색합니다.
부모 문화권은 적절한 대체 문화권으로 정의됩니다. 리소스를 제공하는 것이 예외를 throw하는 것보다 낫기 때문에 부모를 백업 후보로 고려하세요. 이 프로세스를 통해 리소스를 다시 사용할 수도 있습니다. 자식 문화권이 요청된 리소스를 지역화할 필요가 없는 경우에만 부모 수준에서 특정 리소스를 포함해야 합니다. 예를 들어,
en
위성 어셈블리(중립 영어),en-GB
위성 어셈블리(영국에서 사용되는 영어),en-US
위성 어셈블리(미국에서 사용되는 영어)를 제공하는 경우,en
위성에는 공통 용어가 포함되고,en-GB
및en-US
위성은 차이가 있는 용어에 대해서만 재정의를 제공합니다.각 문화권에는 CultureInfo.Parent 속성에 의해 정의된 하나의 부모만 있습니다. 그러나 그 부모는 또 다른 부모를 가질 수도 있습니다. 문화의 Parent 속성이 CultureInfo.InvariantCulture를 반환할 때 부모 문화권의 검색이 중지됩니다. 자원 폴백의 경우 불변 문화권은 부모 문화권이나 리소스를 가질 수 있는 문화권으로 간주되지 않습니다.
원래 지정된 문화권과 모든 부모를 검색했으며 리소스를 아직 찾을 수 없는 경우 기본(대체) 문화권에 대한 리소스가 사용됩니다. 일반적으로 기본 문화권에 대한 리소스는 주 애플리케이션 어셈블리에 포함됩니다. 그러나 속성 값을 지정하여 리소스의 SatelliteLocation 최종 대체 위치가 주 어셈블리가 아닌 위성 어셈블리임을 나타낼 수 있습니다.
비고
기본 리소스는 주 어셈블리를 사용하여 컴파일할 수 있는 유일한 리소스입니다. 위성 어셈블리를 NeutralResourcesLanguageAttribute 특성을 사용하여 지정하지 않으면 궁극적인 대체(최종 부모)가 됩니다. 따라서 기본 어셈블리에 항상 기본 리소스 집합을 포함하는 것이 좋습니다. 이렇게 하면 예외가 발생하는 것을 방지할 수 있습니다. 기본 리소스 파일을 포함하면 모든 리소스에 대한 대체를 제공하고 문화권에 특정하지 않더라도 항상 사용자에 대해 하나 이상의 리소스가 있는지 확인합니다.
마지막으로 런타임이 기본(대체) 문화권에 대한 리소스 파일을 찾지 못하면 리소스를 찾을 수 없음을 알리는 MissingManifestResourceException 또는 MissingSatelliteAssemblyException 예외가 발생합니다. 리소스 파일을 찾았지만 요청된 리소스가 없는 경우 요청이 반환됩니다
null
.
위성 어셈블리에 대한 최종 예비 옵션
필요에 따라 주 어셈블리에서 리소스를 제거하고 런타임이 특정 문화권에 해당하는 위성 어셈블리에서 최종 대체 리소스를 로드하도록 지정할 수 있습니다. 대체 프로세스를 제어하려면 생성자를 사용하고 NeutralResourcesLanguageAttribute(String, UltimateResourceFallbackLocation) Resource Manager가 주 어셈블리에서 또는 위성 어셈블리에서 대체 리소스를 추출해야 하는지 여부를 지정하는 매개 변수 값을 UltimateResourceFallbackLocation 제공합니다.
다음 .NET Framework 예제에서는 이 특성을 사용하여 NeutralResourcesLanguageAttribute 프랑스어(fr
) 언어에 대한 위성 어셈블리에 애플리케이션의 대체 리소스를 저장합니다. 이 예제에는 이름이 지정된 Greeting
단일 문자열 리소스를 정의하는 두 개의 텍스트 기반 리소스 파일이 있습니다. 첫 번째 resources.fr.txt프랑스어 리소스를 포함합니다.
Greeting=Bon jour!
두 번째 리소스는ru.txt러시아어 리소스를 포함합니다.
Greeting=Добрый день
이 두 파일은 명령줄에서 리소스 파일 생성기(resgen.exe) 를 실행하여 .resources 파일로 컴파일됩니다. 프랑스어 리소스의 경우 명령은 다음과 같습니다.
resgen.exe resources.fr.txt
러시아어 리소스의 경우 명령은 다음과 같습니다.
resgen.exe resources.ru.txt
.resources 파일은 다음과 같이 프랑스어 리소스에 대한 명령줄에서 어셈블리 링커(al.exe) 를 실행하여 동적 링크 라이브러리에 포함됩니다.
al /t:lib /embed:resources.fr.resources /culture:fr /out:fr\Example1.resources.dll
러시아어 리소스는 다음과 같습니다.
al /t:lib /embed:resources.ru.resources /culture:ru /out:ru\Example1.resources.dll
애플리케이션 소스 코드는 Example1.cs 또는 Example1.vb 파일에 상주합니다. 기본 애플리케이션 리소스가 fr 하위 디렉터리에 있음을 나타내는 특성이 포함 NeutralResourcesLanguageAttribute 됩니다. Resource Manager를 인스턴스화하고, 리소스 값을 Greeting
검색하고, 콘솔에 표시합니다.
using System;
using System.Reflection;
using System.Resources;
[assembly:NeutralResourcesLanguage("fr", UltimateResourceFallbackLocation.Satellite)]
public class Example
{
public static void Main()
{
ResourceManager rm = new ResourceManager("resources",
typeof(Example).Assembly);
string greeting = rm.GetString("Greeting");
Console.WriteLine(greeting);
}
}
Imports System.Reflection
Imports System.Resources
<Assembly: NeutralResourcesLanguage("fr", UltimateResourceFallbackLocation.Satellite)>
Module Example
Public Sub Main()
Dim rm As New ResourceManager("resources", GetType(Example).Assembly)
Dim greeting As String = rm.GetString("Greeting")
Console.WriteLine(greeting)
End Sub
End Module
그런 다음 다음과 같이 명령줄에서 C# 소스 코드를 컴파일할 수 있습니다.
csc Example1.cs
Visual Basic 컴파일러에 대한 명령은 매우 유사합니다.
vbc Example1.vb
주 어셈블리에 포함된 리소스가 없으므로 스위치를 사용하여 /resource
컴파일할 필요가 없습니다.
언어가 러시아어 이외의 다른 시스템에서 예제를 실행하면 다음 출력이 표시됩니다.
Bon jour!
제안된 패키징 대안
시간 또는 예산 제약 조건으로 인해 애플리케이션이 지원하는 모든 하위 문화권에 대한 리소스 집합을 만들지 못할 수 있습니다. 대신 모든 관련 하위 문화권에서 사용할 수 있는 부모 문화권에 대한 단일 위성 어셈블리를 만들 수 있습니다. 예를 들어 지역별 영어 리소스를 요청하는 사용자가 검색하는 단일 영어 위성 어셈블리(en)와 지역별 독일어 리소스를 요청하는 사용자를 위한 단일 독일어 위성 어셈블리(de)를 제공할 수 있습니다. 예를 들어 독일(de-DE), 오스트리아(de-AT), 스위스(de-CH)에서 사용되는 독일어에 대한 요청은 독일 위성 어셈블리(de)로 대체됩니다. 기본 리소스는 최종 대체이므로 대부분의 애플리케이션 사용자가 요청할 리소스이므로 이러한 리소스를 신중하게 선택합니다. 이 방법은 덜 문화적으로 구체적이지만 애플리케이션의 지역화 비용을 크게 줄일 수 있는 리소스를 배포합니다.
참고하십시오
- .NET 앱의 리소스
- 전역 어셈블리 캐시
- 리소스 파일 만들기
- 위성 어셈블리 만들기
.NET