Slang as Localization

Slang as Localization

Today, it has become a must for widely-used applications to have some basic features like dark mode, different localizations and many more. That is why, most experienced engineers always start the application with architecting these basic features, leaving room for further implementation. There are many choices out there to implement localization in Flutter application. In this article, let's talk about the way I like to implement one using Slang.

Firstly, let's create a sample project:

flutter create slang_project

Now, let's create packages directory to hold private packages of the app and create app_localization package in it.

 cd packages && flutter create --template=package app_localization

It is time to add slang packages in pubspec.yaml.

name: app_localization
description: This package contains app localization.

environment:
  sdk: ">=3.0.0 <4.0.0"

dependencies:
  slang: ^4.4.0
  slang_flutter: ^4.4.0

dev_dependencies:
  build_runner: ^2.4.14
  slang_build_runner: ^4.4.0

pubspec.yaml

Now, let's add the build_runner configuration for the slang in build.yaml file. For more custom configuration, please refer here.

targets:
  $default:
    builders:
      slang_build_runner:
        options:
          base_locale: en
          fallback_strategy: base_locale
          input_directory: lib
          input_file_pattern: .i18n.json
          output_directory: lib
          output_file_pattern: .g.dart
          translate_var: tr

build.yaml

We can add create json files for translations in lib directory and populate them.

{
  "welcomeMessage": "Welcome to the application!",
  "changeLocale": "Change locale here"
}

string_en.i18n.json

{
  "welcomeMessage": "Добро пожаловать в приложение!",
  "changeLocale": "Измените локализацию здесь"
}

string_ru.i18n.json

Now, go to app_localization directory and run slang build runner as below and it will generate necessary classes to use in the app.

cd app_localization && dart run slang

It is time to import the private app_localization package into our main app, for this in main app's pubspec.yaml file import as below and run flutter pub get:

...
dependencies:
  flutter:
    sdk: flutter
  flutter_localizations: // add this
    sdk: flutter

  cupertino_icons: ^1.0.8
  
  app_localization:  // add this
    path: packages/app_localization
...

pubspec.yaml

In main.dart, wrap MyApp() with TranslationProvider and add recommended necessary import path:

import 'package:app_localization/strings.g.dart';
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  runApp(
    TranslationProvider(
      child: const MyApp(),
    ),
  );
}

main.dart

And add locale lines in MaterialApp as below:

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,
      ),
      locale: TranslationProvider.of(context).flutterLocale,
      supportedLocales: AppLocaleUtils.supportedLocales, 
      localizationsDelegates: GlobalMaterialLocalizations.delegates, 
      home: const MyHomePage(title: 'Slang Demo'),
    );
  }
}

Add the supported locales to your Info.plist file.

<key>CFBundleLocalizations</key>
<array>
   <string>en</string>
   <string>ru</string>
</array>

ios/Runner/Info.plist

From now on, our app supports en and ru localizations, and this list can be further expanded by adding new localized json files in the app_localization directory and that's it. We change the locale using the method:

LocaleSettings.setLocale(AppLocale.en);

MyHomePage widget would look like this:

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) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              context.tr.welcomeMessage,
            ),
            const SizedBox(height: 32),
            InkWell(
              onTap: () {
                if (LocaleSettings.currentLocale == AppLocale.en) {
                  LocaleSettings.setLocale(AppLocale.ru);
                } else {
                  LocaleSettings.setLocale(AppLocale.en);
                }
              },
              child: Container(
                padding: const EdgeInsets.all(8),
                decoration: BoxDecoration(
                  color: Colors.black12,
                  borderRadius: BorderRadius.circular(16),
                ),
                child: Text(context.tr.changeLocale),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

Output:

0:00
/0:12

What is left is to add logic to save the selected locale in local storage and set it at the beginning of the application. I leave it for you...

For more features and configuration, please go through the documentation:

slang | Dart package
Localization / Internationalization (i18n) solution. Use JSON, YAML, CSV, or ARB files to create typesafe translations via source generation.

Full example is at the link below:

GitHub - khamidjon/slang_project
Contribute to khamidjon/slang_project development by creating an account on GitHub.