Localizely logo
  • Home
  • Getting started
  • How it works
  • Pricing
  • FAQ
Sign up

Flutter Over-the-Air translation updates

Update translations in your Flutter apps without shipping a new build.

Documentation

Introduction

Localizely lets you update translations in your Flutter applications over the air. Fix a typo, refine a phrase, or add a missing translation, and your users see the change on their next app start, with no new release to the App Store or Google Play and no waiting for review.

It is ideal for correcting mistakes that slipped into a release, polishing copy after launch, and keeping translations current between app versions.

Flutter Over-the-Air diagram

Getting started

Most Flutter apps are localized with the intl package and a tool that generates the localization code. The sections below show how to add Over-the-Air (OTA) translation updates to such a project. Pick the tab that matches your setup.

The gen_l10n tool is the standard way of localizing Flutter applications. It ships with the Flutter SDK, so there is nothing extra to install. This guide assumes your app is already localized with it. If not, start with our guide to setting up and localizing apps using the gen_l10n tool, then come back here to enable Over-the-Air updates.

A complete sample app with Over-the-Air integration is available on GitHub.

Step 1: Generate an SDK token

Open the Over-the-Air page of your project in Localizely and generate an SDK token. You will need it when you configure the SDK in your Flutter project.

Step 2: Create a distribution

On the same page, create a distribution. A project can have several distributions, but one is enough for most apps. Note the generated Distribution ID, which you will also need for the SDK configuration.

Step 3: Create a release

A release is a snapshot of your project's translations, made available to the apps connected to the distribution. Whenever you want to push updated translations, create a new release. Each release can carry the following settings:

  • Description (optional): A short note about what changed.
  • Min version (optional): The lowest semantic version of your app that should receive the update.
  • Max version (optional): The highest semantic version of your app that should receive the update.

New releases are visible only to app builds that initialized the SDK with the prerelease flag set to true. This lets your team verify translation changes internally before you publish the release to all users.

Step 4: Add the Localizely SDK to your project

Add localizely_sdk to your Flutter project by running the following command:

flutter pub add localizely_sdk

This adds a dependency like the following to your pubspec.yaml file:

dependencies:
    localizely_sdk: ^2.7.7

Recent Flutter versions no longer generate localization code as a synthetic package, so make sure your l10n.yaml file writes the generated code into your lib directory. The sample app uses the following configuration:

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

Next, generate the localization file the SDK needs by running:

dart run localizely_sdk:generate

Note: In Flutter 3.22.0, running the command dart run localizely_sdk:generate may produce false analyzer errors. This issue has been resolved in Flutter 3.22.1. If you need to use 3.22.0 and encounter these errors, running flutter pub get again should fix the problem.

To regenerate the code automatically whenever your .arb files change, add build_runner to your dev_dependencies and run it in watch mode:

flutter pub add build_runner -d
dart run build_runner watch

Once the localization file is generated, point the localizationsDelegates and supportedLocales properties of your MaterialApp widget at it.

...
import 'l10n/generated/localizely_localizations.dart';

class MyApp extends StatelessWidget {
  ...

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      ...
      localizationsDelegates: LocalizelyLocalizations.localizationsDelegates,
      supportedLocales: LocalizelyLocalizations.supportedLocales,
      ...
    );
  }
}

Step 5: Initialize the SDK

You will need the SDK token from Step 1 and the Distribution ID from Step 2. In your main.dart file, initialize the SDK before running the app and call updateTranslations once the localization delegates are in place:

import 'package:flutter/material.dart';
import 'l10n/generated/app_localizations.dart';
import 'l10n/generated/localizely_localizations.dart';
import 'package:localizely_sdk/localizely_sdk.dart'; // Import sdk package

void main() {
  Localizely.init('<SDK_TOKEN>', '<DISTRIBUTION_ID>'); // Init sdk 
  Localizely.setPreRelease(true); // Add this only if you want to use prereleases
  Localizely.setAppVersion('<APP_VERSION>'); // Add this only if you want to explicitly set the application version, or in cases when automatic detection is not possible (e.g. Flutter web apps)
  
  runApp(MaterialApp(
      onGenerateTitle: (context) => AppLocalizations.of(context)!.appTitle,
      localizationsDelegates: LocalizelyLocalizations.localizationsDelegates,
      supportedLocales: LocalizelyLocalizations.supportedLocales,
      home: HomePage()));
}

class HomePage extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  bool _isLoading = true;

  @override
  void initState() {
    super.initState();

    // Call 'updateTranslations' after localization delegates initialization
    Localizely.updateTranslations().then(
        (response) => setState(() {
              _isLoading = false;
            }),
        onError: (error) => setState(() {
              _isLoading = false;
            }));
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(title: Text(AppLocalizations.of(context)!.pageHomeTitle)),
        body: Center(
            child: _isLoading ? CircularProgressIndicator() : Column(children: <Widget>[Text(AppLocalizations.of(context)!.welcome)])));
  }
}

Avoid committing secrets such as the SDK token and Distribution ID to version control. In real-world projects, keep them in environment variables and load them at runtime with a package like flutter_dotenv.

Note: Ensure you have added INTERNET permission for Android devices.

Note: Localizely.updateTranslations() should be called just once on app start, as shown in the given example. Please do not call it frequently after the app starts.

Note: The Over-the-Air support for Flutter apps that use gen_l10n tool for localization is added in the localizely_sdk 2.5.0.

Usage

Using string keys in code

Nothing changes in the rest of your code. Refer to your string keys exactly as before:

AppLocalizations.of(context)!.title

Hint: In case you can't see updated translations in the app after successful OTA retrieval, please check if you have missed some of the steps.
Some tips that can help you: check if you have created a new release with the latest changes on Localizely, check if you are working with enabled or disabled prereleases, check if you are using the same languages on the Localizely and within the app, and check if you need to rebuild widgets tree after OTA update.

Changing the locale

Switching locales works exactly as it did before you added the SDK.

Frequently Asked Questions (FAQ)

What constitutes a Monthly Active User (MAU)?

When an app that uses the Localizely SDK starts for the first time on a device, the SDK generates a unique, random device identifier. Its sole purpose is to count active users over a given period. It is not used for any other form of tracking and contains no user or device information.

What happens when I exceed the Monthly Active User (MAU) quota?

Over-the-Air updates are not switched off automatically when you exceed your MAU quota. We will let you know, and you will have enough time to upgrade your OTA add-on to match your needs.

What happens when the app has no internet access?

The app falls back to the translations it last fetched from Localizely, or, failing that, to the translations bundled at build time. As soon as the app is back online, it fetches the latest release again.

Tired of manually editing translation files?

Our platform streamlines software localization for you.

Try now for Free
Localizely logo
About
Free tools
Boring stuff
  • Privacy Policy
  • Terms of Service
  • Cookie Policy
Newsletter
Copyrights 2026 © Localizely