Desventuras na Terra da Tradução: Uma Odisséia Multilíngue de Desenvolvimento de Software

Internacionalização de aplicativos com Angular 16.x

TL;DR

Para configurar sua aplicação angular, você vai precisar instalar e configurar o pacote @ngx-translate, para isso, no terminal digite:

npm install @ngx-translate/core @ngx-translate/http-loader
ShellScript

Para configurar, abre o seu arquivo app.module.ts e adicione um import:

import {NgModule} from '@angular/core';
import {BrowserModule} from '@angular/platform-browser';
import {HttpClientModule, HttpClient} from '@angular/common/http';
import {TranslateModule, TranslateLoader} from '@ngx-translate/core';
import {AppComponent} from './app';

@NgModule({
    imports: [
        BrowserModule,
        HttpClientModule,
        TranslateModule.forRoot({
            loader: {
                provide: TranslateLoader,
                useFactory: HttpLoaderFactory,
                deps: [HttpClient]
            }
        })
    ],
    bootstrap: [AppComponent]
})
export class AppModule { }
JavaScript

Também é necessário adicionar um loader:

import {NgModule} from '@angular/core';
import {BrowserModule} from '@angular/platform-browser';
import {HttpClientModule, HttpClient} from '@angular/common/http';
import {TranslateModule, TranslateLoader} from '@ngx-translate/core';
import {TranslateHttpLoader} from '@ngx-translate/http-loader';
import {AppComponent} from './app';

export function createTranslateLoader(http: HttpClient) {
    return new TranslateHttpLoader(http, './assets/i18n/', '.json');
}

@NgModule({
    imports: [
        BrowserModule,
        HttpClientModule,
        TranslateModule.forRoot({
            loader: {
                provide: TranslateLoader,
                useFactory: HttpLoaderFactory,
                deps: [HttpClient]
            }
        })
    ],
    bootstrap: [AppComponent]
})
export class AppModule { }
JavaScript

Os parâmetros da função são um httpclient, a pasta onde estão os arquivos de tradução e o formato que os arquivos de tradução.

Agora é preciso injetar o serviço de tradução no app.component.ts.

import { Component, OnInit } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
register();

@Component({
  selector: 'app-root',
  templateUrl: 'app.component.html',
  styleUrls: ['app.component.scss'],
})
export class AppComponent {
  constructor(
    public translate: TranslateService
  ) {
    translate.setDefaultLang('pt-BR');
    translate.use('pt-BR');
  }
}
JavaScript

Agora você pode criar os arquivos de tradução, que nada mais são do que um arquivo com JSON, na pasta que foi indicada durante a configuração (./assets/i18n). O arquivo nome do arquivo deve ser o código do idioma, por exemplo, pt-BR.json. Veja como você pode estruturar o arquivo

{
  "hello_world": "Olá mundo!",
  "profile": {
    "name": "nome"
  }
}
JSON

Caso você possua módulos e seu componente está dentro desse módulo, você precisará importar o serviço de tradução nesse módulo.

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { IonicModule } from '@ionic/angular';
import { LoginPageRoutingModule } from './login-routing.module';
import { LoginPage } from './login.page';
import { TranslateModule } from '@ngx-translate/core';

@NgModule({
  imports: [
    CommonModule,
    FormsModule,
    IonicModule,
    LoginPageRoutingModule,
    TranslateModule
  ],
  declarations: [LoginPage]
})
export class LoginPageModule {}
JavaScript

Por último, mas não menos importante, fazer a chamada para a tradução da string

<p>{{hello_world | translate}}</p>
<p>{{profile.name | translate}}</p>
HTML

Importante: para que o Angular traduza novas strings, é necessário reiniciar o servidor para que ele capture o arquivo de tradução (json) alterado.

Historinha pra descontrair

Hoje recebi, quer dizer, peguei para mim a tarefa de configurar o pacote de tradução da aplicação que estamos desenvolvendo. Nós já temos outros sistemas que contam com a feature de vários idiomas, eu imaginava que sabia como funcionava, baseado em absolutamente nada.

A primeira coisa que fiz, foi procurar pelo que eu achava que era o pacote que faria a tradução, o “i18n”, se você entende alguma coisa de tradução você provavelmente pode ter dado uma risadinha, por ora a piada fica interna, no final eu explico.

Procurei pelo google Angular i18n, encontrei um guia no site oficial, que tinha um vídeo bem explicativo sobre internacionalização. Primeira coisa foi descobri foi que não era da forma explicada no guia/vídeo que faziamos a tradução de nossos sistemas. Achei bem interessante a forma que o time do Angular recomenda que seja feita a tradução, ao invés de criar um arquivo json com todas as strings do sistema, você marca as tags onde as frases que precisam ser traduzidas e depois com um comando o Angular gera um arquivo com todas as strings que precisam ser traduzidas.

Outra coisa diferente, é que na forma do Angular você faz o build de cada uma das versões traduzidas, então se você tem traduções em pt-br, pt-pt e en, você fará 3 builds. Eles argumentam que essa abordagem elimina a necessidade de carregar todo o arquivo json de tradução, quando em alguns casos algumas strings não serão utilizadas. É um tradeoff de mais complexidade no desenvolvimento e mais espaço gasto no servidor, para que a aplicação consuma menos memória durante a execução e gaste menos em transferência de dados.

Finalmente chega a parte que é mostrado o arquivo de tradução, e como sempre é decepcionante como o google sempre cria coisas extremamente complexas para problemas que podem ser resolvidos de forma simples. O arquivo onde as traduções devem ser feitas é um formato XLF, também conhecido como XLIFF (XML Localisation Interchage File Format). Trata-se de um arquivo xml cheio de informações (que na minha opinião de quem acabou de cair nesse mundo, não faz o menor sentido) e adicionando uma tag “target” você adiciona a tradução. Esse foi o ponto onde eu desisti de tentar usar a ferramenta própria do Angular para a tradução.

Eu teria que convencer que um arquivo json com chave e valor era mais dificil que um XML cheio de informações que tem pouca relação com a tradução em si.

Voltei para o google e olhei outro link, e dessa vez era um link da Digital Ocean, novamente a recomendação era para usar a ferramenta do Angular. Foi aqui que deu uma vergonhazinha da minha falta de conhecimento. O nome i18n não é o nome de um pacote, é um “numerônio” (numeronym), onde o 18 representa as 18 letras que tem entre as letras “i” e “n” na palavra “internacionalization”. Outro “numerônio” é a11y para a palavra “accessibility”, este eu ainda não esbarrei, mas já estou preparado para esse momento kk.

Cheguei a mesma conclusão, inviavél utilizar a forma recomendada pelo Angular. Com isso decidido, finalmente me rendi e fui ver o código de outra aplicação que já possui o pacote de tradução funcionando.

Primeira coisa que fiz foi identificar tudo o que consegui que trava de tradução, que encontrei, o que foi surpreendentemente pouco, o que é um bom sinal, pouca coisa para configurar.

Fui até uma das telas onde existia tradução e dei um ctrl+click no pipe de tradução, que me levou para dentro da pasta do pacote @ngx-translate (sugestivo não?), tentei npm install @ngx-translate sem sucesso. De volta para o senhor google, procurei pelo pacote e encotrei o github do pacote que felizmente tem um guia bem simples de seguir.

O guia mostra várias opções, o que para que está perdido como eu acaba dificultado, mesmo sabendo que no futuro essas informações vão fazer total sentido.

No final acabei utilizando o sistema usado anteriormente em outros projetos, evitando uma série de dores de cabeça, foi um bom aprendizado hoje. Só de descobrir a existência desse tal de numerônio já valeu a pesquisa.

Aprendi também que existe diferença entre internacionalização e localização (locale), a internacionalização é a tradução das strings do projeto enquanto a localização é alterar por exemplo como um valor monetário deve ser exibido, ou se um número deve usar vírgula ou ponto para separa as casas decimais.

Leave a Reply

Your email address will not be published. Required fields are marked *