Criando aplicação multi-idioma no Flutter
Tags: flutter, dart, braziliandevs, language
Published: 2024-06-21 11:28:53

Neste artigo, vou guiá-lo passo a passo sobre como implementar um seletor de idioma moderno e funcional em sua aplicação Flutter. Vamos explorar como criar um toggle de idioma de forma intuitiva e fácil de usar, garantindo que seus usuários possam alternar entre diferentes idiomas de forma suave e sem complicações. Vamos começar?

&nbsp;

## Tópicos

- [Introdução](#introdução) 
- [Passo a passo](#passo-a-passo)
	- [Passo 1: Criando nosso projeto Flutter](#passo-1-criando-nosso-projeto-flutter)
	- [Passo 2: Adicionando o flutter_localizations, intl e provider](#passo-2-adicionando-flutterlocalizations-intl-e-provider)
	- [Passo 3: Gerando arquivos de tradução](#passo-3-gerando-arquivos-de-tradução)
	- [Passo 4: Configurando as linguagens na nossa aplicação](#passo-4-configurando-as-linguagens-na-nossa-aplicação)
	- [Passo 5: Adicionando traduções na nossa aplicação](#passo-5-adicionando-traduções-na-nossa-aplicação)
	- [Passo 6: Fazendo toggle de idiomas](#passo-6-fazendo-toggle-de-idiomas)
- [Conclusão](#conclusão)
- [Referências](#referências)

&nbsp;

## Introdução

Se você está desenvolvendo uma aplicação que visa um público global, ou simplesmente deseja oferecer suporte a múltiplos idiomas, um seletor de idioma é essencial.
A alternância entre idiomas é importante pois oferece uma experiencia melhor para o usuário, permitindo que ele escolha um idioma de sua preferência de maneira rápida e fácil.
Neste artigo, você vai aprender de maneira rápida como fazer sua aplicação ter suporte a diferentes idiomas.
Lembrando que neste artigo faremos a alternância entre 2 idiomas, mas a partir disso você pode fazer com quantos idiomas desejar. Então, mão na massa!

&nbsp;

## Passo a passo



### Passo 1: Criando nosso projeto Flutter

Para criar nosso projeto Flutter, vamos simplesmente rodar o seguinte comando

```bash
flutter create internationalization_example
```

Aqui batizamos o nome do nosso projeto como "internationalization_example". Você pode colocar o nome que preferir.

&nbsp;

### Passo 2: Adicionando flutter_localizations, intl e provider

Agora, vamos adicionar os packages que precisamos para o nosso toggle de idiomas. Para isso, dentro do nosso projeto flutter vamos rodar os seguintes comandos:

- Adicionando **flutter_localizations**: Este pacote será para adicionar suporte a outros idiomas já que por padrão o Flutter suporta somente o Inglês.

```bash
flutter pub add flutter_localization
```

- Adicionando o **intl**: Este pacote oferece recursos de internacionalização e localização, incluindo tradução de mensagens, plurais e gêneros, formatação e análise de data/número e texto bidirecional.

```bash
flutter pub add intl:any
```

- Adicionando o **provider**: Utilizaremos este para injeção de dependência que vamos precisar mais pra frente.

```bash
flutter pub add provider
```

⚠️ **Agora uma pequena alteração:** 
No nosso arquivo `pubspec.yaml`, precisaremos alterar a forma de declaração do nosso **flutter_localization** como mostrado abaixo e após isso dar um `ctrl + s` para reinstalar as nossas dependências:

```diff
dependencies:
	flutter:
		sdk: flutter
+	flutter_localizations:
+		sdk: flutter
	# The following adds the Cupertino Icons font to your application.
	# Use with the CupertinoIcons class for iOS style icons.
	cupertino_icons: ^1.0.6
-	flutter_localization: ^0.2.0
	intl: any
	provider: ^6.1.2
```

&nbsp;

### Passo 3: Gerando arquivos de tradução

Dentro da pasta `lib` vamos criar uma pasta chamada `l10n` e dentro criar um arquivo chamado `app_en.arb` para os textos em inglês (**en** é a sigla da linguagem desejada, você pode colocar a sigla da linguagem que quiser) e um chamado `app_pt.arb` para textos em português.

Vamos escrever nossas traduções da seguinte forma:


```dart
// app_en.arb
{
    "helloWorld": "Hello World!",
    "counterMsg": "You have pushed the button this many times:"
}
```

```dart
// app_pt.arb
{
    "helloWorld": "Olá mundo",
    "counterMsg": "Você apertou o botão essa quantidade de vezes:"
}
```

> Lembrando que as chaves das traduções devem ser **exatamente** iguais nos dois arquivos.

Você deverá fazer isso para todos os textos que deseja traduzir na sua aplicação. "Ah mas eu tenho um montão de textos nela!". Então... boa sorte.  👍

_**Curiosidade**: A sigla **l10n** é assim porque na palavra **localization** tem 10 letras entre a letra L e a letra N._

Criados os nossos arquivos, para ativar a nossa geração dos arquivos de tradução, vamos no nosso arquivo `pubspec.yaml` novamente e habilitar a flag `generate` como no exemplo abaixo:

```yaml
flutter:
	# The following line ensures that the Material Icons font is
	# included with your application, so that you can use the icons in
	# the material Icons class.
	uses-material-design: true
	generate: true
```

Agora, para gerar nossos arquivos, rodamos o seguinte comando:

```bash
flutter gen-l10n
```

Estes arquivos gerados ficarão localizados em `dart_tool/flutter_gen/gen_l10n.` 

> _**Não mexa nesses arquivos.** Toda alteração nas traduções deve ser feita **somente** nos arquivos .arb_

&nbsp;

### Passo 4: Configurando as linguagens na nossa aplicação

Agora configuraremos nosso `MyApp`, afinal, é a partir dele que a mágica acontece.

>O **MyApp** é onde fica o nosso **MaterialApp** que nada mais é que a **raiz de um aplicativo Flutter**, que fornece uma estrutura base para navegação, estilização e internacionalização.

Dito isso, vamos adicionar as nossas configurações de internacionalização:

```dart
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:internationalization_flutter_example/app/my_home_page.dart';


class MyApp extends StatelessWidget {
	const MyApp({super.key});
  
	@override
	Widget build(BuildContext context) {
		return MaterialApp(
			title: 'Flutter Demo',
			theme: ThemeData(
				colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
				useMaterial3: true,
			),
			// Delegações de internacionalização globais 
			localizationsDelegates: const [
				AppLocalizations.delegate,
				GlobalMaterialLocalizations.delegate,
				GlobalWidgetsLocalizations.delegate,
				GlobalCupertinoLocalizations.delegate,
			],
			// linguagens que nossa aplicação irá suportar
			supportedLocales: const [
				Locale('en'),
				Locale('pt'),
			],
			// idioma atual da nossa aplicação
			locale: const Locale('pt'),
			home: const MyHomePage(title: 'Flutter Demo Home Page'),
		);
	}
}
```

&nbsp;

### Passo 5: Adicionando traduções na nossa aplicação

Para adicionar as traduções nas páginas da nossa aplicação, vamos substituir os textos presentes na aplicação pelas chaves correspondentes do arquivo gerado com o comando `flutter gen-l10n` como no exemplo abaixo:

```dart
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
...

appBar: AppBar(
	// adicionando texto da chave helloWorld
	title: Text(AppLocalizations.of(context)!.helloWorld),
),
```

> **Nota:** a cada mudança nos arquivos .arb é necessário rodar novamente o comando `flutter gen-l10n` para que as mudanças persistam nos arquivos de tradução gerados.

&nbsp;

### Passo 6: Fazendo toggle de idiomas

Agora, por fim, vamos fazer nosso toggle de idiomas!! Para isso vamos criar uma controller que vai estender de `ChangeNotifier` (vamos usar o `ChangeNotifier` para que a nossa tela fique escutando qualquer alteração na nossa classe) 

Nesta classe vamos criar uma variável booleana (vou chamá-la de `isEnglish`) que recebe por padrão `true`

Criada a variável, criaremos agora uma função `void` que toda vez que for chamada o valor da variável mudará para sua negação (isso significa que se ela for true se tornará false e vice-versa) e logo após notificamos essa alteração usando `notifyListeners();`.

Nossa controller ficará da seguinte forma: 

```dart
import 'package:flutter/material.dart';

class LanguageController extends ChangeNotifier {
    bool isEnglish = true;

  void toggleLanguage() {
    isEnglish = !isEnglish;
    notifyListeners();
  }
}
```

Agora voltando ao nosso `MyApp`, vamos injetar o nosso controller que é a nossa dependência:

```dart

class MyApp extends StatelessWidget {
	const MyApp({super.key});
 
	@override
	Widget build(BuildContext context) {
		// adicionamos o ChangeNotifierProvider para fornecer o LanguageController
		return ChangeNotifierProvider(
			// criamos uma instância de LanguageController
			create: (context) => LanguageController(),
			builder: (context, child) {
				// acessamos o LanguageController por meio do Provider
				final languageController = Provider.of<LanguageController>(context);
				return MaterialApp(
					title: 'Flutter Demo',
					theme: ThemeData(
						colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
						useMaterial3: true,
					),
					localizationsDelegates: const [
						AppLocalizations.delegate,
						GlobalMaterialLocalizations.delegate,
						GlobalWidgetsLocalizations.delegate,
						GlobalCupertinoLocalizations.delegate,
					],
					supportedLocales: const [
						Locale('en'),
						Locale('pt'),
					],
					// acessamos o atributo isEnglish do LanguageController para definir o idioma
					// se false, o idioma será português (pt), caso contrário, será inglês (en)
					locale: languageController.isEnglish ? const Locale('en') : const Locale('pt'),
					home: const MyHomePage(title: 'Flutter Demo Home Page'),
				);
			},
		);
	}
}

```

>  O `ChangeNotifierProvider` é uma classe do pacote `provider` no Flutter, que é usado para fornecer uma instância de um `ChangeNotifier` aos widgets descendentes na árvore de widgets. Sendo assim, o método `create` é chamado para criar uma instância de `LanguageController` para que possamos acessar os dados ou regras de negócio presentes nele. 

Agora, na nossa tela, vamos adicionar o nosso botão para mudar o idioma da nossa aplicação:

```dart
class MyHomePage extends StatefulWidget {
	const MyHomePage({super.key, required this.title});
	final String title;

	@override
	State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
	@override
	Widget build(BuildContext context) {
		// acessamos o LanguageController por meio do Provider
		final languageController = Provider.of<LanguageController>(context);

		return Scaffold(
			appBar: AppBar(
				backgroundColor: Theme.of(context).colorScheme.inversePrimary,
				title: Text(AppLocalizations.of(context)!.helloWorld),
			),
			body: Center(
				child: Column(
					mainAxisAlignment: MainAxisAlignment.center,
					children: <Widget>[
						Text(
							AppLocalizations.of(context)!.counterMsg,
						),
						Text(
							'2',
							style: Theme.of(context).textTheme.headlineMedium,
						),
					],
				),
			),
			floatingActionButton: FloatingActionButton(
				// chamando nossa função do LanguageController
				onPressed: languageController.toggleLanguage,
				tooltip: 'Toggle Language',
				child: const Icon(Icons.language),
			),
		);
	}
}

```

Ao fim disso, nosso toggle de idiomas já está funcionando, basta clicar no botão flutuante e o idioma da nossa aplicação mudará assim como demonstrado abaixo:

{% embed https://www.youtube.com/watch?v=K5bqQo1fy8g %}

E pronto, agora você pode alternar entre os idiomas que quiser na sua aplicação!
## Conclusão

Implementar uma alternância entre idiomas é uma excelente maneira de tornar sua aplicação acessível a usuários de diversos países. Com estes seis passos, você pode implementar essa funcionalidade de forma fácil e eficiente. Abaixo, disponibilizo o repositório de exemplo e links úteis para auxiliá-lo. Em caso de dúvidas, sinta-se a vontade para entrar em contato. Obrigado por ler até aqui. Espero que tenha gostado e até a próxima! 

## Referências

- [Package: intl](https://pub.dev/packages/intl)
- [Package: flutter_localization](https://pub.dev/packages/flutter_localization)
- [Package: provider](https://pub.dev/packages/provider)
- [Repositório: internationalization_flutter_example](https://github.com/AdryanneKelly/internationalization_flutter_example)
- [VIdeo: Implement Multiple language in flutter app](https://www.youtube.com/watch?v=o5NngkDJcSQ&list=PLtv9iIMaJiqsmxhdoEjFaj7BcTuBn-Pfy)


_Meus agradecimentos a @clintonrocha98, @cherryramatis e @redrodrigoc vocês são demais 💜_