Share via


Use o Sistema de Gerenciamento de Recursos do Windows 10 em um aplicativo ou jogo herdado

Os aplicativos e jogos NET e Win32 com frequência são localizados em diferentes idiomas como forma de expandir seu mercado endereçável total. Para obter mais informações sobre a proposta de valor de localização do aplicativo, consulte Globalização e localização. Empacotando o aplicativo ou jogo .NET ou Win32 como um pacote .msix ou .appx, você pode aproveitar o Sistema de Gerenciamento de Recursos para carregar recursos de aplicativo personalizados para o contexto em tempo de execução. Este tópico detalhado descreve as técnicas.

A localização de um aplicativo Win32 tradicional pode ser feita de várias maneiras, mas o Windows 8 introduziu um novo sistema de gerenciamento de recurso que funciona em todas as linguagens de programação, em todos os tipos de aplicativos e oferece funcionalidade além da localização simples. Chamaremos esse sistema de "MRT" neste tópico. Antigamente, esse termo significava "Modern Resource Technology, tecnologia de recursos modernos", mas o termo "moderno" foi descontinuado. O gerenciador de recursos também pode ser conhecido como MRM (Modern Resource Manager, gerenciador de recursos moderno) ou PRI (Package Resource Index, indexador de recursos de pacote).

Quando agrupado com a implantação baseada em MSIX ou .appx (por exemplo, da Microsoft Store), o MRT pode entregar automaticamente os recursos mais aplicáveis para um determinado usuário/dispositivo, minimizando o tamanho do download e da instalação do seu aplicativo. Essa redução de tamanho pode ser significativa para aplicativos com uma grande quantidade de conteúdo localizado, podendo ser da ordem de vários gigabytes para jogos AAA. Os benefícios adicionais do MRT incluem listagens localizadas no Windows Shell e na Microsoft Store, lógica de fallback automática sempre que o idioma preferido de um usuário não corresponder aos seus recursos disponíveis.

Este documento descreve a arquitetura de alto nível do MRT e oferece um guia de portabilidade que ajuda na migração de aplicativos Win32 herdados para o MRT com alterações mínimas no código. Assim que a migração para o MRT é feita, benefícios adicionais (como a capacidade de segmentar recursos por fator de escala ou tema do sistema) tornam-se disponíveis para o desenvolvedor. Vale observar que a localização baseada em MRT funciona tanto para aplicativos UWP quanto para aplicativos Win32 processados pela Ponte de Desktop (também conhecido como "Centennial").

Em muitas situações, é possível continuar a usar os formatos de localização e o código-fonte existentes e fazer a integração com o MRT para resolver recursos em runtime e minimizar o tamanho dos downloads, ou seja, não é uma abordagem do tipo tudo ou nada. A tabela a seguir apresenta um resumo do trabalho e do custo/benefício estimado para cada estágio. Essa tabela não inclui tarefas que não sejam de localização, como as que fornecem ícones de aplicativos com alta resolução ou alto contraste. Para obter mais informações sobre como oferecer vários ativos para blocos, ícones e outros, consulte Personalizar seus recursos para idioma, escala, alto contraste e outros qualificadores.

Trabalho Benefício Custo estimado
Localizar o manifesto do pacote O mínimo de trabalho exigido para que seu conteúdo localizado apareça no Shell do Windows e na Microsoft Store Small
Usar o MRT na identificação e localização de recursos Pré-requisito que minimiza os tamanhos de download e instalação; fallback automático de idioma Médio
Fazer o build de pacotes de recursos Última etapa para minimizar o tamanho do download e da instalação Small
Migrar para formatos de recursos e APIs MRT Tamanho dos arquivos bem menores (conforme a tecnologia de recursos existente) grande

Introdução

Grande parte dos aplicativos não triviais possui elementos de interface do usuário conhecidos como recursos e que são desacoplados do código do aplicativo (em contraste com os valores embutido em código de autoria do próprio código-fonte). Há vários motivos que levam a preferência por recursos em vez de valores codificados, como a facilidade de edição por quem não é desenvolvedor, por exemplo, mas um dos principais motivos é habilitar que o aplicativo escolha diferentes representações do mesmo recurso lógico em runtime. Por exemplo, o texto que será exibido em um botão (ou a imagem que será exibida em um ícone) pode variar dependendo do(s) idioma(s) que o usuário entende, das características do dispositivo de vídeo ou se o usuário tem alguma tecnologia adaptativa habilitada.

Portanto, o objetivo principal de toda tecnologia de gerenciamento de recursos é traduzir, em runtime, uma solicitação de um nome de recurso lógico ou simbólico (como SAVE_BUTTON_LABEL) pelo melhor valor real possível (por exemplo, "Salvar") de um conjunto de possíveis candidatos (por exemplo, "Salvar", "Speichern" ou "저장"). O MRT oferece essa função e habilita os aplicativos a identificar candidatos a recursos com o uso de uma grande variedade de atributos, chamados de qualificadores, como o idioma do usuário, o fator de escala da exibição, o tema selecionado pelo usuário e outros fatores ambientais. O MRT ainda oferece suporte a qualificadores personalizados para os aplicativos que precisam dele (por exemplo, um aplicativo pode oferecer ativos gráficos diferentes para usuários que fizeram login com uma conta versus usuários convidados, sem necessidade de adicionar explicitamente essa verificação em toda parte do aplicativo). O MRT trabalha com recursos de sequência de caracteres e recursos baseados em arquivos, em que os recursos baseados em arquivos são implementados como referências aos dados externos (os próprios arquivos).

Exemplo

Este é um exemplo simples de um aplicativo que tem rótulos de texto em dois botões (openButton e saveButton) e um arquivo PNG usado em um logotipo (logoImage). Os rótulos de texto são traduzidos para o inglês e o alemão, e o logotipo é otimizado para exibições normais em desktops (fator de escala de 100%) e telefones de alta resolução (fator de escala de 300%). É importante observar que esse diagrama apresenta uma visão conceitual de alto nível do modelo; ele não mapeia exatamente a implementação.

Screenshot of a Source code label, a Lookup table label, and a Files on disk label.

No gráfico, o código do aplicativo faz referência aos três nomes de recursos lógicos. No runtime, a GetResource pseudo-função usa o MRT para procurar esses nomes de recursos na tabela de recursos (conhecida como arquivo PRI) e encontrar o candidato mais adequado com base nas condições ambientais (o idioma do usuário e o fator de escala de exibição). No caso dos rótulos, as sequências de caracteres são usadas de forma direta. No caso da imagem do logotipo, as sequências de caracteres são interpretadas como nomes de arquivos e os arquivos são lidos do disco.

Se o usuário fala um idioma que não seja inglês ou alemão, ou tem um fator de escala de exibição diferente de 100% ou 300%, o MRT escolhe o candidato correspondente "mais próximo" com base em um conjunto de regras de fallback (consulte Sistema de gerenciamento de recursos para obter mais informações).

Observe que o MRT oferece suporte a recursos personalizados para mais de um qualificador, por exemplo, se a imagem do logotipo contivesse texto incorporado que também precisasse ser localizado, o logotipo teria quatro candidatos: EN/Scale-100, DE/Scale-100, EN/Scale-300 e DE/Scale-300.

Seções deste documento

As seções a seguir descrevem as tarefas de alto nível necessárias à integração do MRT com o seu aplicativo.

Fase 0: Fazer o build de um pacote de aplicativos

Nesta seção, é descrito como fazer com que seu aplicativo de desktop existente seja gerado como um build de um pacote de aplicativos. Não são usados recursos MRT nessa etapa.

Fase 1: Localizar o manifesto do aplicativo

Nesta seção, é descrito como localizar o manifesto do aplicativo (para que ele apareça corretamente no Shell do Windows), ao mesmo tempo, em que ainda usa o formato de recurso herdado e a API em pacotes e localiza recursos.

Fase 2: Como usar o MRT para identificar e localizar recursos

Nesta seção, é descrito como modificar o código do aplicativo (e talvez o layout do recurso) para localizar os recursos usando o MRT e continuar usando os formatos de recursos e as APIs existentes para carregar e consumir os recursos.

Fase 3: Fazer o build de pacotes de recursos

Nesta seção, são descritas as alterações finais necessárias na separação dos seus recursos em pacotes de recursos separados, o que minimiza o tamanho do download (e da instalação) do seu aplicativo.

Não abordado neste documento

Assim que concluir as Fases 0-3 acima, você terá um "agrupamento" de aplicativos que pode ser enviado à Microsoft Store e que minimiza o tamanho do download e da instalação para os usuários, por meio da omissão dos recursos que não são necessários (por exemplo, idiomas que eles não falam). É possível melhorar ainda mais o tamanho e a funcionalidade do aplicativo realizando uma última etapa.

Fase 4: Migrar para formatos de recursos MRT e APIs

Essa fase está fora do escopo deste documento; ela envolve a transferência de seus recursos (principalmente sequências de caracteres) de formatos herdados, como DLLs MUI ou montagens de recursos .NET, para arquivos PRI. Com isso, é possível obter mais economia de espaço para tamanhos de download e instalação. Isso também permite o uso de outros recursos do MRT, como a minimização do download e da instalação de arquivos de imagem com base no fator de escala, nas configurações de acessibilidade e muito mais.

Fase 0: Fazer o build de um pacote de aplicativos

Antes de fazer quaisquer alterações nos recursos do seu aplicativo, é preciso primeiramente substituir a tecnologia atual de empacotamento e instalação pela tecnologia padrão de empacotamento e implantação da UWP. Isso pode ser feito de três maneiras:

  • Caso tenha um aplicativo da área de trabalho grande com um instalador complexo ou utilize lotes de pontos de extensibilidade do SO, é possível usar a ferramenta Desktop App Converter para gerar o layout de arquivo UWP e as informações de manifesto a partir do instalador de aplicativo existente (por exemplo, um MSI).
  • Caso tenha um aplicativo da área de trabalho menor, com uma quantidade pequena de arquivos ou um instalador simples e sem ganchos de extensibilidade, é possível criar o layout do arquivo e as informações do manifesto de forma manual.
  • Caso esteja recompilando a partir da origem e quiser atualizar seu aplicativo para ser um aplicativo UWP puro, é possível criar um novo projeto no Visual Studio e confiar no IDE de forma que ele faça a maioria do trabalho por você.

Caso queira usar o Desktop App Converter, consulte Empacotar um aplicativo da área de trabalho usando o Desktop App Converter para ter mais informações sobre o processo de conversão. É possível encontrar um conjunto completo de amostras do conversor da área de trabalho no repositório do GitHub de amostras de Ponte de Desktop para UWP.

Caso queira criar o pacote manualmente, é necessário criar uma estrutura de diretórios que inclua todos os arquivos do aplicativo (executáveis e conteúdo, mas com exceção do código-fonte) e um arquivo de manifesto do pacote (.appxmanifest). É possível encontrar um exemplo na amostra Olá, Mundo do GitHub, mas um arquivo de manifesto do pacote básico que executa o executável da área de trabalho denominado ContosoDemo.exe é o seguinte, em que o texto em destaque seria substituído por seus próprios valores.

<?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>

Para obter mais informações sobre o arquivo de manifesto do pacote e o layout do pacote, consulte Manifesto do pacote do aplicativo.

Por último, caso esteja usando o Visual Studio na criação de um novo projeto e na migração do código existente, consulte Criar um aplicativo "Olá, mundo". É possível incluir o código existente no novo projeto, mas talvez seja necessário fazer alterações significativas no código (principalmente na interface do usuário) para que ele seja executado como um aplicativo UWP puro. Essas alterações estão fora do escopo deste documento.

Fase 1: Localizar o manifesto

Etapa 1.1: Atualizar sequências de caracteres e ativos no manifesto

Na Fase 0, foi criado um arquivo de manifesto do pacote básico (.appxmanifest) para o seu aplicativo (com base nos valores fornecidos ao conversor, extraídos do MSI ou inseridos manualmente no manifesto), mas ele não conterá informações localizadas nem oferecerá suporte a recursos adicionais, como ativos de bloco inicial de alta resolução e outros.

Para garantir que o nome e a descrição do seu aplicativo sejam localizados de forma correta, é necessário que se defina alguns recursos em um conjunto de arquivos de recursos e que se atualize o manifesto do pacote para que faça referência a eles.

Criação de um arquivo de recurso padrão

A primeira etapa é criar um arquivo de recurso padrão em seu idioma padrão (por exemplo, inglês dos EUA). Isso pode ser feito de forma manual com um editor de texto ou por meio do Resource Designer no Visual Studio.

Caso queira criar os recursos manualmente:

  1. Crie um arquivo XML denominado resources.resw e coloque esse arquivo em uma Strings\en-us subpasta do seu projeto. Use o código BCP-47 adequado se o idioma padrão não for o inglês dos EUA.
  2. No arquivo XML, adicione o conteúdo a seguir, no qual o texto em destaque é substituído pelo texto adequado para seu aplicativo, em seu idioma padrão.

Observação

O comprimento de algumas dessas sequências de caracteres está sujeito a restrições. Para obter mais informações, consulte 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>

Caso queira usar o designer no Visual Studio:

  1. Crie a Strings\en-us pasta (ou outro idioma, se necessário) em seu projeto e adicione um Novo item à pasta raiz do projeto, usando o nome padrão de resources.resw. Não se esqueça de escolher Arquivo de recursos (.resw) e não Dicionário de recursos, um Dicionário de recursos é um arquivo usado por aplicativos XAML.
  2. Por meio do designer, insira as seguintes sequências de caracteres (use as mesmas Names, mas substitua o Values pelo texto adequado para seu aplicativo):

Screenshot showing the Resources.resw file showing the Name and Value columns. for the resources.

Observação

Caso comece com o designer do Visual Studio, é sempre possível editar o XML diretamente pressionando F7. Mas caso comece com um arquivo XML mínimo, o designer não reconhece o arquivo porque faltam muitos metadados adicionais; é possível corrigir esse problema copiando as informações XSD padrão de um arquivo gerado pelo designer para o arquivo XML editado manualmente.

Atualize o manifesto para que faça referência aos recursos

Depois que os valores estiverem definidos no .resw arquivo, a próxima etapa é atualizar o manifesto para que faça referência às sequências de caracteres do recurso. Mais uma vez, é possível editar um arquivo XML diretamente ou usar o Designer de manifesto do Visual Studio.

Caso esteja editando XML diretamente, abra o arquivo AppxManifest.xml e faça as seguintes alterações nos valores em destaque, use esse texto exato, não o texto específico do seu aplicativo. Não é um requisito usar exatamente esses nomes de recursos, pode escolher o que quiser, mas o que for escolhido deve corresponder exatamente ao .resw que está no arquivo. Esses nomes devem corresponder aos Names que foi criado no arquivo .resw, prefixados com o esquema ms-resource: e o namespace Resources/.

Observação

Vários elementos do manifesto foram omitidos neste trecho, não exclua nada.

<?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>

Caso esteja usando o designer de manifesto do Visual Studio, abra o arquivo .appxmanifest e altere os valores em destaque na guia *Aplicativo e na guia Empacotamento:

Screenshot of the Visual Studio Manifest Designer showing the Application tab with the Display name and Description text boxes called out.

Screenshot of the Visual Studio Manifest Designer showing the Packaging tab with the Package display name and Publisher display name text boxes called out.

Etapa 1.2: Fazer o build do arquivo PRI, criar um pacote MSIX e verificar se está funcionando

Agora, deve ser possível fazer o build do arquivo .pri e deploy o aplicativo para verificar se as informações corretas (no idioma padrão) estão aparecendo no menu Iniciar.

Caso esteja fazendo o build no Visual Studio, basta pressionar Ctrl+Shift+B para criar o projeto e, em seguida, clicar com o botão direito do mouse no projeto e escolher Deploy no menu de contexto.

Caso esteja fazendo o build manualmente, siga estas etapas para criar um arquivo de configuração para a ferramenta MakePRI e para gerar o próprio arquivo .pri (é possível encontrar mais informações em Empacotamento manual do aplicativo):

  1. Abra um prompt de comando do desenvolvedor na pasta Visual Studio 2017 ou Visual Studio 2019 no menu Iniciar.

  2. Mude para o diretório raiz do projeto (aquele que contém o arquivo .appxmanifest e a pasta Sequências de caracteres).

  3. Digite o comando a seguir, substituindo "contoso_demo.xml" por um nome que seja adequado ao seu projeto e "en-US" pelo idioma padrão do seu aplicativo (ou mantenha como en-US, se for o caso). Observe que o arquivo XML é criado no diretório responsável (não no diretório do projeto), uma vez que não faz parte do aplicativo (é possível escolher qualquer outro diretório que quiser, mas não se esqueça de substituir esse diretório em comandos futuros).

    makepri createconfig /cf ..\contoso_demo.xml /dq en-US /pv 10.0 /o
    

    Para ver o que cada parâmetro faz, digite makepri createconfig /?, mas em resumo:

    • /cf define o nome do arquivo de configuração (a saída desse comando)
    • /dq define os qualificadores padrão, nesse caso, o idioma en-US
    • /pv define a versão da plataforma, neste caso o Windows 10
    • /o define para Substituir o arquivo de saída se ele existir
  4. Agora que tem um arquivo de configuração, execute MakePRI novamente para pesquisar recursos no disco e empacotar os recursos em um arquivo PRI. Substitua "contoso_demop.xml" pelo nome do arquivo XML que foi usado na etapa anterior e certifique-se de especificar o diretório responsável para a entrada e a saída:

    makepri new /pr . /cf ..\contoso_demo.xml /of ..\resources.pri /mf AppX /o
    

    Para ver o que cada parâmetro faz, digite makepri new /?, mas em resumo:

    • /pr define a raiz do projeto (nesse caso, o diretório atual)
    • /cf define o nome do arquivo de configuração, criado na etapa anterior
    • /of define o arquivo de saída
    • /mf cria um arquivo de mapeamento (para podermos excluir arquivos do pacote em uma etapa posterior)
    • /o define para Substituir o arquivo de saída se ele existir
  5. Agora tem um arquivo .pri com os recursos de idioma padrão (por exemplo, en-US). Para verificar se funcionou corretamente, é possível executar o comando a seguir:

    makepri dump /if ..\resources.pri /of ..\resources /o
    

    Para ver o que cada parâmetro faz, digite makepri dump /?, mas em resumo:

    • /if define o nome do arquivo de entrada
    • /of define o nome do arquivo de saída (.xml será anexado automaticamente)
    • /o define para Substituir o arquivo de saída se ele existir
  6. Por fim, é possível abrir ..\resources.xml em um editor de texto e verificar se ele lista seus valores <NamedResource> (como ApplicationDescription e PublisherDisplayName) junto com os valores <Candidate> do idioma padrão escolhido (haverá outro conteúdo no início do arquivo; ignore por enquanto).

É possível abrir o arquivo de mapeamento ..\resources.map.txt para verificar se ele contém os arquivos necessários para o seu projeto (inclusive o arquivo PRI, que não faz parte do diretório do projeto). É importante destacar que o arquivo de mapeamento não incluirá uma referência ao seu arquivo resources.resw porque o conteúdo desse arquivo já foi integrado ao arquivo PRI. Entretanto, ele incluirá outros recursos, como os nomes de arquivos de suas imagens.

Fazendo o build e assinatura do pacote

Agora que o arquivo PRI foi criado, é possível fazer o build e assinar o pacote:

  1. Para criar o pacote do aplicativo, execute o comando a seguir, substituindo contoso_demo.appx pelo nome do arquivo .msix/.appx que quer criar e garantindo que seja escolhido um diretório diferente para o arquivo (esta amostra usa o diretório responsável; ela pode estar em qualquer lugar, mas não deve ser o diretório do projeto).

    makeappx pack /m AppXManifest.xml /f ..\resources.map.txt /p ..\contoso_demo.appx /o
    

    Para ver o que cada parâmetro faz, digite makeappx pack /?, mas em resumo:

    • /m define o arquivo de manifesto que será usado
    • /f define o arquivo de mapeamento que será usado (criado na etapa anterior)
    • /p define o nome do pacote de saída
    • /o define para Substituir o arquivo de saída se ele existir
  2. Após a criação do pacote, ele deve ser assinado. A maneira mais fácil de obter um certificado de autenticação é criando um projeto vazio do Universal Windows no Visual Studio e fazendo uma cópia do arquivo .pfx que ele cria, mas é possível criar um manualmente com o uso dos utilitários MakeCert e Pvk2Pfx, conforme descrito em Como criar um certificado de assinatura de pacote de aplicativo.

    Importante

    Caso crie um certificado de autenticação manualmente, verifique se os arquivos estão em um diretório diferente do projeto original ou da origem do pacote; do contrário, ele pode ser incluído como parte do pacote, inclusive a chave privada.

  3. Use o comando a seguir para assinar o pacote. Observe que o Publisher especificado no elemento Identity do AppxManifest.xml deve corresponder ao Subject do certificado (esse não é o elemento <PublisherDisplayName>, que é o nome de exibição localizado que será mostrado aos usuários). Como sempre, substitua os nomes dos arquivos contoso_demo... pelos nomes adequados ao seu projeto e (muito importante) verifique se o arquivo .pfx não está no diretório atual ( do contrário, ele terá sido criado como parte do seu pacote, incluindo a chave de assinatura privada.):

    signtool sign /fd SHA256 /a /f ..\contoso_demo_key.pfx ..\contoso_demo.appx
    

    Para ver o que cada parâmetro faz, digite signtool sign /?, mas em resumo:

    • /fd define o algoritmo do resumo de arquivos (SHA256 é o padrão para .appx)
    • /a selecionará automaticamente o melhor certificado
    • /f especifica o arquivo de entrada que contém o certificado de autenticação

Por fim, basta clicar duas vezes no arquivo .appx para fazer a instalação ou, se preferir a linha de comando, abra um prompt do PowerShell, vá até o diretório que contém o pacote e digite o seguinte (substituindo contoso_demo.appx pelo nome do pacote):

add-appxpackage contoso_demo.appx

Caso receba erros em relação ao certificado não ser confiável, verifique se ele foi adicionado ao repositório do computador (não ao repositório do usuário). Basta usar a linha de comando ou o Finder para adicionar o certificado ao repositório do computador.

Para usar a linha de comando:

  1. Execute um prompt de comando do Visual Studio 2017 ou Visual Studio 2019 como administrador.

  2. Mude para o diretório que contém o arquivo .cer (lembre-se de garantir que ele esteja fora dos diretórios originais ou de projeto).

  3. Digite o comando a seguir, substituindo contoso_demo.cer nome do arquivo:

    certutil -addstore TrustedPeople contoso_demo.cer
    

    Para ver o que cada parâmetro faz, basta fazer a execução do certutil -addstore /?, mas em resumo:

    • -addstore adiciona um certificado a um repositório de certificados
    • TrustedPeople indica o repositório no qual o certificado está localizado

Para usar o Finder:

  1. Navegue até a pasta que contém o arquivo .pfx
  2. Clique duplo no arquivo .pfx e o Assistente de importação da certificação deve ser exibido
  3. Escolha Local Machine e clique em Next
  4. Aceite a solicitação de elevação de administrador do Controle de Conta de Usuário, caso seja exibida, e clique em Next
  5. Digite a senha da chave privada, se houver, e clique em Next
  6. Selecione Place all certificates in the following store
  7. Clique em Browse, e escolha a pasta Trusted People (e não a "Fornecedores confiáveis")
  8. Clique em Next e, em seguida, em Finish

Após adicionar o certificado ao repositório Trusted People, tente instalar o pacote novamente.

Agora o aplicativo deve aparecer na lista "All apps" do menu Iniciar, com as informações corretas do arquivo .resw / .pri. Caso veja uma sequência de caracteres em branco ou a sequência de caracteres ms-resource:..., então algo deu errado, verifique novamente suas edições e confirme se estão corretas. Ao clicar com o botão direito do mouse no aplicativo no menu Iniciar, é possível marcar o aplicativo como um bloco e verificar se as informações corretas também são exibidas ali.

Etapa 1.3: Adicionar mais idiomas de suporte

Uma vez que as alterações foram feitas no manifesto do pacote e o arquivo resources.resw inicial foi criado, é fácil adicionar outros idiomas.

Criar recursos localizados adicionais

Primeiro, crie os valores de recursos localizados adicionais.

Na pasta Strings, crie pastas adicionais para cada idioma que oferecer suporte usando o código BCP-47 adequado (por exemplo, Strings\de-DE). Em cada uma dessas pastas, crie um arquivo resources.resw (usando um editor XML ou o designer do Visual Studio) que inclua os valores de recursos traduzidos. Supõe-se que as sequências de caracteres localizadas já estejam disponíveis em algum lugar e que basta copiar essas sequências para o arquivo .resw; este documento não aborda a etapa de tradução em si.

Por exemplo, o arquivo Strings\de-DE\resources.resw pode se parecer com isto, com o texto em destaque alterado de en-US:

<?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>

As etapas a seguir pressupõem que foram adicionados recursos para ambos de-DE e fr-FR, mas o mesmo padrão pode ser seguido para qualquer idioma.

Atualize o manifesto do pacote para listar os idiomas com suporte

O manifesto do pacote deve ser atualizado para listar os idiomas com suporte do aplicativo. O Desktop App Converter adiciona o idioma padrão, mas os outros devem ser adicionados de maneira explícita. Caso esteja editando o arquivo AppxManifest.xml diretamente, atualize o node Resources da seguinte forma, adicionando quantos elementos forem necessários, substituindo os idiomas adequados que tiver suporte e garantindo que a primeira entrada da lista seja o idioma padrão (fallback). Neste exemplo, o padrão é inglês (EUA) com suporte adicional para alemão (Alemanha) e francês (França):

<Resources>
  <Resource Language="EN-US" />
  <Resource Language="DE-DE" />
  <Resource Language="FR-FR" />
</Resources>

Caso esteja usando o Visual Studio, não será preciso fazer nada; ao olhar para o Package.appxmanifest, você verá o valor especial x-generate, que faz com que o processo de build insira os idiomas encontrados em seu projeto (com base nas pastas nomeadas com os códigos BCP-47). Observe que esse não é um valor válido para um manifesto do pacote real; ele só funciona em projetos do Visual Studio:

<Resources>
  <Resource Language="x-generate" />
</Resources>

Fazer o re-build com os valores localizados

Agora é possível fazer o build e o deploy do aplicativo novamente e, se fizer a alteração da preferência de idioma no Windows, será possível ver os valores recém-localizados aparecerem no menu Iniciar (as instruções sobre como alterar o idioma estão abaixo).

Para o Visual Studio, novamente, é possível usar o recurso Ctrl+Shift+B para fazer o build e clicar com o botão direito do mouse no projeto para Deploy.

Caso esteja fazendo o build do projeto manualmente, siga as mesmas etapas acima, mas insira os idiomas adicionais, separados por sublinhados, na lista de qualificadores padrão (/dq) ao criar o arquivo de configuração. Por exemplo, para dar suporte aos recursos em inglês, alemão e francês adicionados na etapa anterior:

makepri createconfig /cf ..\contoso_demo.xml /dq en-US_de-DE_fr-FR /pv 10.0 /o

Isso cria um arquivo PRI que contém todos os idiomas especificados, que podem ser usados com facilidade para testes. Se o tamanho total dos seus recursos for pequeno, ou se oferecer suporte a apenas um pequeno número de idiomas, isso pode ser aceitável para o seu aplicativo de envio; somente no caso de você querer os benefícios de minimizar o tamanho da instalação/download dos seus recursos é que precisa fazer o trabalho adicional de build dos pacotes de idiomas separados.

Teste com os valores localizados

É só adicionar um novo idioma preferencial da interface do usuário ao Windows para testar as novas alterações localizadas. Não é necessário fazer download de pacotes de idiomas, reinicializar o sistema ou fazer com que toda a interface do usuário do Windows seja exibida em um idioma estrangeiro.

  1. Executar o aplicativo Settings (Windows + I)
  2. Acesse Time & language
  3. Acesse Region & language
  4. Clique em Add a language
  5. Digite (ou selecione) o idioma de sua preferência (por exemplo, Deutsch ou German)
  • Se houver subidiomas, escolha aquele de sua preferência (por exemplo, Deutsch / Deutschland)
  1. Selecione o novo idioma na lista de idiomas
  2. Clique em Set as default

Agora, abra o menu Iniciar e pesquise pelo seu aplicativo, e devem ser exibidos os valores localizados para o idioma selecionado (outros aplicativos também podem aparecer localizados). Caso não veja o nome localizado de imediato, aguarde alguns minutos até que o cache do menu Iniciar seja atualizado. Para voltar à sua linguagem nativa, basta definir como o idioma padrão na lista de idiomas.

Etapa 1.4: Localização de mais partes do manifesto do pacote (opcional)

Outras seções do manifesto do pacote podem ser localizadas. Por exemplo, se o seu aplicativo lida com extensões de arquivos, ele deverá ter uma extensão windows.fileTypeAssociation no manifesto, usando o texto em destaque em verde exatamente como mostrado (já que ele se referirá a recursos) e substituindo o texto em destaque em amarelo por informações específicas do seu aplicativo:

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

Também é possível adicionar essas informações usando o Visual Studio Manifest Designer, usando a guia Declarations, observando os valores em destaque:

Screenshot of the Visual Studio Manifest Designer showing the Declarations tab with the Display name and Info tip text boxes called out.

Agora, adicione os nomes de recursos correspondentes a cada um de seus arquivos .resw, substituindo o texto em destaque pelo texto adequado ao seu aplicativo (lembre-se de fazer isso em todos os idiomas com suporte.):

... existing content...
<data name="FileTypeDisplayName">
  <value>Contoso Demo File</value>
</data>
<data name="FileTypeInfoTip">
  <value>Files used by Contoso Demo App</value>
</data>

Isso será exibido em partes do shell do Windows, como o Explorador de arquivos:

Screenshot of File Explorer showing a tooltip that says Files used by Contoso Demo App.

Faça o build e teste o pacote da mesma forma que antes, aplicando todos os novos cenários que devem mostrar as novas sequências de caracteres da interface do usuário.

Fase 2: Como usar o MRT para identificar e localizar recursos

A seção anterior ensinou como usar o MRT para localizar o arquivo de manifesto do aplicativo para que o Shell do Windows exiba corretamente o nome do aplicativo e outros metadados. Não foram necessárias alterações no código para isso; bastou que fossem usados arquivos .resw e algumas ferramentas adicionais. Esta seção ensinará como usar o MRT para localizar recursos nos formatos de recursos existentes e usar o código de tratamento de recursos existente com alterações mínimas.

Pressuposições sobre o layout de arquivo e o código do aplicativo existentes

Como há muitas maneiras de localizar aplicativos Win32 Desktop, este documento faz algumas pressuposições simplificadoras sobre a estrutura do aplicativo existente que será preciso mapear para o seu ambiente específico. Talvez tenha de fazer algumas alterações na base de código ou no layout de recursos existentes para estar em conformidade com os requisitos do MRT, e isso está fora do escopo deste documento.

Layout do arquivo de recurso

Este artigo pressupõe que todos os seus recursos localizados tenham os mesmos nomes de arquivo (por exemplo, contoso_demo.exe.mui ou contoso_strings.dll ou contoso.strings.xml), mas que estejam localizados em pastas diferentes com nomes BCP-47 (en-US, de-DE, etc.). Não importa quantos arquivos de recursos existam, quais são seus nomes, quais são seus formatos de arquivo/APIs associadas e entre outros. A única coisa que importa é que cada recurso lógico tenha o mesmo nome de arquivo (mas que esteja em um diretório físico diferente).

Como um contraexemplo, se o seu aplicativo usar uma estrutura de arquivos simples com um único diretório Resources contendo os arquivos english_strings.dll e french_strings.dll, ele não será bem mapeado para o MRT. Uma estrutura melhor é um Resources diretório com subdiretórios e arquivos en\strings.dll e fr\strings.dll. Também é possível usar o mesmo nome de arquivo base, mas com qualificadores integrados, como strings.lang-en.dll e strings.lang-fr.dll, mas usar diretórios com os códigos de idioma é muito mais simples do ponto de vista conceitual, portanto, vamos nos focar nisso.

Observação

Ainda é possível usar o MRT e os benefícios do empacotamento, mesmo que não seja possível seguir essa convenção de nomenclatura de arquivos; isso só requer mais trabalho.

Por exemplo, o aplicativo pode ter um conjunto de comandos de interface do usuário personalizados (usados para rótulos de botões e outros) em um arquivo de texto simples chamado ui.txt, localizado em uma pasta 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...

Código de carregamento de recursos

Este artigo pressupõe que, em algum ponto do seu código, você queira localizar o arquivo que contém um recurso localizado, carregar esse recurso e usar o mesmo. As APIs usadas para carregar os recursos, as APIs usadas para extrair os recursos e outras, não têm importância. No pseudocódigo, há basicamente três etapas:

set userLanguage = GetUsersPreferredLanguage()
set resourceFile = FindResourceFileForLanguage(MY_RESOURCE_NAME, userLanguage)
set resource = LoadResource(resourceFile) 
    
// now use 'resource' however you want

O MRT requer apenas a alteração das duas primeiras etapas desse processo, como você determina os melhores recursos candidatos e como você localiza esses recursos. Ele não requer que uma alteração na forma como os recursos são carregados ou usados (embora ofereça instalações para fazer isso, caso queira usufruir deles).

Por exemplo, o aplicativo pode usar a API do Win32 GetUserPreferredUILanguages, a função CRT sprintf e a API do Win32 CreateFile para substituir as três funções de pseudocódigo acima e, em seguida, analisar manualmente o arquivo de texto em busca de pares name=value. (Os detalhes não têm importância; a intenção é apenas ilustrar que o MRT não tem impacto sobre as técnicas usadas para lidar com os recursos depois que eles são localizados).

Etapa 2.1: Alterações no código para usar o MRT para localizar arquivos

Não é difícil comutar seu código para usar o MRT na localização de recursos. Isso requer o uso de alguns tipos de WinRT e algumas linhas de código. Os principais tipos que serão usados são os seguintes:

  • ResourceContext, que encapsula o conjunto de valores de qualificador ativo atualmente (idioma, fator de escala, entre outros).
  • ResourceManager (a versão WinRT, não a versão .NET), que habilita o acesso a todos os recursos do arquivo PRI
  • ResourceMap, que representa um subconjunto específico dos recursos no arquivo PRI (neste exemplo, os recursos baseados em arquivo versus os recursos de sequência)
  • NamedResource, que representa um recurso lógico e todos os seus possíveis candidatos
  • ResourceCandidate, que representa um único recurso candidato concreto

Em pseudocódigo, a maneira de resolver um determinado nome de arquivo de recurso (como UICommands\ui.txt no exemplo acima) é a seguinte:

// 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

Observe, em particular, que o código não solicita uma pasta de idioma específica, como UICommands\en-US\ui.txt, mesmo que seja dessa forma que os arquivos existam no disco. No entanto, ele solicita o nome do arquivo UICommands\ui.txtlógico e depende do MRT para encontrar o arquivo adequado no disco em um dos diretórios de idiomas.

Desse ponto em diante, o aplicativo de amostra pode continuar a usar CreateFile para carregar o absoluteFileName e analisar os pares name=value como antes; nenhuma lógica precisa ser alterada no aplicativo. Caso esteja escrevendo em C# ou C++/CX, o código real não é muito mais complicado do que isso (e, na verdade, muitas das variáveis intermediárias podem ser eliminadas), consulte a seção sobre Carregamento de recursos do .NET, abaixo. Os aplicativos baseados em C++/WRL serão mais complexos em razão das APIs de baixo nível baseadas em COM que são usadas para ativar e chamar as APIs do WinRT, mas as etapas fundamentais são as mesmas, consulte a seção sobre Carregamento de recursos do Win32 MUI, abaixo.

Carregamento de recursos do .NET

Como o .NET tem um mecanismo interno para localizar e carregar recursos (conhecido como "Assemblies Satélite"), não há nenhum código explícito a ser substituído, como no exemplo sintético acima, no .NET, basta que as DLLs de recursos estejam nos diretórios adequados e elas serão localizadas automaticamente para você. Quando um aplicativo é empacotado como MSIX ou .appx com o uso de pacotes de recursos, a estrutura de diretórios é um pouco diferente: em vez de os diretórios de recursos serem subdiretórios do diretório principal do aplicativo, eles são pares dele (ou não estão presentes se o usuário não tiver o idioma listado em suas preferências).

Por exemplo, imagine um aplicativo .NET com o seguinte layout, em que todos os arquivos existem na pasta MainApp:

+ MainApp
|--+ en-us
|  \--- MainApp.resources.dll
|--+ de-de
|  \--- MainApp.resources.dll
|--+ fr-fr
|  \--- MainApp.resources.dll
\--- MainApp.exe

Após a conversão para .appx, o layout terá a seguinte aparência, pressupondo en-US que seja o idioma padrão e o usuário tenha os idiomas alemão e francês em sua lista de idiomas:

+ 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

Como os recursos localizados deixaram de existir em subdiretórios abaixo do local de instalação do executável principal, a resolução de recursos .NET interna falha. Por sorte, o .NET tem um mecanismo muito bem definido para tratar as tentativas de carregamento de assembly que falharam: o evento AssemblyResolve. Um aplicativo .NET que usa MRT precisa se registrar para esse evento e fornecer o assembly ausente para o subsistema de recursos .NET.

Um exemplo conciso de como usar as APIs do WinRT para localizar assemblies satélites que são usados pelo .NET é o seguinte; o código apresentado foi intencionalmente compactado para exibir uma implementação mínima, embora seja possível ver que ele mapeia de perto o pseudocódigo acima, com o código ResolveEventArgs passado fornecendo o nome do assembly que precisamos localizar. Uma versão executável desse código (com comentários detalhados e tratamento de erros) é encontrada no arquivo PriResourceRsolver.cs da amostra do .NET Resolvedor Assembly no 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);
  }
}

Com base na classe acima, seria possível adicionar o seguinte em algum lugar no início do código de inicialização do aplicativo (antes que qualquer recurso localizado precise carregar):

void EnableMrtResourceLookup()
{
  AppDomain.CurrentDomain.AssemblyResolve += PriResourceResolver.ResolveResourceDll;
}

O runtime do .NET acionará o evento AssemblyResolve sempre que não conseguir encontrar as DLLs de recursos, momento em que o manipulador de eventos fornecido localizará o arquivo desejado por meio do MRT e devolverá o assembly.

Observação

Caso seu aplicativo já tenha um manipulador AssemblyResolve para outras finalidades, é necessário integrar o código de resolução de recursos ao código existente.

Carregamento de recursos Win32 MUI

O carregamento de recursos Win32 MUI é basicamente o mesmo que o carregamento de assemblies satélite .NET, mas com o uso de código C++/CX ou C++/WRL. O uso do C++/CX permite a criação de um código muito mais simples que se assemelha ao código C# acima, mas usa extensões de linguagem C++, opções de compilador e sobrecarga de runtime adicional que é melhor ser evitada. Nesse caso, o uso do C++/WRL oferece uma solução de impacto muito menor ao custo de um código mais detalhado. Contudo, caso conheça a programação ATL (ou COM em geral), o WRL deve ser algo que seja familiar.

A função da amostra a seguir explica como usar o C++/WRL para carregar uma DLL de recurso específica e devolver uma HINSTANCE que pode ser usada para carregar outros recursos usando as APIs de recursos Win32 comuns. Observe que, diferente da amostra em C# que inicializa explicitamente o ResourceContext com o idioma solicitado pelo runtime do .NET, esse código se baseia no idioma atual do usuário.

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

Fase 3: Como fazer o build de pacotes de recursos

Agora que temos um "pacote grande" que contém todos os recursos, há dois caminhos para fazer o build de pacotes principais e de recursos separados para minimizar o tamanho do download e da instalação:

  • Pegue um pacote grande existente e execute na ferramenta Bundle Generator para a criação automática de pacotes de recursos. Essa é a abordagem preferida quando se tem um sistema de build que já produz um pacote grande e se deseja realizar o pós-processamento para gerar os pacotes de recursos.
  • Faça a produção direta dos pacotes de recursos individuais e faça o build deles em um agrupamento. Essa é a abordagem preferida caso tenha mais controle sobre o seu sistema de build e puder fazer o build dos pacotes diretamente.

Etapa 3.1: Criação do agrupamento

Com a ferramenta Bundle Generator

Para usar a ferramenta Bundle Generator, o arquivo de configuração PRI criado para o pacote tem de ser atualizado manualmente para remover a seção <packaging>.

Caso esteja usando o Visual Studio, consulte Garantir que os recursos sejam instalados em um dispositivo, mesmo que o dispositivo requeira esses recursos, para obter informações sobre como fazer o build de todas as linguagens no pacote principal, criando os arquivos priconfig.packaging.xml e arquivos priconfig.default.xml.

Caso esteja fazendo a edição manual de arquivos, siga estas etapas:

  1. Crie o arquivo de configuração do mesmo modo que antes, substituindo o caminho, o nome de arquivo e os idiomas corretos:

    makepri createconfig /cf ..\contoso_demo.xml /dq en-US_de-DE_es-MX /pv 10.0 /o
    
  2. Abra manualmente o arquivo .xml criado e exclua a seção &lt;packaging&rt; inteira (mas deixe o resto intacto):

    <?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>
        ...
        ...
    
  3. Faça o build do arquivo .pri e do pacote .appx como antes, por meio do arquivo de configuração atualizado e dos nomes adequados de diretório e arquivo (consulte acima para obter mais informações sobre esses comandos):

    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
    
  4. Após a criação do pacote, use o comando a seguir para criar o agrupamento, usando o diretório e os nomes de arquivo adequados:

    BundleGenerator.exe -Package ..\contoso_demo.appx -Destination ..\bundle -BundleName contoso_demo
    

Em seguida, siga para a etapa final, a assinatura (veja abaixo).

Criação manual de pacotes de recursos

A criação manual de pacotes de recursos requer que seja executado um conjunto um pouco diferente de comandos para fazer o build de arquivos .pri e .appx separados, todos eles são semelhantes aos comandos usados acima para criar pacotes grandes, portanto, não há necessidade de explicação. Observação: Todos os comandos pressupõem que o diretório atual é o diretório que contém o arquivo AppXManifest.xml, mas todos os arquivos estão no diretório responsável (é possível usar um diretório diferente, se necessário, mas não se deve poluir o diretório do projeto com nenhum desses arquivos). Como sempre, substitua os nomes de arquivos "Contoso" pelos de sua preferência.

  1. Execute o comando a seguir para criar um arquivo de configuração que nomeie apenas o idioma padrão como o qualificador padrão, nesse caso, en-US:

    makepri createconfig /cf ..\contoso_demo.xml /dq en-US /pv 10.0 /o
    
  2. Crie um arquivo padrão .pri e um arquivo .map.txt para o pacote principal, além de um conjunto adicional de arquivos para cada idioma que se encontra em seu projeto, com o comando a seguir:

    makepri new /pr . /cf ..\contoso_demo.xml /of ..\resources.pri /mf AppX /o
    
  3. Execute o comando a seguir para a criação do pacote principal (que contém o código executável e os recursos de idioma padrão). Como sempre, altere o nome da forma que achar melhor, embora deva colocar o pacote em um diretório separado para facilitar a criação do agrupamento no futuro (este exemplo usa o diretório ..\bundle):

    makeappx pack /m .\AppXManifest.xml /f ..\resources.map.txt /p ..\bundle\contoso_demo.main.appx /o
    
  4. Após a criação do pacote principal, execute o comando a seguir uma vez em cada idioma adicional (ou seja, repita esse comando para cada arquivo de mapa de idioma gerado na etapa anterior). Mais uma vez, a saída deve estar em um diretório separado (o mesmo do pacote principal). Observe que o idioma é especificado tanto na opção /f e quanto na opção /p, e o uso do novo argumento /r (que indica que um pacote de recursos é desejado):

    makeappx pack /r /m .\AppXManifest.xml /f ..\resources.language-de.map.txt /p ..\bundle\contoso_demo.de.appx /o
    
  5. Combine todos os pacotes do diretório agrupado em um único arquivo .appxbundle. A nova opção /d especifica o diretório a ser usado para todos os arquivos do agrupamento (é por isso que os arquivos .appx são colocados em um diretório separado na etapa anterior):

    makeappx bundle /d ..\bundle /p ..\contoso_demo.appxbundle /o
    

A última etapa do build do pacote é a assinatura.

Etapa 3.2: Assinatura do agrupamento

Após a criação do arquivo .appxbundle (por meio da ferramenta Bundle Generator ou manualmente), haverá um único arquivo que contém o pacote principal e todos os pacotes de recursos. A última etapa é assinar o arquivo para que o Windows instale o arquivo:

signtool sign /fd SHA256 /a /f ..\contoso_demo_key.pfx ..\contoso_demo.appxbundle

Isso produzirá um arquivo .appxbundle assinado que contém o pacote principal e todos os pacotes de recursos específico a um idioma. Ele pode receber um clique duplo, assim como um arquivo de pacote, para instalar o aplicativo e qualquer idioma(s) adequado(s) com base nas preferências de idioma do Windows do usuário.