Примечание
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Приложения и игры .NET и Win32 часто локализованы на разных языках, чтобы расширить общий адресируемый рынок. Дополнительные сведения о ценности локализации приложения см. в разделе Глобализация и локализация. Упаковав приложение или игру .NET или Win32 в виде пакета MSIX или .appx, вы можете использовать систему управления ресурсами для загрузки ресурсов, адаптированных к контексту времени выполнения. В этом подробном разделе описываются методы.
Существует множество способов локализации традиционного приложения Win32, но Windows 8 представила новую систему управления ресурсами , которая работает на разных языках программирования, в разных типах приложений и предоставляет функциональные возможности над простой локализацией. Эта система будет называться "MRT" в этом разделе. Изначально это означало "Современные ресурсы технологий", но от термина "Современные" отказались. Диспетчер ресурсов также может быть известен как MRM (современный диспетчер ресурсов) или PRI (индекс ресурсов пакета).
В сочетании с развертыванием на основе MSIX или на основе .appx (например, из Microsoft Store) MRT может автоматически доставлять наиболее применимые ресурсы для конкретного пользователя или устройства, что сводит к минимуму размер загрузки и установки приложения. Это уменьшение размера может быть значительным для приложений с большим объемом локализованного контента, возможно, в несколько гигабайтов для AAA-игр. Дополнительные преимущества MRT включают локализованные списки в Оболочке Windows и Microsoft Store, автоматическую резервную логику, если предпочтительный язык пользователя не соответствует доступным ресурсам.
В этом документе описывается высокоуровневая архитектура MRT и предоставляется руководство по переносу устаревших приложений Win32 в MRT с минимальными изменениями кода. После перехода к MRT дополнительные преимущества (например, возможность сегментировать ресурсы по коэффициенту масштабирования или системной теме) становятся доступными для разработчика. Обратите внимание, что локализация на основе MRT работает как для приложений UWP, так и для приложений Win32, обработанных с помощью Desktop Bridge (также известных как «Centennial»).
Во многих ситуациях вы можете продолжать использовать существующие форматы локализации и исходный код при интеграции с MRT для разрешения ресурсов во время выполнения и минимизации размеров загрузки — это не подход ко всем или ничего. В следующей таблице приведены сведения о работе и предполагаемой стоимости и преимуществах каждого этапа. Эта таблица не включает задачи, не относящиеся к локализации, например предоставление значков приложений с высоким разрешением или высокой контрастностью. Дополнительную информацию о предоставлении нескольких ресурсов для плиток, значков и так далее см. в разделе Настройка ресурсов для языка, масштабирования, высокой контрастности и других квалификаторов.
Работа | Преимущества | Расчетная стоимость |
---|---|---|
Локализация манифеста пакета | Не требуется минимальная работа, необходимая для отображения локализованного содержимого в оболочке Windows и в Microsoft Store | Небольшой |
Использование MRT для идентификации и поиска ресурсов | Предварительные требования для минимизации размеров загрузки и установки; Автоматический резервный вариант языка | Средний |
Создание пакетов ресурсов | Последний шаг, чтобы свести к минимуму размеры загрузки и установки | Небольшой |
Миграция на форматы ресурсов и API MRT | Значительно меньше размеров файлов (в зависимости от существующей технологии ресурсов) | Крупный |
Введение
Большинство нетривиальных приложений содержат элементы пользовательского интерфейса, известные как ресурсы , которые отделены от кода приложения (в отличие от жестко закодированных значений , созданных в самом исходном коде). Существует несколько причин, чтобы предпочесть ресурсы для жестко закодированных значений — простота редактирования не разработчиками, например, но одна из ключевых причин заключается в том, чтобы приложение мог выбирать различные представления одного и того же логического ресурса во время выполнения. Например, текст, отображаемый на кнопке (или изображение, отображаемое на значке), может отличаться в зависимости от языков, которые понимает пользователь, характеристики устройства отображения или какие-либо вспомогательные технологии включены.
Таким образом, основной целью любой технологии управления ресурсами является перевод, во время выполнения запрос на логического или символьного
Пример
Ниже приведен простой пример приложения с текстовыми метками на двух кнопках (openButton
и saveButton
) и PNG-файле, используемом для логотипа (logoImage
). Текстовые метки локализованы на английском и немецком языках, и логотип оптимизирован для обычных экранов рабочего стола (100% коэффициент масштабирования) и телефонов с высоким разрешением (300% коэффициент масштабирования). Обратите внимание, что на этой схеме представлено высокоуровневое концептуальное представление модели; он не сопоставляется точно с реализацией.
На рисунке код приложения ссылается на три имена логических ресурсов. Во время выполнения псевдо-функция GetResource
использует MRT для поиска этих имен ресурсов в таблице ресурсов (известной как PRI-файл) и находит наиболее подходящего кандидата на основе условий окружающей среды (язык пользователя и масштаб отображения). В случае меток строки используются напрямую. В случае изображения логотипа строки интерпретируются как имена файлов, а файлы считываются с диска.
Если пользователь говорит на языке, отличном от английского или немецкого, либо с коэффициентом масштабирования, отличным от 100% или 300%, MRT выбирает ближайший подходящий кандидат на основе набора резервных правил (см. в системе управления ресурсами для получения дополнительных сведений).
Обратите внимание, что MRT поддерживает ресурсы, адаптированные к нескольким квалификаторам — например, если изображение логотипа содержит встроенный текст, который также необходимо локализовать, у логотипа будет четыре кандидата: EN/Scale-100, DE/Scale-100, EN/Scale-300 и DE/Scale-300.
Разделы в этом документе
В следующих разделах описаны высокоуровневые задачи, необходимые для интеграции MRT с приложением.
Этап 0. Создание пакета приложения
В этом разделе описывается, как подготовить ваше существующее настольное приложение для создания в виде пакета приложений. На этом этапе функции MRT не используются.
Этап 1. Локализация манифеста приложения
В этом разделе описывается локализация манифеста приложения (чтобы оно отображалось правильно в оболочке Windows) при использовании устаревшего формата ресурсов и API для упаковки и поиска ресурсов.
Этап 2. Использование MRT для идентификации и поиска ресурсов
В этом разделе описывается изменение кода приложения (и, возможно, макета ресурсов) для поиска ресурсов с помощью MRT, а также использование существующих форматов ресурсов и API для загрузки и использования ресурсов.
Этап 3. Создание пакетов ресурсов
В этом разделе описаны окончательные изменения, необходимые для разделения ресурсов на отдельные пакеты ресурсов, минимизируя размер загрузки (и установки) приложения.
Не рассматривается в этом документе
После завершения этапов 0-3 выше у вас будет пакет приложения, который можно опубликовать в Microsoft Store. Он позволит свести к минимуму размер загрузки и установки для пользователей, пропуская ресурсы, в которых они не нуждаются, например, языки, которые они не используют. Дальнейшие улучшения размера приложения и функциональности можно сделать, выполнив один последний шаг.
Этап 4. Миграция в форматы ресурсов MRT и API
Этот этап выходит за рамки этого документа; это влечет за собой перемещение ресурсов (особенно строк) из устаревших форматов, таких как библиотеки DLL MUI или сборки ресурсов .NET в файлы PRI. Это может привести к дальнейшей экономии места при загрузке и установке. Он также позволяет использовать другие функции MRT, такие как минимизация загрузки и установки файлов изображений на основе коэффициента масштабирования, параметров специальных возможностей и т. д.
Этап 0. Создание пакета приложения
Прежде чем вносить изменения в ресурсы приложения, необходимо сначала заменить текущую технологию упаковки и установки стандартной технологией упаковки и развертывания UWP. Это можно сделать тремя способами.
- Если у вас есть большое классическое приложение с сложным установщиком или используется множество точек расширяемости ОС, вы можете использовать средство Desktop App Converter для создания макета файла UWP и сведений о манифесте из существующего установщика приложений (например, MSI).
- Если у вас есть небольшое настольное приложение с относительно небольшим количеством файлов или простым установщиком и без возможностей расширения, вы можете создать макет файла и информацию манифеста вручную.
- Если вы пересобираете из исходного кода и хотите обновить приложение, чтобы сделать его чистым приложением UWP, вы можете создать новый проект в Visual Studio и довериться интегрированной среде разработки, чтобы выполнить большую часть работы за вас.
Если вы хотите использовать Конвертер приложений рабочего стола, см. Упаковка приложения рабочего стола с помощью Конвертера приложений рабочего стола для получения дополнительных сведений о процессе преобразования. Полный набор примеров Desktop Converter можно найти в репозитории GitHub моста Desktop Bridge для UWP.
Замечание
Преобразователь приложений для настольных ПК устарел. Пожалуйста, используйте новое и усовершенствованное средство MSIX для упаковки настольных приложений.
Если вы хотите вручную создать пакет, необходимо создать структуру каталогов, содержащую все файлы приложения (исполняемые файлы и содержимое, но не исходный код) и файл манифеста пакета (APPxmanifest). Пример можно найти в GitHub-примереHello, World, но базовый файл манифеста пакета, который запускает исполняемый файл рабочего стола под названием ContosoDemo.exe
, выглядит следующим образом: выделенный текст будет заменен собственными значениями.
<?xml version="1.0" encoding="utf-8" ?>
<Package xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest"
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
IgnorableNamespaces="uap mp rescap">
<Identity Name="Contoso.Demo"
Publisher="CN=Contoso.Demo"
Version="1.0.0.0" />
<Properties>
<DisplayName>Contoso App</DisplayName>
<PublisherDisplayName>Contoso, Inc</PublisherDisplayName>
<Logo>Assets\StoreLogo.png</Logo>
</Properties>
<Dependencies>
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.14393.0"
MaxVersionTested="10.0.14393.0" />
</Dependencies>
<Resources>
<Resource Language="en-US" />
</Resources>
<Applications>
<Application Id="ContosoDemo" Executable="ContosoDemo.exe"
EntryPoint="Windows.FullTrustApplication">
<uap:VisualElements DisplayName="Contoso Demo" BackgroundColor="#777777"
Square150x150Logo="Assets\Square150x150Logo.png"
Square44x44Logo="Assets\Square44x44Logo.png"
Description="Contoso Demo">
</uap:VisualElements>
</Application>
</Applications>
<Capabilities>
<rescap:Capability Name="runFullTrust" />
</Capabilities>
</Package>
Более подробную информацию о файле манифеста пакета и структуре пакета см. в манифесте пакета приложения.
Наконец, если вы используете Visual Studio для создания нового проекта и переноса вашего существующего кода, см. статью о создании приложения "Hello, world". Вы можете включить существующий код в новый проект, но вам, скорее всего, придется внести значительные изменения кода (особенно в пользовательском интерфейсе), чтобы запустить как чистое приложение UWP. Эти изменения находятся вне области этого документа.
Этап 1. Локализация манифеста
Шаг 1.1. Обновление строк и ресурсов в манифесте
На этапе 0 вы создали базовый файл манифеста пакета (.appxmanifest) для приложения (на основе значений, предоставленных преобразователю, извлеченных из MSI или вручную введенных в манифест), но он не будет содержать локализованные сведения, а также не будет поддерживать дополнительные функции, такие как ресурсы с высоким разрешением начальных плиток и т. д.
Чтобы убедиться, что имя и описание приложения правильно локализованы, необходимо определить некоторые ресурсы в наборе файлов ресурсов и обновить манифест пакета, чтобы ссылаться на них.
Создание файла ресурсов по умолчанию
Первым шагом является создание файла ресурсов по умолчанию на языке по умолчанию (например, на английском языке). Это можно сделать вручную с помощью текстового редактора или с помощью конструктора ресурсов в Visual Studio.
Если вы хотите создать ресурсы вручную, выполните следующие действия.
- Создайте XML-файл с именем
resources.resw
и поместите его в папкуStrings\en-us
внутри вашего проекта. Используйте соответствующий код BCP-47, если язык по умолчанию не является американским вариантом английского. - В XML-файле добавьте следующее содержимое, где выделенный текст заменяется соответствующим текстом приложения на языке по умолчанию.
Замечание
Существуют ограничения на длину некоторых из этих строк. Дополнительные сведения см. в разделе VisualElements.
<?xml version="1.0" encoding="utf-8"?>
<root>
<data name="ApplicationDescription">
<value>Contoso Demo app with localized resources (English)</value>
</data>
<data name="ApplicationDisplayName">
<value>Contoso Demo Sample (English)</value>
</data>
<data name="PackageDisplayName">
<value>Contoso Demo Package (English)</value>
</data>
<data name="PublisherDisplayName">
<value>Contoso Samples, USA</value>
</data>
<data name="TileShortName">
<value>Contoso (EN)</value>
</data>
</root>
Если вы хотите использовать конструктор в Visual Studio:
- Создайте в проекте папку
Strings\en-us
(или другой язык) и добавьте новый элемент в корневую папку проекта, используя имяresources.resw
по умолчанию. Обязательно выберите файл ресурсов (.resw), а не словарь ресурсов — это файл, который используется в XAML-приложениях. - Используя конструктор, введите следующие строки (используйте тот же
Names
, но заменитеValues
на соответствующий текст для вашего приложения):
Замечание
Если начать с конструктора Visual Studio, вы всегда можете редактировать XML напрямую, нажав клавишу F7
. Но если начать с минимального XML-файла, конструктор не распознает файл, поскольку в нем отсутствует много дополнительных метаданных; вы можете это исправить, скопировав стандартные сведения XSD из созданного конструктором файла в ваш вручную отредактированный XML-файл.
Обновление манифеста для ссылки на ресурсы
После определения значений в .resw
файле следующим шагом является обновление манифеста для ссылки на строки ресурсов. Опять же, вы можете редактировать XML-файл напрямую или полагаться на конструктор манифестов Visual Studio.
Если вы редактируете XML напрямую, откройте файл AppxManifest.xml
и внесите следующие изменения в выделенные значения и. Используйте этот точный текст, а не текст, характерный для вашего приложения. Нет необходимости использовать эти точные имена ресурсов ( вы можете выбрать свой собственный), но все, что вы выбираете, должно точно соответствовать тому, что находится в .resw
файле. Эти имена должны совпадать с Names
, который вы создали в файле .resw
, с префиксом в соответствии со схемой ms-resource:
и пространством имен Resources/
.
Замечание
Многие элементы манифеста были опущены из этого фрагмента кода. Не удаляйте ничего!
<?xml version="1.0" encoding="utf-8"?>
<Package>
<Properties>
<DisplayName>ms-resource:Resources/PackageDisplayName</DisplayName>
<PublisherDisplayName>ms-resource:Resources/PublisherDisplayName</PublisherDisplayName>
</Properties>
<Applications>
<Application>
<uap:VisualElements DisplayName="ms-resource:Resources/ApplicationDisplayName"
Description="ms-resource:Resources/ApplicationDescription">
<uap:DefaultTile ShortName="ms-resource:Resources/TileShortName">
<uap:ShowNameOnTiles>
<uap:ShowOn Tile="square150x150Logo" />
</uap:ShowNameOnTiles>
</uap:DefaultTile>
</uap:VisualElements>
</Application>
</Applications>
</Package>
Если вы используете конструктор манифестов Visual Studio, откройте файл .appxmanifest и измените выделенные значения на значения во вкладке "Приложение" и вкладке "Упаковка".
Шаг 1.2. Сборка PRI-файла, создание пакета MSIX и проверка его работы
Теперь вы можете создать .pri
файл и развернуть приложение, чтобы убедиться, что в меню "Пуск" отображается правильная информация (на языке по умолчанию).
Если вы создаете в Visual Studio, просто нажмите Ctrl+Shift+B
, чтобы создать проект, а затем щелкните проект правой кнопкой мыши и выберите Deploy
в контекстном меню.
Если вы собираете вручную, выполните следующие действия, чтобы создать файл конфигурации для средства MakePRI
и сам файл .pri
(подробности в руководстве по упаковке приложений ):
Откройте командную строку разработчика из папки Visual Studio 2019 или Visual Studio 2022 в меню "Пуск".
Перейдите в корневой каталог проекта (тот, который содержит файл .appxmanifest и папку Strings ).
Введите следующую команду, заменив "contoso_demo.xml" именем, подходящим для проекта, и "en-US" языком приложения по умолчанию (или сохраняйте его en-US, если применимо). Обратите внимание, что XML-файл создается в родительском каталоге (не в каталоге проекта), так как он не является частью приложения (вы можете выбрать любой другой каталог, который вы хотите, но обязательно замените его в будущих командах).
makepri createconfig /cf ..\contoso_demo.xml /dq en-US /pv 10.0 /o
Вы можете ввести
makepri createconfig /?
, чтобы узнать, что делает каждый параметр, но вкратце:-
/cf
задает имя файла конфигурации (выходные данные этой команды) -
/dq
задает квалификаторы по умолчанию, в этом случае языкen-US
-
/pv
задает версию платформы, в данном случае Windows 10 -
/o
задает режим перезаписи выходного файла, если файл существует
-
Теперь у вас есть файл конфигурации, запустите
MakePRI
еще раз, чтобы выполнить поиск диска для ресурсов и упаковать их в PRI-файл. Замените "contoso_demop.xml" именем XML-файла, использованным на предыдущем шаге, и обязательно укажите родительский каталог для входных и выходных данных:makepri new /pr . /cf ..\contoso_demo.xml /of ..\resources.pri /mf AppX /o
Вы можете ввести
makepri new /?
сведения о том, что делает каждый параметр, но в кратце:-
/pr
задает корневой каталог проекта (в данном случае текущий каталог) -
/cf
задает имя файла конфигурации, созданное на предыдущем шаге -
/of
задает выходной файл -
/mf
создает файл сопоставления (поэтому мы можем исключить файлы в пакете на следующем шаге) -
/o
задает режим перезаписи выходного файла, если файл существует
-
Теперь у вас есть
.pri
файл с языковыми ресурсами по умолчанию (например, en-US). Чтобы убедиться в правильности работы, выполните следующую команду:makepri dump /if ..\resources.pri /of ..\resources /o
Вы можете ввести
makepri dump /?
сведения о том, что делает каждый параметр, но в кратце:-
/if
задает имя входного файла -
/of
задает имя выходного файла (.xml
будет добавлено автоматически) -
/o
задает режим перезаписи выходного файла, если файл существует
-
Наконец, можно открыть
..\resources.xml
в текстовом редакторе и проверить, перечислены ли<NamedResource>
значения (например,ApplicationDescription
иPublisherDisplayName
) вместе с<Candidate>
значениями выбранного языка по умолчанию (в начале файла будет другое содержание; пока не обращайте на это внимания).
Вы можете открыть файл сопоставления ..\resources.map.txt
, чтобы убедиться, что он содержит файлы, необходимые для вашего проекта (включая файл PRI, который не является частью каталога проекта). Важно, что файл сопоставления не включать ссылку на файл resources.resw
, так как содержимое этого файла уже внедрено в PRI-файл. Однако он будет содержать другие ресурсы, такие как имена файлов изображений.
Создание и подписание пакета
Теперь PRI-файл построен, вы можете создать и подписать пакет:
Чтобы создать пакет приложения, выполните следующую команду, заменив
contoso_demo.appx
имя файла MSIX/.appx, который вы хотите создать, и убедитесь, что выберите другой каталог для файла (в этом примере используется родительский каталог; он может быть в любом месте, но не должен быть каталогом проекта).makeappx pack /m AppXManifest.xml /f ..\resources.map.txt /p ..\contoso_demo.appx /o
Вы можете ввести
makeappx pack /?
сведения о том, что делает каждый параметр, но в кратце:-
/m
задает используемый файл манифеста -
/f
задает используемый файл сопоставления (созданный на предыдущем шаге) -
/p
задает имя выходного пакета -
/o
задает режим перезаписи выходного файла, если файл существует
-
После создания пакета его необходимо подписать. Самый простой способ получить сертификат подписи — создать пустой универсальный проект Windows в Visual Studio и скопировать
.pfx
создаваемый файл, но его можно создать вручную с помощьюMakeCert
служебныхPvk2Pfx
программ, как описано в разделе "Создание сертификата подписи пакета приложения".Это важно
Если вы вручную создаете сертификат подписи, убедитесь, что файлы размещаются в другом каталоге, отличном от исходного проекта или источника пакета, в противном случае он может быть включен в состав пакета, включая закрытый ключ!
Чтобы подписать пакет, используйте следующую команду. Обратите внимание, что
Publisher
, указанные в элементеIdentity
элементаAppxManifest.xml
, должны соответствоватьSubject
сертификата (это , а не, элемент<PublisherDisplayName>
, который является локализованным отображаемым именем для отображения пользователям). Как обычно, заменитеcontoso_demo...
имена файлов именами, соответствующими вашему проекту, и убедитесь, что.pfx
файл не находится в текущем каталоге (в противном случае он был создан в составе пакета, включая закрытый ключ подписи!):signtool sign /fd SHA256 /a /f ..\contoso_demo_key.pfx ..\contoso_demo.appx
Вы можете ввести
signtool sign /?
сведения о том, что делает каждый параметр, но в кратце:-
/fd
задает алгоритм дайджеста файлов (SHA256 по умолчанию для .appx) -
/a
Автоматически выбирает лучший сертификат -
/f
указывает входной файл, содержащий сертификат подписи
-
Наконец, теперь вы можете дважды щелкнуть .appx
файл, чтобы установить его, или если вы предпочитаете командную строку, можно открыть строку PowerShell, перейти в каталог, содержащий пакет, и ввести следующее (заменив contoso_demo.appx
его именем):
add-appxpackage contoso_demo.appx
Если вы получаете сообщения об ошибках, что сертификат не является доверенным, убедитесь, что он добавлен в системное хранилище (, а не в пользовательское хранилище). Чтобы добавить сертификат в хранилище компьютеров, можно использовать командную строку или проводник Windows.
Чтобы использовать командную строку, выполните следующие действия.
Запустите командную строку Visual Studio 2019 или Visual Studio 2022 от имени администратора.
Перейдите в каталог, содержащий
.cer
файл (не забудьте убедиться, что это находится за пределами исходных каталогов или каталогов проектов!)Введите следующую команду, заменив
contoso_demo.cer
на имя файла:certutil -addstore TrustedPeople contoso_demo.cer
Вы можете запустить
certutil -addstore /?
, чтобы узнать, что делает каждый параметр, но вкратце:-
-addstore
добавляет сертификат в хранилище сертификатов -
TrustedPeople
указывает хранилище, в которое помещается сертификат
-
Чтобы использовать проводник Windows, выполните приведенные действия.
- Перейдите в папку, содержащую
.pfx
файл - Дважды щелкните
.pfx
файл и откроется мастер импорта сертификатов - Выберите
Local Machine
и щелкнитеNext
- Подтвердите запрос повышения прав администрирования в UAC, если он отображается, и щелкните
Next
. - Введите пароль для закрытого ключа, если есть один, и нажмите кнопку
Next
- Выберите
Place all certificates in the following store
- Щелкните
Browse
и выберите папкуTrusted People
(не "Доверенные издатели") - Щелкните
Next
и затемFinish
После добавления сертификата в Trusted People
хранилище повторите установку пакета.
Теперь ваше приложение должно появиться в списке "Все приложения" меню "Пуск" с правильными сведениями из файла .resw
/ .pri
. Если вы видите пустую строку или строку ms-resource:...
, то что-то пошло не так, дважды проверьте изменения и убедитесь, что они правильные. Если щелкнуть приложение правой кнопкой мыши в меню "Пуск", вы можете закрепить его как плитку и убедиться, что там также отображаются правильные сведения.
Шаг 1.3. Добавление дополнительных поддерживаемых языков
После внесения изменений в манифест пакета и создания исходного resources.resw
файла можно легко добавить дополнительные языки.
Создание дополнительных локализованных ресурсов
Сначала создайте дополнительные локализованные значения ресурсов.
В папке Strings
создайте дополнительные папки для каждого языка, поддерживаемого с помощью соответствующего кода BCP-47 (например, Strings\de-DE
). В каждой из этих папок создайте resources.resw
файл (с помощью редактора XML или конструктора Visual Studio), включающего преобразованные значения ресурсов. Предполагается, что у вас уже есть локализованные строки, доступные где-то, и вам просто нужно скопировать их в .resw
файл. Этот документ не охватывает сам шаг перевода.
Например, файл
<?xml version="1.0" encoding="utf-8"?>
<root>
<data name="ApplicationDescription">
<value>Contoso Demo app with localized resources (German)</value>
</data>
<data name="ApplicationDisplayName">
<value>Contoso Demo Sample (German)</value>
</data>
<data name="PackageDisplayName">
<value>Contoso Demo Package (German)</value>
</data>
<data name="PublisherDisplayName">
<value>Contoso Samples, DE</value>
</data>
<data name="TileShortName">
<value>Contoso (DE)</value>
</data>
</root>
В следующих шагах предполагается, что вы добавили ресурсы для обоих de-DE
и fr-FR
, но один и тот же шаблон можно использовать для любого языка.
Обновление манифеста пакета до списка поддерживаемых языков
Манифест пакета должен быть обновлен для перечисления языков, поддерживаемых приложением. Desktop App Converter добавляет язык по умолчанию, но другие должны быть добавлены явным образом. Если вы редактируете файл AppxManifest.xml
напрямую, обновите узел Resources
следующим образом, добавив столько элементов, сколько вам нужно, и замените нужные соответствующие языки, которые вы поддерживаете, и убедитесь, что первая запись в списке является языком по умолчанию (резервный вариант).
В этом примере по умолчанию используется английский (США) с дополнительной поддержкой как немецкого (Германия) так и французского (Франция):
<Resources>
<Resource Language="EN-US" />
<Resource Language="DE-DE" />
<Resource Language="FR-FR" />
</Resources>
Если вы используете Visual Studio, вам не нужно ничего делать; Если вы посмотрите Package.appxmanifest
, следует увидеть специальное значение x-generate , которое приводит к тому, что процесс сборки вставляет языки, которые он находит в проекте (на основе папок с кодами BCP-47). Обратите внимание, что это недопустимое значение для реального манифеста пакета; он работает только для проектов Visual Studio:
<Resources>
<Resource Language="x-generate" />
</Resources>
Повторная сборка с локализованными значениями
Теперь вы можете создать и развернуть приложение, опять же, и если вы измените языковые предпочтения в Windows, в меню "Пуск" отображаются только что локализованные значения (инструкции по изменению языка приведены ниже).
Для Visual Studio можно просто использовать Ctrl+Shift+B
для сборки и щелкнуть проект правой кнопкой мыши, чтобы Deploy
.
Если вы создаете проект вручную, выполните те же действия, что и выше, но добавьте дополнительные языки, разделенные подчеркиваниями, в список квалификаторов по умолчанию (/dq
) при создании файла конфигурации. Например, для поддержки английских, немецких и французских ресурсов, добавленных на предыдущем шаге:
makepri createconfig /cf ..\contoso_demo.xml /dq en-US_de-DE_fr-FR /pv 10.0 /o
При этом будет создан файл PRI, содержащий все указанные языки, которые можно легко использовать для тестирования. Если общий размер ваших ресурсов невелик или вы поддерживаете только небольшое количество языков, это может быть приемлемо для вашего приложения для доставки. Только если вы хотите воспользоваться преимуществами минимизации размера установки и загрузки ваших ресурсов, вам нужно выполнить дополнительную работу по созданию отдельных языковых пакетов.
Тестирование с локализованными значениями
Чтобы протестировать новые локализованные изменения, вы просто добавите новый предпочитаемый язык пользовательского интерфейса в Windows. Нет необходимости скачивать языковые пакеты, перезагружать систему или отображать весь пользовательский интерфейс Windows на иностранном языке.
-
Settings
Запуск приложения (Windows + I
) - Перейдите по адресу
Time & language
- Перейдите по адресу
Region & language
- Щелкните
Add a language
. - Введите (или выберите) нужный язык (например
Deutsch
, илиGerman
)- Если есть вложенные языки, выберите нужный (например,
Deutsch / Deutschland
)
- Если есть вложенные языки, выберите нужный (например,
- Выбор нового языка в списке языков
- Щелкните
Set as default
.
Теперь откройте меню "Пуск" и найдите приложение, и вы увидите локализованные значения выбранного языка (другие приложения также могут отображаться локализованными). Если локализованное имя не отображается сразу, подождите несколько минут, пока кэш меню "Пуск" не будет обновлен. Чтобы вернуться к собственному языку, просто сделайте его языком по умолчанию в списке языков.
Шаг 1.4. Локализация дополнительных частей манифеста пакета (необязательно)
Можно локализовать другие разделы манифеста пакета. Например, если приложение обрабатывает расширения файлов, оно должно иметь windows.fileTypeAssociation
расширение в манифесте, используя зеленый выделенный текст точно так же, как показано (так как он будет ссылаться на ресурсы) и заменяя желтый выделенный текст информацией, относяющейся к приложению:
<Extensions>
<uap:Extension Category="windows.fileTypeAssociation">
<uap:FileTypeAssociation Name="default">
<uap:DisplayName>ms-resource:Resources/FileTypeDisplayName</uap:DisplayName>
<uap:Logo>Assets\StoreLogo.png</uap:Logo>
<uap:InfoTip>ms-resource:Resources/FileTypeInfoTip</uap:InfoTip>
<uap:SupportedFileTypes>
<uap:FileType ContentType="application/x-contoso">.contoso</uap:FileType>
</uap:SupportedFileTypes>
</uap:FileTypeAssociation>
</uap:Extension>
</Extensions>
Эти сведения также можно добавить с помощью конструктора манифестов Visual Studio, используя вкладку Declarations
, и обратить внимание на выделенные значения .
Теперь добавьте соответствующие имена ресурсов в каждый из файлов
... existing content...
<data name="FileTypeDisplayName">
<value>Contoso Demo File</value>
</data>
<data name="FileTypeInfoTip">
<value>Files used by Contoso Demo App</value>
</data>
Затем это отобразится в элементах оболочки Windows, таких как Проводник.
Создайте и протестируйте пакет, как и раньше, выполняя все новые сценарии, которые должны отображать новые строки пользовательского интерфейса.
Этап 2. Использование MRT для идентификации и поиска ресурсов
В предыдущем разделе показано, как использовать MRT для локализации файла манифеста приложения, чтобы оболочка Windows правильно отображала имя приложения и другие метаданные. Для этого не требуется никаких изменений кода; он просто требует использования .resw
файлов и некоторых дополнительных средств. В этом разделе показано, как использовать MRT для поиска ресурсов в существующих форматах ресурсов и использования существующего кода обработки ресурсов с минимальными изменениями.
Предположения о существующем макете файла и коде приложения
Так как существует множество способов локализации классических приложений Win32, в этом документе показано, как упростить предположения о структуре существующего приложения, которую необходимо сопоставить с конкретной средой. Возможно, вам потребуется внести некоторые изменения в существующую базу кода или макет ресурсов, чтобы соответствовать требованиям MRT, и они в значительной степени выходят за рамки этого документа.
Макет файла ресурсов
В этой статье предполагается, что локализованные ресурсы имеют одинаковые имена файлов (например, contoso_demo.exe.mui
или contoso_strings.dll
contoso.strings.xml
) но они помещаются в разные папки с именами BCP-47 (en-US
, de-DE
и т. д.). Это не имеет значения, сколько файлов ресурсов у вас есть, каковы их имена, какие форматы файлов / связанные API и т. д. Единственное, что важно, заключается в том, что каждый логический ресурс имеет одно и то же имя файла (но помещается в другой физический каталог).
В качестве противоположного примера, если ваше приложение использует плоскую файловую структуру с одним каталогом Resources
, содержащим файлы english_strings.dll
и french_strings.dll
, это не будет хорошо сопоставляться с MRT. Более эффективная структура будет каталогом Resources
с подкаталогами и файлами en\strings.dll
и fr\strings.dll
. Кроме того, можно использовать одно и то же базовое имя файла с такими встроенными квалификаторами, как strings.lang-en.dll
и strings.lang-fr.dll
, однако использование каталогов с языковыми кодами концептуально проще, поэтому мы сосредоточимся на этом.
Замечание
По-прежнему можно использовать MRT и преимущества упаковки, даже если вы не можете следовать этому соглашению об именовании файлов; это просто требует больше работы.
Например, приложение может иметь набор пользовательских команд пользовательского интерфейса (используемых для меток кнопок и т. д.) в простом текстовом файле с именемui.txt, который выложен в папку UICommands :
+ ProjectRoot |--+ Strings | |--+ en-US | | \--- resources.resw | \--+ de-DE | \--- resources.resw |--+ UICommands | |--+ en-US | | \--- ui.txt | \--+ de-DE | \--- ui.txt |--- AppxManifest.xml |--- ...rest of project...
Код загрузки ресурсов
В этой статье предполагается, что в какой-то момент в коде вы хотите найти файл, содержащий локализованный ресурс, загрузить его, а затем использовать его. API, используемые для загрузки ресурсов, API, используемые для извлечения ресурсов и т. д., не важны. В псевдокоде в основном три шага:
set userLanguage = GetUsersPreferredLanguage() set resourceFile = FindResourceFileForLanguage(MY_RESOURCE_NAME, userLanguage) set resource = LoadResource(resourceFile) // now use 'resource' however you want
MRT требует только изменения первых двух шагов в этом процессе - как определить лучшие ресурсы кандидатов и как их найти. Это не требует изменения того, как вы загружаете или используете ресурсы (хотя он предоставляет средства для этого, если вы хотите воспользоваться преимуществами).
Например, приложение может использовать API GetUserPreferredUILanguages
Win32, функцию sprintf
CRT и API CreateFile
Win32 для замены трех функций псевдокода выше, а затем вручную проанализировать текстовый файл, который ищет name=value
пары. (Сведения не важны. Это просто для иллюстрации того, что MRT не влияет на методы, используемые для обработки ресурсов после их расположения).
Шаг 2.1. Изменение кода для поиска файлов с помощью MRT
Переключение кода на использование MRT для поиска ресурсов несложно. Для этого требуется использование нескольких типов WinRT и нескольких строк кода. Основные типы, которые будут использоваться, приведены ниже.
- ResourceContext, который инкапсулирует текущий активный набор значений квалификатора (язык, коэффициент масштабирования и т. д.).
- ResourceManager (версия WinRT, а не версия .NET), которая обеспечивает доступ ко всем ресурсам из файла PRI.
- ResourceMap, представляющий определенное подмножество ресурсов в файле PRI (в этом примере файловые ресурсы и строковые ресурсы)
- NamedResource, представляющий логический ресурс и все возможные кандидаты.
- ResourceCandidate, представляющий один конкретный ресурс кандидата
В псевдокоде способ разрешения заданного имени файла ресурса (например UICommands\ui.txt
, в примере выше) выглядит следующим образом:
// Get the ResourceContext that applies to this app set resourceContext = ResourceContext.GetForViewIndependentUse() // Get the current ResourceManager (there's one per app) set resourceManager = ResourceManager.Current // Get the "Files" ResourceMap from the ResourceManager set fileResources = resourceManager.MainResourceMap.GetSubtree("Files") // Find the NamedResource with the logical filename we're looking for, // by indexing into the ResourceMap set desiredResource = fileResources["UICommands\ui.txt"] // Get the ResourceCandidate that best matches our ResourceContext set bestCandidate = desiredResource.Resolve(resourceContext) // Get the string value (the filename) from the ResourceCandidate set absoluteFileName = bestCandidate.ValueAsString
Обратите внимание, что код не запрашивает определенную языковую папку, как UICommands\en-US\ui.txt
, хотя файлы существуют на диске. Вместо этого он запрашивает логические имя файла UICommands\ui.txt
и использует MRT, чтобы найти соответствующий файл на диске в одном из каталогов языка.
Отсюда пример приложения может продолжать использовать CreateFile
для загрузки absoluteFileName
и синтаксического анализа пар name=value
так же, как и раньше; ни одна из этой логики не должна изменяться в приложении. Если вы пишете в C# или C++/CX, фактический код не гораздо сложнее, чем это (и на самом деле многие промежуточные переменные могут быть многочисленными) — см. раздел о загрузке ресурсов .NETниже. Приложения на базе C++/WRL будут более сложными из-за низкоуровневых API на базе COM, которые используются для активации и вызова API WinRT, но основные шаги будут теми же. См. раздел о загрузке ресурсов MUI в Win32, ниже.
Загрузка ресурсов .NET
Так как .NET имеет встроенный механизм для поиска и загрузки ресурсов (известных как "вспомогательные сборки"), в .NET нет необходимости заменять код, как это сделано в синтетическом примере выше. Вам просто нужно поместить ваши ресурсные DLL в соответствующие каталоги, и они автоматически обнаруживаются. Если приложение упаковано как MSIX или .appx с помощью пакетов ресурсов, структура каталогов немного отличается: директории ресурсов не являются подкаталогами основного каталога приложения, а находятся на одном уровне с ним (или отсутствуют, если язык не указан в настройках пользователя).
Например, представьте приложение .NET со следующим макетом, где все файлы существуют в папке MainApp
:
+ MainApp |--+ en-us | \--- MainApp.resources.dll |--+ de-de | \--- MainApp.resources.dll |--+ fr-fr | \--- MainApp.resources.dll \--- MainApp.exe
После преобразования в .appx макет будет выглядеть примерно так, при условии, что en-US
является языком по умолчанию, и в списке языков пользователя указаны как немецкий, так и французский.
+ WindowsAppsRoot |--+ MainApp_neutral | |--+ en-us | | \--- MainApp.resources.dll | \--- MainApp.exe |--+ MainApp_neutral_resources.language_de | \--+ de-de | \--- MainApp.resources.dll \--+ MainApp_neutral_resources.language_fr \--+ fr-fr \--- MainApp.resources.dll
Так как локализованные ресурсы больше не существуют в вложенных каталогах в директории установки основного исполняемого файла программы, встроенное разрешение ресурсов .NET не удается. К счастью, .NET имеет четко определенный механизм обработки неудачных попыток загрузки сборки — AssemblyResolve
событие. Приложение .NET с помощью MRT должно зарегистрировать это событие и предоставить недостающую сборку для подсистемы ресурсов .NET.
Краткий пример использования API WinRT для поиска спутниковых сборок, используемых .NET, выглядит следующим образом: представленный код намеренно упрощён, чтобы показать минимальную реализацию, хотя видно, что он тесно соответствует псевдокоду выше, где переданный ResolveEventArgs
предоставляет имя сборки, которую необходимо найти. Запустите версию этого кода (с подробными комментариями и обработкой ошибок) можно найти в файле PriResourceRsolver.cs
в примере сопоставителя сборок .NET наGitHub.
static class PriResourceResolver
{
internal static Assembly ResolveResourceDll(object sender, ResolveEventArgs args)
{
var fullAssemblyName = new AssemblyName(args.Name);
var fileName = string.Format(@"{0}.dll", fullAssemblyName.Name);
var resourceContext = ResourceContext.GetForViewIndependentUse();
resourceContext.Languages = new[] { fullAssemblyName.CultureName };
var resource = ResourceManager.Current.MainResourceMap.GetSubtree("Files")[fileName];
// Note use of 'UnsafeLoadFrom' - this is required for apps installed with .appx, but
// in general is discouraged. The full sample provides a safer wrapper of this method
return Assembly.UnsafeLoadFrom(resource.Resolve(resourceContext).ValueAsString);
}
}
Учитывая приведенный выше класс, вы добавите следующее в код запуска приложения (прежде чем все локализованные ресурсы потребуется загрузить):
void EnableMrtResourceLookup()
{
AppDomain.CurrentDomain.AssemblyResolve += PriResourceResolver.ResolveResourceDll;
}
Среда выполнения .NET создаст событие AssemblyResolve
всякий раз, когда она не сможет найти библиотеки DLL ресурсов, в этот момент предоставленный обработчик событий найдет необходимый файл при помощи MRT и возвратит сборку.
Замечание
Если ваше приложение уже имеет AssemblyResolve
обработчик, используемый для других целей, потребуется интегрировать код, отвечающий за разрешение ресурсов, в существующий код.
Загрузка ресурсов MUI Win32
Загрузка ресурсов Win32 MUI по сути аналогична загрузке вспомогательных сборок .NET, но вместо этого используется код на C++/CX или C++/WRL. Использование C++/CX обеспечивает гораздо более простой код, который тесно соответствует приведенному выше коду C#, но он использует расширения языка C++, ключи компилятора и дополнительные издержки времени выполнения, которых вы, возможно, захотите избежать. Если это так, использование C++/WRL обеспечивает решение с минимальным воздействием, хотя и с более многословным кодом. Тем не менее, если вы знакомы с программированием ATL (или COM в целом), WRL должен показаться вам знакомым.
В следующем примере функции показано, как использовать C++/WRL для загрузки определенной библиотеки DLL ресурсов и возврата HINSTANCE
, которые можно использовать для загрузки дополнительных ресурсов с помощью обычных API ресурсов Win32. Обратите внимание, что в отличие от примера C#, который явно инициализирует ResourceContext
язык, запрошенный средой выполнения .NET, этот код использует текущий язык пользователя.
#include <roapi.h>
#include <wrl\client.h>
#include <wrl\wrappers\corewrappers.h>
#include <Windows.ApplicationModel.resources.core.h>
#include <Windows.Foundation.h>
#define IF_FAIL_RETURN(hr) if (FAILED((hr))) return hr;
HRESULT GetMrtResourceHandle(LPCWSTR resourceFilePath, HINSTANCE* resourceHandle)
{
using namespace Microsoft::WRL;
using namespace Microsoft::WRL::Wrappers;
using namespace ABI::Windows::ApplicationModel::Resources::Core;
using namespace ABI::Windows::Foundation;
*resourceHandle = nullptr;
HRESULT hr{ S_OK };
RoInitializeWrapper roInit{ RO_INIT_SINGLETHREADED };
IF_FAIL_RETURN(roInit);
// Get Windows.ApplicationModel.Resources.Core.ResourceManager statics
ComPtr<IResourceManagerStatics> resourceManagerStatics;
IF_FAIL_RETURN(GetActivationFactory(
HStringReference(
RuntimeClass_Windows_ApplicationModel_Resources_Core_ResourceManager).Get(),
&resourceManagerStatics));
// Get .Current property
ComPtr<IResourceManager> resourceManager;
IF_FAIL_RETURN(resourceManagerStatics->get_Current(&resourceManager));
// get .MainResourceMap property
ComPtr<IResourceMap> resourceMap;
IF_FAIL_RETURN(resourceManager->get_MainResourceMap(&resourceMap));
// Call .GetValue with supplied filename
ComPtr<IResourceCandidate> resourceCandidate;
IF_FAIL_RETURN(resourceMap->GetValue(HStringReference(resourceFilePath).Get(),
&resourceCandidate));
// Get .ValueAsString property
HString resolvedResourceFilePath;
IF_FAIL_RETURN(resourceCandidate->get_ValueAsString(
resolvedResourceFilePath.GetAddressOf()));
// Finally, load the DLL and return the hInst.
*resourceHandle = LoadLibraryEx(resolvedResourceFilePath.GetRawBuffer(nullptr),
nullptr, LOAD_LIBRARY_AS_DATAFILE | LOAD_LIBRARY_AS_IMAGE_RESOURCE);
return S_OK;
}
Этап 3. Создание пакетов ресурсов
Теперь, когда у вас есть "жировый пакет", содержащий все ресурсы, существует два пути к созданию отдельных основных пакетов и пакетов ресурсов, чтобы свести к минимуму размеры загрузки и установки:
- Возьмите существующий пакет жира и запустите его через инструмент генератора пакетов для автоматического создания пакетов ресурсов. Это предпочтительный подход, если у вас есть система сборки, которая уже создает большой пакет, и вы хотите обработать его, чтобы создать пакеты ресурсов.
- Непосредственно создайте отдельные пакеты ресурсов и соберите их в единый пакет. Это предпочтительный подход, если у вас есть больший контроль над системой сборки и вы можете создавать пакеты напрямую.
Шаг 3.1. Создание пакета
Использование средства генератора пакетов
Чтобы использовать средство генератора пакетов, файл конфигурации PRI, созданный для пакета, необходимо вручную обновить, чтобы удалить <packaging>
раздел.
Если вы используете Visual Studio, обратитесь к убедитесь, что на устройстве установлены ресурсы независимо от того, требуется ли для них сведения о том, как создать все языки в основной пакет, создав файлы priconfig.packaging.xml
и priconfig.default.xml
.
Если вы редактируете файлы вручную, выполните следующие действия.
Создайте файл конфигурации так же, как и раньше, заменив правильный путь, имя файла и языки:
makepri createconfig /cf ..\contoso_demo.xml /dq en-US_de-DE_es-MX /pv 10.0 /o
Вручную откройте созданный
.xml
файл и удалите весь<packaging&rt;
раздел (но сохраните все остальное без изменений):<?xml version="1.0" encoding="UTF-8" standalone="yes" ?> <resources targetOsVersion="10.0.0" majorVersion="1"> <!-- Packaging section has been deleted... --> <index root="\" startIndexAt="\"> <default> ... ...
Соберите файл
.pri
и пакет.appx
как раньше, используя обновленный файл конфигурации и соответствующие имена для каталогов и файлов (см. дополнительные сведения об этих командах):makepri new /pr . /cf ..\contoso_demo.xml /of ..\resources.pri /mf AppX /o makeappx pack /m AppXManifest.xml /f ..\resources.map.txt /p ..\contoso_demo.appx /o
После создания пакета используйте следующую команду, чтобы создать пакет, используя соответствующие имена каталогов и файлов:
BundleGenerator.exe -Package ..\contoso_demo.appx -Destination ..\bundle -BundleName contoso_demo
Теперь вы можете перейти к последнему шагу, подписав (см. ниже).
Создание пакетов ресурсов вручную
Для создания пакетов ресурсов вручную требуется немного другой набор команд для сборки отдельных файлов .pri
и .appx
— эти команды аналогичны тем, что использовались выше для создания больших пакетов, поэтому минимальное объяснение дается. Примечание. Все команды предполагают, что текущий каталог является каталогом, содержащим AppXManifest.xml
файл, но все файлы помещаются в родительский каталог (при необходимости можно использовать другой каталог, но при необходимости не следует загрязнять каталог проекта любым из этих файлов). Как всегда, замените имена файлов Contoso собственными именами файлов.
Используйте следующую команду, чтобы создать файл конфигурации, который назначает только язык по умолчанию в качестве квалификатора. В этом случае
en-US
:makepri createconfig /cf ..\contoso_demo.xml /dq en-US /pv 10.0 /o
Создайте файлы по умолчанию
.pri
и.map.txt
для основного пакета, а также дополнительный набор файлов для каждого языка, найденного в проекте, используя следующую команду:makepri new /pr . /cf ..\contoso_demo.xml /of ..\resources.pri /mf AppX /o
Используйте следующую команду, чтобы создать основной пакет (который содержит исполняемый код и языковые ресурсы по умолчанию). Как всегда, измените имя по вашему усмотрению, но следует поместить пакет в отдельный каталог, чтобы упростить создание сборки (в этом примере используется каталог
..\bundle
):makeappx pack /m .\AppXManifest.xml /f ..\resources.map.txt /p ..\bundle\contoso_demo.main.appx /o
После создания основного пакета используйте следующую команду один раз для каждого дополнительного языка (т. е. повторите эту команду для каждого файла карты языка, созданного на предыдущем шаге). Опять же, выходные данные должны находиться в отдельном каталоге (тот же, что и основной пакет). Обратите внимание, что язык указан оба в параметре
/f
и параметре/p
, а также использование нового аргумента/r
(который указывает, что пакет ресурсов требуется):makeappx pack /r /m .\AppXManifest.xml /f ..\resources.language-de.map.txt /p ..\bundle\contoso_demo.de.appx /o
Объедините все пакеты из каталога пакета в один
.appxbundle
файл. Новый/d
параметр указывает каталог, используемый для всех файлов в пакете (именно поэтому.appx
файлы помещаются в отдельный каталог на предыдущем шаге):makeappx bundle /d ..\bundle /p ..\contoso_demo.appxbundle /o
Последний шаг в создании пакета — подпись.
Шаг 3.2. Подписывание пакета
После создания .appxbundle
файла (с помощью средства генератора пакетов или вручную) у вас будет один файл, содержащий основной пакет, а также все пакеты ресурсов. Последний шаг заключается в том, чтобы подписать файл, чтобы Windows установит его:
signtool sign /fd SHA256 /a /f ..\contoso_demo_key.pfx ..\contoso_demo.appxbundle
При этом создается подписанный .appxbundle
файл, содержащий основной пакет, а также все пакеты ресурсов, относящиеся к языку. Его можно дважды щелкнуть так же, как файл пакета, чтобы установить приложение, а также любой соответствующий язык на основе языковых параметров Windows пользователя.