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

add easy_localization_storage, easy_localization_shared_preferences_storage and easy_localization_helper #719

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 24 additions & 34 deletions example/lib/main.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:easy_localization_storage/easy_localization_storage.dart';
//import 'package:easy_localization_loader/easy_localization_loader.dart'; // import custom loaders
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
Expand All @@ -8,17 +9,17 @@ import 'lang_view.dart';

void main() async {
WidgetsFlutterBinding.ensureInitialized();
await EasyLocalization.ensureInitialized();
await EasyLocalization.ensureInitialized(EasyLocalizationInMemoryStorage());

runApp(EasyLocalization(
supportedLocales: [
supportedLocales: const [
Locale('en', 'US'),
Locale('ar', 'DZ'),
Locale('de', 'DE'),
Locale('ru', 'RU')
],
path: 'resources/langs',
child: MyApp(),
child: const MyApp(),
// fallbackLocale: Locale('en', 'US'),
// startLocale: Locale('de', 'DE'),
// saveLocale: false,
Expand All @@ -40,6 +41,8 @@ void main() async {
}

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

@override
Widget build(BuildContext context) {
return MaterialApp(
Expand All @@ -49,18 +52,18 @@ class MyApp extends StatelessWidget {
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Easy localization'),
home: const MyHomePage(title: 'Easy localization'),
);
}
}

class MyHomePage extends StatefulWidget {
MyHomePage({Key? key, required this.title}) : super(key: key);
const MyHomePage({Key? key, required this.title}) : super(key: key);

final String title;

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

class _MyHomePageState extends State<MyHomePage> {
Expand All @@ -83,7 +86,7 @@ class _MyHomePageState extends State<MyHomePage> {
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(LocaleKeys.title).tr(),
title: const Text(LocaleKeys.title).tr(),
actions: <Widget>[
TextButton(
onPressed: () {
Expand All @@ -93,20 +96,15 @@ class _MyHomePageState extends State<MyHomePage> {
builder: (_) => LanguageView(), fullscreenDialog: true),
);
},
child: Icon(
Icons.language,
color: Colors.white,
),
child: const Icon(Icons.language, color: Colors.white),
),
],
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Spacer(
flex: 1,
),
const Spacer(flex: 1),
Text(
LocaleKeys.gender_with_arg,
style: TextStyle(
Expand All @@ -124,27 +122,23 @@ class _MyHomePageState extends State<MyHomePage> {
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
FaIcon(FontAwesomeIcons.male),
const FaIcon(FontAwesomeIcons.male),
Switch(value: _gender, onChanged: switchGender),
FaIcon(FontAwesomeIcons.female),
const FaIcon(FontAwesomeIcons.female),
],
Comment on lines 124 to 128
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Enhance gender switch accessibility.

The gender switch lacks proper accessibility labels which could make it difficult for screen readers.

Add semantic labels:

- const FaIcon(FontAwesomeIcons.male),
- Switch(value: _gender, onChanged: switchGender),
- const FaIcon(FontAwesomeIcons.female),
+ const FaIcon(FontAwesomeIcons.male, semanticsLabel: 'Male'),
+ Switch(
+   value: _gender,
+   onChanged: switchGender,
+   semanticLabel: 'Switch gender',
+ ),
+ const FaIcon(FontAwesomeIcons.female, semanticsLabel: 'Female'),
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
children: <Widget>[
FaIcon(FontAwesomeIcons.male),
const FaIcon(FontAwesomeIcons.male),
Switch(value: _gender, onChanged: switchGender),
FaIcon(FontAwesomeIcons.female),
const FaIcon(FontAwesomeIcons.female),
],
children: <Widget>[
const FaIcon(FontAwesomeIcons.male, semanticsLabel: 'Male'),
Switch(
value: _gender,
onChanged: switchGender,
semanticLabel: 'Switch gender',
),
const FaIcon(FontAwesomeIcons.female, semanticsLabel: 'Female'),
],

),
Spacer(
flex: 1,
),
Text(LocaleKeys.msg).tr(args: ['aissat', 'Flutter']),
Text(LocaleKeys.msg_named)
const Spacer(flex: 1),
const Text(LocaleKeys.msg).tr(args: ['aissat', 'Flutter']),
const Text(LocaleKeys.msg_named)
.tr(namedArgs: {'lang': 'Dart'}, args: ['Easy localization']),
Text(LocaleKeys.clicked).plural(counter),
const Text(LocaleKeys.clicked).plural(counter),
TextButton(
onPressed: () {
incrementCounter();
},
child: Text(LocaleKeys.clickMe).tr(),
),
SizedBox(
height: 15,
child: const Text(LocaleKeys.clickMe).tr(),
),
const SizedBox(height: 15),
Text(
plural(LocaleKeys.amount, counter,
format: NumberFormat.currency(
Expand All @@ -153,24 +147,20 @@ class _MyHomePageState extends State<MyHomePage> {
color: Colors.grey.shade900,
fontSize: 18,
fontWeight: FontWeight.bold)),
SizedBox(
height: 20,
),
const SizedBox(height: 20),
ElevatedButton(
onPressed: () {
context.resetLocale();
},
child: Text(LocaleKeys.reset_locale).tr(),
),
Spacer(
flex: 1,
child: const Text(LocaleKeys.reset_locale).tr(),
),
const Spacer(flex: 1),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: incrementCounter,
child: Text('+1'),
child: const Text('+1'),
),
);
}
Expand Down
2 changes: 0 additions & 2 deletions example/macos/Flutter/GeneratedPluginRegistrant.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@
import FlutterMacOS
import Foundation

import shared_preferences_foundation

func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
}
2 changes: 2 additions & 0 deletions example/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ dependencies:
cupertino_icons: ^1.0.2
easy_localization:
path: ../
easy_localization_storage:
path: ../packages/easy_localization_storage
Comment on lines +28 to +29
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Missing dependency: easy_localization_helper

According to the PR objectives and AI summary, this PR introduces both easy_localization_storage and easy_localization_helper packages. However, the easy_localization_helper dependency is missing from the pubspec.yaml.

Add the missing dependency:

 easy_localization_storage:
   path: ../packages/easy_localization_storage
+easy_localization_helper:
+  path: ../packages/easy_localization_helper
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
easy_localization_storage:
path: ../packages/easy_localization_storage
easy_localization_storage:
path: ../packages/easy_localization_storage
easy_localization_helper:
path: ../packages/easy_localization_helper

font_awesome_flutter: 9.0.0-nullsafety

#custom loaders
Expand Down
1 change: 1 addition & 0 deletions lib/src/asset_loader.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import 'dart:convert';
import 'dart:ui';

import 'package:easy_localization/easy_localization.dart';
import 'package:easy_localization_helper/easy_localization_helper.dart';
import 'package:flutter/services.dart';

/// abstract class used to building your Custom AssetLoader
Expand Down
5 changes: 3 additions & 2 deletions lib/src/easy_localization_app.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import 'dart:async';

import 'package:easy_localization/easy_localization.dart';
import 'package:easy_localization/src/easy_localization_controller.dart';
import 'package:easy_localization_storage/easy_localization_storage.dart';
import 'package:easy_logger/easy_logger.dart';
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
Expand Down Expand Up @@ -159,8 +160,8 @@ class EasyLocalization extends StatefulWidget {
/// ensureInitialized needs to be called in main
/// so that savedLocale is loaded and used from the
/// start.
static Future<void> ensureInitialized() async =>
await EasyLocalizationController.initEasyLocation();
static Future<void> ensureInitialized(EasyLocalizationStorage storage) async =>
await EasyLocalizationController.initEasyLocation(storage);

/// Customizable logger
static EasyLogger logger = EasyLogger(name: '🌎 Easy Localization');
Expand Down
44 changes: 29 additions & 15 deletions lib/src/easy_localization_controller.dart
Original file line number Diff line number Diff line change
@@ -1,18 +1,31 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:easy_localization_helper/easy_localization_helper.dart';
import 'package:easy_localization_storage/easy_localization_storage.dart';
import 'package:flutter/material.dart';
import 'package:intl/intl_standalone.dart'
if (dart.library.html) 'package:intl/intl_browser.dart';
import 'package:shared_preferences/shared_preferences.dart';

import 'translations.dart';

class EasyLocalizationController extends ChangeNotifier {
static Locale? _savedLocale;
static late Locale _deviceLocale;
static EasyLocalizationStorage? _storage;
static EasyLocalizationStorage get storage {
if (_storage == null) {
throw StateError(
'EasyLocalizationController not initialized. Call initEasyLocation first.');
Comment on lines +16 to +17
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Correct method name from 'initEasyLocation' to 'initEasyLocalization'

The method name initEasyLocation seems inconsistent with the class name EasyLocalizationController. It should be initEasyLocalization to match the naming convention and avoid confusion.

Apply this diff to correct the method name and error message:

- throw StateError(
-     'EasyLocalizationController not initialized. Call initEasyLocation first.');
+ throw StateError(
+     'EasyLocalizationController not initialized. Call initEasyLocalization first.');
-static Future<void> initEasyLocation(EasyLocalizationStorage storage) async {
+static Future<void> initEasyLocalization(EasyLocalizationStorage storage) async {

Update all references to this method accordingly.

Also applies to: 219-221

}
return _storage!;
}

static set storage(EasyLocalizationStorage storage) {
_storage = storage;
}

late Locale _locale;
Locale? _fallbackLocale;
List<Locale>? _supportedLocales;
late List<Locale> _supportedLocales;

final Function(FlutterError e) onLoadError;
final AssetLoader assetLoader;
Expand Down Expand Up @@ -161,9 +174,11 @@ class EasyLocalizationController extends ChangeNotifier {
final result = <String, dynamic>{};
final loaderFutures = <Future<Map<String, dynamic>?>>[];

// need scriptCode, it might be better to use ignoreCountryCode as the variable name of useOnlyLangCode
final Locale desiredLocale =
useOnlyLangCode ? Locale.fromSubtags(languageCode: locale.languageCode, scriptCode: locale.scriptCode) : locale;
// need scriptCode, it might be better to use ignoreCountryCode as the variable name of useOnlyLangCode
final Locale desiredLocale = useOnlyLangCode
? Locale.fromSubtags(
languageCode: locale.languageCode, scriptCode: locale.scriptCode)
: locale;

List<AssetLoader> loaders = [
assetLoader,
Expand Down Expand Up @@ -197,34 +212,33 @@ class EasyLocalizationController extends ChangeNotifier {

Future<void> _saveLocale(Locale? locale) async {
if (!saveLocale) return;
final preferences = await SharedPreferences.getInstance();
await preferences.setString('locale', locale.toString());
await storage.setLocale(value: locale);
EasyLocalization.logger('Locale $locale saved');
}

static Future<void> initEasyLocation() async {
final preferences = await SharedPreferences.getInstance();
final strLocale = preferences.getString('locale');
_savedLocale = strLocale?.toLocale();
static Future<void> initEasyLocation(EasyLocalizationStorage storage) async {
EasyLocalizationController.storage = storage;
_savedLocale = await storage.getLocale();
final foundPlatformLocale = await findSystemLocale();
_deviceLocale = foundPlatformLocale.toLocale();
EasyLocalization.logger.debug('Localization initialized');
}

Future<void> deleteSaveLocale() async {
_savedLocale = null;
final preferences = await SharedPreferences.getInstance();
await preferences.remove('locale');
storage.setLocale();
EasyLocalization.logger('Saved locale deleted');
}

Locale get deviceLocale => _deviceLocale;
Locale? get savedLocale => _savedLocale;

Future<void> resetLocale() async {
final locale = selectLocaleFrom(_supportedLocales!, deviceLocale, fallbackLocale: _fallbackLocale);
final locale = selectLocaleFrom(_supportedLocales, deviceLocale,
fallbackLocale: _fallbackLocale);

EasyLocalization.logger('Reset locale to $locale while the platform locale is $_deviceLocale and the fallback locale is $_fallbackLocale');
EasyLocalization.logger(
'Reset locale to $locale while the platform locale is $_deviceLocale and the fallback locale is $_fallbackLocale');
await setLocale(locale);
}
}
Expand Down
33 changes: 0 additions & 33 deletions lib/src/utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,39 +29,6 @@ String localeToString(Locale locale, {String separator = '_'}) {
return locale.toString().split('_').join(separator);
}

/// [Easy Localization] locale helper
extension LocaleToStringHelper on Locale {
/// Convert [locale] to String with custom separator
String toStringWithSeparator({String separator = '_'}) {
return toString().split('_').join(separator);
}
}

/// [Easy Localization] string locale helper
extension StringToLocaleHelper on String {
/// Convert string to [Locale] object
Locale toLocale({String separator = '_'}) {
final localeList = split(separator);
switch (localeList.length) {
case 2:
return localeList.last.length == 4 // scriptCode length is 4
? Locale.fromSubtags(
languageCode: localeList.first,
scriptCode: localeList.last,
)
: Locale(localeList.first, localeList.last);
case 3:
return Locale.fromSubtags(
languageCode: localeList.first,
scriptCode: localeList[1],
countryCode: localeList.last,
);
default:
return Locale(localeList.first);
}
}
}

extension MapExtension<K> on Map<K, dynamic> {
void addAllRecursive(Map<K, dynamic> other) {
for (final entry in other.entries) {
Expand Down
29 changes: 29 additions & 0 deletions packages/easy_localization_helper/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Miscellaneous
*.class
*.log
*.pyc
*.swp
.DS_Store
.atom/
.buildlog/
.history
.svn/
migrate_working_dir/

# IntelliJ related
*.iml
*.ipr
*.iws
.idea/

# The .vscode folder contains launch configuration and tasks you configure in
# VS Code which you may wish to be included in version control, so this line
# is commented out by default.
#.vscode/

# Flutter/Dart/Pub related
# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock.
/pubspec.lock
**/doc/api/
.dart_tool/
build/
10 changes: 10 additions & 0 deletions packages/easy_localization_helper/.metadata
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
# This file should be version controlled and should not be manually edited.

version:
revision: "603104015dd692ea3403755b55d07813d5cf8965"
channel: "stable"

project_type: package
3 changes: 3 additions & 0 deletions packages/easy_localization_helper/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
## 0.0.1

* TODO: Describe initial release.
1 change: 1 addition & 0 deletions packages/easy_localization_helper/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
TODO: Add your license here.
Loading