Compatibilidade com diferentes idiomas e culturas

Os aplicativos incluem recursos que servem especificamente para uma determinada cultura. Por exemplo, um aplicativo pode incluir strings específicas de uma cultura que são traduzidas para o idioma da localidade atual. É uma prática recomendada manter os recursos culturais específicos separados do restante do aplicativo. O Android resolve recursos culturais e de idioma específicos com base na configuração de localidade do sistema. Você pode oferecer compatibilidade para diferentes localidades usando o diretório de recursos no seu projeto Android.

Além disso, é possível especificar recursos adaptados à cultura das pessoas que usam seu aplicativo. Você pode fornecer qualquer tipo de recurso apropriado para o idioma e a cultura dos seus usuários. Por exemplo, a captura de tela a seguir mostra um aplicativo exibindo recursos drawable e de string na localidade padrão do dispositivo (en_US) e em espanhol (es_ES).

O aplicativo mostra um texto e um ícone diferentes, dependendo da localidade atual

Figure 1. Um aplicativo que usa recursos diferentes dependendo da localidade atual

Caso tenha criado o projeto usando as Ferramentas do Android SDK (leia Como criar um projeto Android), você terá acesso a 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 mantêm os valores da string.

A compatibilidade com diferentes idiomas vai além do uso de recursos específicos de localidade. Alguns usuários escolhem um idioma que usa scripts da direita para a esquerda (RTL), como árabe ou hebraico, para a localidade da IU. Outros usuários exibem ou geram conteúdo em um idioma que usa scripts RTL, mesmo que tenham definido um idioma que usa scripts da esquerda para a direita (LTR), como o inglês, como a localidade da IU. Para oferecer compatibilidade aos dois tipos de usuários, seu aplicativo precisa fazer o seguinte:

  • Incluir um layout de IU RTL para localidades RTL.
  • Detectar e declarar a direção do texto que é exibido dentro de mensagens formatadas. Normalmente, basta você chamar o método que determina a direção dos dados de texto.

Criar diretórios de localidade e arquivos de recursos

Para adicionar compatibilidade com mais localidades, crie diretórios adicionais dentro de res/. O nome de cada diretório deve seguir o seguinte 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 apropriados de acordo com as configurações de localidade no dispositivo em tempo de execução. Para mais informações, consulte Como fornecer recursos alternativos.

Depois de decidir para quais localidades seu aplicativo oferecerá compatibilidade, crie os subdiretórios e arquivos de recursos. Por exemplo:

MyProject/
    res/
       values/
           strings.xml
       values-b+es/
           strings.xml
       mipmap/
           country_flag.png
       mipmap-b+es+ES/
           country_flag.png

Por exemplo, estes são diferentes arquivos de recursos para diversos idiomas:

Strings em inglês (localidade padrão), /values/strings.xml:

<resources>
    <string name="hello_world">Hello World!</string>
</resources>

Strings em espanhol (localidade es), /values-es/strings.xml:

<resources>
    <string name="hello_world">¡Hola Mundo!</string>
</resources>

Ícone da bandeira dos Estados Unidos (localidade padrão), /mipmap/country_flag.png:

O ícone da bandeira dos Estados Unidos

Figura 2. Ícone usado para o código de idioma padrão (en_US)

Ícone da bandeira da Espanha (localidade es_ES), /mipmap-b+es+ES/country_flag.png:

O ícone da bandeira da Espanha

Figura 3. Ícone usado para a localidade es_ES

Observação: você pode usar o qualificador de localidade (ou qualquer qualificador de configuração) em todos os tipos de recurso, como se quisesse fornecer versões localizadas do seu drawable de bitmap. Para mais informações, consulte Localização.

Usar os recursos no seu aplicativo

Você pode referenciar os recursos no seu código-fonte e outros arquivos XML usando cada atributo name do recurso.

No código-fonte, é possível referenciar um recurso de string com a sintaxe R.<resource type>.<resource name>. Há diversos métodos que aceitam um recurso dessa maneira.

Por exemplo:

Kotlin

// Get a string resource from your app's Resources
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 from your app's Resources
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 outros arquivos XML, você poderá referenciar um recurso de string com a sintaxe @<resource type>/<resource name> sempre que o atributo XML aceitar um valor compatível.

Por exemplo:

<ImageView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:src="@mipmap/country_flag" />

Formatar texto em mensagens

Uma das tarefas mais comuns em um aplicativo é formatar o texto. As mensagens localizadas são formatadas ao inserir texto e dados numéricos nas posições apropriadas. Ao lidar com uma IU da direita para esquerda (RTL, na sigla em inglês) ou dados da direita para esquerda, a formatação simples pode exibir saídas de texto incorretas ou até mesmo ilegíveis.

Em geral, os idiomas como árabe, hebraico, persa e urdu são escritos na direção RTL. No entanto, alguns dos elementos, como números e texto da esquerda para a direita (LTR, na sigla em inglês) incorporados, são gravados na direção LTR dentro do texto RTL. Os idiomas que usam scripts LTR, incluindo o inglês, também são bidirecionais porque podem conter scripts RTL incorporados que precisam ser exibidos em uma direção RTL.

Na maioria das vezes, são os próprios aplicativos que geram essas instâncias de texto de direção oposta incorporada. Eles inserem dados de texto de uma linguagem arbitrária — e uma direção de texto arbitrária — em mensagens localizadas. Em geral, essa mistura de direções não inclui uma indicação clara de onde o texto de direção oposta começa e termina. Essas características do texto gerado pelo aplicativo causam a maioria dos problemas.

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 aplicativo o insere em uma mensagem localizada. As situações a seguir são exemplos de casos em que há uma grande probabilidade de que o texto não apareça corretamente:

  • Inserido no início da mensagem:

    PERSON_NAME está ligando para você

  • Começa com um número, como em endereços ou números de telefone:

    987 654-3210

  • Começa com pontuação, como em um número de telefone:

    +19876543210

  • Termina com pontuação:

    Você tem certeza?

  • Já tem as duas direções:

    A palavra בננה é banana em hebraico.

Exemplo

Por exemplo, suponha que um aplicativo às vezes precise exibir a mensagem “Você quis dizer% s?”, com um endereço inserido no lugar do “%s” no tempo de execução. Como o aplicativo é compatível com uma IU para localidades diferentes, a mensagem é proveniente de um recurso específico de localidade e aplica a direção RTL quando um código de idioma RTL está em uso. Para uma IU em hebraico, isso seria exibido da seguinte maneira:

האם התכוונת ל %s?

No entanto, a sugestão pode vir de um banco de dados que não inclui texto no idioma do local. Por exemplo, se o endereço em questão for para um local na Califórnia, ele aparecerá no banco de dados usando o texto em inglês. Se você inserir o endereço “15 Bay Street, Laurel, CA” na mensagem RTL sem fornecer dicas sobre a direção, o resultado não será o esperado nem correto:

האם התכוונת ל 15 Bay Street, Laurel, CA?

Observe que o número da casa aparece à direita do endereço, não para a esquerda como pretendido. Isso faz com que o número pareça um código postal estranho. O mesmo problema pode ocorrer se você incluir o texto RTL em uma mensagem que usa a direção do texto LTR.

Explicação e solução

O problema do exemplo anterior ocorre porque o formatador de texto não especifica que “15” é parte do endereço. Por isso, o sistema não pode determinar se “15” é parte do texto RTL que vem antes dele ou do texto LTR que vem depois.

Para resolver esse problema, use o método unicodeWrap(), encontrado na classe BidiFormatter, em todas as partes do texto que você inseriu em uma mensagem localizada. Estas são as únicas situações em que não é recomendável usar unicodeWrap():

  • O texto está sendo inserido em uma string legível por máquina, como uma consulta URI ou SQL.
  • Você já sabe que o pedaço de texto está corretamente envolvido.

O método unicodeWrap() detecta a direção de uma string e a envolve em caracteres de formatação Unicode que declaram essa direção. Como o “15” agora aparece dentro do texto declarado como LTR, ele é exibido na posição correta:

האם התכוונת ל 15 Bay Street, Laurel, CA?

O snippet de código a seguir 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));

Observação: caso seu aplicativo seja destinado ao Android 4.3 (nível 18 da API) ou posteriores, use a versão do BidiFormatter encontrado no Android Framework. Caso contrário, use a versão de BidiFormatter encontrado 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 aplicativo:

Kotlin

var myIntAsString = "$myInt"

Java

String myIntAsString = String.format("%d", myInt);

Isso formatará os números da maneira adequada 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 um código de idioma que usa o próprio conjunto de dígitos, como o persa e a maioria das localidades em árabe, poderá haver problemas se os parâmetros forem números. Isso ocorre porque o número é formatado nos dígitos do código do idioma, 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 o primeiro parâmetro. O argumento da localidade deve ser Locale.US.

Compatibilidade com o espelhamento de layout

As pessoas que usam scripts RTL preferem uma interface de usuário RTL, 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 nas configurações do aplicativo e sua equivalente RTL:

A área de notificação está alinhada à direita no canto superior direito, já o botão “Menu” da barra de aplicativos está perto do canto superior esquerdo. Além disso, o conteúdo na parte principal da tela é alinhado à esquerda e aparece em LTR, e o botão “Voltar” está perto do canto inferior esquerdo e aponta para a esquerda. A notificação é alinhada à esquerda no canto superior esquerdo, já o botão “Menu” da barra de aplicativos fica perto do canto superior direito. Além disso, o conteúdo na parte principal da tela é alinhado à direita e aparece em RTL e o botão “Voltar” está perto do canto inferior direito e aponta para a direita.
Figura 4. Variantes LTR e RTL de uma tela

Ao adicionar suporte RTL ao seu aplicativo, é muito importante ter em mente o seguinte:

  • O espelhamento de texto RTL só é compatível com aplicativos quando usado em dispositivos que executam o Android 4.2 (nível 17 da API) ou versões posteriores. Para saber como oferecer compatibilidade com o espelhamento de texto em dispositivos mais antigos, consulte Oferecer compatibilidade com aplicativos legados.
  • Para testar se o aplicativo é compatível com a direção de texto RTL, aplique as opções do desenvolvedor e convide pessoas que usam scripts RTL para usar seu aplicativo.

Observação: para visualizar as diretrizes de design adicionais relacionadas ao espelhamento de layout, incluindo uma lista de elementos que você deve ou não espelhar, consulte as diretrizes de Material Design para Bidirecionalidade.

Ao espelhar o layout da IU no seu aplicativo para que ele apareça como RTL em uma localidade RTL, conclua as etapas nas seções a seguir.

Modificar os arquivos de versão e manifesto

Modifique o arquivo build.gradle do módulo do aplicativo e o arquivo de manifesto da seguinte maneira:

build.gradle (Module: app)

android {
    ...
    defaultConfig {
        targetSdkVersion 17 // Or higher
        ...
    }
}

AndroidManifest.xml

<manifest ... >
    ...
    <application ...
        android:supportsRtl="true">
    </application>
</manifest>

Observação: caso seu aplicativo seja destinado ao Android 4.1.1 (nível 16 da API) ou versões anteriores, o atributo android:supportsRtl será ignorado, junto com os valores start e end que aparecem nos arquivos de layout do aplicativo. Nesse caso, o espelhamento de layout RTL não acontecerá automaticamente no seu aplicativo.

Atualizar os recursos existentes

Converta left e right para start e end, respectivamente, em cada um dos arquivos de recursos de layout existentes. Ao fazer isso, você permite que a estrutura alinhe os elementos da IU do aplicativo com base nas configurações de idioma do usuário.

Observação: antes de atualizar os recursos, aprenda a oferecer compatibilidade com aplicativos legados ou aplicativos destinados ao Android 4.1.1 (nível 16 da API) e versões anteriores.

Para usar os recursos de alinhamento RTL da estrutura, altere os atributos nos arquivos de layout que aparecem na Tabela 1.

Tabela 1. Atributos que serão usados quando seu aplicativo for compatível com várias direções de texto

Atributo compatível somente com LTR Atributo compatível com LTR e RTL
android:gravity="left" android:gravity="start"
android:gravity="right" android:gravity="end"
android:layout_gravity="left" android:layout_gravity="start"
android:layout_gravity="right" android:layout_gravity="end"
android:paddingLeft android:paddingStart
android:paddingRight android:paddingEnd
android:drawableLeft android:drawableStart
android:drawableRight android:drawableEnd
android:layout_alignLeft android:layout_alignStart
android:layout_alignRight android:layout_alignEnd
android:layout_marginLeft android:layout_marginStart
android:layout_marginRight android:layout_marginEnd
android:layout_alignParentLeft android:layout_alignParentStart
android:layout_alignParentRight android:layout_alignParentEnd
android:layout_toLeftOf android:layout_toStartOf
android:layout_toRightOf android:layout_toEndOf

A Tabela 2 mostra como o sistema gerencia os atributos de alinhamento da IU com base na versão do SDK de destino, com a definição de left e right, bem como de start e end.

Tabela 2. Comportamento de alinhamento do elemento da IU com base na versão do SDK de destino e nos atributos definidos

Direcionamento para o Android 4.2
Nível 17 da API ou posterior?
Esquerda e direita definidas? Início e término definidos? Resultado
Sim Sim Sim start e end resolvidos e modificação de left e right
Sim Sim Não Somente left e right são usados
Sim Não Sim Somente 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 Somente left e right são usados
Não Não Sim start e end resolvidos para left e right

Adicionar recursos específicos de direção e idioma

Esta etapa envolve a adição de versões específicas dos seus arquivos de recursos de layout, drawables e valores que contêm valores personalizados para diferentes idiomas e direções de texto.

No Android 4.2 (nível 17 da API) e versões posteriores, você pode usar os qualificadores de recurso -ldrtl (layout-direção-direita-para-esquerda) e -ldltr (layout-direção-esquerda-para-direita). Para manter a compatibilidade com o carregamento de recursos existentes anteriores, 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 compatibilidade com scripts RTL, como os idiomas hebraico, árabe e persa. Para fazer isso, adicione um layout-ldrtl/ ao seu diretório res/, conforme mostrado no exemplo a seguir:

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 somente para texto em árabe, sua estrutura de diretório será a seguinte:

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 maioria dos elementos de estrutura da IU é automaticamente compatível com a direção do texto RTL. No entanto, vários elementos da estrutura, 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 seus arquivos de manifesto correspondentes incluam o atributo android:supportsRtl="true".

Oferecer compatibilidade com aplicativos legados

Caso seu aplicativo seja direcionado ao Android 4.1.1 (nível 16 da API) ou versões posteriores, inclua também os atributos left e right, além de start e end.

Para verificar se o layout deve usar a direção do texto RTL, aplique a seguinte 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 versões posteriores das Android SDK Build Tools.

Testar o uso de opções do desenvolvedor

Em dispositivos que executam o Android 4.4 (nível 19 da API) ou versões posteriores, é possível ativar Force RTL layout direction nas opções do desenvolvedor no dispositivo. Com essa configuração, você pode ver o texto que usa scripts LTR, como texto em inglês, no modo RTL.

Atualizar a lógica do aplicativo

Esta seção descreve o que deve ser especificamente atualizado na lógica do seu aplicativo ao adaptá-lo para processar várias direções de texto.

Alterações da propriedade

Para gerenciar uma alteração em qualquer propriedade relacionada à RTL—como direção do layout, parâmetros de layout, preenchimento, direção do texto, alinhamento de texto ou posicionamento de drawable—use a chamada onRtlPropertiesChanged(). Essa chamada permite obter a direção do layout atual e atualizar objetos View de uma atividade da maneira adequada.

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 um diálogo ou um elemento correspondente, configure 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 exigem a consideração adicional:

onMeasure()
As medições da visualização podem variar dependendo da direção do texto.
onLayout()
Se criar o próprio layout de implementação, você precisará chamar super() na sua versão de onLayout() e adaptar a lógica personalizada para que ela seja compatível com scripts RTL.
onDraw()
Se você estiver implementando uma visualização personalizada ou adicionando funcionalidade avançada a um desenho, atualize seu código para oferecer compatibilidade com scripts RTL. Use o código a seguir 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 precisa ser espelhado para um layout de RTL, conclua uma destas etapas com base na versão do Android em execução no dispositivo:

  • Em dispositivos que executam o Android 4.3 (nível 18 da API) e versões anteriores, você precisa adicionar e definir arquivos de recurso -ldrtl.
  • No Android 4.4 (nível 19 da API) e versões posteriores, você pode usar android:autoMirrored="true" ao definir seu drawable, o que permite ao sistema gerenciar o espelhamento de layout RTL.

    Observação: o atributo android:autoMirrored só funciona para drawables simples em que o espelhamento bidirecional é simplesmente um espelhamento gráfico de todo o drawable. Se o drawable contiver vários elementos, ou se refleti-lo mudaria sua interpretação, faça você mesmo o espelhamento. Sempre que possível, trabalhe com um especialista em bidirecionamento para determinar se os drawables espelhados fazem sentido para os usuários.

Gravidade

Se o código do seu aplicativo estiver usando Gravity.LEFT ou Gravity.RIGHT, você precisará alterar esses valores para Gravity.START e Gravity.END, respectivamente.

Por exemplo, se você estiver usando o seguinte código:

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-o para:

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 existente que lida com valores alinhados à esquerda e à direita, mesmo se estiver usando start e end para seus valores de gravidade.

Observação: ao aplicar suas configurações de gravidade, use uma versão sobrecarregada de Gravity.apply() que inclui um argumento layoutDirection.

Margem e preenchimento

Para oferecer compatibilidade a scripts RTL no seu aplicativo, siga estas práticas recomendadas relacionadas aos valores de margem e preenchimento:

Veja também