Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using Easy Localization witout context #210

Open
Overman775 opened this issue Jun 23, 2020 · 24 comments
Open

Using Easy Localization witout context #210

Overman775 opened this issue Jun 23, 2020 · 24 comments
Labels
enhancement New feature or request

Comments

@Overman775
Copy link
Collaborator

No description provided.

@Overman775 Overman775 added the enhancement New feature or request label Jun 23, 2020
@pumuckelo
Copy link

@Overman775 Hi Overmann, did you find a workaround to use localization outside of widgets?

@Overman775
Copy link
Collaborator Author

@pumuckelo nope, have an idea, I’ll implement it later

@ncuillery
Copy link

Isn't that already done?

I see a tr function in public.dart that can be called without context argument.

@VictorCamargo
Copy link

That would be very helpful.

@chunlee-thong
Copy link

@ncuillery even tr function doesn't need context but using tr outside the widget tree doesn't work

@6h4n3m
Copy link

6h4n3m commented Aug 12, 2020

@ncuillery even tr function doesn't need context but using tr outside the widget tree doesn't work

Can you provide an example of your code and the errors you're getting? because the static tr() function works fine outside widget trees.

@pumuckelo
Copy link

but how does it get access to the language files

@aissat aissat pinned this issue Nov 25, 2020
@Overman775
Copy link
Collaborator Author

@aissat #321 may be delete Localization.of(context) from public.dart ?

@Overman775
Copy link
Collaborator Author

context removed from tr() and plural() in PR #343

@jonasN5
Copy link

jonasN5 commented Mar 23, 2021

Can someone give an implementation example?
The only way I can think of at the moment is:

  1. Create an instance of EasyLocalizationController
  2. Call controller.loadTranslations()
  3. Create an instance of Localization
  4. Call localization.load(translations)
  5. Translate with localization.tr
    That would also mean exposing EasyLocalizationController and Translations and Localization.

@jonasN5
Copy link

jonasN5 commented Mar 24, 2021

I finally got it to work. Someone should document the following somewhere, because it definitely is not currently.
First off: findSystemLocale() will not work when called from an isolate in the background. Don't ask me why, I just had to debug that to find out it is the case. This is important, because therefore EasyLocalizationController.deviceLocale will not be set.
Thus, you have to use the following code from an isolate:

Step 1:

Call context.resetLocale(); somewhere in MyApp.build(), because the currently documented saveLocale will not save anything anywhere. Calling resetLocale will actually save the deviceLocale to SharedPreferences, which we can retrieve even in an isolate.

Step 2: code executed in the isolate

import 'package:easy_localization/src/easy_localization_controller.dart';
import 'package:easy_localization/src/localization.dart';
  /// A manually created instance of Localization to enable translating without context.
  final Localization L = Localization.instance;
/// Method to load translations since context is not available in isolate.
Future<void> loadTranslations() async {

  //this will only set EasyLocalizationController.savedLocale
  await EasyLocalizationController.initEasyLocation();

  final controller = EasyLocalizationController(
    saveLocale: true, //mandatory to use EasyLocalizationController.savedLocale
    fallbackLocale: AppConstants.SUPPORTED_LOCALES[0],
    supportedLocales: AppConstants.SUPPORTED_LOCALES,
    assetLoader: const RootBundleAssetLoader(),
    useOnlyLangCode: false,
    useFallbackTranslations: true,
    path: AppConstants.LOCALIZATION_ASSET_PATH,
    onLoadError: (FlutterError e) {
    },
  );

  //Load translations from assets
  await controller.loadTranslations();

  //load translations into exploitable data, kept in memory
  Localization.load(controller.locale, translations: controller.translations, fallbackTranslations: controller.fallbackTranslations);
}

Step 3: now you can actually translate

L.tr(you_string_key);

@TarekMedhat
Copy link

I finally got it to work. Someone should document the following somewhere, because it definitely is not currently.
First off: findSystemLocale() will not work when called from an isolate in the background. Don't ask me why, I just had to debug that to find out it is the case. This is important, because therefore EasyLocalizationController.deviceLocale will not be set.
Thus, you have to use the following code from an isolate:

Step 1:

Call context.resetLocale(); somewhere in MyApp.build(), because the currently documented saveLocale will not save anything anywhere. Calling resetLocale will actually save the deviceLocale to SharedPreferences, which we can retrieve even in an isolate.

Step 2: code executed in the isolate

import 'package:easy_localization/src/easy_localization_controller.dart';
import 'package:easy_localization/src/localization.dart';
  /// A manually created instance of Localization to enable translating without context.
  final Localization L = Localization.instance;
/// Method to load translations since context is not available in isolate.
Future<void> loadTranslations() async {

  //this will only set EasyLocalizationController.savedLocale
  await EasyLocalizationController.initEasyLocation();

  final controller = EasyLocalizationController(
    saveLocale: true, //mandatory to use EasyLocalizationController.savedLocale
    fallbackLocale: AppConstants.SUPPORTED_LOCALES[0],
    supportedLocales: AppConstants.SUPPORTED_LOCALES,
    assetLoader: const RootBundleAssetLoader(),
    useOnlyLangCode: false,
    useFallbackTranslations: true,
    path: AppConstants.LOCALIZATION_ASSET_PATH,
    onLoadError: (FlutterError e) {
    },
  );

  //Load translations from assets
  await controller.loadTranslations();

  //load translations into exploitable data, kept in memory
  Localization.load(controller.locale, translations: controller.translations, fallbackTranslations: controller.fallbackTranslations);
}

Step 3: now you can actually translate

L.tr(you_string_key);

This solution worked but resetLocale saves the deviceLocale and inf deviceLocale wasn't in supportedLocale it will lead to an excpetion (ex: "assets/localizations/fr.json not found").

So instead of using resetLocale I used setLocale(context.locale), this will make sure to save the fallbackLocale instead of deviceLocale if the deviceLocale not supported

@nkulic
Copy link

nkulic commented Jul 18, 2021

I finally got it to work. Someone should document the following somewhere, because it definitely is not currently.
First off: findSystemLocale() will not work when called from an isolate in the background. Don't ask me why, I just had to debug that to find out it is the case. This is important, because therefore EasyLocalizationController.deviceLocale will not be set.
Thus, you have to use the following code from an isolate:

Step 1:

Call context.resetLocale(); somewhere in MyApp.build(), because the currently documented saveLocale will not save anything anywhere. Calling resetLocale will actually save the deviceLocale to SharedPreferences, which we can retrieve even in an isolate.

Step 2: code executed in the isolate

import 'package:easy_localization/src/easy_localization_controller.dart';
import 'package:easy_localization/src/localization.dart';
  /// A manually created instance of Localization to enable translating without context.
  final Localization L = Localization.instance;
/// Method to load translations since context is not available in isolate.
Future<void> loadTranslations() async {

  //this will only set EasyLocalizationController.savedLocale
  await EasyLocalizationController.initEasyLocation();

  final controller = EasyLocalizationController(
    saveLocale: true, //mandatory to use EasyLocalizationController.savedLocale
    fallbackLocale: AppConstants.SUPPORTED_LOCALES[0],
    supportedLocales: AppConstants.SUPPORTED_LOCALES,
    assetLoader: const RootBundleAssetLoader(),
    useOnlyLangCode: false,
    useFallbackTranslations: true,
    path: AppConstants.LOCALIZATION_ASSET_PATH,
    onLoadError: (FlutterError e) {
    },
  );

  //Load translations from assets
  await controller.loadTranslations();

  //load translations into exploitable data, kept in memory
  Localization.load(controller.locale, translations: controller.translations, fallbackTranslations: controller.fallbackTranslations);
}

Step 3: now you can actually translate

L.tr(you_string_key);

I am trying to implement your code but getting error Null check operator used on a null value pointing to context.resetLocale() method that I'm calling inside build() method

final Localization L = Localization.instance;

Future<void> loadTranslations() async {...}

Future main() async {
  await loadTranslations();

  // await EasyLocalization.ensureInitialized();
  runApp(
    App(store: store)
    
    // EasyLocalization(
    //   path: 'assets/translations',
    //   assetLoader: CodegenLoader(),
    //   supportedLocales: [
    //     Locale('en', 'US'),
    //     Locale('hr', 'HR'),
    //   ],
    //   child: App(store: store),
    // ),
    
   //.... 
  @override
  Widget build(BuildContext context) {
    context.resetLocale(); // error pointing here

@Fintasys
Copy link

Fintasys commented Jul 23, 2021

I had the same issue as @nkulic and I had to change the assetLoader because I use CodeGen.

  import 'package:weddy/gen/codegen_loader.g.dart';
  ...
  assetLoader: const CodegenLoader(),

and I could remove context.resetLocale(); it wasn't necessary anymore.

@nkulic
Copy link

nkulic commented Jul 23, 2021

I had the same issue as @nkulic and I had to change the assetLoader because I use CodeGen.

  import 'package:weddy/gen/codegen_loader.g.dart';
  ...
  assetLoader: const CodegenLoader(),

and I could remove context.resetLocale(); it wasn't necessary anymore.

I ended up using a very recent and new package fast_i18n

@dmrcierhn
Copy link

I finally got it to work. Someone should document the following somewhere, because it definitely is not currently. First off: findSystemLocale() will not work when called from an isolate in the background. Don't ask me why, I just had to debug that to find out it is the case. This is important, because therefore EasyLocalizationController.deviceLocale will not be set. Thus, you have to use the following code from an isolate:

Step 1:

Call context.resetLocale(); somewhere in MyApp.build(), because the currently documented saveLocale will not save anything anywhere. Calling resetLocale will actually save the deviceLocale to SharedPreferences, which we can retrieve even in an isolate.

Step 2: code executed in the isolate

import 'package:easy_localization/src/easy_localization_controller.dart';
import 'package:easy_localization/src/localization.dart';
  /// A manually created instance of Localization to enable translating without context.
  final Localization L = Localization.instance;
/// Method to load translations since context is not available in isolate.
Future<void> loadTranslations() async {

  //this will only set EasyLocalizationController.savedLocale
  await EasyLocalizationController.initEasyLocation();

  final controller = EasyLocalizationController(
    saveLocale: true, //mandatory to use EasyLocalizationController.savedLocale
    fallbackLocale: AppConstants.SUPPORTED_LOCALES[0],
    supportedLocales: AppConstants.SUPPORTED_LOCALES,
    assetLoader: const RootBundleAssetLoader(),
    useOnlyLangCode: false,
    useFallbackTranslations: true,
    path: AppConstants.LOCALIZATION_ASSET_PATH,
    onLoadError: (FlutterError e) {
    },
  );

  //Load translations from assets
  await controller.loadTranslations();

  //load translations into exploitable data, kept in memory
  Localization.load(controller.locale, translations: controller.translations, fallbackTranslations: controller.fallbackTranslations);
}

Step 3: now you can actually translate

L.tr(you_string_key);

i have a similar problem and i tried this solution but im getting an error "MissingPluginException(No implementation found for method getAll on channel plugins.flutter.io/shared_preferences)".

await EasyLocalizationController.initEasyLocation(); when this line is work i get this error. how can i solve this?

@Musta-Pollo
Copy link

Thanks a lot for your help. It worked for me ❤️.

I wanted to get working translations in the background thread when using awesome_notifications—adding this to execute in the background thread when the main thread is dead worked for me.

await EasyLocalization.ensureInitialized();
      final controller = EasyLocalizationController(
        saveLocale: true,
        fallbackLocale: const Locale('en'),
        supportedLocales: const [
          Locale('en'),
          Locale('cs'),
        ],
        assetLoader: const CodegenLoader(),
        useOnlyLangCode: false,
        useFallbackTranslations: true,
        path: '/assets/translations/',
        onLoadError: (FlutterError e) {},
      );

      //Load translations from assets
      await controller.loadTranslations();

      //load translations into exploitable data, kept in memory
      Localization.load(controller.locale,
          translations: controller.translations,
          fallbackTranslations: controller.fallbackTranslations);

And then this worked normally: LocaleKeys.notifications_your_quote.tr()

In context:

static Future<void> onActionReceivedMethod(
      ReceivedAction receivedAction) async {
    SendPort? port = IsolateNameServer.lookupPortByName('main');

    if (port != null) {
      port.send(receivedAction);
    } else {
      if ((UniversalPlatform.isAndroid || UniversalPlatform.isIOS)) {
        var quotesData = data;
        if (await getLocaleIndex() == 1) {
          quotesData = data_cz;
        }
        parseAllQuotes(quotesData).then((value) => quotesProvider = value);
      }
      await Hive.initFlutter();
      Hive.registerAdapter(HabitAdapter());
      Hive.registerAdapter(RewardAdapter());
      Hive.registerAdapter(QuoteAdapter());
      await Hive.openBox<Habit>(habitsBoxName);
      await Hive.openBox(settingsBoxName);
      await Hive.openBox<Reward>(rewardsBoxName);
      await Hive.openBox<Quote>(favouriteQuotesBoxName);
      await EasyLocalization.ensureInitialized();
      final controller = EasyLocalizationController(
        saveLocale: true,
        fallbackLocale: const Locale('en'),
        supportedLocales: const [
          Locale('en'),
          Locale('cs'),
        ],
        assetLoader: const CodegenLoader(),
        useOnlyLangCode: false,
        useFallbackTranslations: true,
        path: '/assets/translations/',
        onLoadError: (FlutterError e) {},
      );

      //Load translations from assets
      await controller.loadTranslations();

      //load translations into exploitable data, kept in memory
      Localization.load(controller.locale,
          translations: controller.translations,
          fallbackTranslations: controller.fallbackTranslations);
      await AwesomeNotifications().initialize(
        'resource://drawable/ic_stat_onesignal_default',
        [
          NotificationChannel(
            channelKey: getChannelNameByType(NotificationSettings.habits),
            channelName: getChannelNameByType(NotificationSettings.habits),
            channelDescription:
                LocaleKeys.notifications_habits_notifications.tr(),
            defaultColor: primaryColor_74,
            ledColor: Colors.blue,
            enableLights: true,
            importance: NotificationImportance.High,
            channelShowBadge: true,
          ),
          NotificationChannel(
            channelKey: getChannelNameByType(NotificationSettings.quotes),
            channelName: getChannelNameByType(NotificationSettings.quotes),
            importance: NotificationImportance.Default,
            channelDescription:
                LocaleKeys.notifications_quotes_notifications.tr(),
            defaultColor: secondaryColorGreen_43,
            ledColor: Colors.green,
          ),
          NotificationChannel(
            channelKey: getChannelNameByType(NotificationSettings.rewards),
            channelName: getChannelNameByType(NotificationSettings.rewards),
            importance: NotificationImportance.Default,
            channelDescription:
                LocaleKeys.notifications_rewards_notifications.tr(),
            defaultColor: Colors.black,
            ledColor: Colors.green,
          ),
        ],
        // debug: true,
      );
      await doneHabit(receivedAction);
    }
  }

@bw-flagship
Copy link
Collaborator

Looks like we don't need code here, but just add one of the solutions to the documentation and maybe to the example

@armandsLa
Copy link

armandsLa commented Apr 29, 2024

It's not necessary to always load the Localization when running in isolate. The instance can now be passed as an input parameter. The only situation when it's required to load Localization is when running from another Dart entry point.

Import Localization class:
import 'package:easy_localization/src/localization.dart';

Pass the Localization.instance as input parameter:
await compute(methodToRun, Localization.instance);

Get the translation:
localization.tr(<key>)

@bw-flagship it would be great if Localization could be accessible without the need to import it specifically.

@bw-flagship
Copy link
Collaborator

I see, thanks for the explanation! Feel free to open a pr :)

@Mistic92
Copy link

Hi, I'm trying to use EasyLocalization with WorkManager. When I try method with using EasyLocalizationController looks like there is no such class. Is this solution up to date?

@bw-flagship
Copy link
Collaborator

@Mistic92 This solution is up-to-date, but I have no experience with work manager and can't tell you if this should work out of the box

@Mistic92
Copy link

@bw-flagship it worked, I had to explicitly import from

import 'package:easy_localization/src/localization.dart';
import 'package:easy_localization/src/easy_localization_controller.dart';

as Android Studio didn't want to import from that location. Even now I'm getting warning but solution works

Import of a library in the 'lib/src' directory of another package. (Documentation)  Try importing a public library that exports this library, or removing the import.

@bw-flagship
Copy link
Collaborator

@Mistic92 got it. Then #669 will work for you. However, it seems like it's not worked on at the moment

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests