Os apps incluem recursos que podem ser específicos para uma determinada cultura. Por exemplo, um app pode incluir strings próprias de uma cultura que são traduzidas para o idioma da localidade atual.
É recomendável manter os recursos específicos da cultura separados do restante do app. O Android resolve recursos específicos de idioma e cultura com base na configuração de localidade do sistema. Você pode oferecer compatibilidade com diferentes localidades usando o diretório de recursos no seu projeto Android.
Você pode especificar recursos adaptados às culturas das pessoas que
usam seu app e fornecer qualquer tipo de recurso
adequado para o idioma e a cultura dos seus usuários. Por exemplo, as
capturas de tela abaixo mostram um app exibindo recursos drawable e de string na
localidade padrão do dispositivo (en_US
) e em espanhol
(es_ES
).
Quando você cria um projeto usando as Ferramentas do SDK
do Android, elas geram um diretório res/
no nível superior
do projeto. Dentro desse diretório res/
, há subdiretórios para diversos tipos
de recursos. Há também alguns arquivos padrão, como res/values/strings.xml
,
que armazenam os valores de string.
O suporte a diferentes idiomas vai além do uso de recursos específicos de localidade. Alguns usuários escolhem um idioma que usa texto da direita para a esquerda (RTL), como árabe ou hebraico, para a localidade da interface. Outros usuários que definem a localidade da interface para um idioma que usa texto da esquerda para a direita (LTR), como inglês, podem acessar ou gerar conteúdo em um idioma que use texto da direita para a esquerda (RTL). Para oferecer suporte aos dois tipos de usuários, seu app precisa fazer o seguinte:
- Empregar um layout de IU RTL para localidades RTL.
- Detectar e declarar a direção dos dados de texto que são exibidos em mensagens formatadas. Geralmente, é possível chamar um método, conforme descrito neste guia, que determina a direção dos dados de texto para você.
Criar diretórios de localidade e arquivos de recursos
Para adicionar suporte a mais localidades, crie mais diretórios dentro de
res/
. O nome de cada diretório precisa seguir este formato:
<resource type>-b+<language code>[+<country code>]
Por exemplo, values-b+es/
contém recursos
de string para localidades com o código de idioma es
. Da mesma forma,
mipmap-b+es+ES/
contém ícones para localidades com o código do idioma es
e o código do país ES
.
O Android carrega os recursos adequados de acordo com as configurações de localidade do dispositivo durante a execução. Para mais informações, consulte Como fornecer recursos alternativos.
Depois de decidir para quais localidades seu app oferecerá suporte, crie os subdiretórios e arquivos de recursos. Exemplo:
MyProject/ res/ values/ strings.xml values-b+es/ strings.xml mipmap/ country_flag.png mipmap-b+es+ES/ country_flag.png
Preencha os arquivos com recursos localizados. Confira abaixo exemplos de arquivos de recursos de string e imagens localizados:
Strings em inglês (localidade padrão) em /values/strings.xml
:
<resources> <string name="hello_world">Hello World!</string> </resources>
Strings em espanhol (localidade es
) em /values-b+es/strings.xml
:
<resources> <string name="hello_world">¡Hola Mundo!</string> </resources>
Ícone da bandeira dos EUA (localidade padrão) em
/mipmap/country_flag.png
:
Ícone da bandeira da Espanha (localidade es_ES
) em
/mipmap-b+es+ES/country_flag.png
:
Observação: é possível usar qualificadores de configuração, como o de localidade, em qualquer tipo de recurso. Por exemplo, você pode fornecer versões localizadas dos drawables de bitmap. Para saber mais, consulte Localizar seu app.
Usar os recursos no seu app
Referencie os recursos no seu código-fonte e em outros arquivos XML usando
o atributo name
de cada recurso:
R.<resource type>.<resource name>
. Há diversos
métodos que aceitam um recurso dessa maneira, como mostrado nestes exemplos:
Kotlin
// Get a string resource val hello = resources.getString(R.string.hello_world) // Or supply a string resource to a method that requires a string TextView(this).apply { setText(R.string.hello_world) }
Java
// Get a string resource String hello = getResources().getString(R.string.hello_world); // Or supply a string resource to a method that requires a string TextView textView = new TextView(this); textView.setText(R.string.hello_world);
Em arquivos XML, você pode referenciar um recurso de string com a sintaxe
@<resource type>/<resource name>
sempre que o atributo XML
aceitar um valor compatível. Confira um exemplo:
<ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@mipmap/country_flag" />
Observação: para que as configurações de idioma do usuário sejam priorizadas
corretamente, especifique os idiomas que têm suporte no app usando a propriedade resConfigs
. Para
mais informações, consulte
Especificar os idiomas com suporte no app.
Formatar texto em mensagens
Uma das tarefas mais comuns em um app é a formatação de texto. As mensagens localizadas são formatadas ao inserir texto e dados numéricos nas posições adequadas. Ao lidar com uma interface ou com dados RTL, a formatação simples pode mostrar textos incorretos ou mesmo ilegíveis.
Idiomas como árabe, hebraico, persa e urdu são escritos na direção RTL. No entanto, alguns elementos, como números e texto LTR incorporado, aparecem como LTR dentro do texto RTL. Os idiomas que usam texto LTR, incluindo o inglês, também são bidirecionais, porque podem conter texto RTL incorporados que precisam ser mostrados na direção RTL.
Um exemplo é quando apps geram instâncias desse tipo de texto incorporado de direção oposta inserindo dados de texto de um idioma arbitrário e uma direção de texto arbitrária em mensagens localizadas. Essa mistura de direções não costuma incluir uma indicação clara de onde o texto em direção oposta começa e termina. Por isso, o texto gerado por apps pode gerar uma experiência ruim do usuário.
Embora o tratamento padrão do sistema de texto bidirecional normalmente renderize o texto conforme o esperado, é possível que ele não seja renderizado corretamente quando o app o inserir em uma mensagem localizada. Confira abaixo exemplos de situações em que o texto pode aparecer incorretamente:
-
Texto inserido no início de uma mensagem:
PERSON_NAME está ligando para você
-
Texto que começa com um número, como um endereço ou telefone:
987 654-3210
-
Texto que começa com pontuação, como um número de telefone:
+19876543210
-
Texto que termina com pontuação:
Tem certeza?
-
Texto que já contém as duas direções:
A palavra בננה significa "banana" em hebraico
Exemplo
Suponha que um app às vezes precise mostrar a mensagem “Você quis dizer %s?”, com um endereço inserido no lugar de “%s” no momento da execução. Como o app oferece suporte a interfaces para localidades diferentes, a mensagem é de um recurso específico de localidade e usa a direção RTL quando uma localidade dessa direção está em uso. Por exemplo, para uma interface em hebraico, a mensagem aparece assim:
האם התכוונת ל %s?
No entanto, a sugestão pode vir de um banco de dados que não inclui texto no idioma da localidade. Se o endereço em questão for de um lugar na Califórnia, ele aparecerá no banco de dados com texto em inglês. Se você inserir o endereço "15 Bay Street, Laurel, CA" na mensagem RTL sem fornecer quaisquer dicas sobre a direção do texto, o resultado não será o esperado nem correto:
האם התכוונת ל 15 Bay Street, Laurel, CA?
O número da casa aparece à direita do endereço, e não à esquerda, como seria esperado. Isso faz com que o número pareça um código postal estranho. O mesmo problema pode ocorrer se você incluir texto RTL em uma mensagem que usa a direção LTR.
Explicação e solução
O problema do exemplo anterior ocorre porque o formatador de texto não especifica que "15" faz parte do endereço. Por isso, o sistema não pode determinar se "15" faz parte do texto RTL que vem antes dele ou do texto LTR que vem depois.
Para resolver o problema, use o método unicodeWrap()
da classe
BidiFormatter
. O método detecta a direção de uma string e a une em caracteres de formatação Unicode
que declaram essa direção.
O snippet de código abaixo demonstra como usar
unicodeWrap()
:
Kotlin
val mySuggestion = "15 Bay Street, Laurel, CA" val myBidiFormatter: BidiFormatter = BidiFormatter.getInstance() // The "did_you_mean" localized string resource includes // a "%s" placeholder for the suggestion. String.format(getString(R.string.did_you_mean), myBidiFormatter.unicodeWrap(mySuggestion))
Java
String mySuggestion = "15 Bay Street, Laurel, CA"; BidiFormatter myBidiFormatter = BidiFormatter.getInstance(); // The "did_you_mean" localized string resource includes // a "%s" placeholder for the suggestion. String.format(getString(R.string.did_you_mean), myBidiFormatter.unicodeWrap(mySuggestion));
Como "15" agora está dentro do texto declarado como LTR, ele será mostrado na posição correta:
האם התכוונת ל 15 Bay Street, Laurel, CA?
Use o método unicodeWrap()
em
todas as partes do texto inserido em uma mensagem localizada, exceto nas situações abaixo:
- O texto está inserido em uma string legível por máquina, como uma consulta de URI ou SQL.
- Você sabe que o texto já foi unido corretamente.
Observação: caso seu app seja destinado ao Android 4.3 (nível 18 da API) ou
mais recente, use a versão do BidiFormatter
disponível no
framework do Android. Caso contrário, use a versão do
BidiFormatter
disponível na Biblioteca de Suporte.
Formatar números
Use strings de formato, e não chamadas de método, para converter números em strings na lógica do app:
Kotlin
var myIntAsString = "$myInt"
Java
String myIntAsString = String.format("%d", myInt);
Os números são formatados corretamente para sua localidade, o que pode incluir o uso de um conjunto diferente de dígitos.
Ao usar
String.format()
para criar uma
consulta SQL em um dispositivo com uma localidade que usa o próprio conjunto de dígitos, como persa
e a maioria das localidades em árabe, poderá haver problemas se os parâmetros da consulta
forem números. Isso acontece porque o número é formatado nos dígitos da localidade, que
são inválidos em SQL.
Para preservar números formatados em ASCII e manter a consulta SQL válida, use
a versão sobrecarregada de
String.format()
, que
inclui uma localidade como primeiro parâmetro. Use o argumento de localidade
Locale.US
.
Suporte ao espelhamento de layout
As pessoas que usam scripts RTL preferem uma interface de usuário RTL, o que inclui menus e textos alinhados à direita, além de setas de encaminhamento apontando para a esquerda.
A Figura 4 mostra o contraste entre a versão LTR de uma tela do app Configurações e a versão RTL equivalente:
Ao adicionar suporte para RTL ao app, não esqueça do seguinte:
- O espelhamento de texto RTL só tem suporte em apps quando usado em dispositivos com o Android 4.2 (nível 17 da API) ou mais recente. Para saber como oferecer suporte ao espelhamento de texto em dispositivos mais antigos, consulte Oferecer suporte a apps legados, neste guia.
- Para testar se o app oferece suporte à direção de texto RTL, use as opções do desenvolvedor para testá-lo, conforme descrito neste guia, e convide pessoas que usam textos RTL para usar o app.
Observação: para conferir outras diretrizes de design relacionadas ao espelhamento de layout, incluindo uma lista de elementos que são e não são adequados para o espelhamento, consulte as diretrizes do Material Design para Bidirecionalidade (link em inglês).
Ao espelhar o layout da interface no seu app para que ele seja mostrado como RTL em uma localidade RTL, conclua as etapas das próximas seções.
Modificar os arquivos de build e de manifesto
Modifique o arquivo build.gradle
do módulo do app e o arquivo de manifesto
desta forma:
build.gradle (Module: app)
Groovy
android { ... defaultConfig { targetSdkVersion 17 // Or higher ... } }
Kotlin
android { ... defaultConfig { targetSdkVersion(17) // Or higher ... } }
AndroidManifest.xml
<manifest ... > ... <application ... android:supportsRtl="true"> </application> </manifest>
Observação: caso seu app seja destinado ao Android 4.1.1 (nível 16 da API) ou
anterior, o atributo android:supportsRtl
será ignorado, junto dos valores
start
e end
que aparecem nos
arquivos de layout do app. Nesse caso, o espelhamento de layout RTL não acontecerá
automaticamente no app.
Atualizar os recursos existentes
Converta left
e right
para start
e
end
, respectivamente, nos arquivos de recursos de layout existentes.
Isso permite que o framework alinhe os elementos da interface do app com base
nas configurações de idioma do usuário.
Observação: antes de atualizar seus recursos, aprenda a oferecer suporte a apps legados ou apps destinados ao Android 4.1.1 (nível 16 da API) e versões anteriores.
Para usar os recursos de alinhamento RTL do framework, altere os atributos nos seus arquivos de layout que aparecem na Tabela 1.
A Tabela 2 mostra como o sistema processa os atributos de alinhamento da IU com base na
versão do SDK de destino, estejam os atributos left
e right
,
bem como os atributos start
e end
,
definidos ou não.
|
Esquerda e direita definidas? | Início e término definidos? | Resultado |
---|---|---|---|
Sim | Sim | Sim |
start e end são usados,
substituindo left e right .
|
Sim | Sim | Não | left e right são usados |
Sim | Não | Sim | start e end são usados |
Não | Sim | Sim |
left e right são usados (start e
end são ignorados)
|
Não | Sim | Não | left e right são usados |
Não | Não | Sim |
start e end resolvem para left e
right
|
Adicionar recursos específicos de direção e idioma
Nesta etapa, serão adicionadas versões específicas dos seus arquivos de recursos de valor, layout e drawables que contém valores personalizados para diferentes idiomas e direções de texto.
No Android 4.2 (nível 17 da API) ou mais recente, você pode usar os qualificadores de recurso -ldrtl
(layout da direita para a esquerda) e -ldltr
(layout da esquerda para a direita). Para manter a compatibilidade
com versões anteriores de recursos existentes, as versões mais antigas do Android usam os
qualificadores de idioma de um recurso para inferir a direção correta do texto.
Suponha que você queira adicionar um arquivo de layout específico para oferecer suporte a textos RTL,
como os idiomas hebraico, árabe e persa. Para fazer isso, adicione um diretório
layout-ldrtl/
ao diretório res/
, conforme
mostrado neste exemplo:
res/ layout/ main.xml This layout file is loaded by default. layout-ldrtl/ main.xml This layout file is loaded for languages using an RTL text direction, including Arabic, Persian, and Hebrew.
Se você quiser adicionar uma versão específica do layout criada apenas para texto em árabe, a estrutura do diretório será esta:
res/ layout/ main.xml This layout file is loaded by default. layout-ar/ main.xml This layout file is loaded for Arabic text. layout-ldrtl/ main.xml This layout file is loaded only for non-Arabic languages that use an RTL text direction.
Observação: os recursos específicos de idioma têm precedência sobre os recursos específicos de direção do layout, que têm precedência sobre os recursos padrão.
Usar widgets compatíveis
A partir do Android 4.2 (nível 17 da API), a maior parte dos elementos da IU do framework é automaticamente compatível
com a direção de texto RTL. No entanto, vários elementos do framework, como
ViewPager
, não são compatíveis com a direção
de texto RTL.
Os widgets da tela inicial são compatíveis com a direção do texto RTL, desde que os
arquivos de manifesto correspondentes incluam a atribuição do atributo
android:supportsRtl="true"
.
Oferecer suporte a apps legados
Caso seu app seja destinado ao Android 4.1.1 (nível 16 da API) ou versões mais antigas, inclua também os atributos
left
e right
, além de
start
e end
.
Para verificar se o layout precisa usar a direção de texto RTL, use esta lógica:
Kotlin
private fun shouldUseLayoutRtl(): Boolean { return if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) { View.LAYOUT_DIRECTION_RTL == layoutDirection } else { false } }
Java
private boolean shouldUseLayoutRtl() { if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) { return View.LAYOUT_DIRECTION_RTL == getLayoutDirection(); } else { return false; } }
Observação: para evitar problemas de compatibilidade, use a versão 23.0.1 ou mais recente das Ferramentas de build do SDK do Android.
Testar o uso de opções do desenvolvedor
Em dispositivos com o Android 4.4 (nível 19 da API) ou versões mais recentes, é possível ativar a configuração Forçar layout da direita p/ esquerda nas Opções do desenvolvedor no dispositivo. Com essa configuração, textos que usam a direção LTR, como texto em inglês, podem ser mostrados no modo RTL.
Atualizar a lógica do app
Esta seção descreve aspectos específicos da lógica do app que precisam ser atualizados ao adaptá-lo para processar várias direções de texto.
Alterações de propriedade
Para gerenciar uma mudança em qualquer propriedade relacionada a RTL, como direção
e parâmetros de layout, preenchimento, direção e alinhamento de texto ou
posicionamento de drawables, use o
callback
onRtlPropertiesChanged()
. Esse callback ajuda você a saber a direção atual do layout e
atualizar os objetos View
de uma atividade corretamente.
Visualizações
Se você estiver criando um widget de IU que não faça parte diretamente da hierarquia de visualização de uma atividade, como uma caixa de diálogo ou um elemento semelhante a um aviso, defina a direção correta do layout com base no contexto. O snippet de código a seguir demonstra como concluir esse processo:
Kotlin
val config: Configuration = context.resources.configuration view.layoutDirection = config.layoutDirection
Java
final Configuration config = getContext().getResources().getConfiguration(); view.setLayoutDirection(config.getLayoutDirection());
Vários métodos da classe View
precisam de
considerações adicionais:
onMeasure()
- As medidas de visualização podem variar, dependendo da direção do texto.
onLayout()
- Se criar o próprio layout de implementação, você vai precisar chamar
super()
na sua versão deonLayout()
e adaptar a lógica personalizada para que ela ofereça suporte a textos RTL. onDraw()
- Se você estiver implementando uma visualização personalizada ou adicionando uma funcionalidade avançada a um
desenho, atualize seu código para oferecer suporte a textos RTL. Use o
código abaixo para determinar se o widget está no modo RTL:
Kotlin
// On devices running Android 4.1.1 (API level 16) and lower, // you can call the isLayoutRtl() system method directly. fun isLayoutRtl(): Boolean = layoutDirection == LAYOUT_DIRECTION_RTL
Java
// On devices running Android 4.1.1 (API level 16) and lower, // you can call the isLayoutRtl() system method directly. public boolean isLayoutRtl() { return (getLayoutDirection() == LAYOUT_DIRECTION_RTL); }
Drawables
Se você tiver um drawable que precise ser espelhado para um layout de RTL, conclua uma destas etapas com base na versão de Android do dispositivo:
-
Em dispositivos com o Android 4.3 (nível 18 da API) e versões anteriores,
adicione e defina arquivos de recurso
-ldrtl
. -
No Android 4.4 (nível 19 da API) e versões mais recentes, use
android:autoMirrored="true"
ao definir seu drawable, o que permite ao sistema processar o espelhamento de layout RTL.Observação: o atributo
android:autoMirrored
funciona apenas para drawables simples, em que o espelhamento bidirecional é simplesmente um espelhamento gráfico do drawable como um todo. Caso o drawable contenha vários elementos ou se refleti-lo mudar a interpretação dele, faça o espelhamento manualmente. Sempre que possível, verifique com um especialista em bidirecionamento se os drawables espelhados fazem sentido para os usuários.
Gravidade
Se o código de layout do app usa Gravity.LEFT
ou
Gravity.RIGHT
, mude esses
valores para Gravity.START
e
Gravity.END
, respectivamente.
Se você tiver um código Kotlin ou Java que depende das
propriedades Gravity.LEFT
ou Gravity.RIGHT
,
será possível adaptá-lo para que ele funcione com essa mudança definindo absoluteGravity
para corresponder a
layoutDirection
Por exemplo, se você estiver usando um código como este:
Kotlin
when (gravity and Gravity.HORIZONTAL_GRAVITY_MASK) { Gravity.LEFT -> { // Handle objects that are left-aligned. } Gravity.RIGHT -> { // Handle objects that are right-aligned. } }
Java
switch (gravity & Gravity.HORIZONTAL_GRAVITY_MASK) { case Gravity.LEFT: // Handle objects that are left-aligned. break; case Gravity.RIGHT: // Handle objects that are right-aligned. break; }
Altere para o seguinte:
Kotlin
val absoluteGravity: Int = Gravity.getAbsoluteGravity(gravity, layoutDirection) when (absoluteGravity and Gravity.HORIZONTAL_GRAVITY_MASK) { Gravity.LEFT -> { // Handle objects that are left-aligned. } Gravity.RIGHT -> { // Handle objects that are right-aligned. } }
Java
final int layoutDirection = getLayoutDirection(); final int absoluteGravity = Gravity.getAbsoluteGravity(gravity, layoutDirection); switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) { case Gravity.LEFT: // Handle objects that are left-aligned. break; case Gravity.RIGHT: // Handle objects that are right-aligned. break; }
Isso significa que você pode manter seu código atual que processa valores alinhados à esquerda e
à direita, mesmo que esteja usando start
e
end
para seus valores de gravidade.
Observação: ao aplicar as configurações de gravidade, use uma
versão sobrecarregada de Gravity.apply()
que inclua um argumento
layoutDirection
.
Margens e padding
Para oferecer suporte a textos RTL no app, siga estas práticas recomendadas relacionadas aos valores de margem e de preenchimento:
-
Use
getMarginStart()
egetMarginEnd()
em vez dos equivalentes do atributo específico da direção,leftMargin
erightMargin
. -
Ao usar
setMargins()
, troque os valores dos argumentosleft
eright
se o app detectar textos RTL. -
Se o app inclui lógica de preenchimento personalizada, substitua
setPadding()
esetPaddingRelative()
.
Suporte à seleção de idioma por app
Em muitos casos, os usuários multilíngues definem um idioma para o sistema, como o inglês, mas querem selecionar outros para apps específicos, como holandês, chinês ou hindi. Para que os apps possam oferecer uma experiência melhor a esses usuários, o Android 13 inclui os recursos abaixo para apps que têm suporte a vários idiomas:
-
Configurações do sistema: um local centralizado em que os usuários podem selecionar um idioma preferido para cada app.
Para informar ao sistema que o aplicativo oferece suporte para vários idiomas, o app precisa declarar o atributo
android:localeConfig
no manifesto dele. Para saber mais, consulte as instruções sobre como criar e declarar um arquivo de recursos no manifesto do app. -
Outras APIs: essas APIs públicas, como os métodos
setApplicationLocales()
egetApplicationLocales()
emLocaleManager
, permitem que os apps definam um idioma diferente daquele usado pelo sistema durante a execução.Apps que usam seletores de idioma personalizados podem usar essas outras APIs para oferecer uma experiência consistente aos usuários, independente do local em que selecionarem as preferências de idioma. As APIs públicas também ajudam a reduzir o código boilerplate e oferecem suporte para APKs divididos. Além disso, elas oferecem suporte ao Backup automático para apps para armazenar as configurações de idioma do usuário no nível do app.
Para oferecer compatibilidade com versões anteriores do Android, APIs equivalentes também estão disponíveis no AndroidX. Recomendamos o uso da Appcompat 1.6.0-beta01 ou versões mais recentes.
Para saber mais, consulte as instruções de como implementar as novas APIs.
Confira também
Outros recursos
Para saber mais sobre como oferecer compatibilidade com dispositivos mais antigos, acesse os seguintes recursos:
Postagens do blog (em inglês)
- Desenvolva apps compatíveis com vários dispositivos para torná-los acessíveis
- Como escrever para públicos globais