translocale_flutter 0.0.1 copy "translocale_flutter: ^0.0.1" to clipboard
translocale_flutter: ^0.0.1 copied to clipboard

Flutter localization package for TransLocale service with over-the-air translations support. Simplifies internationalization and enables updating translations without app releases.

example/lib/main.dart

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:translocale_example/l10n/translocale_extensions.dart';
import 'package:translocale_flutter/translocale_flutter.dart';
import 'l10n/generated/app_localizations.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  // Initialize TransLocale with your API key
  await TransLocale.initialize(
    apiKey: 'tl_live_3mu0eOt79LnuL2DLyr7IBHD',
    apiUrl: 'https://translocale-server-mnigboo-tayormi.globeapp.dev',
    enableLogging: true,
    checkForUpdates: true,
    // Increase the timeout to 30 seconds to give the server more time to respond
    requestTimeout: 30,
  );

  runApp(const MyApp());
}

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

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  Locale _currentLocale = const Locale('en');
  bool _isLoading = false;
  String _updateStatus = '';
  List<Locale> _availableLocales = [];
  bool _hasOtaUpdates = false;
  // Add StreamSubscription for update events
  StreamSubscription? _translationUpdateSubscription;

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

    // Listen for translation updates
    _translationUpdateSubscription =
        TransLocaleDelegateWrapper.onTranslationsUpdated.listen((_) {
      // When we receive an update notification, refresh the UI
      if (mounted) {
        setState(() {
          _hasOtaUpdates = true;
        });
      }
    });
  }

  @override
  void dispose() {
    // Cancel the subscription when the widget is disposed
    _translationUpdateSubscription?.cancel();
    super.dispose();
  }

  Future<void> _loadLocales() async {
    try {
      // Get available locales from API
      final locales = await TransLocale.getAvailableLocales();
      setState(() {
        _availableLocales =
            locales.isNotEmpty ? locales : AppLocalizations.supportedLocales;
      });
    } catch (e) {
      setState(() {
        _availableLocales = AppLocalizations.supportedLocales;
      });
    }
  }

  Future<void> _updateTranslations() async {
    setState(() {
      _isLoading = true;
      _updateStatus = 'Updating translations...';
    });

    try {
      // Implement a simple retry mechanism
      int retryCount = 0;
      const maxRetries = 3;
      bool success = false;

      while (!success && retryCount < maxRetries) {
        try {
          // The TransLocaleDelegateWrapper will be notified automatically when this completes
          await TransLocale.updateTranslations();
          success = true;
        } catch (e) {
          retryCount++;
          if (retryCount >= maxRetries) {
            // If we've exhausted all retries, rethrow the error
            rethrow;
          }

          // Update status to show retry attempt
          setState(() {
            _updateStatus = 'Retry attempt $retryCount of $maxRetries...';
          });

          // Wait a bit before retrying (exponential backoff)
          await Future.delayed(Duration(seconds: 2 * retryCount));
        }
      }

      setState(() {
        _isLoading = false;
        _updateStatus = 'Translations updated successfully!';
      });

      // No need to manually toggle locale - the notification system will handle it
    } catch (e) {
      setState(() {
        _isLoading = false;
        _updateStatus = 'Error: $e';
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'TransLocale Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      locale: _currentLocale,
      // Use supported locales from AppLocalizations
      supportedLocales: AppLocalizations.supportedLocales,

      // ✅ IMPORTANT: This delegate setup is key for OTA translations to work
      localizationsDelegates: [
        // TransLocale delegate must come first
        TransLocaleDelegate(
          supportedLocales: TransLocale.supportedLocales,
          otaEnabled: true,
          fallbackLocale: const Locale('en'),
        ),
        // Then standard Flutter delegates
        AppLocalizations.delegate,
        GlobalMaterialLocalizations.delegate,
        GlobalWidgetsLocalizations.delegate,
        GlobalCupertinoLocalizations.delegate,
      ],

      home: Scaffold(
        appBar: AppBar(
          title: const Text('TransLocale Example'),
          backgroundColor: Colors.deepPurple.shade200,
        ),
        body: Padding(
          padding: const EdgeInsets.all(16.0),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Text(
                'TransLocale Demo',
                style: Theme.of(context).textTheme.headlineSmall,
              ),
              const SizedBox(height: 16),

              // Locale switcher
              Text(
                'Available Locales:',
                style: Theme.of(context).textTheme.titleMedium,
              ),
              const SizedBox(height: 8),
              SingleChildScrollView(
                scrollDirection: Axis.horizontal,
                child: Row(
                  children: _availableLocales.map((locale) {
                    final isSelected =
                        _currentLocale.languageCode == locale.languageCode;
                    return Padding(
                      padding: const EdgeInsets.only(right: 8.0),
                      child: ElevatedButton(
                        onPressed: () {
                          setState(() {
                            _currentLocale = locale;
                          });
                        },
                        style: ElevatedButton.styleFrom(
                          backgroundColor:
                              isSelected ? Colors.deepPurple : null,
                          foregroundColor: isSelected ? Colors.white : null,
                        ),
                        child: Text(locale.toString()),
                      ),
                    );
                  }).toList(),
                ),
              ),

              const SizedBox(height: 24),

              // Update translations button
              ElevatedButton.icon(
                onPressed: _isLoading ? null : _updateTranslations,
                icon: _isLoading
                    ? const SizedBox(
                        width: 20,
                        height: 20,
                        child: CircularProgressIndicator(strokeWidth: 2),
                      )
                    : const Icon(Icons.refresh),
                label: const Text('Update Translations'),
              ),
              if (_updateStatus.isNotEmpty)
                Padding(
                  padding: const EdgeInsets.only(top: 8.0),
                  child: Text(_updateStatus),
                ),

              const SizedBox(height: 24),

              // Translations demo
              Expanded(
                child: Card(
                  elevation: 2,
                  child: Padding(
                    padding: const EdgeInsets.all(16.0),
                    child: Column(
                      crossAxisAlignment: CrossAxisAlignment.start,
                      children: [
                        Text(
                          'Translation Examples',
                          style: Theme.of(context).textTheme.titleMedium,
                        ),
                        const SizedBox(height: 16),

                        // ✅ Using the simple OTA extensions
                        Builder(builder: (context) {
                          final appLocalizations = AppLocalizations.of(context);

                          if (appLocalizations == null) {
                            return const Text('Localizations not ready');
                          }

                          return Column(
                            crossAxisAlignment: CrossAxisAlignment.start,
                            children: [
                              // Standard translations
                              Text('Standard Translation:',
                                  style:
                                      Theme.of(context).textTheme.titleSmall),
                              const SizedBox(height: 8),
                              Text(
                                  'Welcome: ${appLocalizations.welcome_message}'),

                              const SizedBox(height: 16),

                              // OTA translations using extensions
                              Text('OTA Translation (with extension):',
                                  style:
                                      Theme.of(context).textTheme.titleSmall),
                              const SizedBox(height: 8),
                              // ✅ Simply use the Ota suffix on any property
                              Text(
                                  'Welcome: ${appLocalizations.welcomeMessageOta}'),
                              Text(
                                  'Theme: ${appLocalizations.settingsThemeTitleOta}'),

                              const SizedBox(height: 16),

                              if (_hasOtaUpdates)
                                Container(
                                  padding: const EdgeInsets.all(8),
                                  decoration: BoxDecoration(
                                    color: Colors.green.shade50,
                                    borderRadius: BorderRadius.circular(4),
                                    border: Border.all(
                                        color: Colors.green.shade200),
                                  ),
                                  child: Row(
                                    children: [
                                      const Icon(Icons.check_circle,
                                          color: Colors.green),
                                      const SizedBox(width: 8),
                                      Text(
                                        'OTA translations active!',
                                        style: TextStyle(
                                            color: Colors.green.shade800),
                                      ),
                                    ],
                                  ),
                                ),
                            ],
                          );
                        }),
                      ],
                    ),
                  ),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}
1
likes
140
points
24
downloads
screenshot

Publisher

verified publishertranslocale.io

Weekly Downloads

Flutter localization package for TransLocale service with over-the-air translations support. Simplifies internationalization and enables updating translations without app releases.

Homepage
Repository (GitHub)
View/report issues

Topics

#localization #i18n #ota #flutter #l10n

Documentation

Documentation
API reference

Funding

Consider supporting this project:

translocale.io

License

MIT (license)

Dependencies

flutter, flutter_localizations, http, intl, logger, package_info_plus, path, path_provider, shared_preferences, uuid

More

Packages that depend on translocale_flutter