Localizar sequências na interface do usuário e no manifesto do pacote do aplicativo
Para obter mais informações sobre a proposta de valor de localização do aplicativo, consulte Globalização e localização.
Se você deseja que o aplicativo dê suporte a diferentes idiomas de exibição e tem literais de cadeia de caracteres no código, na marcação XAML ou no manifesto do pacote do aplicativo, mova essas cadeias de caracteres para um arquivo de recursos (.resw). Em seguida, você poderá fazer uma cópia traduzida desse arquivo de recursos para cada idioma ao qual o aplicativo dê suporte.
Literais de sequência codificados podem aparecer em código imperativo ou em marcação XAML, por exemplo, como a propriedade Texto de um TextBlock. Eles também podem aparecer no arquivo de origem do manifesto do pacote do aplicativo (o arquivo Package.appxmanifest
), por exemplo, como o valor para Nome de exibição na guia Aplicativo do Designer de Manifesto do Visual Studio. Mova essas sequências para um Arquivo de Recursos (.resw) e substitua os literais de sequência codificados em seu aplicativo e em seu manifesto por referências a identificadores de recursos.
Ao contrário dos recursos de imagem, em que apenas um recurso de imagem está contido em um arquivo de recurso de imagem, vários recursos de sequência estão contidos em um arquivo de recurso de sequência. Um arquivo de recurso de sequência é um Arquivo de Recursos (.resw), e você normalmente cria esse tipo de arquivo em uma pasta \Strings no projeto. Para obter informações básicas sobre como usar qualificadores nos nomes de seus arquivos de recursos (.resw), confira Personalizar seus recursos para idioma, escala e outros qualificadores.
Armazenar sequências em um arquivo de recursos
Defina o idioma padrão do seu aplicativo.
- Com sua solução aberta no Visual Studio, abra o
Package.appxmanifest
. - Na guia Aplicativo, confirme se o idioma padrão está definido adequadamente (por exemplo, "en" ou "en-US"). As etapas restantes pressupõem que você definiu o idioma padrão como "en-US".
Observação
No mínimo, é preciso fornecer recursos de cadeia de caracteres localizados para esse idioma padrão. Esses são os recursos que serão carregados se nenhuma correspondência melhor for encontrada para o idioma preferido do usuário ou as configurações de idioma de exibição.
- Com sua solução aberta no Visual Studio, abra o
Crie um arquivo de recursos (.resw) para o idioma padrão.
- No nó do projeto, crie uma nova pasta e nomeie-a
Strings
. - Em
Strings
, crie uma subpasta e nomeie-aen-US
. - Em
en-US
, crie um novo arquivo de recursos (.resw) (nos tipos de arquivo XAML na caixa de diálogo Adicionar novo item) e confirme se ele se chamaResources.resw
.
Observação
Se você tiver arquivos de recursos do .NET (.resx) que deseja fazer portabilidade, confira Fazer portabilidade de XAML e da interface do usuário.
- No nó do projeto, crie uma nova pasta e nomeie-a
Abra
Resources.resw
e inclua esses recursos de sequência.Strings/en-US/Resources.resw
Neste exemplo, "Greeting" é um identificador de recurso de sequência que você pode consultar na sua marcação, como mostraremos a seguir. Para o identificador "Greeting", uma sequência é fornecida para uma propriedade Text e uma sequência é fornecida para uma propriedade Width. "Greeting.Text" é um exemplo de identificador de propriedade, pois corresponde a uma propriedade de um elemento da interface do usuário. Você também pode, por exemplo, adicionar "Greeting.Foreground" na coluna Nome e definir o Valor como "Vermelho". O identificador "Farewell" é um identificador de recurso de sequência simples, sem subpropriedades e que pode ser carregado a partir de código imperativo, como mostraremos a seguir. A coluna Comentário é um bom lugar para fornecer instruções especiais aos tradutores.
Neste exemplo, como temos uma entrada de identificador de recurso de sequência simples chamada "Farewell", não podemos também ter identificadores de propriedade baseados nesse mesmo identificador. Portanto, adicionar "Farewell.Text" causaria um erro de entrada duplicada durante a compilação de
Resources.resw
.Os identificadores de recursos não diferenciam maiúsculas de minúsculas e devem ser exclusivos por arquivo de recurso. Use identificadores de recursos significativos para fornecer contexto adicional aos tradutores. E não altere os identificadores de recursos depois que os recursos de sequência forem enviados para tradução. As equipes de localização usam o identificador de recursos para acompanhar adições, exclusões e atualizações nos recursos. As alterações nos identificadores de recursos, também conhecidas como "mudança de identificadores de recursos", exigem que as sequências sejam retraduzidas, porque parecerá que as sequências foram excluídas e outras adicionadas.
Consultar um identificador de recurso de sequência do XAML
Use uma diretiva x:Uid para associar um controle ou outro elemento em sua marcação a um identificador de recurso de sequência.
<TextBlock x:Uid="Greeting"/>
Em tempo de execução, \Strings\en-US\Resources.resw
é carregado (já que no momento esse é o único arquivo de recursos no projeto). A diretiva x:Uid em TextBlock faz com que uma pesquisa seja realizada para encontrar identificadores de propriedade dentro de Resources.resw
que contenham o identificador de recurso de sequência "Greeting". Os identificadores de propriedade "Greeting.Text" e "Greeting.Width" são encontrados, e seus valores são aplicados ao TextBlock, substituindo todos os valores definidos localmente na marcação. O valor "Greeting.Foreground" também seria aplicado se você o tivesse adicionado. Mas apenas identificadores de propriedade são usados para definir propriedades em elementos de marcação XAML. Portanto, definir x:Uid como "Farewell" neste TextBlock não teria efeito. Resources.resw
contém o identificador de recurso de cadeia de caracteres "Farewell", mas não contém identificadores de propriedade para ele.
Ao atribuir um identificador de recurso de sequência a um elemento XAML, certifique-se de que todos os identificadores de propriedade desse identificador sejam apropriados para o elemento XAML. Por exemplo, se você definir x:Uid="Greeting"
em um TextBlock, "Greeting.Text" será resolvido, pois o tipo TextBlock tem uma propriedade Text. Mas se você definir x:Uid="Greeting"
em um botão, "Greeting.Text" causará um erro em tempo de execução porque o tipo botão não tem uma propriedade Text. Uma solução para esse caso é criar um identificador de propriedade chamado "ButtonGreeting.Content" e definir x:Uid="ButtonGreeting"
no Botão.
Em vez de definir a Largura de um Arquivo de Recursos, você provavelmente desejará permitir que os controles sejam dimensionados dinamicamente de acordo com o conteúdo.
Observação Para propriedades anexadas, você precisa de uma sintaxe especial na coluna Nome de um arquivo .resw. Por exemplo, para definir um valor para a propriedade anexada AutomationProperties.Name para o identificador "Greeting", isso é o que você inseriria na coluna Nome.
Greeting.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name
Consultar um identificador de recurso de sequência a partir do código
Você pode fazer upload explicitamente de um recurso de sequência com base em um identificador de recurso de sequência simples.
Observação
Se você tiver uma chamada para qualquer método GetForCurrentView que possa ser executado em um thread de trabalho/em segundo plano, proteja essa chamada com um teste if (Windows.UI.Core.CoreWindow.GetForCurrentThread() != null)
. Chamar GetForCurrentView de um thread de trabalho/em segundo plano resulta na exceção "<typename> não pode ser criado em threads que não têm um CoreWindow."
var resourceLoader = Windows.ApplicationModel.Resources.ResourceLoader.GetForCurrentView();
this.myXAMLTextBlockElement.Text = resourceLoader.GetString("Farewell");
auto resourceLoader{ Windows::ApplicationModel::Resources::ResourceLoader::GetForCurrentView() };
myXAMLTextBlockElement().Text(resourceLoader.GetString(L"Farewell"));
auto resourceLoader = Windows::ApplicationModel::Resources::ResourceLoader::GetForCurrentView();
this->myXAMLTextBlockElement->Text = resourceLoader->GetString("Farewell");
Você pode usar esse mesmo código de dentro de uma biblioteca de classes (Universal Windows) ou um projeto biblioteca do Windows Runtime (Universal Windows). Em runtime, os recursos do aplicativo que está hospedando a biblioteca são carregados. É recomendável que uma biblioteca carregue os recursos do aplicativo que a hospeda, pois é provável que o aplicativo tenha um maior grau de localização. Se uma biblioteca precisar fornecer recursos, ela deverá dar ao aplicativo de hospedagem a opção de substituir esses recursos como entrada.
Se um nome de recurso for segmentado (ele contém caracteres "."), substitua pontos por caracteres de barra ("/") no nome do recurso. Os identificadores de propriedade, por exemplo, contêm pontos; então, você precisaria fazer essa substituição para carregar um deles a partir do código.
this.myXAMLTextBlockElement.Text = resourceLoader.GetString("Fare/Well"); // <data name="Fare.Well" ...> ...
Em caso de dúvida, você pode usar MakePri.exe para despejar o arquivo PRI do seu aplicativo. O uri
de cada recurso é mostrado no arquivo despejado.
<ResourceMapSubtree name="Fare"><NamedResource name="Well" uri="ms-resource://<GUID>/Resources/Fare/Well">...
Consulte um identificador de recurso de sequência no manifesto do pacote do aplicativo
Abra o arquivo de origem do manifesto do pacote do aplicativo (o arquivo
Package.appxmanifest
), no qual, por padrão, oDisplay name
do aplicativo é expresso como um literal de cadeia de caracteres.Para criar uma versão localizável dessa sequência, abra
Resources.resw
e adicione um novo recurso de sequência com o nome "AppDisplayName" e o valor "Adventure Works Cycles".Substitua o literal de cadeia de caracteres de nome de exibição por uma referência ao identificador de recurso de sequência que você acabou de criar ("AppDisplayName"). Use o esquema URI (“Uniform Resource Identifier”)
ms-resource
para fazer isso.Repita esse processo para cada sequência no manifesto que deseja localizar. Por exemplo, o nome curto do aplicativo (que você pode configurar para aparecer no bloco do aplicativo na tela de início). Para obter uma lista de todos os itens no manifesto do pacote do aplicativo que você pode localizar, confira Itens de manifesto localizáveis.
Localizar os recursos de sequência
Faça uma cópia do Arquivo de Recursos (.resw) para outro idioma.
- Em "Strings", crie uma subpasta e a nomeie como "de-DE" para Deutsch (Deutschland).
Observação Para o nome da pasta, você pode usar qualquer tag de idioma BCP-47. Consulte Personalizar recursos de idioma, escala e outros qualificadores para obter detalhes sobre o qualificador de idioma e uma lista de tags de idioma comuns. - Faça uma cópia do
Strings/en-US/Resources.resw
na pastaStrings/de-DE
.
- Em "Strings", crie uma subpasta e a nomeie como "de-DE" para Deutsch (Deutschland).
Traduza as sequências.
- Abra
Strings/de-DE/Resources.resw
e traduza os valores na coluna Valor. Você não precisa traduzir os comentários.
Strings/de-DE/Resources.resw
- Abra
Se desejar, repita as etapas 1 e 2 para outro idioma.
Strings/fr-FR/Resources.resw
Testar seu aplicativo
Teste o aplicativo para seu idioma de exibição padrão. Em seguida, você pode alterar o idioma de exibição em Configurações>Hora e idioma>Região e idioma>Idiomas e testar novamente seu aplicativo. Observe as sequências na interface do usuário e também no shell (por exemplo, a barra de título, que é o nome de exibição, e o Nome curto nos blocos).
Observação Se for encontrado um nome de pasta que corresponda à configuração do idioma de exibição, o arquivo de recursos dentro dessa pasta será carregado. Caso contrário, o fallback ocorre, terminando com os recursos para o idioma padrão do seu aplicativo.
Fatoração de sequências em vários arquivos de recursos
Você pode manter todas as sequências em um único arquivo de recursos (resw) ou fatorá-las em vários arquivos de recursos. Por exemplo, talvez você queira manter suas mensagens de erro em um arquivo de recursos, as sequências de manifesto do pacote do aplicativo em outro e as sequências da interface do usuário em um terceiro. Esta é a aparência da sua estrutura de pastas nesse caso.
Para definir o escopo de uma referência de identificador de recurso de sequência a um arquivo específico, basta adicionar /<resources-file-name>/
antes do identificador. O exemplo de marcação abaixo pressupõe que ErrorMessages.resw
contém um recurso cujo nome é "PasswordTooWeak.Text" e cujo valor descreve o erro.
<TextBlock x:Uid="/ErrorMessages/PasswordTooWeak"/>
Você só precisa adicionar /<resources-file-name>/
antes do identificador de recurso de cadeia de caracteres para arquivos de recursos diferentes de Resources.resw
. Isso ocorre porque "Resources.resw" é o nome de arquivo padrão, então é isso que se presume se você omitir um nome de arquivo (como fizemos nos exemplos anteriores neste tópico).
O exemplo de código abaixo pressupõe que ErrorMessages.resw
contém um recurso cujo nome é "MismatchedPasswords" e cujo valor descreve o erro.
Observação
Se você tiver uma chamada para qualquer método GetForCurrentView que possa ser executado em um thread de trabalho/em segundo plano, proteja essa chamada com um teste if (Windows.UI.Core.CoreWindow.GetForCurrentThread() != null)
. Chamar GetForCurrentView de um thread de trabalho/em segundo plano resulta na exceção "<typename> não pode ser criado em threads que não têm um CoreWindow."
var resourceLoader = Windows.ApplicationModel.Resources.ResourceLoader.GetForCurrentView("ErrorMessages");
this.myXAMLTextBlockElement.Text = resourceLoader.GetString("MismatchedPasswords");
auto resourceLoader{ Windows::ApplicationModel::Resources::ResourceLoader::GetForCurrentView(L"ErrorMessages") };
myXAMLTextBlockElement().Text(resourceLoader.GetString(L"MismatchedPasswords"));
auto resourceLoader = Windows::ApplicationModel::Resources::ResourceLoader::GetForCurrentView("ErrorMessages");
this->myXAMLTextBlockElement->Text = resourceLoader->GetString("MismatchedPasswords");
Se você fosse mover seu recurso "AppDisplayName" de Resources.resw
para ManifestResources.resw
, no manifesto do pacote do aplicativo, você mudaria ms-resource:AppDisplayName
para ms-resource:/ManifestResources/AppDisplayName
.
Se um nome de arquivo de recurso for segmentado (contém caracteres "."), deixe os pontos no nome ao referenciá-lo. Não substitua pontos por caracteres de barra ("/"), como faria para um nome de recurso.
var resourceLoader = Windows.ApplicationModel.Resources.ResourceLoader.GetForCurrentView("Err.Msgs");
Em caso de dúvida, você pode usar MakePri.exe para despejar o arquivo PRI do seu aplicativo. O uri
de cada recurso é mostrado no arquivo despejado.
<ResourceMapSubtree name="Err.Msgs"><NamedResource name="MismatchedPasswords" uri="ms-resource://<GUID>/Err.Msgs/MismatchedPasswords">...
Carregar uma sequência para um idioma específico ou outro contexto
O ResourceContext padrão (obtido ao criar um ResourceContext.GetForCurrentView) contém um valor de qualificador para cada nome de qualificador, representando o contexto de runtime padrão (em outras palavras, as configurações do usuário atual e do computador). Os arquivos de recursos (.resw) são correspondidos (com base nos qualificadores em seus nomes) com os valores do qualificador nesse contexto de runtime.
Mas pode haver momentos em que você deseja que seu aplicativo substitua as configurações do sistema e seja explícito sobre o idioma, a escala ou outro valor de qualificador a ser usado ao procurar um arquivo de recursos correspondente para carregar. Por exemplo, talvez você queira que os usuários possam selecionar um idioma alternativo para dicas de ferramentas ou mensagens de erro.
Você pode fazer isso construindo um novo ResourceContext (em vez de usar o padrão), substituindo os valores e, em seguida, usando esse objeto de contexto em suas pesquisas de sequência.
var resourceContext = new Windows.ApplicationModel.Resources.Core.ResourceContext(); // not using ResourceContext.GetForCurrentView
resourceContext.QualifierValues["Language"] = "de-DE";
var resourceMap = Windows.ApplicationModel.Resources.Core.ResourceManager.Current.MainResourceMap.GetSubtree("Resources");
this.myXAMLTextBlockElement.Text = resourceMap.GetValue("Farewell", resourceContext).ValueAsString;
Usar QualifierValues como no exemplo de código acima funciona para qualquer qualificador. Para o caso especial de Idioma, você pode fazer isso como alternativa.
resourceContext.Languages = new string[] { "de-DE" };
Para o mesmo efeito em um nível global, você pode substituir os valores de qualificador no ResourceContext padrão. Mas, em vez disso, recomendamos que chame ResourceContext.SetGlobalQualifierValue. Você define valores uma vez com uma chamada para SetGlobalQualifierValue e então esses valores entram em vigor no ResourceContext padrão sempre que você o usa para pesquisas.
Windows.ApplicationModel.Resources.Core.ResourceContext.SetGlobalQualifierValue("Language", "de-DE");
var resourceLoader = Windows.ApplicationModel.Resources.ResourceLoader.GetForCurrentView();
this.myXAMLTextBlockElement.Text = resourceLoader.GetString("Farewell");
Alguns qualificadores têm um provedor de dados do sistema. Assim, em vez de chamar SetGlobalQualifierValue, você poderia ajustar o provedor por meio da própria API. Por exemplo, este código mostra como definir PrimaryLanguageOverride.
Windows.Globalization.ApplicationLanguages.PrimaryLanguageOverride = "de-DE";
Atualização de sequências em resposta a eventos de alteração de valor do qualificador
Seu aplicativo em execução pode responder a alterações nas configurações do sistema que afetam os valores de qualificador no ResourceContext padrão. Qualquer uma dessas configurações do sistema invoca o evento MapChanged em ResourceContext.QualifierValues.
Em resposta a esse evento, você pode recarregar suas sequências do ResourceContext padrão.
public MainPage()
{
this.InitializeComponent();
...
// Subscribe to the event that's raised when a qualifier value changes.
var qualifierValues = Windows.ApplicationModel.Resources.Core.ResourceContext.GetForCurrentView().QualifierValues;
qualifierValues.MapChanged += new Windows.Foundation.Collections.MapChangedEventHandler<string, string>(QualifierValues_MapChanged);
}
private async void QualifierValues_MapChanged(IObservableMap<string, string> sender, IMapChangedEventArgs<string> @event)
{
var dispatcher = this.myXAMLTextBlockElement.Dispatcher;
if (dispatcher.HasThreadAccess)
{
this.RefreshUIText();
}
else
{
await dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () => this.RefreshUIText());
}
}
private void RefreshUIText()
{
var resourceLoader = Windows.ApplicationModel.Resources.ResourceLoader.GetForCurrentView();
this.myXAMLTextBlockElement.Text = resourceLoader.GetString("Farewell");
}
Carregar sequências de uma biblioteca de classes ou de uma biblioteca do Windows Runtime
Os recursos de sequência de uma biblioteca de classes referenciada (Universal Windows) ou biblioteca do Windows Runtime (Universal Windows) normalmente são adicionados a uma subpasta do pacote no qual são incluídos durante o processo de build. O identificador de recurso de tal sequência geralmente assume a forma de LibraryName/ResourcesFileName/ResourceIdentifier.
Uma biblioteca pode obter um ResourceLoader para os próprios recursos. Por exemplo, o código a seguir ilustra como uma biblioteca ou um aplicativo que faz referência a ela pode obter um ResourceLoader para os recursos de sequência da biblioteca.
var resourceLoader = Windows.ApplicationModel.Resources.ResourceLoader.GetForCurrentView("ContosoControl/Resources");
this.myXAMLTextBlockElement.Text = resourceLoader.GetString("exampleResourceName");
Para uma biblioteca do Windows Runtime (Universal Windows), se o namespace padrão for segmentado (contém caracteres "."), use pontos no nome do mapa de recursos.
var resourceLoader = Windows.ApplicationModel.Resources.ResourceLoader.GetForCurrentView("Contoso.Control/Resources");
Você não precisa fazer isso para uma biblioteca de classes (Universal Windows). Em caso de dúvida, você pode especificar as opções de linha de comando MakePri.exe para despejar o arquivo PRI do componente ou da biblioteca. O uri
de cada recurso é mostrado no arquivo despejado.
<NamedResource name="exampleResourceName" uri="ms-resource://Contoso.Control/Contoso.Control/ReswFileName/exampleResourceName">...
Carregamento de sequências de outros pacotes
Os recursos de um pacote do aplicativo são gerenciados e acessados por meio do próprio ResourceMap de nível superior do pacote, que pode ser acessado no ResourceManager atual. Dentro de cada pacote, vários componentes podem ter suas próprias subárvores de ResourceMap, que você pode acessar via ResourceMap.GetSubtree.
Um pacote de estrutura pode acessar seus próprios recursos com um URI de identificador de recurso absoluto. Consulte também Esquemas de URI.
Carregamento de sequências em aplicativos não empacotados
A partir da versão 1903 do Windows (atualização de maio de 2019), os aplicativos não empacotados também podem aproveitar o Sistema de Gerenciamento de Recursos.
Basta criar seus controles/bibliotecas de usuário do UWP e armazenar todas as sequências em um arquivo de recursos. Em seguida, você pode fazer referência a um identificador de recurso de sequência de XAML, fazer referência a um identificador de recurso de sequência de código ou carregar sequências de uma biblioteca de classes ou de uma biblioteca do Windows Runtime.
Para usar recursos em aplicativos não empacotados, é preciso realizar algumas ações:
- Use GetForViewIndependentUse em vez de GetForCurrentView ao resolver recursos do código, pois não há exibição atual em cenários não empacotados. A exceção a seguir vai ocorrer se você chamar GetForCurrentView em cenários não empacotados: Contextos de recursos não podem ser criados em threads que não têm um CoreWindow.
- Use MakePri.exe para gerar manualmente o arquivo resources.pri do seu aplicativo.
- Execute
makepri new /pr <PROJECTROOT> /cf <PRICONFIG> /of resources.pri
- O <PRICONFIG> deve omitir a seção "<empacotamento>" para que todos os recursos sejam agrupados em um único arquivo resources.pri. Se estiver usando o arquivo de configuração padrão MakePri.exe criado por createconfig, você precisará excluir a seção "<empacotamento>" manualmente depois que ela for criada.
- O <PRICONFIG> deve conter todos os indexadores relevantes necessários para mesclar todos os recursos do seu projeto em um único arquivo resources.pri. O arquivo de configuração MakePri.exe padrão criado por createconfig inclui todos os indexadores.
- Se você não usar a configuração padrão, certifique-se de que o indexador PRI esteja habilitado (revise a configuração padrão para saber como fazer isso) para mesclar PRIs encontrados em referências de projeto UWP, referências NuGet e assim por diante, que estão localizados dentro da raiz do projeto.
Observação
Ao omitir
/IndexName
e pelo projeto não ter um manifesto do aplicativo, o namespace IndexName/root do arquivo PRI é definido automaticamente como Application, que o runtime entende como aplicativos não empacotados (isso remove a dependência física anterior da ID do pacote). Ao especificar URIs de recurso, ms-resource:/// que omitem o namespace raiz inferem Application como o namespace raiz para aplicativos não empacotados (ou você pode especificar Application explicitamente como em ms-resource://Application/).
- Execute
- Copie o arquivo PRI para o diretório de saída de build do .exe
- Execute o .exe
Observação
O Sistema de Gerenciamento de Recursos usa o idioma de exibição do sistema em vez da lista de idiomas preferidos do usuário ao resolver recursos com base no idioma em aplicativos não empacotados. A lista de idiomas preferidos do usuário só é usada para aplicativos UWP.
Importante
Você deve recriar manualmente os arquivos PRI sempre que os recursos forem modificados. Recomendamos o uso de um script pós-build que manipule o comando MakePri.exe e copie a saída resources.pri para o diretório .exe.