Como as principais bibliotecas de front-end lidam com i18n

Tempo de leitura: 7 minutes

Uma forma de as empresas alcançarem novos clientes é falar a língua deles. Para fazer isso, os desenvolvedores precisam usar a internacionalização e a localização em seus aplicativos para oferecer produtos e conteúdo nos idiomas nativos dos usuários.

Internacionalização, ou i18n (18 é o número de letras entre i e n), é o processo de construção de seu produto para suportar vários idiomas. Isso pode incluir separar o texto do código e usar uma biblioteca para formatar datas com base em diferentes países e fusos horários. Quando seu produto estiver pronto para adicionar suporte para idiomas específicos, você poderá passar para a localização.

Localização, ou l10n, é o processo de adicionar suporte para uma região, país ou idioma específico. Isso é diferente de traduzir texto para outro idioma, embora a localização possa incluir tradução. Aqui estão algumas coisas que você deve ter em mente ao localizar um produto:

  • Formatação de data, como DD/MM/AAAA vs. MM/DD/AAAA
  • Formatação de nomes, já que em alguns países os sobrenomes são exibidos antes dos nomes
  • Moeda
  • Medições (sistema imperial vs. sistema métrico)

As imagens também devem ser adaptadas a um determinado mercado, especialmente aquelas que exibem texto.

Lembre-se de que um CMS headless pode ajudá-lo a obter localização facilmente. Strapi, o CMS headless de código aberto líder com uma comunidade de mais de 135.000 usuários, oferece soluções personalizáveis para gerenciar e localizar seu conteúdo.

Em menos de uma hora, você pode usar o Strapi para ter endpoints de API e um painel de administração prontos para uso. Com GraphQL ou Rest, você pode consumir qualquer endpoint da API Strapi de qualquer cliente (Vue, React ou Angular, por exemplo), o que lhe dá grande flexibilidade.

 

Flutter

Criada pelo Google em 2017, Flutter é uma biblioteca que está ganhando força rapidamente. Como esperado de uma empresa global como o Google, a internacionalização faz parte da biblioteca e pode ser implementada quase instantaneamente.

O Flutter suporta não apenas texto traduzido, mas também plurais, formatação de números e datas e texto da direita para a esquerda ou da esquerda para a direita. Isso o torna uma escolha sólida para desenvolvedores.

 

Internacionalize seu aplicativo Flutter

Para começar, atualize seu pubspec.yaml. Adicione generate true para gerar automaticamente os arquivos .dart necessários para cada localidade que você adicionar.

# ...
    dependencies:
      flutter:
        sdk: flutter
      flutter_localizations:  //Adicione esse
        sdk: flutter.   // esse
      intl: ^0.18.1.    // esse
    
    flutter:
      generate: true     // e finalmente, este
      uses-material-design: true
    
    # ...

Execute flutter pub get para obter os pacotes necessários.

Crie um arquivo l10n.yaml em seu diretório raiz. Isso informa ao Flutter onde encontrar suas traduções e onde gerar os arquivos dart.

arb-dir: lib/l10n
    template-arb-file: app_en.arb
    output-localization-file: app_localizations.dart

Em seguida, crie um diretório I10n na sua pasta lib e crie seus arquivos de tradução. Aqui está um exemplo de arquivo app_en.arb:

{
  "appTitle": "Home Page"
}

Em seu arquivo main.dart, importe o pacote dart flutter_localizations e adicione os delegados de localizações e os idiomas suportados. Usei inglês e francês aqui, mas é claro que você pode adicionar o seu próprio.

import 'package:flutter/material.dart';
    import 'package:flutter_localizations/flutter_localizations.dart'; // Nova importação
    
    return MaterialApp(
      title: 'Flutter Demo App',
      // Os pacotes Material, Cupertino e widgets agora serão localizados corretamente
      localizationsDelegates: const [
        GlobalMaterialLocalizations.delegate,
        GlobalWidgetsLocalizations.delegate,
        GlobalCupertinoLocalizations.delegate,
      ],
      supportedLocales: const [
        Locale('en', ''), // English 
        Locale('fr', ''), // French
      ],
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );

Execute o aplicativo com flutter run. Você deverá ver estes arquivos em sua ferramenta .dart-tool:

  • .dart_tool/flutter_gen/gen_l10n/app_localizations.dart
  • .dart_tool/flutter_gen/gen_l10n/app_localizations_en.dart
  • .dart_tool/flutter_gen/gen_l10n/app_localizations_fr.dart

Agora vamos adicionar nossa mensagem localizada.

import 'package:flutter/material.dart';
    import 'package:flutter_localizations/flutter_localizations.dart';
    //Nosso arquivo gen_l10n recém-gerado
    import 'package:flutter_gen/gen_l10n/app_localizations.dart'; 
    
    return MaterialApp(
      title: 'Localizations Sample App',
      localizationsDelegates: const [
        AppLocalizations.delegate, // Novo delegado
        GlobalMaterialLocalizations.delegate,
        GlobalWidgetsLocalizations.delegate,
        GlobalCupertinoLocalizations.delegate,
      ],
      supportedLocales: const [
        Locale('en', ''),
        Locale('fr', ''),
      ],
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );

Agora você pode acessar suas traduções através do AppLocalizations. Você poderia, por exemplo, passar um título para sua página inicial assim:

MyHomePage(title: AppLocalizations.of(context)!.appTitle)

 

Limitações do Flutter

O pacote de internacionalização tem poucas limitações, suportando muitos recursos necessários, como o tratamento de plurais ou texto bidirecional. Por ser uma linguagem muito nova, porém, o Flutter não possui a riqueza de pacotes de terceiros oferecidos com Ionic ou React. Além disso, o tamanho do pacote normalmente é maior que 4 MB.

 

Ionic

Mais antigo que o Flutter, o Ionic foi criado em 2013 e é uma biblioteca sólida que oferece aos desenvolvedores a capacidade de ter uma base de código para qualquer plataforma. Ionic oferece suporte para muitos frameworks, incluindo Angular, Vue e até mesmo React. Vou me concentrar no Angular aqui, pois o React será abordado abaixo.

Embora o Angular tenha um módulo de internacionalização integrado, a configuração é mais difícil para aplicativos Ionic. Como resultado, surgiram duas bibliotecas de terceiros:

Embora transloco seja mais recente e ofereça recursos como suporte SSR, ngx-translate é uma biblioteca sólida e confiável que existe há mais tempo e é adorada pelos desenvolvedores Angular. Usaremos ngx-translate como nossa biblioteca de tradução aqui.

Internacionalize seu aplicativo Ionic

Para começar, você precisará instalar a biblioteca necessária.

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

Em seu src/app/assets, adicione uma pasta i18n com suas traduções. Por exemplo, aqui está um arquivo en.json:

{
      "title": "Welcome",
      "description": "This is an Ionic app translated by ngx-translate"
}

Acesse app.module.ts e adicione seus módulos (TranslateModule, TranslateLoader, etc.). Isso informará ao seu aplicativo onde suas traduções estão localizadas e como carregá-las.

import { NgModule } from '@angular/core';
    import { BrowserModule } from '@angular/platform-browser';
    import { RouteReuseStrategy } from '@angular/router';
    import { TranslateModule, TranslateLoader } from '@ngx-translate/core';
    import { TranslateHttpLoader } from '@ngx-translate/http-loader';
    import { HttpClientModule, HttpClient } from '@angular/common/http';
    import { IonicModule, IonicRouteStrategy } from '@ionic/angular';
    import { AppComponent } from './app.component';
    import { AppRoutingModule } from './app-routing.module';
    
    /* New function to load our translation files*/
    export function HttpLoaderFactory(http: HttpClient) {
      return new TranslateHttpLoader(http, "./assets/i18n/", ".json");
    }
    /* Add HttpClientModule & TranslateModule to our imports */
    @NgModule({
      declarations: [AppComponent],
      entryComponents: [],
      imports: [HttpClientModule, BrowserModule, 
        TranslateModule.forRoot({
            loader: {
              provide: TranslateLoader,
              useFactory: HttpLoaderFactory,
              deps: [HttpClient]
            }
          }),
        , IonicModule.forRoot(), AppRoutingModule],
      providers: [{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy }],
      bootstrap: [AppComponent],
    })
    export class AppModule {}

Em app.component.ts, defina seu idioma padrão.

import { Component } from '@angular/core';
    import { TranslateService } from '@ngx-translate/core';
    @Component({
      selector: 'app-root',
      templateUrl: 'app.component.html',
      styleUrls: ['app.component.scss'],
    })
    export class AppComponent {
      constructor(public translate: TranslateService) {
        this.initializeApp();
      }
      initializeApp() {
        this.translate.addLangs(['en', 'fr']);
        this.translate.setDefaultLang('en');
      }
    }

Finalmente, tente exibir algum texto traduzido.

<div id="container">
        <strong>{{ 'title' | translate }} </strong>
        <p>{{ 'description' | translate }}</p>
</div>

Limitações do Ionic

Existem aspectos específicos do Ionic que requerem algumas soluções alternativas.

Módulos e traduções de carregamento lento

Para módulos de carregamento lento, você também precisará importar módulos de tradução; caso contrário, a tradução não funcionará. Não se esqueça de usar forChild em vez de forRoot.

import { NgModule } from '@angular/core';
    import { CommonModule } from '@angular/common';
    import { IonicModule } from '@ionic/angular';
    import { FormsModule } from '@angular/forms';
    import { HomePage } from './home.page';
    import { HomePageRoutingModule } from './home-routing.module';
    import { TranslateModule, TranslateLoader } from '@ngx-translate/core';
    import { HttpClient } from '@angular/common/http';
    import { TranslateHttpLoader } from '@ngx-translate/http-loader';
    
    /* Once again, load your translations*/
    export function HttpLoaderFactory(http: HttpClient) {
      return new TranslateHttpLoader(http, "./assets/i18n/", ".json");
    }
    
    /* Add the translation module again, but this time, with forChild() */
    @NgModule({
      imports: [
        TranslateModule.forChild({
          loader: {
            provide: TranslateLoader,
            useFactory: HttpLoaderFactory,
            deps: [HttpClient]
          }
        }),
        CommonModule,
        FormsModule,
        IonicModule,
        HomePageRoutingModule
      ],
      declarations: [HomePage]
    })
    export class HomePageModule {}

Pluralização e Gênero

A pluralização e a formatação de gênero não estão incluídas no ngx-translate. No entanto, existe um plugin para lidar com esses recursos e é reconhecido pela biblioteca oficial ngx-translate.

React

React precisa de pouca introdução. Criado pelo Facebook em 2013, rapidamente se tornou o favorito dos fãs de muitos desenvolvedores front-end.

Duas bibliotecas principais estão disponíveis para internacionalização no React:

Embora ambos sejam populares (12.000 e 6.000 estrelas do GitHub, respectivamente), o react-i18next parece ter conquistado os desenvolvedores. Esta biblioteca tem a vantagem adicional de pertencer ao ecossistema i18next, um framework de tradução que oferece suporte para React, React Native e Electron, entre outros. Os desenvolvedores podem aprender uma vez e traduzi-lo facilmente em muitas estruturas diferentes.

 

Internacionalize seu aplicativo React

Para usar react-i18next, primeiro instale a biblioteca:

npm install react-i18next i18next --save

Na sua pasta src, ao lado do index.js, crie um arquivo i18n.js onde você adicionará suas traduções e conectará o react-i18next ao React.

import i18n from "i18next";
    import { initReactI18next } from "react-i18next";
    // Pro tip: Move them into their own JSON files
    const resources = {
      en: {
        translation: {
          "welcome_message": "Hello and Welcome to React"
        }
      },
      fr: {
        translation: {
          "welcome_message": "Bonjour et bienvenue à React"
        }
      }
    };
    i18n
      .use(initReactI18next) // Connect react-i18next to React
      .init({
        resources,
        lng: "en", // default language
        interpolation: {
          escapeValue: false // react already safe from xss
        }
      });
      export default i18n;

Em seguida, em seu index.js, importe seu arquivo i18n.js recém-criado:

import React from 'react';
    import ReactDOM from 'react-dom';
    import './index.css';
    import './i18n';
    import App from './App';
    
    ReactDOM.render(
      <React.StrictMode>
        <App />
      </React.StrictMode>,
      document.getElementById('root')
    );

Você pode acessar sua tradução através, por exemplo, do useTranslationhook.

import logo from './logo.svg';
    import './App.css';
    import { useTranslation } from 'react-i18next';
    function App() {
      const { t } = useTranslation();
      return (
        <div className="App">
          <header className="App-header">
            <img src={logo} className="App-logo" alt="logo" />
            <p>
            {t('welcome_message')}
            </p>
          </header>
        </div>
      );
    }
    export default App;

Limitações do React

A biblioteca é abrangente e cobre muitos recursos necessários. Plurais, interpolação, formatação, aninhamento e muito mais são tratados pelo react-i18next.

A única coisa um pouco complicada é traduzir texto com HTML. Por exemplo, “Olá, <i>{{nome}}</i>! Vá para sua <Link to=”/inbox”>caixa de entrada</Link> para ver suas novas mensagens”.

React-i18next lida com esse caso de uso transformando sua string em um nó de árvore e usando tags de substituição.

Sua string seria então dividida:

Trans.children = [
'Hello, ', // 0: a string
{ name: ‘Marie’ }, // 1: <strong> with interpolation
‘! Go to your ’, // 2: a string
{ children: ['inbox'] }, // 3: <Link> with a string child
' to see your new messages' // 4: another string
]

 

Nos seus arquivos de tradução, você teria Olá, <1>{{name}}</1>! Vá para sua <3>caixa de entrada</3> para ver suas novas mensagens. A ginástica mental para descobrir o índice certo pode ser confusa.

 

Conclusão

Os usuários são muito mais propensos a interagir com produtos em seu próprio idioma, portanto, oferecer suporte para mais idiomas e regiões pode trazer a você usuários que seus concorrentes não conseguem acessar. Se você internacionalizar seu produto antecipadamente, será mais capaz de adicionar suporte para outras localidades à medida que você aumenta a escala.

Você pode reduzir o tempo de desenvolvimento com o Strapi. Com seu plugin de internacionalização, você pode criar diferentes versões de conteúdo para cada idioma e país em um editor fácil de usar. Todo o seu conteúdo está disponível através de endpoints de API, permitindo que você conecte facilmente seu frontend. Esteja você desenvolvendo para web ou mobile, Strapi pode ajudá-lo em seu processo de localização.

Caso você só trabalhe com Flutter, ainda existe diversos packages de tradução, que facilita a vida do desenvolvedor. Sobre i18n