Internacionalização: Tornando a Web Acessível a Todos

A Ecma International, Comitê Técnico 39, ou simplesmente TC39, é um grupo de desenvolvedores de JavaScript, implementadores de tecnologia, acadêmicos e outras partes interessadas que, juntamente com a comunidade, apoiam e desenvolvem o JavaScript como plataforma.

Os participantes do TC39 geralmente compartilham algo interessante usando sua profunda compreensão do JavaScript. Mas algumas pessoas pensam que foram longe demais dos problemas dos desenvolvedores comuns. Onde está o desenvolvedor do idioma e onde está a pessoa que escreve frontends todos os dias na prática?

Vamos nos familiarizar com o relatório, que combina a profundidade do entendimento e a alta aplicabilidade prática . Conheça a nova história de Romulo Cintra sobre questões de internacionalização que serão tratadas pela nova API, que em breve aparecerá em JavaScript.



Romulo Cintra - TC39 delegado, trabalha com desenvolvimento e arquitetura há mais de 10 anos, especializado em web, desenvolvimento móvel e nuvens. Neste relatório, você aprenderá em primeira mão o copresidente do MessageFormat Working Group , quais opções já estão disponíveis para solucionar problemas existentes e de que forma elas serão resolvidas usando a nova API no próprio JavaScript.

Abaixo do corte, a transcrição textual completa do relatório Romulo e um link para o vídeo. Se você gosta de ler - este artigo tem tudo; você não perderá nada. Se você tiver tempo para iniciar a gravação de vídeo, terá cerca de uma hora de boa gravação de vídeo com slides interessantes e inglês compreensível.

Narração adicional em nome do orador.


Há três coisas que você precisa saber sobre o estado da internacionalização e localização: tudo é muito, muito, muito ruim. Meu nome é Romulo Cintra e estou envolvido em aplicativos de arquitetura financeira. Converso muito com as pessoas do TC39 e vejo como elas tentam tornar o mundo JavaScript um lugar melhor. Além disso, sou um forte defensor do código aberto e, nas horas vagas, sou professor da Escola de Tecnologia de Barcelona.

A questão da internacionalização é muito importante. Aconteceu que em nossa Terra existem muitos povos e idiomas diferentes. No mundo de hoje, existem cerca de 195 países e 6 mil idiomas. Isso torna nossa tarefa extremamente difícil. Pense em outra coisa: escrevo artigos e leio relatórios em inglês, não em russo; já temos um problema de internacionalização. Se alguém não fala inglês, ele será excluído da nossa conversa com você. Para impedir que isso acontecesse, a internacionalização foi inventada.

A internacionalização inglesa abrevia como i18n. O número 18 é o número de caracteres entre as letras ie nesta palavra. Em resumo, a internacionalização é o design do software, a fim de simplificar a localização o máximo possível. Graças à internacionalização, o software pode suportar configurações locais, idioma, moeda e assim por diante. A internacionalização torna a web mais acessível a todos. Aqui você pode traçar um paralelo com o desenvolvimento por meio de testes (desenvolvimento orientado a testes): primeiro, o teste é escrito e, em seguida, o código; com a internacionalização é necessário fazer o mesmo. Geralmente, as pessoas pensam em internacionalização depois que o código é escrito, mas está errado.

Semelhante a i18n, l10n é a abreviação de localização e 10 é o número de caracteres entre o primeiro l e o último n. Localização é a adaptação de um produto ao ambiente cultural e de idioma em que é distribuído. Ou seja, você precisa não apenas converter "Olá" para "Olá", mas também usar a moeda local, separador decimal etc., ou seja, tornar o software mais familiar para o usuário. É mais do que apenas uma tradução.

Quantos idiomas seus projetos da web suportam? Muitos têm mais de dois. Existe alguém que tem mais de cinco? Que tal 15? Suportamos cerca de 25 idiomas. Não temos um apoio muito bom, porque a internacionalização não está organizada da melhor maneira. No decorrer do relatório, explicarei como melhorar a internacionalização e falarei sobre as medidas que estamos tomando.

Então, repito mais uma vez: internacionalização significa simplificar a localização, fornecendo suporte para ela no nível da arquitetura. E localização é a adaptação do software às realidades locais. A tradução muitas vezes não corresponde ao original - vamos dar um exemplo da indústria cinematográfica, onde o nome do filme "Pain and Gain" foi traduzido como "Blood and Sweat: Anabolics".



Ou outro exemplo: um anúncio para um banho russo, no qual a tradução em inglês diz "crematório russo" (crematório russo).



Duvido que isso atraia clientes, pelo menos vivos. Internacionalização e localização são tão importantes precisamente porque nos permitem transmitir exatamente o que queremos dizer ao usuário. Em essência, a internacionalização é o fornecimento de acessibilidade, porque se você não consegue entender o software com o qual trabalha, suas opções são limitadas. É benéfico para todos que o software seja mais acessível, pois fornece uma gama maior de usuários e, portanto, uma renda mais alta; também melhora a web.

Messageformat


Considere os exemplos de código:

'es-ES': { 
    HELLO_WORLD: '¡Hola mundo!' 
}, 
'en-GB': { 
    HELLO_WORLD: 'Hello world!'

Precisamos traduzir nossos objetos de string. Temos uma variável HELLO_WORLDcom as linhas correspondentes em cada idioma. Para essa tradução em vários idiomas (por exemplo, Java), existe o formato MessageFormat . Vamos tentar descobrir o que é. Primeiro, um pouco sobre algumas tecnologias básicas - vamos começar com o Unicode. Esse é um padrão que cria um espaço único para caracteres de diferentes idiomas. Vamos fazer uma analogia com o xadrez: cada tipo de peça pode ter uma forma diferente, mas sempre sabemos onde exatamente elas devem estar no tabuleiro. Bem, é claro, existem diferentes formatos Unicode com diferentes números de bytes: UTF-8, UTF-16 e UTF-32. Agora, a metatag mais usada é o UTF-8. Com Unicode, o navegador pode exibir caracteres especiais, se essa tag`metaesqueça, ninguém vai entender que tipo de símbolos temos na página.

Além do Unicode, duas outras tecnologias importantes são CLDR e ICU. O CLDR é um tipo de banco de dados de alfabetos, países, moedas, fusos horários, etc., armazenados em diferentes idiomas do mundo. Nem todos os 6 mil idiomas do mundo estão presentes nele, ainda há trabalhos em andamento nesse banco de dados. A última atualização foi em outubro passado. Outro projeto importante é a UTI. Este é um imenso banco de dados de palavras, números e símbolos de diferentes idiomas, fornecidos na forma de métodos de classificação, normalização, formatação etc. Essas bibliotecas são usadas em muitas linguagens de programação. Em JavaScript, a ICU está no centro da API Intl. Mas existem tantos materiais diversos nos idiomas do mundo que precisam ser exibidos nos navegadores que o trabalho de incluí-los nesses padrões está longe de estar completo.

MessageFormat é um formato que permite associar uma chave específica a uma mensagem específica em um idioma específico. Em alguns casos, as variáveis podem ser passadas para MessageFormat , elas as definem e as inserem na linha final. O mesmo problema foi resolvido de uma maneira ligeiramente diferente em outros idiomas. No Android, o MessageFormat é implementado em Java. Lá, para trabalhar com esse formato, não é necessária uma biblioteca especial; o Android é capaz de interagir com ele mesmo. No iOS, existe uma API muito semelhante à do JavaScript. Ele está embutido no sistema, não há necessidade de baixar nada, basta passar a linha necessária para o método desta API.

Como esse problema foi resolvido no JavaScript? Ainda não. Mas temos muitas bibliotecas que oferecem uma solução.



Ele mostra o número de downloads dos mais populares deles (e dois menos populares, fluentes do Mozilla e fbt do Facebook). Quase dois milhões de downloads ocorrem toda semana, portanto, há uma necessidade de bibliotecas para internacionalização.

Bibliotecas


Introduziremos brevemente algumas dessas bibliotecas e começaremos com o i18next. Seus desenvolvedores fizeram muitas alterações no MessageFormat , e ele não segue completamente a UTI. No entanto, é uma biblioteca muito boa. Sua implementação do MessageFormat tem muitas vantagens, por exemplo, a capacidade de usar a interpolação de strings (que não está disponível no formato ICU). No entanto, também há desvantagens, por exemplo, mensagens plurais não podem ser colocadas na mesma linha que a única, como pode ser feito na UTI.

Uma das bibliotecas de internacionalização mais famosas é intl-messageformat. Toda semana é baixado mais de 700 mil vezes. Seu apoio é tratado pelo meu colega, Long Hu. Sua popularidade é explicada pelo fato de que o react-intl é criado em cima dele. Portanto, se você usar o React, provavelmente terá esta biblioteca. O desenvolvedor dela também participa do ECMA-402 e, portanto, ele tenta cumprir o padrão da UTI.

var MESSAGES = { 
    'en-US': { 
        NUM_PHOTOS: 'You have {numPhotos, plural, ' +
            '=0 {no photos.}' +
            '=1 {one photo.}' +
            'other {# photos.}}'
}, 
    'es-MX': {
        NUM_PHOTOS: 'Usted {numPhotos, plural, ' +
            '=0 {no tiene fotos.}' + 
            '=1 {tiene una foto.}' 
            +'other {tiene # fotos.}}' 
    } 
};

Sua implementação é muito semelhante à MessageFormat . Aqui você pode passar variáveis ​​e indicar a necessidade do plural.

Antes de passar para os exemplos de código, vou falar sobre mais duas novas bibliotecas que estão na moda, elas foram criadas pelo Facebook e Mozilla.



A API inteira não pode ser mostrada como um todo, mas aceite minha palavra: os desenvolvedores dessas bibliotecas fizeram o melhor possível, existe exatamente o que estamos perdendo no momento. É verdade que o Facebook criou seu próprio estilo: sua própria marcação, a capacidade de executar durante o layout, a extração de mapas de hash de strings que podem ser traduzidas automaticamente. O problema é que tudo isso se concentra na escala com a qual o programador médio raramente trabalha. O projeto é muito jovem e eles querem integrá-lo a outras bibliotecas conhecidas, por exemplo, com o React. No futuro, ele provavelmente ganhará popularidade.

Todas as opções acima são bibliotecas que precisam ser baixadas adicionalmente, elas não são incorporadas ao navegador. Com apenas um navegador, não iremos longe, então tudo está ruim com a localização. MessageFormat pode nos ajudar a mudar esse estado de coisas . Enquanto não podemos usá-lo, mas acredite: o futuro está com ele. Agora, estamos trabalhando ativamente, estabelecendo partes interessadas, procurando novas idéias para o novo MessageFormat . Na sua versão original, esse formato já está desatualizado, as necessidades dos desenvolvedores evoluíram significativamente desde a sua criação. O novo formato deve ser feito com alta qualidade e fácil de usar.

Intl.DateTimeFormat


Os navegadores já possuem muitos mecanismos internos de internacionalização e localização, a maioria deles simplesmente não os conhece e não os utiliza. Você já ouviu falar sobre Intl.DateTimeFormat? Neste projeto, estamos constantemente criando novas APIs. É provável que não haja mais necessidade de Moment.js , Day.js , date-fns .

const myDate = new Date(); 
new Intl.DateTimeFormat('ru', { timeStyle : 'short'}).format(myDate); 
// short → 19:49 
// medium → 19:49:17 
// long → 19:49:17 GMT+2
// full → 19:49:17  ,  

Há timeStyle, ele foi criado há alguns meses e permite que você formate a data e a hora sem recorrer ao Moment.js. Além disso, existe um método formatRange . Qualquer tarefa associada à escolha de um período (como em sites com uma função de reserva) é sempre difícil. Mas o método para isso já existe no navegador. E, o mais importante, esse método oferece suporte à internacionalização, eliminando a necessidade de baixar bibliotecas adicionais.

Intl.RelativeTimeFormat


Trabalhei na documentação para a segunda parte deste projeto e, se você também quiser participar, precisamos de ajuda para traduzir para o russo e em conformidade com os padrões. RelativeTimeFormat é necessário quando você precisa fazer uma contagem regressiva.

const myTime = new Intl.RelativeTimeFormat('ru', { style: 'narrow' }); 
myTime.format(2 , 'quarter'); 
//Style Narrow : +2 . → in 2 qtrs. → dentro de 2 trim. 
//Style Long :  2  → in 2 quarters → dentro de 2 trimestres

Agora, é bastante simples fazer isso, você pode especificar o tempo em dois dias, duas semanas, em um quarto, etc. Anteriormente, essa formatação na Web não existia.

const myTime = new Intl.RelativeTimeFormat('ru', { style: 'narrow' }); 
myTime.format(2 , 'day'); 
//Style Narrow : +2 . → in 2 days → dentro de 2 días 
//Style Long :  2  → dentro de 2 días myTime.format(-1 , 'day');
//Style Narrow : -1 . → 1 day ago → hace 1 día 
//Style Long : 1   → 1 day ago → hace 1 día //Numeric(auto) :  → yesterday → ayer 

Aqui está um exemplo em russo. Você mesmo pode testar a operação deste código, porque ele já está no seu navegador.

const myTime = new Intl.RelativeTimeFormat('ru', { style: 'narrow' }); 
myTime.format(20 , 'seconds'); 
//Style Narrow : +20  → in 20 sec. → dentro de 20 s 
//Style Long :  20  → in 20 seconds → dentro de 20 segundos

Este método é muito útil, pois pode dar tempo no formato curto que você vê acima. Enfatizo que, por tudo isso, você não precisa usar nenhuma biblioteca de terceiros.

Intl.NumberFormat


A próxima coisa que eu queria compartilhar é Intl.NumberFormat . Vou falar sobre o terceiro estágio, mas apenas o segundo é apresentado nos exemplos, porque algumas mudanças ainda estão sendo discutidas. Intl.NumberFormat trabalha com unidades e formulários de registro. Vale a pena prestar atenção ao que ele faz com as unidades: ele permite que você trabalhe com estilos diferentes.

new Intl.NumberFormat("ru", { 
style: "unit", 
unit: "liter", unitDisplay: "long" 
}).format(16); 
// → 16  → 16 liters → 16 litros

Todas as unidades são retiradas do UTC 35, e existem muitas. No total, são apresentadas aqui cerca de 140 unidades para formatação. Então agora a internacionalização está mais fácil do que nunca. Você só precisa traduzir suas linhas, e toda a dinâmica necessária já está contida no navegador.

const nbr = 987654321; 
new Intl.NumberFormat('ru', { notation: 'scientific' }).format(nbr); 
// → 9,877E8 → 9.877E8 (en-US) 
new Intl.NumberFormat('ru', { notation: 'engineering' }).format(nbr); 
// → 987,654E6 → 987.654E6 (en-US) 
new Intl.NumberFormat('ru', { notation: 'compact' }).format(nbr); 
// → 988  → 988M (en-US) → 9.9亿 (zn-CN) 
new Intl.NumberFormat('ru', { notation: 'compact', compactDisplay: 'long' }).format(nbr); 
// → 988  → 988 millions (fr)

Agora, para os formulários de gravação. Para ser sincero, não os uso com muita frequência, porque não uso a forma de gravação com o expoente (registro científico) e não preciso apresentar grandes números. Mas se você precisar, existe uma API correspondente especialmente para você.

Intl.ListFormat


Outra API útil é o Intl.ListFormat , que já está no terceiro estágio e permite formatar listas de duas maneiras diferentes. Suponha que eu precise dizer a frase "Eu vou para o HolyJS". Podemos fazer uma lista que inclui as linhas "Moscou" e "St. Petersburg ”, especifique o parâmetro“ conjunção ”, e as linhas serão combinadas pela união da língua russa“ e ”. Este é um recurso completamente novo e muito útil.



Se você especificar "disjunção", obteremos a união "ou".



Por fim, a função pode determinar automaticamente o idioma e o alfabeto usados ​​e classificar os itens da lista de acordo.

Regras Internacionais


Outra API importante é Intl.PluralRules . Essa API é a mais antiga de todas, mas por algum motivo ninguém a usa.



Quando vejo as listas de finalistas em corridas ou no futebol, os números são sempre indicados ao lado dos nomes: "1", "2", "3" etc. Mas isso não corresponde à maneira como dizemos que seria muito mais próximo para fala, escreva “1º”, “2º”, “3º”. E para isso, existem APIs especiais, que não são tão difíceis de usar.



Por exemplo, podemos escrever as frases "1 gato", "0 gatos", "0,5 gatos", "1,5 gatos" e a API selecionará automaticamente a final correta do plural.

Intl.DisplayNames


Essa é uma das APIs mais populares, porque muitas vezes precisamos exibir listas de países. Suponha que tenhamos uma lista de países - por exemplo, em um banco de dados ou em JSON. Então, sempre que você alterna o idioma, precisamos carregar um JSON separado com uma nova lista de países, moedas e assim por diante. Existem muitos desses JSONs e como isso termina? Criamos um microsserviço no qual um banco de dados com vários idiomas é incorporado e extraímos todos os dados dele. É claro que, no exemplo da lista de países, tivemos sorte e precisamos atualizar os dados com pouca frequência - mas nem sempre será assim, certo? Não podemos resolver todos os problemas de uma só vez, mas o DisplayNames resolve alguns deles. Você tem a API como no exemplo abaixo e pode solicitar apenas uma lista de moedas ou apenas uma lista de países:

const currencyNames = new Intl.DisplayNames(['en'], {type: 'currency'}); currencyNames.of('USD'); // "US Dollar" 
currencyNames.of('EUR'); // "Euro" 
currencyNames.of('TWD'); // "New Taiwan Dollar" 
currencyNames.of('CNY'); // "Chinese Yuan"


const languageNames = new Intl.DisplayNames(['en'], {type: 'language'}); languageNames.of('fr'); // "French" 
languageNames.of('de'); // "German" 
languageNames.of('fr-CA'); // "Canadian French" 
languageNames.of('zh-Hant'); // "Traditional Chinese"

Isso é uma coisa muito útil. Funciona não apenas com países e moedas: da mesma maneira, você pode trabalhar com meses, dias da semana e muitas outras coisas necessárias como desenvolvedor.

Resultados e planos para o futuro


Até agora, falamos sobre APIs existentes. Vamos seguir para os nossos planos para o futuro. Minha língua materna é o português Então, nos meus sites, preciso oferecer suporte a pelo menos português e inglês. E como estamos muito perto da Espanha, o espanhol também é útil. Portugal é um país muito pequeno e a França também não está tão longe, por isso seria bom adicionar o francês a esta lista.

Para nós MessageFormatmuito relevante e aparecerá em breve. Existem bibliotecas e desenvolvedores que trabalham nelas. Todos esses desenvolvedores estão trabalhando em questões relacionadas. A maioria dos criadores das bibliotecas mais populares e das grandes empresas (Netflix, Amazon, Facebook) concorda pelo menos em uma coisa: agora há uma necessidade urgente de internacionalização. Isso também é indicado por dois milhões de downloads por semana. Portanto, agora podemos escrever MessageFormat novamente e fazê-lo de maneira com qualidade.

Quem se beneficiará com a internacionalização adequada? A web inteira: todas as empresas, todos os projetos, todas as bibliotecas. Bibliotecas como Intl.MessageFormatnão desaparecerá em lugar algum, mas começará a funcionar de uma nova maneira. Você não precisará baixar dados, pois todos os dados já estarão no navegador. Provavelmente, você não precisará mudar para uma nova biblioteca. Algumas dessas bibliotecas já funcionam como polyfills para algumas implementações. Algumas implementações que mencionei estão no terceiro estágio e não são implementadas em todos os navegadores. Mas bibliotecas como Intl.MessageFormat fornecem polyfillings para essa funcionalidade. Em geral, um novo capítulo na história da web está chegando - uma verdadeira revolução. A web se tornará acessível e compreensível para todos. Isto é extremamente importante.

Eu acredito que é muito importante garantir a exclusividade do nosso projeto. Se houver um formato que possa ser usado em C ++, Java e JavaScript, por que não usar esse formato em qualquer lugar? Quando escrevemos páginas da Web, geralmente precisamos criar versões móveis delas; nesse caso, temos que trabalhar muito duas vezes. Se tivéssemos um formato para tudo, poderíamos simplesmente usar os recursos e a API existentes. Precisamos de um novo nível de integração com ferramentas. A internacionalização é fornecida não apenas pelo trabalho de desenvolvedores diretamente envolvidos nela. Para ela, a modularidade é extremamente importante, porque geralmente é conveniente usar suas próprias ferramentas de formatação, seu próprio código. Portanto, você não deve fechar a API, ela deve estar aberta para poder conectar o que a situação exige.Outro ponto importante: essas APIs devem ser nativas. Os CLDRs fornecem os dados que a API de internacionalização precisa. Se você estiver executando o Windows ou MacOS, já está baixando dados do CLDR. O CLDR é um repositório exclusivo; ninguém duplica sua função. Isso significa que os dados podem ser baixados apenas uma vez e tornados comuns a todo o sistema operacional. Se todos os dados da API Intl já estiverem carregados no sistema operacional, por que não fornecê-los para todo o software desse sistema?Se todos os dados da API Intl já estiverem carregados no sistema operacional, por que não fornecê-los para todo o software desse sistema?Se todos os dados da API Intl já estiverem carregados no sistema operacional, por que não fornecê-los para todo o software desse sistema?

Nossa experiência nos ensinou a lembrar que não estamos sozinhos, que não apenas os programadores estão trabalhando na internacionalização. Somos desenvolvedores, não tradutores. Suponhamos que precisamos fazer um feed de linha em nossa interface e os enviamos para a empresa de tradução. Porém, os tradutores geralmente não têm contexto para essas linhas. Isso também está ausente no MessageFormat . Às vezes, isso leva a erros, como já vimos no exemplo mencionado com o crematório russo.

Finalmente, acredito que as APIs para internacionalização devem ser fáceis de usar e todos devem poder fazer internacionalização - isso não deve levar muito tempo e esforço. Ao escrever código para internacionalização, você precisa ser guiado desde o início. Afinal, com o TDD, eles primeiro escrevem um teste e depois codificam; vamos começar nossos projetos na Web com esse princípio com a internacionalização e localização corretas. Isso nos permitirá criar sites convenientes e acessíveis a todos.
HolyJS 2020 Piter «Speak my language %app%». , , : . HolyJS 2020 Piter . , .

All Articles