Create an account

Very important

  • To access the important data of the forums, you must be active in each forum and especially in the leaks and database leaks section, send data and after sending the data and activity, data and important content will be opened and visible for you.
  • You will only see chat messages from people who are at or below your level.
  • More than 500,000 database leaks and millions of account leaks are waiting for you, so access and view with more activity.
  • Many important data are inactive and inaccessible for you, so open them with activity. (This will be done automatically)


Thread Rating:
  • 264 Vote(s) - 3.62 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Flutter localization without context

#1
I am trying to localize my app in flutter. I created the needed string.arb files for the supported languages.

Why does `AppLocalizations.of(context)` need a context?

I simply want to access the named strings in the files/locales files/classes.
At some point in the app I build a List and fill it later via overriding some fields with a separate class.

However, this class has no context but I want to use localized strings in it.
Can I write a method which gets me the Localization of whatever String I put in?
Reply

#2
There is a library called [easy_localization][1] that does localization without context, you can simply use that one. Library also provides more convenient approach of writing less code and still localizing all the segments of the app. An example main class:


void main() {
WidgetsFlutterBinding.ensureInitialized();
SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
]).then((_) {
runApp(EasyLocalization(
child: MyApp(),
useOnlyLangCode: true,
startLocale: Locale('nl'),
fallbackLocale: Locale('nl'),
supportedLocales: [
Locale('nl'),
Locale('en'),
],
path: 'lang',
));
});
}

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: SplashScreen(),
supportedLocales: EasyLocalization.of(context).supportedLocales,
locale: EasyLocalization.of(context).locale,
localizationsDelegates: [
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
DefaultCupertinoLocalizations.delegate,
EasyLocalization.of(context).delegate,
],
localeResolutionCallback: (locale, supportedLocales) {
if (locale == null) {
EasyLocalization.of(context).locale = supportedLocales.first;
Intl.defaultLocale = '${supportedLocales.first}';
return supportedLocales.first;
}

for (Locale supportedLocale in supportedLocales) {
if (supportedLocale.languageCode == locale.languageCode) {
EasyLocalization.of(context).locale = supportedLocale;
Intl.defaultLocale = '$supportedLocale';
return supportedLocale;
}
}

EasyLocalization.of(context).locale = supportedLocales.first;
Intl.defaultLocale = '${supportedLocales.first}';
return supportedLocales.first;
},
);
}
}

Also don't forget to put localization path to your `pubspec.yamal` file!

After all of this is done, you can simply just use it in a `Text` widget like this:

Text(tr('someJsonKey'),),

[1]:

[To see links please register here]

Reply

#3
If you would prefer to not use a package then here is a solution that worked for me. Now the most [common implementation][1] of `AppLocalizations` I've seen usually has these two lines:

```dart
//.........
static const LocalizationsDelegate<AppLocalizations> delegate =
_AppLocalizationsDelegate();

static AppLocalizations of(BuildContext context) {
return Localizations.of<AppLocalizations>(context, AppLocalizations);
}
//.........
```

The implementation of the delegate would look something like this:

```dart
class _AppLocalizationsDelegate extends LocalizationsDelegate<AppLocalizations> {
const _AppLocalizationsDelegate();

@override
Future<AppLocalizations> load(Locale locale) async {
AppLocalizations localizations = new AppLocalizations(locale);
await localizations.load();

return localizations;
}

//... the rest omitted for brevity
}
```

Notice the load method on the delegate returns a `Future<AppLocalizations>`. The load method is usually called once from main and never again so you can take advantage of that by adding a static instance of `AppLocalizations` to the delegate. So now your delegate would look like this:

```dart
class _AppLocalizationsDelegate extends LocalizationsDelegate<AppLocalizations> {
const _AppLocalizationsDelegate();

static AppLocalizations instance;

@override
Future<AppLocalizations> load(Locale locale) async {
AppLocalizations localizations = new AppLocalizations(locale);
await localizations.load();

instance = localizations; // set the static instance here

return localizations;
}

//... the rest omitted for brevity
}
```

Then on your `AppLocalizations` class you would now have:

```dart
//.........
static const LocalizationsDelegate<AppLocalizations> delegate =
_AppLocalizationsDelegate();

static AppLocalizations of(BuildContext context) {
return Localizations.of<AppLocalizations>(context, AppLocalizations);
}

static AppLocalizations get instance => _AppLocalizationsDelegate.instance; // add this
//.........

```

Now in your translate helper method you could have:

```dart
String tr(String key) {
return AppLocalizations.instance.translate(key);
}
```

No context needed.

[1]:

[To see links please register here]

Reply

#4
In my case, I am using the Minimal internationalization version.

Adapting chinloyal's answer to the [Minimal internationalization version][1].

Apply chinloyal's solution but with this difference:

From this:

@override
Future<AppLocalizations> load(Locale locale) {
return SynchronousFuture<AppLocalizations>(AppLocalizations(locale));
}


To this:

@override
Future<AppLocalizations> load(Locale locale) async {
var localizations =
await SynchronousFuture<AppLocalizations>(AppLocalizations(locale));

instance = localizations; // set the static instance here

return localizations;
}


[1]:

[To see links please register here]

Reply

#5
We can resolve this by using [get_it][1] easily, we can use the string anywhere after this setup.


1. Install this to your vscode [Flutter Intl VSCode Extension](

[To see links please register here]

)
2. setup `pubspec.yaml`
```
dependencies:
flutter:
sdk: flutter
flutter_localizations: # Add this line
sdk: flutter # Add this line
intl: ^0.17.0 # Add this line
get_it: ^7.2.0 # Add this line


flutter:
uses-material-design: true
generate: true # Add this line


flutter_intl: # Add this line
enabled: true # Add this line
class_name: I10n # Add this line
main_locale: en # Add this line
arb_dir: lib/core/localization/l10n # Add this line
output_dir: lib/core/localization/generated # Add this line
```

3. Setup `main.dart`
```
import 'package:component_gallery/core/localization/generated/l10n.dart';
import 'package:component_gallery/locator.dart';
import 'package:component_gallery/ui/pages/home.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';

void main() {
setupLocator();
runApp(App());
}

class App extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
localizationsDelegates: [
I10n.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: I10n.delegate.supportedLocales,
localeResolutionCallback: (deviceLocale, supportedLocales) {
if (supportedLocales
.map((e) => e.languageCode)
.contains(deviceLocale?.languageCode)) {
return deviceLocale;
} else {
return const Locale('en', '');
}
},
home: HomePage(),
);
}
}
```
4. setup `locator.dart`
```
import 'package:component_gallery/core/services/navigation_service.dart';
import 'package:get_it/get_it.dart';

GetIt locator = GetIt.instance;

void setupLocator() {
locator.registerLazySingleton(() => I10n());
}

```
5. Use it with Get_it without context as
```
final I10n _i10n = locator<I10n>();
class MessageComponent extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Text(
_i10n.sample,
textAlign: TextAlign.center,
);
}
}

```


[1]:

[To see links please register here]

Reply

#6
If you know the desired `Locale` then you could use:

```
final locale = Locale('en');
AppLocalizations t = await AppLocalizations.delegate.load(locale);
println(t.someTranslationKey);
```

Instead of hardcoding `Locale('en')` you could implement some kind of resolver to find out what the desired locale is. The supported languages are `AppLocalizations.supportedLocales`.
Reply

#7
**Latest:** the current [Flutter Intl][1] plugin makes this approach obsolete, at least if you use a supported IDE. You have a context-free alternative there:

S.current.translationKey

----------

**Previous:** Starting from the suggestions of [Stuck,][2] this is the final solution I found. It isn't as cheap as the simple lookup with the context, so only use it if really necessary and make sure you call it once and use as many times as possible. But this approach works even if you have no context at all, for instance, you are in a background service or any other program part without UI.

```dart
Future<AppLocalizations> loadLocalization() async {
final parts = Intl.getCurrentLocale().split('_');
final locale = Locale(parts.first, parts.last);
return await AppLocalizations.delegate.load(locale);
}
```

Using it is just the same as usual:

```dart
final t = await loadLocalization();
print(t.translationKey);
```

Update: the singleton I suggested in the comments could look like:

```dart
class Localization {
static final Localization _instance = Localization._internal();
AppLocalizations? _current;

Localization._internal();

factory Localization() => _instance;

Future<AppLocalizations> loadCurrent() async {
if (_current == null) {
final parts = Intl.getCurrentLocale().split('_');
final locale = Locale(parts.first, parts.last);
_current = await AppLocalizations.delegate.load(locale);
}
return Future.value(_current);
}

void invalidate() {
_current = null;
}
}
```

and used like:

final t = await Localization().loadCurrent();

To keep track of language changes, call this from your main `build()`:

PlatformDispatcher.instance.onLocaleChanged = () => Localization().invalidate();


[1]:

[To see links please register here]

[2]:

[To see links please register here]

Reply

#8
My 2 cents into it, just not to loose the solution :)

I totally get why Flutter localization solutions needs BuildContext - makes total sense. But, if I explicitly don't want runtime language switch, and happy with the app restart?

That's the solution I came up with that seems to work pretty well.

Assuming you've followed Flutter's [official localization steps][1], create a global variable that will be used to accessing the `AppLocalizations` class.

i18n.dart:
```dart
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';

AppLocalizations get tr => _tr!; // helper function to avoid typing '!' all the time
AppLocalizations? _tr; // global variable

class AppTranslations {
static init(BuildContext context) {
_tr = AppLocalizations.of(context);
}
}
```

Now, somewhere in your main wrapper (the one below `MaterialApp`) call to set the localizations for the currently selected locale:

```dart
AppTranslations.init(context);
```
It could be `initState()` or even `build()` of the main widget (it's safe to call this multiple times, obviously).

Now you can simply call:

```dart
import 'package:my_app/i18n.dart'

...
Text(tr.welcome_text)

// or

print(tr.welcome_text);
...
```

[1]:

[To see links please register here]

Reply

#9
I was already using [easy_localization][1] package, so this found me very easy.

Trick I used to get app language without context as below

*en-US.json*

{
"app_locale":"en"
}

*ar-SA.json*

{
"app_locale":"ar"
}

Used it like a way in utility/extension function


LocaleKeys.app_locale.tr() //will return 'en' for English, 'ar' for Arabic


[1]:

[To see links please register here]

Reply

#10
The best approach is using Flutter Intl (Flutter i18n plugins) as it is built by Flutter developers. It has a method to use without context like the following (Code example from the [Visual Studio Marketplace details page][2]):

Widget build(BuildContext context) {
return Column(children: [
Text(
S.of(context).pageHomeConfirm,
),
Text(
S.current.pageHomeConfirm,// If you don't have `context` to pass
),
]);
}



More details on [official plugin page][1] and [Visual Studio Marketplace details page][2]


[1]:

[To see links please register here]

[2]:

[To see links please register here]

Reply



Forum Jump:


Users browsing this thread:
1 Guest(s)

©0Day  2016 - 2023 | All Rights Reserved.  Made with    for the community. Connected through