lokalise_flutter_sdk 1.1.0 copy "lokalise_flutter_sdk: ^1.1.0" to clipboard
lokalise_flutter_sdk: ^1.1.0 copied to clipboard

Lokalise Flutter SDK over-the-air translations updates. This package provides new translations from lokalise.com without a new app release.

Lokalise Flutter SDK #

The lokalise_flutter_sdk package provides support for over-the-air translation updates from lokalise.com.

Features #

  • .arb to .dart file processor, inspired by and following in the footsteps of flutter gen-l10n.
  • Custom localization class based on AppLocalizations by flutter gen-l10n for seamless replacement.
  • Over-The-Air functionality to deliver your text updates faster.

πŸ“˜ Note on .arb file management

This SDK does not cover managing (downloading and uploading) the .arb files. For that, we recommend our Lokalise CLIv2.

Getting started #

You need to have a working Flutter project. To get started with Flutter internationalization, check out the official documentation.

Enabling the Over-The-Air functionality in your project requires the following actions:

  1. Prepare your Lokalise project.
  2. Prepare your Flutter project.
  3. Integrate the SDK into your application.

Preparing your Flutter project #

1. Update pubspec.yaml #

Add the intl and lokalise_flutter_sdk packages to the pubspec.yaml file:

dependencies:
  flutter:
    sdk: flutter
  flutter_localizations:        # Add this line
    sdk: flutter                # Add this line   
  intl: any                     # Add this line 
  lokalise_flutter_sdk: ^1.1.0  # Add this line

2. Add the .arb files to the lib/l10n/ directory #

Add the ARB files to the lib/l10n/ directory of your Flutter project. We recommend that you download them from Lokalise.

On the Download section, select the Flutter (.arb) format, enable the File structure -> One file per language. Bundle structure: option, and set the value to intl_%LANG_ISO%.%FORMAT%.

Flutter is considered to be an Other platform on Lokalise. Therefore, assign your keys appropriately to the Other platform (learn how).

πŸ“˜ Example .arb file for test purposes

For testing purposes, you can manually add an intl_en.arb file. For example:

{
   "@@locale": "en",
   "helloWorld": "Hello World!",
   "@helloWorld": {
     "description": "The conventional newborn programmer greeting"
   },
   "title": "Yes, this is a title!"
}

Add one ARB file for each locale that you need to support in your Flutter app. Name them using the following pattern: intl_LOCALE.arb. Here's an example of using an intl_es.arb file:

{
   "helloWorld": "Β‘Hola Mundo!"
}

3. Set up the project and generate .dart files #

Install dependencies by running:

flutter pub get

Generate the .dart files from the provided .arb files:

flutter pub run lokalise_flutter_sdk:gen-lok-l10n

You should see the generated files in the lib/l10n/generated/ directory.

Integrating the SDK in your app #

The package provides Lokalise and Lt classes. The Lt class is generated and the name is customizable.

Lt is used to:

  • Configure the localization in the app using Lt.delegate, Lt.supportedLocales and Lt.localizationsDelegates parameters.
  • Retrieve the translations using Lt.of(context) calls.

Lokalise is used to:

  • Configure a Lokalise project to use with the help of the Lokalise.init method.
  • Retrieve the latest translations using the Lokalise.instance.update() method.

1. Import all necessary packages and classes #

import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:lokalise_flutter_sdk/lokalise_flutter_sdk.dart';
import 'l10n/generated/l10n.dart';

2. Configure the Lokalise project in the main function #

void main() async { // Due to some implementation details, we require the `main` function to be `async`.
    WidgetsFlutterBinding.ensureInitialized();
    await Lokalise.init(
        projectId: 'Project ID',
        sdkToken: 'Lokalise SDK Token', // Make sure that the `sdkToken` is an SDK token (not an API token or JWT).
        preRelease: true, // Add this only if you want to use prereleases. Use the Bundle freeze functionality in production
    );
    runApp(const MyApp());
}

3. Configure localization in the app widget #

class MyApp extends StatelessWidget {
    const MyApp({Key? key}) : super(key: key);

    @override
    Widget build(BuildContext context) {
        return MaterialApp(
            title: 'Lokalise SDK',
            theme: ThemeData(
                primarySwatch: Colors.blue,
            ),
            home: const MyHomePage(),
            // You can use  Lt.localizationsDelegates for shorter declaration of localizationsDelegates
            localizationsDelegates: const [ 
              Lt.delegate, // This adds Lt to the delegate call stack
              GlobalMaterialLocalizations.delegate,
              GlobalWidgetsLocalizations.delegate,
              GlobalCupertinoLocalizations.delegate,
            ],
            supportedLocales: Lt.supportedLocales, // This lists supported locales based on available languages in the generated `.dart` files
        );
    }
}

4. Add the Lokalise.instance.update() call to your initial page #

class MyHomePage extends StatefulWidget {
    const MyHomePage({Key? key}) : super(key: key);

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

class _MyHomePageState extends State<MyHomePage> {
  bool _isLoading = true;

    @override
    void initState() {
        super.initState();
        Lokalise.instance.update().then( // This is an async call, handle it appropriately
            (_) => setState(() => _isLoading = false),
            onError: (error) => setState(() => _isLoading = false),
        );
    }

    @override
    Widget build(BuildContext context) {
        return Scaffold(
            appBar: AppBar(
                title: Text(Lt.of(context).title),
            ),
            body: Center(
              child: _isLoading 
                ? const CircularProgressIndicator() 
                : Center(
                    child: Text(Lt.of(context).helloWorld),
            )),
        );
    }
}

5. (Optional) Updating translations on app resume. #

We recommend updating translations every time the app resumes from the background, to achieve that, you can use the WidgetsBindingObserver class implementing didChangeAppLifecycleState method. This will complement the previous step of updating translations on the app start.

class MyHomePage extends StatefulWidget {
    const MyHomePage({Key? key}) : super(key: key);

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

// Add mixin WidgetsBindingObserver
class _MyHomePageState extends State<MyHomePage> with WidgetsBindingObserver {
    bool _isLoading = true;

    @override
    void initState() {
        super.initState();
        // Add this as observer
        WidgetsBinding.instance.addObserver(this);
        _updateTranslations();
    }

    void _updateTranslations() {
        setState(() => _isLoading = true);
        // Ensures the application has the latest translations
        Lokalise.instance.update().then(
            (_) => setState(() => _isLoading = false),
            onError: (error) => setState(() => _isLoading = false),
            );
    }

    @override
    void didChangeAppLifecycleState(AppLifecycleState state) { //
        super.didChangeAppLifecycleState(state);
        // Update translations on resume event
        if (state == AppLifecycleState.resumed) { 
            _updateTranslations();
        }
    }

    @override
    Widget build(BuildContext context) {
        return Scaffold(
            appBar: AppBar(
                title: Text(Lt.of(context).title), // Gets the translation
            ),
            body: Center(
                child: _isLoading
                    ? const CircularProgressIndicator()
                    : Center(
                        child: Text(Lt.of(context).helloWorld), // Gets the translation
                    ),
            ),
        );
    }
}

The resulting app #

πŸ“˜ Sample app

You can also find a sample Flutter app with the integrated SDK on GitHub.

Here's a full example that demonstrates usage of the Flutter SDK (important lines are marked with comments):

import 'package:flutter/material.dart';
import 'package:lokalise_flutter_sdk/lokalise_flutter_sdk.dart'; // Imports the SDK
import 'l10n/generated/l10n.dart'; // Imports the generated Lt class

void main() async {
    WidgetsFlutterBinding.ensureInitialized();
    // Configures the SDK
    await Lokalise.init(
        projectId: 'Project ID',
        sdkToken: 'Lokalise SDK Token',
        // Add this only if you want to use prereleases. Use the Bundle freeze functionality in production
        preRelease: true,
    );
    runApp(const MyApp());
}

class MyApp extends StatelessWidget {
    const MyApp({Key? key}) : super(key: key);

    @override
    Widget build(BuildContext context) {
        return MaterialApp(
            title: 'Lokalise SDK',
            theme: ThemeData(
                primarySwatch: Colors.blue,
            ),
            home: const MyHomePage(),
            localizationsDelegates: Lt.localizationsDelegates,
            supportedLocales: Lt.supportedLocales,
        );
    }
}

class MyHomePage extends StatefulWidget {
    const MyHomePage({Key? key}) : super(key: key);

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

class _MyHomePageState extends State<MyHomePage> with WidgetsBindingObserver {
    bool _isLoading = true;

    @override
    void initState() {
        super.initState();
        WidgetsBinding.instance.addObserver(this);
        _updateTranslations();
    }

    void _updateTranslations() {
        setState(() => _isLoading = true);
        // Ensures the application has the latest translations
        Lokalise.instance.update().then(
            (_) => setState(() => _isLoading = false),
            onError: (error) => setState(() => _isLoading = false),
        );
    }

    @override
    void didChangeAppLifecycleState(AppLifecycleState state) {
        super.didChangeAppLifecycleState(state);
        if (state == AppLifecycleState.resumed) {
            _updateTranslations();
        }
    }

    @override
    Widget build(BuildContext context) {
        return Scaffold(
            appBar: AppBar(
                title: Text(Lt.of(context).title), // Gets the translation
            ),
            body: Center(
                child: _isLoading
                    ? const CircularProgressIndicator()
                    : Center(
                        child: Text(Lt.of(context).helloWorld), // Gets the translation
                    ),
            ),
        );
    }
}

πŸ“˜ Note on updating local translations

After the translations have been changed (lib/l10n/intl_LOCALE.arb), use the flutter pub run lokalise_flutter_sdk:gen-lok-l10n command to regenerate the Dart classes.

Testing #

You can initialize the SDK in your tests without saving data or performing API calls and being able to mock the SDK results, for example:

await Lokalise.initMock(
    cachedBundleTranslations: {
        const Locale('en'): {'hello': 'Hello world'},
        const Locale('es'): {'hello': 'Hola mundo'},
    },
    remoteBundleTranslations: {
        const Locale('en'): {'hello': 'Hello world 2'},
        const Locale('es'): {'hello': 'Hola mundo 2'},
    },
);

Additional details #

Bundle freeze #

To use the bundle freeze functionality, the SDK uses the version key from the pubspec.yaml located in the Flutter project root.

Given a version: 1.2.3+4 value, 1.2.3 is extracted and passed to the OTA server.

Customization #

You can customize the Dart class name generated by the gen-lok-l10n command by adding a lok-l10n.yaml file in lib/l10n like so:

output-class: 'MyCustomClassName'

Limitations and known issues #

You can check the limitations and workarounds for known issues here.

License #

This plugin is licensed under the BSD 3 Clause License.

Copyright (c) Lokalise team.

16
likes
0
pub points
92%
popularity

Publisher

verified publisherlokalise.com

Lokalise Flutter SDK over-the-air translations updates. This package provides new translations from lokalise.com without a new app release.

Homepage

License

unknown (license)

Dependencies

archive, dart_style, flutter, http, intl, intl_translation, logger, package_info_plus, path, petitparser, shared_preferences, yaml

More

Packages that depend on lokalise_flutter_sdk