From 11d396a451ff06762bb139f7e464539381d3893e Mon Sep 17 00:00:00 2001 From: basemosama Date: Tue, 1 Jul 2025 11:25:14 +0300 Subject: [PATCH 01/10] feat: Bump version to 0.3.0 and update dependencies - 86c47h79a --- .flutter-plugins-dependencies | 2 +- pubspec.yaml | 17 ++++++++--------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index 85a21cd..db939f4 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"flutter_secure_storage","path":"E:\\\\Sdk\\\\cache\\\\hosted\\\\pub.dev\\\\flutter_secure_storage-9.2.4\\\\","native_build":true,"dependencies":[]},{"name":"path_provider_foundation","path":"E:\\\\Sdk\\\\cache\\\\hosted\\\\pub.dev\\\\path_provider_foundation-2.2.4\\\\","shared_darwin_source":true,"native_build":true,"dependencies":[]},{"name":"shared_preferences_foundation","path":"E:\\\\Sdk\\\\cache\\\\hosted\\\\pub.dev\\\\shared_preferences_foundation-2.5.2\\\\","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"android":[{"name":"flutter_secure_storage","path":"E:\\\\Sdk\\\\cache\\\\hosted\\\\pub.dev\\\\flutter_secure_storage-9.2.4\\\\","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"E:\\\\Sdk\\\\cache\\\\hosted\\\\pub.dev\\\\path_provider_android-2.0.27\\\\","native_build":true,"dependencies":[]},{"name":"shared_preferences_android","path":"E:\\\\Sdk\\\\cache\\\\hosted\\\\pub.dev\\\\shared_preferences_android-2.4.0\\\\","native_build":true,"dependencies":[]}],"macos":[{"name":"flutter_secure_storage_macos","path":"E:\\\\Sdk\\\\cache\\\\hosted\\\\pub.dev\\\\flutter_secure_storage_macos-3.1.3\\\\","native_build":true,"dependencies":[]},{"name":"path_provider_foundation","path":"E:\\\\Sdk\\\\cache\\\\hosted\\\\pub.dev\\\\path_provider_foundation-2.2.4\\\\","shared_darwin_source":true,"native_build":true,"dependencies":[]},{"name":"shared_preferences_foundation","path":"E:\\\\Sdk\\\\cache\\\\hosted\\\\pub.dev\\\\shared_preferences_foundation-2.5.2\\\\","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"linux":[{"name":"flutter_secure_storage_linux","path":"E:\\\\Sdk\\\\cache\\\\hosted\\\\pub.dev\\\\flutter_secure_storage_linux-1.2.2\\\\","native_build":true,"dependencies":[]},{"name":"path_provider_linux","path":"E:\\\\Sdk\\\\cache\\\\hosted\\\\pub.dev\\\\path_provider_linux-2.1.11\\\\","native_build":false,"dependencies":[]},{"name":"shared_preferences_linux","path":"E:\\\\Sdk\\\\cache\\\\hosted\\\\pub.dev\\\\shared_preferences_linux-2.4.1\\\\","native_build":false,"dependencies":["path_provider_linux"]}],"windows":[{"name":"flutter_secure_storage_windows","path":"E:\\\\Sdk\\\\cache\\\\hosted\\\\pub.dev\\\\flutter_secure_storage_windows-3.1.2\\\\","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"E:\\\\Sdk\\\\cache\\\\hosted\\\\pub.dev\\\\path_provider_windows-2.1.7\\\\","native_build":false,"dependencies":[]},{"name":"shared_preferences_windows","path":"E:\\\\Sdk\\\\cache\\\\hosted\\\\pub.dev\\\\shared_preferences_windows-2.4.1\\\\","native_build":false,"dependencies":["path_provider_windows"]}],"web":[{"name":"flutter_secure_storage_web","path":"E:\\\\Sdk\\\\cache\\\\hosted\\\\pub.dev\\\\flutter_secure_storage_web-1.2.1\\\\","dependencies":[]},{"name":"shared_preferences_web","path":"E:\\\\Sdk\\\\cache\\\\hosted\\\\pub.dev\\\\shared_preferences_web-2.4.2\\\\","dependencies":[]}]},"dependencyGraph":[{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":["path_provider"]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_foundation","path_provider_linux","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_foundation","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"shared_preferences","dependencies":["shared_preferences_android","shared_preferences_foundation","shared_preferences_linux","shared_preferences_web","shared_preferences_windows"]},{"name":"shared_preferences_android","dependencies":[]},{"name":"shared_preferences_foundation","dependencies":[]},{"name":"shared_preferences_linux","dependencies":["path_provider_linux"]},{"name":"shared_preferences_web","dependencies":[]},{"name":"shared_preferences_windows","dependencies":["path_provider_windows"]}],"date_created":"2025-01-19 20:43:59.275999","version":"3.27.2","swift_package_manager_enabled":false} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"flutter_secure_storage","path":"/Users/basemosama/.pub-cache/hosted/pub.dev/flutter_secure_storage-9.2.4/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"path_provider_foundation","path":"/Users/basemosama/.pub-cache/hosted/pub.dev/path_provider_foundation-2.4.1/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"shared_preferences_foundation","path":"/Users/basemosama/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.5.4/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false}],"android":[{"name":"flutter_secure_storage","path":"/Users/basemosama/.pub-cache/hosted/pub.dev/flutter_secure_storage-9.2.4/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"path_provider_android","path":"/Users/basemosama/.pub-cache/hosted/pub.dev/path_provider_android-2.2.17/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"shared_preferences_android","path":"/Users/basemosama/.pub-cache/hosted/pub.dev/shared_preferences_android-2.4.10/","native_build":true,"dependencies":[],"dev_dependency":false}],"macos":[{"name":"flutter_secure_storage_macos","path":"/Users/basemosama/.pub-cache/hosted/pub.dev/flutter_secure_storage_macos-3.1.3/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"path_provider_foundation","path":"/Users/basemosama/.pub-cache/hosted/pub.dev/path_provider_foundation-2.4.1/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"shared_preferences_foundation","path":"/Users/basemosama/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.5.4/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false}],"linux":[{"name":"flutter_secure_storage_linux","path":"/Users/basemosama/.pub-cache/hosted/pub.dev/flutter_secure_storage_linux-1.2.3/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"path_provider_linux","path":"/Users/basemosama/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"shared_preferences_linux","path":"/Users/basemosama/.pub-cache/hosted/pub.dev/shared_preferences_linux-2.4.1/","native_build":false,"dependencies":["path_provider_linux"],"dev_dependency":false}],"windows":[{"name":"flutter_secure_storage_windows","path":"/Users/basemosama/.pub-cache/hosted/pub.dev/flutter_secure_storage_windows-3.1.2/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"path_provider_windows","path":"/Users/basemosama/.pub-cache/hosted/pub.dev/path_provider_windows-2.3.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"shared_preferences_windows","path":"/Users/basemosama/.pub-cache/hosted/pub.dev/shared_preferences_windows-2.4.1/","native_build":false,"dependencies":["path_provider_windows"],"dev_dependency":false}],"web":[{"name":"flutter_secure_storage_web","path":"/Users/basemosama/.pub-cache/hosted/pub.dev/flutter_secure_storage_web-1.2.1/","dependencies":[],"dev_dependency":false},{"name":"shared_preferences_web","path":"/Users/basemosama/.pub-cache/hosted/pub.dev/shared_preferences_web-2.4.3/","dependencies":[],"dev_dependency":false}]},"dependencyGraph":[{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":["path_provider"]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_foundation","path_provider_linux","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_foundation","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"shared_preferences","dependencies":["shared_preferences_android","shared_preferences_foundation","shared_preferences_linux","shared_preferences_web","shared_preferences_windows"]},{"name":"shared_preferences_android","dependencies":[]},{"name":"shared_preferences_foundation","dependencies":[]},{"name":"shared_preferences_linux","dependencies":["path_provider_linux"]},{"name":"shared_preferences_web","dependencies":[]},{"name":"shared_preferences_windows","dependencies":["path_provider_windows"]}],"date_created":"2025-07-01 11:10:57.120032","version":"3.32.4","swift_package_manager_enabled":{"ios":false,"macos":false}} \ No newline at end of file diff --git a/pubspec.yaml b/pubspec.yaml index 66bf51f..2b9664c 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: playx_localization description: Easily manage and update app localization with a simple implementation and a lot of utilities. -version: 0.2.2 +version: 0.3.0 homepage: https://sourcya.io repository: https://github.com/playx-flutter/playx_localization issue_tracker: https://github.com/playx-flutter/playx_localization/issues @@ -11,25 +11,24 @@ topics: - internationalization environment: - sdk: ">=3.0.0 <4.0.0" + sdk: ">=3.5.0 <4.0.0" + flutter: ">=3.24.0 <4.0.0" dependencies: flutter: sdk: flutter flutter_localizations: sdk: flutter - playx_core: ^0.6.1 - intl: ^0.19.0 - easy_localization: ^3.0.7 + playx_core: ^0.7.3 + intl: any + easy_localization: ^3.0.7+1 shared_preferences_platform_interface: ^2.4.1 -dependency_overrides: - win32: ^5.10.0 dev_dependencies: flutter_test: sdk: flutter - flutter_lints: ^5.0.0 - lints: ^5.1.1 + flutter_lints: ^6.0.0 + lints: ^6.0.0 flutter: From e92e1d115af606bc5af7ecf65650fcbd2c69ad21 Mon Sep 17 00:00:00 2001 From: basemosama Date: Tue, 1 Jul 2025 11:39:03 +0300 Subject: [PATCH 02/10] feat: Enhance num extensions with improved formatting and utility functions - 86c47h79a This commit introduces several enhancements to the `NumExtensions` class: - **Improved Currency Formatting:** - `toFormattedCurrencyNumber`: Now accepts an optional `currencySymbol` and defaults to `"#,##0.00##"` format. - `toLocalizedCurrencyNumber`: New function to format currency based on the current `PlayxLocalization` locale. Defaults to `ar_EG` for Arabic locales. - **Flexible Number Formatting:** - `toFormattedNumber`: Retains its functionality for custom pattern and locale-based formatting. - `toLocalizedArabicNumber` and `toLocalizedEnglishNumber`: Now accept an optional `format` parameter. - `toLocalizedArabicOrEnglishNumber`: Now accepts an optional `format` parameter and uses the respective localized formatting functions. - `toLocalizedNumber`: Now accepts an optional `format` parameter. - **New Utility Function:** - `isZero`: New extension function to check if a number is approximately zero, considering floating-point precision. --- lib/src/extensions/num_extensions.dart | 115 +++++++++++++++++++------ 1 file changed, 90 insertions(+), 25 deletions(-) diff --git a/lib/src/extensions/num_extensions.dart b/lib/src/extensions/num_extensions.dart index d920829..b406062 100644 --- a/lib/src/extensions/num_extensions.dart +++ b/lib/src/extensions/num_extensions.dart @@ -3,49 +3,114 @@ import 'dart:math'; import 'package:intl/intl.dart'; import 'package:playx_localization/src/playx_localization.dart'; -/// Extension functions to help operations on numbers. +/// Extension functions to help perform common operations and formatting on [num] values. extension NumExtensions on num { - ///Extension function to round number to certain number + /// Rounds the number to the given number of decimal places. + /// + /// Example: + /// ```dart + /// 3.14159.roundToPrecision(numbersToRoundTo: 2); // → 3.14 + /// ``` double roundToPrecision({int numbersToRoundTo = 2}) { - final fac = pow(10, numbersToRoundTo).toInt(); - return (this * fac).round() / fac; + final factor = pow(10, numbersToRoundTo).toInt(); + return (this * factor).round() / factor; } - /// Extension function to format number to currency number - /// ``` - /// 1000000 => will be converted to 1000,000.00 + /// Formats the number using a custom pattern and locale, optionally prefixing with a currency symbol. + /// + /// Example: + /// ```dart + /// 1000000.toFormattedCurrencyNumber(currencySymbol: '\$', locale: 'en'); + /// // → $1,000,000.00 /// ``` - String toFormattedCurrencyNumber( - {String format = "#,##0.00", String locale = 'en'}) { + String toFormattedCurrencyNumber({ + String format = "#,##0.00##", + String locale = 'en', + String? currencySymbol, + }) { final numberFormat = NumberFormat(format, locale); - return numberFormat.format(this); + final formatted = numberFormat.format(this); + return currencySymbol != null ? '$currencySymbol$formatted' : formatted; + } + + /// Formats the number as a currency string using the current locale from [PlayxLocalization]. + /// + /// Defaults to Arabic (`ar_EG`) if current locale is Arabic. + String toLocalizedCurrencyNumber({ + String format = "#,##0.00##", + String? locale, + String? currencySymbol, + }) { + final formatLocale = locale ?? + (PlayxLocalization.isCurrentLocaleArabic() + ? 'ar_EG' + : PlayxLocalization.currentLocale.toLanguageTag()); + + final numberFormat = NumberFormat(format, formatLocale); + final formatted = numberFormat.format(this); + return currencySymbol != null ? '$currencySymbol$formatted' : formatted; } - /// Extension function to format number to String - String toFormattedNumber({required String format, String locale = 'en'}) { + /// Formats the number using the given pattern and locale. + /// + /// Example: + /// ```dart + /// 1234.56.toFormattedNumber(format: "#,##0.0", locale: "en_US"); // → 1,234.6 + /// ``` + String toFormattedNumber({ + required String format, + String locale = 'en', + }) { final numberFormat = NumberFormat(format, locale); return numberFormat.format(this); } - /// Extension function to format number to arabic numbers String - String toLocalizedArabicNumber() { - return NumberFormat('#.##', 'ar_EG').format(this); + /// Formats the number using Arabic numerals with optional format. + /// + /// Example: + /// ```dart + /// 123.toLocalizedArabicNumber(); // → ١٢٣ + /// ``` + String toLocalizedArabicNumber({String format = '#.##'}) { + return NumberFormat(format, 'ar_EG').format(this); } - /// Extension function to format number to english numbers String - String toLocalizedEnglishNumber() { - return NumberFormat('#.##', 'en_US').format(this); + /// Formats the number using English numerals with optional format. + /// + /// Example: + /// ```dart + /// 123.toLocalizedEnglishNumber(); // → 123 + /// ``` + String toLocalizedEnglishNumber({String format = '#.##'}) { + return NumberFormat(format, 'en_US').format(this); } - /// Extension function to format number to current arabic or english numbers String - String toLocalizedArabicOrEnglishNumber() { + /// Formats the number using Arabic or English numerals depending on the current locale. + /// + /// Useful for localizing number format without manually checking the locale. + String toLocalizedArabicOrEnglishNumber({String format = '#.##'}) { return PlayxLocalization.isCurrentLocaleArabic() - ? toLocalizedArabicNumber() - : toLocalizedEnglishNumber(); + ? toLocalizedArabicNumber(format: format) + : toLocalizedEnglishNumber(format: format); } - /// Extension function to format number to localized numbers String - String toLocalizedNumber({String locale = 'en'}) { - return NumberFormat('#.##', locale).format(this); + /// Formats the number according to the given or current locale and format. + /// + /// If [locale] is not provided, it uses the current locale from [PlayxLocalization]. + String toLocalizedNumber({ + String? locale, + String format = '#.##', + }) { + final formatLocale = + locale ?? PlayxLocalization.currentLocale.toLanguageTag(); + return NumberFormat(format, formatLocale).format(this); } + + /// Returns `true` if the number is equal to 0 within a small tolerance (useful for floating-point precision). + /// + /// Example: + /// ```dart + /// (0.00000001).isZero(); // → true + /// ``` + bool isZero({double precision = 1e-8}) => abs() < precision; } From 0b7eefb5c45045fde23d8ad43c2df905c966a435 Mon Sep 17 00:00:00 2001 From: basemosama Date: Tue, 1 Jul 2025 11:46:40 +0300 Subject: [PATCH 03/10] feat: Add localization string extensions - 86c47h79a This commit introduces a set of extensions for the `String` class, enhancing its capabilities for localization and language-specific analysis. These extensions include: - Checking for RTL/LTR text direction. - Identifying English and Arabic text. - Checking if a string contains only English or only Arabic characters. - Detecting the presence of numbers. - Stripping Arabic diacritics (tashkeel). - Converting between European and Arabic-Indic digits. - Converting digits to localized format based on the current locale. - Normalizing Arabic letters (e.g., Alef forms). - Removing extra spaces from a string. --- .../localization_string_extensions.dart | 109 ++++++++++++++++-- 1 file changed, 98 insertions(+), 11 deletions(-) diff --git a/lib/src/extensions/localization_string_extensions.dart b/lib/src/extensions/localization_string_extensions.dart index dce70d5..7e22d71 100644 --- a/lib/src/extensions/localization_string_extensions.dart +++ b/lib/src/extensions/localization_string_extensions.dart @@ -1,21 +1,108 @@ -import 'package:easy_localization/easy_localization.dart'; +import '../../playx_localization.dart'; +/// Extension on [String] to help with localization and language-specific analysis. extension LocalizationStringExtensions on String { - /// Check if the string is RTL + /// Returns `true` if the string contains any **right-to-left** characters (e.g. Arabic, Hebrew). bool get isRtl => Bidi.hasAnyRtl(this); - /// Check if the string is LTR + /// Returns `true` if the string does **not** contain RTL characters. bool get isLtr => !isRtl; - /// Regex for english characters - RegExp get englishRegExp => RegExp(r'[a-zA-Z]'); + /// Regular expression for matching **any English letters** (a–z or A–Z). + static final RegExp _englishRegExp = RegExp(r'[a-zA-Z]'); - /// Regex for arabic characters - RegExp get arabicRegExp => RegExp(r'[\u0600-\u06FF]'); + /// Regular expression for matching **any Arabic letters** (includes Arabic and Arabic Supplement Unicode blocks). + static final RegExp _arabicRegExp = RegExp(r'[\u0600-\u06FF\u0750-\u077F]'); - /// Check if the string is english - bool get isEnglish => englishRegExp.hasMatch(this); + /// Regular expression for matching **only Arabic letters** (ignores digits or punctuation). + static final RegExp _onlyArabicRegExp = RegExp(r'^[\u0600-\u06FF\s]+$'); - /// Check if the string is arabic - bool get isArabic => arabicRegExp.hasMatch(this); + /// Regular expression for matching **only English letters**. + static final RegExp _onlyEnglishRegExp = RegExp(r'^[a-zA-Z\s]+$'); + + /// Regular expression to check for any digits. + static final RegExp _numberRegExp = RegExp(r'[0-9]'); + + /// Returns `true` if the string contains **any English** letters. + bool get isEnglish => _englishRegExp.hasMatch(this); + + /// Returns `true` if the string contains **any Arabic** letters. + bool get isArabic => _arabicRegExp.hasMatch(this); + + /// Returns `true` if the string contains **only Arabic** letters (and spaces). + bool get containsOnlyArabic => _onlyArabicRegExp.hasMatch(this.trim()); + + /// Returns `true` if the string contains **only English** letters (and spaces). + bool get containsOnlyEnglish => _onlyEnglishRegExp.hasMatch(this.trim()); + + /// Returns `true` if the string contains **any numeric** digits. + bool get hasNumbers => _numberRegExp.hasMatch(this); + + + /// A list of Arabic diacritics (tashkeel) used in the Arabic language. + static const List _diacritics = [ + '\u064B', // fathatan + '\u064C', // dammatan + '\u064D', // kasratan + '\u064E', // fatha + '\u064F', // damma + '\u0650', // kasra + '\u0651', // shadda + '\u0652', // sukun + '\u0653', // maddah above + '\u0654', // hamza above + '\u0655', // hamza below + ]; + + /// Removes **Arabic diacritics (tashkeel)** from the string. + /// + /// Useful for comparing Arabic words or simplifying them. + String get stripDiacritics { + return replaceAll(RegExp('[${_diacritics.join()}]'), ''); + } + + /// Converts European digits to Arabic-Indic digits. + String toArabicIndicDigits() { + const english = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']; + const arabic = ['٠', '١', '٢', '٣', '٤', '٥', '٦', '٧', '٨', '٩']; + + var result = this; + for (int i = 0; i < english.length; i++) { + result = result.replaceAll(english[i], arabic[i]); + } + return result; + } + + /// Converts Arabic-Indic digits to English digits. + String toEnglishDigits() { + const arabic = ['٠', '١', '٢', '٣', '٤', '٥', '٦', '٧', '٨', '٩']; + const english = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']; + + var result = this; + for (int i = 0; i < arabic.length; i++) { + result = result.replaceAll(arabic[i], english[i]); + } + return result; + } + + /// Converts the string to localized digits based on the current locale. + String toLocalizedDigits({String? locale, bool toArabic = true}) { + final formatLocale = locale ?? PlayxLocalization.currentLocale.toLanguageTag(); + if (formatLocale.startsWith('ar') && toArabic) { + return toArabicIndicDigits(); + } + return toEnglishDigits(); + } + + /// Normalizes Arabic characters like Alef forms to a standard form. + String normalizeArabicLetters() { + return replaceAll(RegExp('[إأآٱ]'), 'ا') + .replaceAll('ى', 'ي') + .replaceAll('ة', 'ه'); + } + + /// Removes redundant spaces from the string. + String removeExtraSpaces() { + return trim().replaceAll(RegExp(r'\s+'), ' '); + } } From 85097f34cdb85b889c38c9c1eabfd28d25afd6a0 Mon Sep 17 00:00:00 2001 From: basemosama Date: Tue, 1 Jul 2025 11:55:06 +0300 Subject: [PATCH 04/10] feat: Add locale info extensions to BuildContext - 86c47h79a This commit introduces new extension methods on `BuildContext` to provide easy access to locale-related information. The following methods have been added: - `currentXLocale`: Returns the current `XLocale` object. - `currentLocale`: Returns the current `Locale`. - `localeTag`: Returns the current locale as a BCP-47 language tag. - `currentLanguageCode`: Returns the current locale's language code. - `fontFamily`: Returns the font family for the current locale. - `isCurrentLocaleArabic`: Checks if the current locale is Arabic. - `isCurrentLocaleEnglish`: Checks if the current locale is English. - `isRtl`: Checks if the current locale is Right-To-Left. - `isLtr`: Checks if the current locale is Left-To-Right. --- .../playx_localization_extensions.dart | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/lib/src/extensions/playx_localization_extensions.dart b/lib/src/extensions/playx_localization_extensions.dart index 62c3e15..8ceb7f6 100644 --- a/lib/src/extensions/playx_localization_extensions.dart +++ b/lib/src/extensions/playx_localization_extensions.dart @@ -3,6 +3,7 @@ import 'package:playx_localization/playx_localization.dart'; import 'package:playx_localization/src/easy_localization/public.dart' as ez; import '../easy_localization/localization.dart'; +import '../widgets/playx_inherited_localization.dart'; /// Strings extension method for access to [tr] and [plural()] /// Example : @@ -204,4 +205,36 @@ extension BuildContextLocalizationExtension on BuildContext { format: format, ); } + + + /// Returns the current `XLocale` object with locale and font info. + XLocale get currentXLocale { + final locale = PlayxInheritedLocalization.of(this); + return locale.locale; + } + + /// Returns the current [Locale] used in the app. + Locale get currentLocale => currentXLocale.locale; + + /// Returns the locale as a BCP-47 language tag (e.g., `en-US`, `ar-EG`). + String get localeTag => currentLocale.toLanguageTag(); + + /// Returns the current locale's language code (e.g., 'en', 'ar'). + String get currentLanguageCode => currentLocale.languageCode; + + /// Returns the font family for the current locale, if provided. + String? get fontFamily => currentXLocale.fontFamily; + + /// Returns true if the current locale is Arabic. + bool get isCurrentLocaleArabic => currentLanguageCode == 'ar'; + + /// Returns true if the current locale is English. + bool get isCurrentLocaleEnglish => currentLanguageCode == 'en'; + + /// Returns true if the current locale is RTL (e.g., Arabic, Hebrew). + bool get isRtl => Bidi.hasAnyRtl(currentLanguageCode); + + /// Returns true if the current locale is LTR. + bool get isLtr => !isRtl; + } From 65fa80c5b4aa0d2de36e3707d675359b40d4e7fb Mon Sep 17 00:00:00 2001 From: basemosama Date: Tue, 1 Jul 2025 12:02:41 +0300 Subject: [PATCH 05/10] feat: Allow customization of localization delegates This commit introduces two new options to `PlayxLocaleConfig`: - `extraDelegates`: Allows adding custom `LocalizationsDelegate`s from other packages or sources. - `customLocalizationDelegateBuilder`: Provides a function to build a completely custom list of delegates, potentially replacing or modifying the default ones. These additions offer more flexibility in configuring the localization delegates used by the application. --- lib/src/config/playx_locale_config.dart | 12 ++++++++++++ lib/src/controller/controller.dart | 7 ++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/lib/src/config/playx_locale_config.dart b/lib/src/config/playx_locale_config.dart index 99389c7..bfd65d1 100644 --- a/lib/src/config/playx_locale_config.dart +++ b/lib/src/config/playx_locale_config.dart @@ -1,3 +1,6 @@ +import 'package:flutter/cupertino.dart'; +import 'package:playx_localization/src/delegate/playx_localization_delegate.dart'; + import '../../playx_localization.dart'; /// Locale config : @@ -55,6 +58,13 @@ class PlayxLocaleConfig { /// Migrate preferences to async storage. final bool migratePrefsToAsync; + /// Additional custom delegates, e.g., from third-party packages. + final List? extraDelegates; + + /// Custom localization delegate builder. + /// This allows you to create a custom list of delegates based on the provided [PlayxLocalizationDelegate]. + final List Function(PlayxLocalizationDelegate delegate)? customLocalizationDelegateBuilder; + PlayxLocaleConfig({ required this.supportedLocales, this.startLocale, @@ -66,6 +76,8 @@ class PlayxLocaleConfig { this.saveLocale = true, this.logMissingKeys = false, this.migratePrefsToAsync = false, + this.extraDelegates, + this.customLocalizationDelegateBuilder, }) : assert(path.isNotEmpty, 'path can not be empty'), assert( supportedLocales.isNotEmpty, 'supportedLocales can not be empty'); diff --git a/lib/src/controller/controller.dart b/lib/src/controller/controller.dart index 0c0456c..71ce099 100644 --- a/lib/src/controller/controller.dart +++ b/lib/src/controller/controller.dart @@ -1,3 +1,5 @@ +import 'dart:nativewrappers/_internal/vm/lib/ffi_allocation_patch.dart'; + import 'package:flutter/cupertino.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:intl/intl_standalone.dart'; @@ -355,8 +357,11 @@ class PlayxLocaleController extends ValueNotifier { } //delegates to be used in material app. - List get delegates => [ + List get delegates => + config.customLocalizationDelegateBuilder?.call(delegate) ?? + [ delegate, + ...?config.extraDelegates, GlobalMaterialLocalizations.delegate, GlobalWidgetsLocalizations.delegate, GlobalCupertinoLocalizations.delegate, From 69c0f2f03ca8e0eb0cb52fccebcd8467718ed9f4 Mon Sep 17 00:00:00 2001 From: basemosama Date: Tue, 1 Jul 2025 13:44:10 +0300 Subject: [PATCH 06/10] feat: Improve localization and add more options This commit introduces several improvements and new features to the localization functionality: - Added `logLocaleChanges` option to `PlayxLocaleConfig` to enable/disable logging of locale changes. - Added `AssetLoader` abstract class and `RootBundleAssetLoader` implementation for loading translation files. This allows for custom asset loading strategies. - Removed dependency on `easy_localization` package and integrated its core logic directly. - Added `LocaleExtension` with `supports` and `toStringWithSeparator` methods. - Added `XLocaleExtension` with `locale` getter and `toStringWithSeparator` method. - Added `toLocale` extension method to `String` for converting a string to a `Locale` object. - Improved logging for locale changes and translation loading errors. - Minor refactoring and code cleanup. --- lib/playx_localization.dart | 16 ++--- lib/src/config/playx_locale_config.dart | 7 +- lib/src/controller/controller.dart | 69 ++++++++++++------- lib/src/controller/translation_manager.dart | 14 ++-- .../delegate/playx_localization_delegate.dart | 6 +- lib/src/easy_localization/asset_loader.dart | 38 ++++++++++ lib/src/easy_localization/localization.dart | 11 +-- lib/src/extensions/locale_extensions.dart | 49 +++++++++++++ .../localization_string_extensions.dart | 28 ++++++++ .../playx_localization_extensions.dart | 2 + lib/src/model/x_locale.dart | 3 - lib/src/playx_localization.dart | 6 +- pubspec.yaml | 1 - 13 files changed, 193 insertions(+), 57 deletions(-) create mode 100644 lib/src/easy_localization/asset_loader.dart create mode 100644 lib/src/extensions/locale_extensions.dart diff --git a/lib/playx_localization.dart b/lib/playx_localization.dart index 24dbd4d..0d36835 100644 --- a/lib/playx_localization.dart +++ b/lib/playx_localization.dart @@ -1,16 +1,6 @@ library; -export 'package:easy_localization/easy_localization.dart' - hide - TextTranslateExtension, - StringTranslateExtension, - BuildContextEasyLocalizationExtension, - TextDirection, - MapExtension, - tr, - trExists, - plural; -export 'package:intl/date_symbol_data_local.dart'; +export 'package:intl/intl.dart'; export 'package:playx_core/playx_core.dart'; export 'package:playx_localization/src/config/playx_locale_config.dart'; export 'package:playx_localization/src/easy_localization/public.dart'; @@ -21,3 +11,7 @@ export 'package:playx_localization/src/extensions/playx_localization_extensions. export 'package:playx_localization/src/model/x_locale.dart'; export 'package:playx_localization/src/playx_localization.dart'; export 'package:playx_localization/src/widgets/playx_localization_builder.dart'; +export 'package:playx_localization/src/widgets/playx_inherited_localization.dart'; +export 'package:playx_localization/src/extensions/locale_extensions.dart'; + + diff --git a/lib/src/config/playx_locale_config.dart b/lib/src/config/playx_locale_config.dart index bfd65d1..509b782 100644 --- a/lib/src/config/playx_locale_config.dart +++ b/lib/src/config/playx_locale_config.dart @@ -2,6 +2,7 @@ import 'package:flutter/cupertino.dart'; import 'package:playx_localization/src/delegate/playx_localization_delegate.dart'; import '../../playx_localization.dart'; +import '../easy_localization/asset_loader.dart'; /// Locale config : /// used to configure out app locales by providing the app with the supported locales and localization settings. @@ -52,9 +53,12 @@ class PlayxLocaleConfig { /// @Default value true final bool saveLocale; - /// Log missing keys in the console. + /// Log missing keys in the console when a key is not found in the current locale file in debug mode. final bool logMissingKeys; + /// Log locale changes in the console when the locale is changed. + final bool logLocaleChanges; + /// Migrate preferences to async storage. final bool migratePrefsToAsync; @@ -75,6 +79,7 @@ class PlayxLocaleConfig { this.assetLoader = const RootBundleAssetLoader(), this.saveLocale = true, this.logMissingKeys = false, + this.logLocaleChanges = true, this.migratePrefsToAsync = false, this.extraDelegates, this.customLocalizationDelegateBuilder, diff --git a/lib/src/controller/controller.dart b/lib/src/controller/controller.dart index 71ce099..af37ee2 100644 --- a/lib/src/controller/controller.dart +++ b/lib/src/controller/controller.dart @@ -1,11 +1,10 @@ -import 'dart:nativewrappers/_internal/vm/lib/ffi_allocation_patch.dart'; - import 'package:flutter/cupertino.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:intl/intl_standalone.dart'; import 'package:playx_localization/playx_localization.dart'; import 'package:playx_localization/src/delegate/playx_localization_delegate.dart'; import 'package:playx_localization/src/easy_localization/translations.dart'; +import 'package:playx_localization/src/extensions/locale_extensions.dart'; import '../easy_localization/localization.dart'; import 'translation_manager.dart'; @@ -48,6 +47,8 @@ class PlayxLocaleController extends ValueNotifier { // Returns the device locale. Locale? deviceLocale; + static PlayxBaseLogger? get logger => PlayxLogger.getLogger('Playx Localization'); + /// current locale index int get currentIndex { if (value == null) { @@ -59,32 +60,32 @@ class PlayxLocaleController extends ValueNotifier { /// set up the base controller to load locales. Future boot() async { - EasyLocalization.logger('Booting Localization'); - + final logger = PlayxLogger.initLogger( + name: 'Playx Localization', + setAsDefault: false, + useColoredFormatter: true); _localizationControllerInstance = this; final lastKnownIndex = await getLastSavedIndexFromPrefs( migratePrefsToAsync: config.migratePrefsToAsync); final foundPlatformLocale = await findSystemLocale(); deviceLocale = foundPlatformLocale.toLocale(); - EasyLocalization.logger( - 'Device Locale ${deviceLocale?.toStringWithSeparator()}'); + logger.i('Device Locale ${deviceLocale?.toStringWithSeparator()}'); XLocale? lastSavedLocale = config.supportedLocales.atOrNull( lastKnownIndex ?? -1, ); - EasyLocalization.logger( + logger.i( 'Last Saved Locale ${lastSavedLocale?.locale.toStringWithSeparator()}'); final locale = _getStartLocale(savedLocale: lastSavedLocale); - EasyLocalization.logger( - 'Start Locale ${locale.locale.toStringWithSeparator()}'); + logger.i('Start Locale ${locale.locale.toStringWithSeparator()}'); //Load translations from assets await loadTranslations(locale); - EasyLocalization.logger('Loaded Translation from assets'); + logger.i('Loaded Translation from assets'); delegate = PlayxLocalizationDelegate( localizationController: this, @@ -92,8 +93,8 @@ class PlayxLocaleController extends ValueNotifier { ); value = locale; - EasyLocalization.logger( - 'translation booted with ${locale.locale.toStringWithSeparator()}✔'); + logger.i( + 'Translation booted with ${locale.locale.toStringWithSeparator()} with index $currentIndex'); } /// Retrieves the last saved theme index from preferences. @@ -111,7 +112,7 @@ class PlayxLocaleController extends ValueNotifier { final lastKnownIndexInPrefs = PlayxPrefs.maybeGetInt( _lastKnownIndexKey, ); - EasyLocalization.logger( + logger?.i( 'Migrating preferences to SharedPreferenceAsync found index $lastKnownIndexInPrefs'); if (lastKnownIndexInPrefs != null) { @@ -151,7 +152,7 @@ class PlayxLocaleController extends ValueNotifier { return getFallbackLocale(); } - ///Get fallback Locale + /// Get fallback Locale /// if fallbackLocale is not null then return it /// if fallbackLocale is null then return english locale if it's supported in the config supported locales. /// if english locale is not supported then return the first locale in the config supported locales. @@ -182,7 +183,12 @@ class PlayxLocaleController extends ValueNotifier { /// if [forceAppUpdate] is true it will force the app to update. Future updateTo(XLocale locale, {bool forceAppUpdate = false}) async { final index = supportedXLocales.indexOf(locale); - if (index < 0) return false; + if (index < 0) { + if (config.logLocaleChanges) { + logger?.error('Locale not found in supported Locales'); + } + return false; + } return _updateLocale( locale: locale, forceAppUpdate: forceAppUpdate, @@ -194,9 +200,10 @@ class PlayxLocaleController extends ValueNotifier { /// if [forceAppUpdate] is true it will force the app to update. Future nextLocale({bool forceAppUpdate = false}) async { final isLastLocale = currentIndex == config.supportedLocales.length - 1; + final index= isLastLocale? 0 : currentIndex + 1; await updateByIndex( - isLastLocale ? 0 : currentIndex + 1, + index, forceAppUpdate: forceAppUpdate, ); } @@ -206,7 +213,12 @@ class PlayxLocaleController extends ValueNotifier { /// if [forceAppUpdate] is true it will force the app to update. Future updateByIndex(int index, {bool forceAppUpdate = false}) async { final locale = config.supportedLocales.atOrNull(index); - if (locale == null) return false; + if (locale == null) { + if (config.logLocaleChanges) { + logger?.error('Locale with index $index not found in supported Locales'); + } + return false; + } return _updateLocale(locale: locale, forceAppUpdate: forceAppUpdate); } @@ -215,7 +227,12 @@ class PlayxLocaleController extends ValueNotifier { Future updateById(String id, {bool forceAppUpdate = false}) async { final locale = config.supportedLocales.firstWhereOrNull((element) => element.id == id); - if (locale == null) return false; + if (locale == null) { + if (config.logLocaleChanges) { + logger?.error('Locale with id $id not found in supported Locales'); + } + return false; + } return _updateLocale(locale: locale, forceAppUpdate: forceAppUpdate); } @@ -275,7 +292,9 @@ class PlayxLocaleController extends ValueNotifier { try { final index = supportedXLocales.indexOf(locale); if (index < 0) { - EasyLocalization.logger.error('Locale not found in supported Locales'); + if (config.logLocaleChanges) { + logger?.error('Locale not found in supported Locales'); + } return false; } @@ -285,18 +304,22 @@ class PlayxLocaleController extends ValueNotifier { if (config.saveLocale) { await PlayxAsyncPrefs.setInt(_lastKnownIndexKey, index); } - + final oldLocale = value; value = locale; if (forceAppUpdate) { await _forceAppUpdate(); } - EasyLocalization.logger( - 'Updated locale to ${locale.name} with code ${locale.locale.toStringWithSeparator()}'); + if (config.logLocaleChanges) { + logger?.i( + 'Updated locale to ${locale.name} with code ${locale.locale.toStringWithSeparator()} at index $index from ${oldLocale?.locale.toStringWithSeparator()}'); + } return true; } catch (e) { - EasyLocalization.logger.error(e); + if (config.logLocaleChanges) { + logger?.error(e); + } return false; } } diff --git a/lib/src/controller/translation_manager.dart b/lib/src/controller/translation_manager.dart index 2a446d7..a1e484a 100644 --- a/lib/src/controller/translation_manager.dart +++ b/lib/src/controller/translation_manager.dart @@ -2,7 +2,9 @@ import 'dart:ui'; import 'package:flutter/foundation.dart'; import 'package:playx_localization/playx_localization.dart'; +import 'package:playx_localization/src/controller/controller.dart'; import 'package:playx_localization/src/easy_localization/translations.dart'; +import 'package:playx_localization/src/extensions/locale_extensions.dart'; class TranslationManager { TranslationManager._(); @@ -44,12 +46,12 @@ class TranslationManager { ); } return (translations: translations, fallbackTranslations: null); - } on FlutterError catch (e) { + } on FlutterError catch (e,s) { // onLoadError(e); - EasyLocalization.logger.error(e.message); + PlayxLocaleController.logger?.error('Error loading translations: ',error: e, stackTrace: s); return (translations: null, fallbackTranslations: null); - } catch (e) { - EasyLocalization.logger.error(e); + } catch (e,s) { + PlayxLocaleController.logger?.error('Error loading translations: ',error: e, stackTrace: s); // onLoadError(FlutterError(e.toString())); return ( translations: null, @@ -62,9 +64,9 @@ class TranslationManager { {required XLocale locale, required PlayxLocaleConfig config}) async { try { return await loadTranslationData(locale: locale, config: config); - } on FlutterError catch (e) { + } on FlutterError catch (e,s) { // Disregard asset not found FlutterError when attempting to load base language fallback - EasyLocalization.logger.error(e.message); + PlayxLocaleController.logger?.error('Error loading translations: ',error: e, stackTrace: s); } return null; } diff --git a/lib/src/delegate/playx_localization_delegate.dart b/lib/src/delegate/playx_localization_delegate.dart index a89feda..b869935 100644 --- a/lib/src/delegate/playx_localization_delegate.dart +++ b/lib/src/delegate/playx_localization_delegate.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:playx_localization/playx_localization.dart'; import 'package:playx_localization/src/controller/controller.dart'; +import 'package:playx_localization/src/extensions/locale_extensions.dart'; import '../easy_localization/localization.dart'; @@ -15,9 +16,7 @@ class PlayxLocalizationDelegate extends LocalizationsDelegate { // final bool useOnlyLangCode; PlayxLocalizationDelegate( - {this.localizationController, this.supportedLocales}) { - EasyLocalization.logger.debug('Init Localization Delegate'); - } + {this.localizationController, this.supportedLocales}); @override bool isSupported(Locale locale) => @@ -25,7 +24,6 @@ class PlayxLocalizationDelegate extends LocalizationsDelegate { @override Future load(Locale locale) async { - EasyLocalization.logger.debug('Load Localization Delegate'); if (localizationController!.translations == null) { final xLocale = localizationController!.searchLocaleByLanguageCode( languageCode: locale.languageCode, countryCode: locale.countryCode); diff --git a/lib/src/easy_localization/asset_loader.dart b/lib/src/easy_localization/asset_loader.dart new file mode 100644 index 0000000..687b841 --- /dev/null +++ b/lib/src/easy_localization/asset_loader.dart @@ -0,0 +1,38 @@ +import 'dart:convert'; +import 'dart:ui'; + +import 'package:flutter/services.dart'; +import 'package:playx_localization/src/extensions/locale_extensions.dart'; + +/// abstract class used to building your Custom AssetLoader +/// Example: +/// ``` +///class FileAssetLoader extends AssetLoader { +/// @override +/// Future> load(String path, Locale locale) async { +/// final file = File(path); +/// return json.decode(await file.readAsString()); +/// } +///} +/// ``` +abstract class AssetLoader { + const AssetLoader(); + Future?> load(String path, Locale locale); +} + +/// +/// default used is RootBundleAssetLoader which uses flutter's assetloader +/// +class RootBundleAssetLoader extends AssetLoader { + const RootBundleAssetLoader(); + + String getLocalePath(String basePath, Locale locale) { + return '$basePath/${locale.toStringWithSeparator(separator: "-")}.json'; + } + + @override + Future?> load(String path, Locale locale) async { + var localePath = getLocalePath(path, locale); + return json.decode(await rootBundle.loadString(localePath)); + } +} \ No newline at end of file diff --git a/lib/src/easy_localization/localization.dart b/lib/src/easy_localization/localization.dart index 1a78b16..68af8c5 100644 --- a/lib/src/easy_localization/localization.dart +++ b/lib/src/easy_localization/localization.dart @@ -1,5 +1,5 @@ -import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/widgets.dart'; +import 'package:intl/intl.dart'; import '../controller/controller.dart'; import 'plural_rules.dart'; @@ -97,7 +97,7 @@ class Localization { translated = _modifiers[formatterName]!(translated); } else { if (logging) { - EasyLocalization.logger.warning( + PlayxLocaleController.logger?.warning( 'Undefined modifier $formatterName, available modifiers: ${_modifiers.keys.toString()}'); } } @@ -212,7 +212,8 @@ class Localization { if (resource == null || (_useFallbackTranslationsForEmptyResources && resource.isEmpty)) { if (logging) { - EasyLocalization.logger.warning('Localization key [$key] not found'); + PlayxLocaleController.logger + ?.warning('Localization key [$key] not found'); } if (_fallbackTranslations == null || !fallback) { return key; @@ -221,8 +222,8 @@ class Localization { if (resource == null || (_useFallbackTranslationsForEmptyResources && resource.isEmpty)) { if (logging) { - EasyLocalization.logger - .warning('Fallback localization key [$key] not found'); + PlayxLocaleController.logger + ?.warning('Fallback localization key [$key] not found'); } return key; } diff --git a/lib/src/extensions/locale_extensions.dart b/lib/src/extensions/locale_extensions.dart new file mode 100644 index 0000000..d8c1fe3 --- /dev/null +++ b/lib/src/extensions/locale_extensions.dart @@ -0,0 +1,49 @@ +import 'dart:ui'; + +import '../../playx_localization.dart'; + +extension LocaleExtension on Locale { + bool supports(Locale locale) { + if (this == locale) { + return true; + } + if (languageCode != locale.languageCode) { + return false; + } + if (countryCode != null && + countryCode!.isNotEmpty && + countryCode != locale.countryCode) { + return false; + } + if (scriptCode != null && scriptCode != locale.scriptCode) { + return false; + } + + return true; + } + + String toStringWithSeparator({String separator = '-'}) { + final parts = []; + if (languageCode.isNotEmpty) { + parts.add(languageCode); + } + if (countryCode != null && countryCode!.isNotEmpty) { + parts.add(countryCode!); + } + if (scriptCode != null && scriptCode!.isNotEmpty) { + parts.add(scriptCode!); + } + return parts.join(separator); + } +} + + +extension XLocaleExtension on XLocale { + Locale get locale => Locale(languageCode, countryCode); + + String toStringWithSeparator({String separator = '-'}) { + return locale.toStringWithSeparator(separator: separator); + } + + +} \ No newline at end of file diff --git a/lib/src/extensions/localization_string_extensions.dart b/lib/src/extensions/localization_string_extensions.dart index 7e22d71..1d66975 100644 --- a/lib/src/extensions/localization_string_extensions.dart +++ b/lib/src/extensions/localization_string_extensions.dart @@ -1,3 +1,7 @@ +import 'dart:ui'; + +import 'package:intl/intl.dart'; + import '../../playx_localization.dart'; /// Extension on [String] to help with localization and language-specific analysis. @@ -105,4 +109,28 @@ extension LocalizationStringExtensions on String { String removeExtraSpaces() { return trim().replaceAll(RegExp(r'\s+'), ' '); } + + + /// 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); + } + } + } diff --git a/lib/src/extensions/playx_localization_extensions.dart b/lib/src/extensions/playx_localization_extensions.dart index 8ceb7f6..fe44d73 100644 --- a/lib/src/extensions/playx_localization_extensions.dart +++ b/lib/src/extensions/playx_localization_extensions.dart @@ -1,6 +1,8 @@ import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; import 'package:playx_localization/playx_localization.dart'; import 'package:playx_localization/src/easy_localization/public.dart' as ez; +import 'package:playx_localization/src/extensions/locale_extensions.dart'; import '../easy_localization/localization.dart'; import '../widgets/playx_inherited_localization.dart'; diff --git a/lib/src/model/x_locale.dart b/lib/src/model/x_locale.dart index a68dd0d..eb36ec2 100644 --- a/lib/src/model/x_locale.dart +++ b/lib/src/model/x_locale.dart @@ -1,4 +1,3 @@ -import 'package:flutter/material.dart'; import 'package:playx_core/playx_core.dart'; ///Defines locales with more information like id and name. @@ -19,8 +18,6 @@ class XLocale extends Equatable { this.fontFamily, }); - Locale get locale => Locale(languageCode, countryCode); - @override List get props => [id, name, languageCode, countryCode, fontFamily]; } diff --git a/lib/src/playx_localization.dart b/lib/src/playx_localization.dart index d012c8e..1744f21 100644 --- a/lib/src/playx_localization.dart +++ b/lib/src/playx_localization.dart @@ -1,6 +1,6 @@ -import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:playx_localization/src/controller/controller.dart'; +import 'package:playx_localization/src/extensions/locale_extensions.dart'; import 'package:playx_localization/src/model/x_locale.dart'; import 'config/playx_locale_config.dart'; @@ -16,6 +16,8 @@ abstract class PlayxLocalization { static PlayxLocaleController get _controller => PlayxLocaleController.controller; + + ///Setup the current app locales with your configuration. ///And loads app supported translations. /// Must be called before calling any other method to initialize dependencies. @@ -23,8 +25,6 @@ abstract class PlayxLocalization { required PlayxLocaleConfig config, }) async { WidgetsFlutterBinding.ensureInitialized(); - EasyLocalization.logger.name = 'Playx_localization'; - EasyLocalization.logger('boot Localization'); final controller = PlayxLocaleController(config: config); return controller.boot(); } diff --git a/pubspec.yaml b/pubspec.yaml index 2b9664c..2811c28 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -21,7 +21,6 @@ dependencies: sdk: flutter playx_core: ^0.7.3 intl: any - easy_localization: ^3.0.7+1 shared_preferences_platform_interface: ^2.4.1 From b2697c39fccaaae93cbc8bfd76e12be9cec83343 Mon Sep 17 00:00:00 2001 From: basemosama Date: Tue, 1 Jul 2025 14:40:46 +0300 Subject: [PATCH 07/10] feat: Update example app --- .flutter-plugins | 17 -- .gitignore | 2 + .../.flutter-plugins-dependencies | 2 +- example/.gitignore | 3 + example/.metadata | 30 +-- example/android/.gitignore | 1 + .../app/{build.gradle => build.gradle.kts} | 18 +- .../MainActivity.kt | 2 +- example/android/build.gradle | 18 -- example/android/build.gradle.kts | 21 ++ example/android/gradle.properties | 2 +- .../gradle/wrapper/gradle-wrapper.properties | 2 +- example/android/settings.gradle | 25 --- example/android/settings.gradle.kts | 25 +++ example/ios/Flutter/Debug.xcconfig | 1 + example/ios/Flutter/Release.xcconfig | 1 + example/ios/Podfile | 43 ++++ example/ios/Runner.xcodeproj/project.pbxproj | 3 + .../xcshareddata/xcschemes/Runner.xcscheme | 3 + example/lib/main.dart | 209 +++++++++--------- example/lib/translation/app_trans.dart | 10 + example/macos/.gitignore | 1 + example/macos/Flutter/Flutter-Debug.xcconfig | 1 + .../macos/Flutter/Flutter-Release.xcconfig | 1 + example/macos/Podfile | 42 ++++ .../macos/Runner.xcodeproj/project.pbxproj | 98 +++++++- .../xcshareddata/xcschemes/Runner.xcscheme | 1 + .../contents.xcworkspacedata | 3 + example/pubspec.lock | 200 ++++++++--------- example/pubspec.yaml | 4 +- 30 files changed, 489 insertions(+), 300 deletions(-) delete mode 100644 .flutter-plugins rename .flutter-plugins-dependencies => example/.flutter-plugins-dependencies (97%) rename example/android/app/{build.gradle => build.gradle.kts} (63%) delete mode 100644 example/android/build.gradle create mode 100644 example/android/build.gradle.kts delete mode 100644 example/android/settings.gradle create mode 100644 example/android/settings.gradle.kts create mode 100644 example/ios/Podfile create mode 100644 example/lib/translation/app_trans.dart create mode 100644 example/macos/Podfile diff --git a/.flutter-plugins b/.flutter-plugins deleted file mode 100644 index 88614b0..0000000 --- a/.flutter-plugins +++ /dev/null @@ -1,17 +0,0 @@ -# This is a generated file; do not edit or check into version control. -flutter_secure_storage=E:\\Sdk\\cache\\hosted\\pub.dev\\flutter_secure_storage-9.2.4\\ -flutter_secure_storage_linux=E:\\Sdk\\cache\\hosted\\pub.dev\\flutter_secure_storage_linux-1.2.2\\ -flutter_secure_storage_macos=E:\\Sdk\\cache\\hosted\\pub.dev\\flutter_secure_storage_macos-3.1.3\\ -flutter_secure_storage_web=E:\\Sdk\\cache\\hosted\\pub.dev\\flutter_secure_storage_web-1.2.1\\ -flutter_secure_storage_windows=E:\\Sdk\\cache\\hosted\\pub.dev\\flutter_secure_storage_windows-3.1.2\\ -path_provider=E:\\Sdk\\cache\\hosted\\pub.dev\\path_provider-2.0.15\\ -path_provider_android=E:\\Sdk\\cache\\hosted\\pub.dev\\path_provider_android-2.0.27\\ -path_provider_foundation=E:\\Sdk\\cache\\hosted\\pub.dev\\path_provider_foundation-2.2.4\\ -path_provider_linux=E:\\Sdk\\cache\\hosted\\pub.dev\\path_provider_linux-2.1.11\\ -path_provider_windows=E:\\Sdk\\cache\\hosted\\pub.dev\\path_provider_windows-2.1.7\\ -shared_preferences=E:\\Sdk\\cache\\hosted\\pub.dev\\shared_preferences-2.3.5\\ -shared_preferences_android=E:\\Sdk\\cache\\hosted\\pub.dev\\shared_preferences_android-2.4.0\\ -shared_preferences_foundation=E:\\Sdk\\cache\\hosted\\pub.dev\\shared_preferences_foundation-2.5.2\\ -shared_preferences_linux=E:\\Sdk\\cache\\hosted\\pub.dev\\shared_preferences_linux-2.4.1\\ -shared_preferences_web=E:\\Sdk\\cache\\hosted\\pub.dev\\shared_preferences_web-2.4.2\\ -shared_preferences_windows=E:\\Sdk\\cache\\hosted\\pub.dev\\shared_preferences_windows-2.4.1\\ diff --git a/.gitignore b/.gitignore index 96486fd..5c5c63d 100644 --- a/.gitignore +++ b/.gitignore @@ -28,3 +28,5 @@ migrate_working_dir/ .dart_tool/ .packages build/ +.flutter-plugins-dependencies +.flutter-plugins diff --git a/.flutter-plugins-dependencies b/example/.flutter-plugins-dependencies similarity index 97% rename from .flutter-plugins-dependencies rename to example/.flutter-plugins-dependencies index db939f4..36ba674 100644 --- a/.flutter-plugins-dependencies +++ b/example/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"flutter_secure_storage","path":"/Users/basemosama/.pub-cache/hosted/pub.dev/flutter_secure_storage-9.2.4/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"path_provider_foundation","path":"/Users/basemosama/.pub-cache/hosted/pub.dev/path_provider_foundation-2.4.1/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"shared_preferences_foundation","path":"/Users/basemosama/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.5.4/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false}],"android":[{"name":"flutter_secure_storage","path":"/Users/basemosama/.pub-cache/hosted/pub.dev/flutter_secure_storage-9.2.4/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"path_provider_android","path":"/Users/basemosama/.pub-cache/hosted/pub.dev/path_provider_android-2.2.17/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"shared_preferences_android","path":"/Users/basemosama/.pub-cache/hosted/pub.dev/shared_preferences_android-2.4.10/","native_build":true,"dependencies":[],"dev_dependency":false}],"macos":[{"name":"flutter_secure_storage_macos","path":"/Users/basemosama/.pub-cache/hosted/pub.dev/flutter_secure_storage_macos-3.1.3/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"path_provider_foundation","path":"/Users/basemosama/.pub-cache/hosted/pub.dev/path_provider_foundation-2.4.1/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"shared_preferences_foundation","path":"/Users/basemosama/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.5.4/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false}],"linux":[{"name":"flutter_secure_storage_linux","path":"/Users/basemosama/.pub-cache/hosted/pub.dev/flutter_secure_storage_linux-1.2.3/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"path_provider_linux","path":"/Users/basemosama/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"shared_preferences_linux","path":"/Users/basemosama/.pub-cache/hosted/pub.dev/shared_preferences_linux-2.4.1/","native_build":false,"dependencies":["path_provider_linux"],"dev_dependency":false}],"windows":[{"name":"flutter_secure_storage_windows","path":"/Users/basemosama/.pub-cache/hosted/pub.dev/flutter_secure_storage_windows-3.1.2/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"path_provider_windows","path":"/Users/basemosama/.pub-cache/hosted/pub.dev/path_provider_windows-2.3.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"shared_preferences_windows","path":"/Users/basemosama/.pub-cache/hosted/pub.dev/shared_preferences_windows-2.4.1/","native_build":false,"dependencies":["path_provider_windows"],"dev_dependency":false}],"web":[{"name":"flutter_secure_storage_web","path":"/Users/basemosama/.pub-cache/hosted/pub.dev/flutter_secure_storage_web-1.2.1/","dependencies":[],"dev_dependency":false},{"name":"shared_preferences_web","path":"/Users/basemosama/.pub-cache/hosted/pub.dev/shared_preferences_web-2.4.3/","dependencies":[],"dev_dependency":false}]},"dependencyGraph":[{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":["path_provider"]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_foundation","path_provider_linux","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_foundation","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"shared_preferences","dependencies":["shared_preferences_android","shared_preferences_foundation","shared_preferences_linux","shared_preferences_web","shared_preferences_windows"]},{"name":"shared_preferences_android","dependencies":[]},{"name":"shared_preferences_foundation","dependencies":[]},{"name":"shared_preferences_linux","dependencies":["path_provider_linux"]},{"name":"shared_preferences_web","dependencies":[]},{"name":"shared_preferences_windows","dependencies":["path_provider_windows"]}],"date_created":"2025-07-01 11:10:57.120032","version":"3.32.4","swift_package_manager_enabled":{"ios":false,"macos":false}} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"flutter_secure_storage","path":"/Users/basemosama/.pub-cache/hosted/pub.dev/flutter_secure_storage-9.2.4/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"path_provider_foundation","path":"/Users/basemosama/.pub-cache/hosted/pub.dev/path_provider_foundation-2.4.1/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"shared_preferences_foundation","path":"/Users/basemosama/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.5.4/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false}],"android":[{"name":"flutter_secure_storage","path":"/Users/basemosama/.pub-cache/hosted/pub.dev/flutter_secure_storage-9.2.4/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"path_provider_android","path":"/Users/basemosama/.pub-cache/hosted/pub.dev/path_provider_android-2.2.17/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"shared_preferences_android","path":"/Users/basemosama/.pub-cache/hosted/pub.dev/shared_preferences_android-2.4.10/","native_build":true,"dependencies":[],"dev_dependency":false}],"macos":[{"name":"flutter_secure_storage_macos","path":"/Users/basemosama/.pub-cache/hosted/pub.dev/flutter_secure_storage_macos-3.1.3/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"path_provider_foundation","path":"/Users/basemosama/.pub-cache/hosted/pub.dev/path_provider_foundation-2.4.1/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"shared_preferences_foundation","path":"/Users/basemosama/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.5.4/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false}],"linux":[{"name":"flutter_secure_storage_linux","path":"/Users/basemosama/.pub-cache/hosted/pub.dev/flutter_secure_storage_linux-1.2.3/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"path_provider_linux","path":"/Users/basemosama/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"shared_preferences_linux","path":"/Users/basemosama/.pub-cache/hosted/pub.dev/shared_preferences_linux-2.4.1/","native_build":false,"dependencies":["path_provider_linux"],"dev_dependency":false}],"windows":[{"name":"flutter_secure_storage_windows","path":"/Users/basemosama/.pub-cache/hosted/pub.dev/flutter_secure_storage_windows-3.1.2/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"path_provider_windows","path":"/Users/basemosama/.pub-cache/hosted/pub.dev/path_provider_windows-2.3.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"shared_preferences_windows","path":"/Users/basemosama/.pub-cache/hosted/pub.dev/shared_preferences_windows-2.4.1/","native_build":false,"dependencies":["path_provider_windows"],"dev_dependency":false}],"web":[{"name":"flutter_secure_storage_web","path":"/Users/basemosama/.pub-cache/hosted/pub.dev/flutter_secure_storage_web-1.2.1/","dependencies":[],"dev_dependency":false},{"name":"shared_preferences_web","path":"/Users/basemosama/.pub-cache/hosted/pub.dev/shared_preferences_web-2.4.3/","dependencies":[],"dev_dependency":false}]},"dependencyGraph":[{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":["path_provider"]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_foundation","path_provider_linux","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_foundation","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"shared_preferences","dependencies":["shared_preferences_android","shared_preferences_foundation","shared_preferences_linux","shared_preferences_web","shared_preferences_windows"]},{"name":"shared_preferences_android","dependencies":[]},{"name":"shared_preferences_foundation","dependencies":[]},{"name":"shared_preferences_linux","dependencies":["path_provider_linux"]},{"name":"shared_preferences_web","dependencies":[]},{"name":"shared_preferences_windows","dependencies":["path_provider_windows"]}],"date_created":"2025-07-01 14:18:51.931116","version":"3.32.5","swift_package_manager_enabled":{"ios":false,"macos":false}} \ No newline at end of file diff --git a/example/.gitignore b/example/.gitignore index 24476c5..8e14b83 100644 --- a/example/.gitignore +++ b/example/.gitignore @@ -5,9 +5,11 @@ *.swp .DS_Store .atom/ +.build/ .buildlog/ .history .svn/ +.swiftpm/ migrate_working_dir/ # IntelliJ related @@ -42,3 +44,4 @@ app.*.map.json /android/app/debug /android/app/profile /android/app/release +!/.flutter-plugins-dependencies diff --git a/example/.metadata b/example/.metadata index b02a7e4..603c641 100644 --- a/example/.metadata +++ b/example/.metadata @@ -4,7 +4,7 @@ # This file should be version controlled and should not be manually edited. version: - revision: "17025dd88227cd9532c33fa78f5250d548d87e9a" + revision: "6fba2447e95c451518584c35e25f5433f14d888c" channel: "stable" project_type: app @@ -13,26 +13,26 @@ project_type: app migration: platforms: - platform: root - create_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a - base_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a + create_revision: 6fba2447e95c451518584c35e25f5433f14d888c + base_revision: 6fba2447e95c451518584c35e25f5433f14d888c - platform: android - create_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a - base_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a + create_revision: 6fba2447e95c451518584c35e25f5433f14d888c + base_revision: 6fba2447e95c451518584c35e25f5433f14d888c - platform: ios - create_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a - base_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a + create_revision: 6fba2447e95c451518584c35e25f5433f14d888c + base_revision: 6fba2447e95c451518584c35e25f5433f14d888c - platform: linux - create_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a - base_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a + create_revision: 6fba2447e95c451518584c35e25f5433f14d888c + base_revision: 6fba2447e95c451518584c35e25f5433f14d888c - platform: macos - create_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a - base_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a + create_revision: 6fba2447e95c451518584c35e25f5433f14d888c + base_revision: 6fba2447e95c451518584c35e25f5433f14d888c - platform: web - create_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a - base_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a + create_revision: 6fba2447e95c451518584c35e25f5433f14d888c + base_revision: 6fba2447e95c451518584c35e25f5433f14d888c - platform: windows - create_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a - base_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a + create_revision: 6fba2447e95c451518584c35e25f5433f14d888c + base_revision: 6fba2447e95c451518584c35e25f5433f14d888c # User provided section diff --git a/example/android/.gitignore b/example/android/.gitignore index 55afd91..be3943c 100644 --- a/example/android/.gitignore +++ b/example/android/.gitignore @@ -5,6 +5,7 @@ gradle-wrapper.jar /gradlew.bat /local.properties GeneratedPluginRegistrant.java +.cxx/ # Remember to never publicly share your keystore. # See https://flutter.dev/to/reference-keystore diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle.kts similarity index 63% rename from example/android/app/build.gradle rename to example/android/app/build.gradle.kts index d2a9c4c..c57c1f9 100644 --- a/example/android/app/build.gradle +++ b/example/android/app/build.gradle.kts @@ -1,8 +1,8 @@ plugins { - id "com.android.application" - id "kotlin-android" + id("com.android.application") + id("kotlin-android") // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. - id "dev.flutter.flutter-gradle-plugin" + id("dev.flutter.flutter-gradle-plugin") } android { @@ -11,17 +11,17 @@ android { ndkVersion = flutter.ndkVersion compileOptions { - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 } kotlinOptions { - jvmTarget = JavaVersion.VERSION_1_8 + jvmTarget = JavaVersion.VERSION_17.toString() } defaultConfig { - applicationId "io.sourcya.playx.localization" - minSdk = flutter.minSdkVersion + applicationId = "io.sourcya.playx.localization.example" + minSdk = 23 targetSdk = flutter.targetSdkVersion versionCode = flutter.versionCode versionName = flutter.versionName @@ -31,7 +31,7 @@ android { release { // TODO: Add your own signing config for the release build. // Signing with the debug keys for now, so `flutter run --release` works. - signingConfig = signingConfigs.debug + signingConfig = signingConfigs.getByName("debug") } } } diff --git a/example/android/app/src/main/kotlin/com/example/playx_localization_example/MainActivity.kt b/example/android/app/src/main/kotlin/com/example/playx_localization_example/MainActivity.kt index c5f281e..f6476a8 100644 --- a/example/android/app/src/main/kotlin/com/example/playx_localization_example/MainActivity.kt +++ b/example/android/app/src/main/kotlin/com/example/playx_localization_example/MainActivity.kt @@ -2,4 +2,4 @@ package com.example.playx_localization_example import io.flutter.embedding.android.FlutterActivity -class MainActivity: FlutterActivity() +class MainActivity : FlutterActivity() diff --git a/example/android/build.gradle b/example/android/build.gradle deleted file mode 100644 index d2ffbff..0000000 --- a/example/android/build.gradle +++ /dev/null @@ -1,18 +0,0 @@ -allprojects { - repositories { - google() - mavenCentral() - } -} - -rootProject.buildDir = "../build" -subprojects { - project.buildDir = "${rootProject.buildDir}/${project.name}" -} -subprojects { - project.evaluationDependsOn(":app") -} - -tasks.register("clean", Delete) { - delete rootProject.buildDir -} diff --git a/example/android/build.gradle.kts b/example/android/build.gradle.kts new file mode 100644 index 0000000..89176ef --- /dev/null +++ b/example/android/build.gradle.kts @@ -0,0 +1,21 @@ +allprojects { + repositories { + google() + mavenCentral() + } +} + +val newBuildDir: Directory = rootProject.layout.buildDirectory.dir("../../build").get() +rootProject.layout.buildDirectory.value(newBuildDir) + +subprojects { + val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name) + project.layout.buildDirectory.value(newSubprojectBuildDir) +} +subprojects { + project.evaluationDependsOn(":app") +} + +tasks.register("clean") { + delete(rootProject.layout.buildDirectory) +} diff --git a/example/android/gradle.properties b/example/android/gradle.properties index 2597170..f018a61 100644 --- a/example/android/gradle.properties +++ b/example/android/gradle.properties @@ -1,3 +1,3 @@ -org.gradle.jvmargs=-Xmx4G -XX:MaxMetaspaceSize=2G -XX:+HeapDumpOnOutOfMemoryError +org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError android.useAndroidX=true android.enableJetifier=true diff --git a/example/android/gradle/wrapper/gradle-wrapper.properties b/example/android/gradle/wrapper/gradle-wrapper.properties index 7bb2df6..348c409 100644 --- a/example/android/gradle/wrapper/gradle-wrapper.properties +++ b/example/android/gradle/wrapper/gradle-wrapper.properties @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-all.zip diff --git a/example/android/settings.gradle b/example/android/settings.gradle deleted file mode 100644 index a42444d..0000000 --- a/example/android/settings.gradle +++ /dev/null @@ -1,25 +0,0 @@ -pluginManagement { - def flutterSdkPath = { - def properties = new Properties() - file("local.properties").withInputStream { properties.load(it) } - def flutterSdkPath = properties.getProperty("flutter.sdk") - assert flutterSdkPath != null, "flutter.sdk not set in local.properties" - return flutterSdkPath - }() - - includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") - - repositories { - google() - mavenCentral() - gradlePluginPortal() - } -} - -plugins { - id "dev.flutter.flutter-plugin-loader" version "1.0.0" - id "com.android.application" version "8.2.1" apply false - id "org.jetbrains.kotlin.android" version "1.8.22" apply false -} - -include ":app" diff --git a/example/android/settings.gradle.kts b/example/android/settings.gradle.kts new file mode 100644 index 0000000..ab39a10 --- /dev/null +++ b/example/android/settings.gradle.kts @@ -0,0 +1,25 @@ +pluginManagement { + val flutterSdkPath = run { + val properties = java.util.Properties() + file("local.properties").inputStream().use { properties.load(it) } + val flutterSdkPath = properties.getProperty("flutter.sdk") + require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" } + flutterSdkPath + } + + includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") + + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} + +plugins { + id("dev.flutter.flutter-plugin-loader") version "1.0.0" + id("com.android.application") version "8.7.3" apply false + id("org.jetbrains.kotlin.android") version "2.1.0" apply false +} + +include(":app") diff --git a/example/ios/Flutter/Debug.xcconfig b/example/ios/Flutter/Debug.xcconfig index 592ceee..ec97fc6 100644 --- a/example/ios/Flutter/Debug.xcconfig +++ b/example/ios/Flutter/Debug.xcconfig @@ -1 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" #include "Generated.xcconfig" diff --git a/example/ios/Flutter/Release.xcconfig b/example/ios/Flutter/Release.xcconfig index 592ceee..c4855bf 100644 --- a/example/ios/Flutter/Release.xcconfig +++ b/example/ios/Flutter/Release.xcconfig @@ -1 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" #include "Generated.xcconfig" diff --git a/example/ios/Podfile b/example/ios/Podfile new file mode 100644 index 0000000..e549ee2 --- /dev/null +++ b/example/ios/Podfile @@ -0,0 +1,43 @@ +# Uncomment this line to define a global platform for your project +# platform :ios, '12.0' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_ios_podfile_setup + +target 'Runner' do + use_frameworks! + + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths + end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_ios_build_settings(target) + end +end diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj index ecf8573..f109a11 100644 --- a/example/ios/Runner.xcodeproj/project.pbxproj +++ b/example/ios/Runner.xcodeproj/project.pbxproj @@ -362,6 +362,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = B996ZRP255; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -541,6 +542,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = B996ZRP255; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -563,6 +565,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = B996ZRP255; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( diff --git a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index 8e3ca5d..e3773d4 100644 --- a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -26,6 +26,7 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit" shouldUseLaunchSchemeArgsEnv = "YES"> diff --git a/example/lib/main.dart b/example/lib/main.dart index 8e94089..711d2d2 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -1,125 +1,126 @@ import 'package:flutter/material.dart'; +import 'package:playx_localization/playx_localization.dart'; +import 'package:playx_localization_example/translation/app_trans.dart'; + +Future main() async { + WidgetsFlutterBinding.ensureInitialized(); + await PlayxCore.bootCore(); + + const locales = [ + XLocale(id: 'en', name: 'English', languageCode: 'en'), + XLocale(id: 'ar', name: 'العربية', languageCode: 'ar'), + ]; + + final config = PlayxLocaleConfig( + supportedLocales: locales, + startLocale: locales.first, + fallbackLocale: locales.first, + useFallbackTranslations: true, + ); + await PlayxLocalization.boot(config: config); -void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); - // This widget is the root of your application. @override Widget build(BuildContext context) { - return MaterialApp( - title: 'Flutter Demo', - theme: ThemeData( - // This is the theme of your application. - // - // TRY THIS: Try running your application with "flutter run". You'll see - // the application has a purple toolbar. Then, without quitting the app, - // try changing the seedColor in the colorScheme below to Colors.green - // and then invoke "hot reload" (save your changes or press the "hot - // reload" button in a Flutter-supported IDE, or press "r" if you used - // the command line to start the app). - // - // Notice that the counter didn't reset back to zero; the application - // state is not lost during the reload. To reset the state, use hot - // restart instead. - // - // This works for code too, not just values: Most code changes can be - // tested with just a hot reload. - colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple), - useMaterial3: true, - ), - home: const MyHomePage(title: 'Flutter Demo Home Page'), - ); + return PlayxLocalizationBuilder(builder: (_, locale) { + return MaterialApp( + supportedLocales: PlayxLocalization.supportedLocales, + localizationsDelegates: PlayxLocalization.localizationDelegates, + locale: locale.locale, + home: const MyHomePage(), + ); + }); } } -class MyHomePage extends StatefulWidget { - const MyHomePage({super.key, required this.title}); - - // This widget is the home page of your application. It is stateful, meaning - // that it has a State object (defined below) that contains fields that affect - // how it looks. - - // This class is the configuration for the state. It holds the values (in this - // case the title) provided by the parent (in this case the App widget) and - // used by the build method of the State. Fields in a Widget subclass are - // always marked "final". - - final String title; - - @override - State createState() => _MyHomePageState(); -} - -class _MyHomePageState extends State { - int _counter = 0; - - void _incrementCounter() { - setState(() { - // This call to setState tells the Flutter framework that something has - // changed in this State, which causes it to rerun the build method below - // so that the display can reflect the updated values. If we changed - // _counter without calling setState(), then the build method would not be - // called again, and so nothing would appear to happen. - _counter++; - }); - } +class MyHomePage extends StatelessWidget { + const MyHomePage({super.key}); @override Widget build(BuildContext context) { - // This method is rerun every time setState is called, for instance as done - // by the _incrementCounter method above. - // - // The Flutter framework has been optimized to make rerunning build methods - // fast, so that you can just rebuild anything that needs updating rather - // than having to individually change instances of widgets. + print('Current Locale: ${PlayxLocalization.currentLocale} context :${context.locale.toStringWithSeparator()}'); return Scaffold( - appBar: AppBar( - // TRY THIS: Try changing the color here to a specific color (to - // Colors.amber, perhaps?) and trigger a hot reload to see the AppBar - // change color while the other colors stay the same. - backgroundColor: Theme.of(context).colorScheme.inversePrimary, - // Here we take the value from the MyHomePage object that was created by - // the App.build method, and use it to set our appbar title. - title: Text(widget.title), - ), - body: Center( - // Center is a layout widget. It takes a single child and positions it - // in the middle of the parent. - child: Column( - // Column is also a layout widget. It takes a list of children and - // arranges them vertically. By default, it sizes itself to fit its - // children horizontally, and tries to be as tall as its parent. - // - // Column has various properties to control how it sizes itself and - // how it positions its children. Here we use mainAxisAlignment to - // center the children vertically; the main axis here is the vertical - // axis because Columns are vertical (the cross axis would be - // horizontal). - // - // TRY THIS: Invoke "debug painting" (choose the "Toggle Debug Paint" - // action in the IDE, or press "p" in the console), to see the - // wireframe for each widget. - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const Text( - 'You have pushed the button this many times:', - ), - Text( - '$_counter', - style: Theme.of(context).textTheme.headlineMedium, + appBar: AppBar( + title: Text( + AppTrans.changeLanguageTitle.tr(context: context), + ), + ), + body: SafeArea( + child: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + '${context.tr(AppTrans.changeLanguageTitle)} : بلاي', + style: TextStyle( + fontSize: 18, + color: + ('${context.tr(AppTrans.changeLanguageTitle)} : بلاي') + .isArabic + ? Colors.blueAccent + : Colors.black), + ), + const SizedBox( + height: 20, + ), + ElevatedButton( + onPressed: () { + showDialog( + context: context, + builder: (ctx) => Center( + child: Card( + margin: const EdgeInsets.all(8), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + AppTrans.changeLanguageTitle + .tr(context: context), + style: const TextStyle(fontSize: 20), + ), + ...PlayxLocalization.supportedXLocales + .map((e) => ListTile( + onTap: () { + PlayxLocalization.updateById( + e.id, + forceAppUpdate: false); + Navigator.pop(ctx); + }, + title: Text(e.name), + trailing: PlayxLocalization + .currentXLocale.id == + e.id + ? const Icon( + Icons.done, + color: Colors.lightBlue, + ) + : const SizedBox.shrink(), + )) + , + ], + ), + ))); + }, + child: Text(AppTrans.chooseLanguage.tr(context: context))) + ], ), - ], + ), ), - ), - floatingActionButton: FloatingActionButton( - onPressed: _incrementCounter, - tooltip: 'Increment', - child: const Icon(Icons.add), - ), // This trailing comma makes auto-formatting nicer for build methods. - ); + floatingActionButton: FloatingActionButton.extended( + onPressed: () { + PlayxLocalization.updateByIndex( + PlayxLocalization.isCurrentLocaleArabic() ? 0 : 1, + forceAppUpdate: false); + }, + label: Text( + 'change_language_title'.tr(context: context), + ), + icon: const Icon(Icons.update), + )); } } diff --git a/example/lib/translation/app_trans.dart b/example/lib/translation/app_trans.dart new file mode 100644 index 0000000..07dabd5 --- /dev/null +++ b/example/lib/translation/app_trans.dart @@ -0,0 +1,10 @@ +// DO NOT EDIT. This is code generated via package:easy_localization/generate.dart + +abstract class AppTrans { + AppTrans._(); + + static const appName = 'app_name'; + static const chooseLanguage = 'choose_language'; + static const changeLanguageTitle = 'change_language_title'; + static const title = 'title'; +} diff --git a/example/macos/.gitignore b/example/macos/.gitignore index 746adbb..21a0d06 100644 --- a/example/macos/.gitignore +++ b/example/macos/.gitignore @@ -5,3 +5,4 @@ # Xcode-related **/dgph **/xcuserdata/ +/Podfile.lock diff --git a/example/macos/Flutter/Flutter-Debug.xcconfig b/example/macos/Flutter/Flutter-Debug.xcconfig index c2efd0b..4b81f9b 100644 --- a/example/macos/Flutter/Flutter-Debug.xcconfig +++ b/example/macos/Flutter/Flutter-Debug.xcconfig @@ -1 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" #include "ephemeral/Flutter-Generated.xcconfig" diff --git a/example/macos/Flutter/Flutter-Release.xcconfig b/example/macos/Flutter/Flutter-Release.xcconfig index c2efd0b..5caa9d1 100644 --- a/example/macos/Flutter/Flutter-Release.xcconfig +++ b/example/macos/Flutter/Flutter-Release.xcconfig @@ -1 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" #include "ephemeral/Flutter-Generated.xcconfig" diff --git a/example/macos/Podfile b/example/macos/Podfile new file mode 100644 index 0000000..29c8eb3 --- /dev/null +++ b/example/macos/Podfile @@ -0,0 +1,42 @@ +platform :osx, '10.14' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\"" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_macos_podfile_setup + +target 'Runner' do + use_frameworks! + + flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths + end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_macos_build_settings(target) + end +end diff --git a/example/macos/Runner.xcodeproj/project.pbxproj b/example/macos/Runner.xcodeproj/project.pbxproj index aee9050..2478db5 100644 --- a/example/macos/Runner.xcodeproj/project.pbxproj +++ b/example/macos/Runner.xcodeproj/project.pbxproj @@ -27,6 +27,8 @@ 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; + 8B44AA877385D68EC44D5391 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 131C8BFB6EFD785F48B1CD75 /* Pods_RunnerTests.framework */; }; + C0386B32D6070ADD8290B582 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C4A75E8D5063ABAC3506EBEF /* Pods_Runner.framework */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -60,11 +62,13 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 12B6DA19D15460159D3C28F4 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; + 131C8BFB6EFD785F48B1CD75 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; - 33CC10ED2044A3C60003C045 /* playx_localization_example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "playx_localization_example.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + 33CC10ED2044A3C60003C045 /* playx_localization_example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = playx_localization_example.app; sourceTree = BUILT_PRODUCTS_DIR; }; 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; @@ -76,8 +80,14 @@ 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; + 34CAEC91CC0D5EABB0F07A0B /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; + 9B24FF06405C1D7B37A85299 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + B9539FC04843A34568666C5B /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + C4A75E8D5063ABAC3506EBEF /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + C4FDF5DC35CBE98629384323 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; + C6D25D62760F056B7A8FCA8F /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -85,6 +95,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 8B44AA877385D68EC44D5391 /* Pods_RunnerTests.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -92,6 +103,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + C0386B32D6070ADD8290B582 /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -125,6 +137,7 @@ 331C80D6294CF71000263BE5 /* RunnerTests */, 33CC10EE2044A3C60003C045 /* Products */, D73912EC22F37F3D000D13A0 /* Frameworks */, + 55B9EC6008FF5A7ED8E13E22 /* Pods */, ); sourceTree = ""; }; @@ -172,9 +185,25 @@ path = Runner; sourceTree = ""; }; + 55B9EC6008FF5A7ED8E13E22 /* Pods */ = { + isa = PBXGroup; + children = ( + B9539FC04843A34568666C5B /* Pods-Runner.debug.xcconfig */, + 9B24FF06405C1D7B37A85299 /* Pods-Runner.release.xcconfig */, + 34CAEC91CC0D5EABB0F07A0B /* Pods-Runner.profile.xcconfig */, + C6D25D62760F056B7A8FCA8F /* Pods-RunnerTests.debug.xcconfig */, + 12B6DA19D15460159D3C28F4 /* Pods-RunnerTests.release.xcconfig */, + C4FDF5DC35CBE98629384323 /* Pods-RunnerTests.profile.xcconfig */, + ); + name = Pods; + path = Pods; + sourceTree = ""; + }; D73912EC22F37F3D000D13A0 /* Frameworks */ = { isa = PBXGroup; children = ( + C4A75E8D5063ABAC3506EBEF /* Pods_Runner.framework */, + 131C8BFB6EFD785F48B1CD75 /* Pods_RunnerTests.framework */, ); name = Frameworks; sourceTree = ""; @@ -186,6 +215,7 @@ isa = PBXNativeTarget; buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; buildPhases = ( + 156CD16E2CA168FE8400C308 /* [CP] Check Pods Manifest.lock */, 331C80D1294CF70F00263BE5 /* Sources */, 331C80D2294CF70F00263BE5 /* Frameworks */, 331C80D3294CF70F00263BE5 /* Resources */, @@ -204,11 +234,13 @@ isa = PBXNativeTarget; buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( + 85F6AC850285891EA27470F9 /* [CP] Check Pods Manifest.lock */, 33CC10E92044A3C60003C045 /* Sources */, 33CC10EA2044A3C60003C045 /* Frameworks */, 33CC10EB2044A3C60003C045 /* Resources */, 33CC110E2044A8840003C045 /* Bundle Framework */, 3399D490228B24CF009A79C7 /* ShellScript */, + 3ECC30B42FC4F8B10FD7A893 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -291,6 +323,28 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ + 156CD16E2CA168FE8400C308 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; 3399D490228B24CF009A79C7 /* ShellScript */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; @@ -329,6 +383,45 @@ shellPath = /bin/sh; shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; }; + 3ECC30B42FC4F8B10FD7A893 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + 85F6AC850285891EA27470F9 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -380,6 +473,7 @@ /* Begin XCBuildConfiguration section */ 331C80DB294CF71000263BE5 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = C6D25D62760F056B7A8FCA8F /* Pods-RunnerTests.debug.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CURRENT_PROJECT_VERSION = 1; @@ -394,6 +488,7 @@ }; 331C80DC294CF71000263BE5 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 12B6DA19D15460159D3C28F4 /* Pods-RunnerTests.release.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CURRENT_PROJECT_VERSION = 1; @@ -408,6 +503,7 @@ }; 331C80DD294CF71000263BE5 /* Profile */ = { isa = XCBuildConfiguration; + baseConfigurationReference = C4FDF5DC35CBE98629384323 /* Pods-RunnerTests.profile.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CURRENT_PROJECT_VERSION = 1; diff --git a/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index a2ebdcc..f35dc28 100644 --- a/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -59,6 +59,7 @@ ignoresPersistentStateOnLaunch = "NO" debugDocumentVersioning = "YES" debugServiceExtension = "internal" + enableGPUValidationMode = "1" allowLocationSimulation = "YES"> diff --git a/example/macos/Runner.xcworkspace/contents.xcworkspacedata b/example/macos/Runner.xcworkspace/contents.xcworkspacedata index 1d526a1..21a3cc1 100644 --- a/example/macos/Runner.xcworkspace/contents.xcworkspacedata +++ b/example/macos/Runner.xcworkspace/contents.xcworkspacedata @@ -4,4 +4,7 @@ + + diff --git a/example/pubspec.lock b/example/pubspec.lock index d4fac28..f767bb1 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -1,54 +1,54 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: - args: + ansicolor: dependency: transitive description: - name: args - sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596 + name: ansicolor + sha256: "50e982d500bc863e1d703448afdbf9e5a72eb48840a4f766fa361ffd6877055f" url: "https://pub.dev" source: hosted - version: "2.4.2" + version: "2.0.3" async: dependency: transitive description: name: async - sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" + sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb" url: "https://pub.dev" source: hosted - version: "2.11.0" + version: "2.13.0" boolean_selector: dependency: transitive description: name: boolean_selector - sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.2" characters: dependency: transitive description: name: characters - sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" + sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 url: "https://pub.dev" source: hosted - version: "1.3.0" + version: "1.4.0" clock: dependency: transitive description: name: clock - sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.1.2" collection: dependency: transitive description: name: collection - sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf + sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" url: "https://pub.dev" source: hosted - version: "1.19.0" + version: "1.19.1" cupertino_icons: dependency: "direct main" description: @@ -57,22 +57,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.8" - easy_localization: - dependency: transitive - description: - name: easy_localization - sha256: fa59bcdbbb911a764aa6acf96bbb6fa7a5cf8234354fc45ec1a43a0349ef0201 - url: "https://pub.dev" - source: hosted - version: "3.0.7" - easy_logger: - dependency: transitive - description: - name: easy_logger - sha256: c764a6e024846f33405a2342caf91c62e357c24b02c04dbc712ef232bf30ffb7 - url: "https://pub.dev" - source: hosted - version: "0.0.2" equatable: dependency: transitive description: @@ -85,26 +69,26 @@ packages: dependency: transitive description: name: fake_async - sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" url: "https://pub.dev" source: hosted - version: "1.3.1" + version: "1.3.3" ffi: dependency: transitive description: name: ffi - sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6" + sha256: "289279317b4b16eb2bb7e271abccd4bf84ec9bdcbe999e278a94b804f5630418" url: "https://pub.dev" source: hosted - version: "2.1.3" + version: "2.1.4" file: dependency: transitive description: name: file - sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d" + sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 url: "https://pub.dev" source: hosted - version: "6.1.4" + version: "7.0.1" flutter: dependency: "direct main" description: flutter @@ -122,10 +106,10 @@ packages: dependency: "direct dev" description: name: flutter_lints - sha256: "3f41d009ba7172d5ff9be5f6e6e6abb4300e263aab8866d2a0842ed2a70f8f0c" + sha256: "3105dc8492f6183fb076ccf1f351ac3d60564bff92e20bfc4af9cc1651f4e7e1" url: "https://pub.dev" source: hosted - version: "4.0.0" + version: "6.0.0" flutter_localizations: dependency: transitive description: flutter @@ -143,10 +127,10 @@ packages: dependency: transitive description: name: flutter_secure_storage_linux - sha256: bf7404619d7ab5c0a1151d7c4e802edad8f33535abfbeff2f9e1fe1274e2d705 + sha256: be76c1d24a97d0b98f8b54bce6b481a380a6590df992d0098f868ad54dc8f688 url: "https://pub.dev" source: hosted - version: "1.2.2" + version: "1.2.3" flutter_secure_storage_macos: dependency: transitive description: @@ -201,10 +185,10 @@ packages: dependency: transitive description: name: intl - sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf + sha256: "3df61194eb431efc39c4ceba583b95633a403f46c9fd341e550ce0bfa50e9aa5" url: "https://pub.dev" source: hosted - version: "0.19.0" + version: "0.20.2" js: dependency: transitive description: @@ -217,18 +201,18 @@ packages: dependency: transitive description: name: leak_tracker - sha256: "7bb2830ebd849694d1ec25bf1f44582d6ac531a57a365a803a6034ff751d2d06" + sha256: "6bb818ecbdffe216e81182c2f0714a2e62b593f4a4f13098713ff1685dfb6ab0" url: "https://pub.dev" source: hosted - version: "10.0.7" + version: "10.0.9" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: "9491a714cca3667b60b5c420da8217e6de0d1ba7a5ec322fab01758f6998f379" + sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573 url: "https://pub.dev" source: hosted - version: "3.0.8" + version: "3.0.9" leak_tracker_testing: dependency: transitive description: @@ -241,18 +225,18 @@ packages: dependency: transitive description: name: lints - sha256: "976c774dd944a42e83e2467f4cc670daef7eed6295b10b36ae8c85bcbf828235" + sha256: a5e2b223cb7c9c8efdc663ef484fdd95bb243bff242ef5b13e26883547fce9a0 url: "https://pub.dev" source: hosted - version: "4.0.0" + version: "6.0.0" matcher: dependency: transitive description: name: matcher - sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb + sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 url: "https://pub.dev" source: hosted - version: "0.12.16+1" + version: "0.12.17" material_color_utilities: dependency: transitive description: @@ -265,89 +249,89 @@ packages: dependency: transitive description: name: meta - sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 + sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c url: "https://pub.dev" source: hosted - version: "1.15.0" + version: "1.16.0" path: dependency: transitive description: name: path - sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" + sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" url: "https://pub.dev" source: hosted - version: "1.9.0" + version: "1.9.1" path_provider: dependency: transitive description: name: path_provider - sha256: "3087813781ab814e4157b172f1a11c46be20179fcc9bea043e0fba36bc0acaa2" + sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd" url: "https://pub.dev" source: hosted - version: "2.0.15" + version: "2.1.5" path_provider_android: dependency: transitive description: name: path_provider_android - sha256: "2cec049d282c7f13c594b4a73976b0b4f2d7a1838a6dd5aaf7bd9719196bee86" + sha256: d0d310befe2c8ab9e7f393288ccbb11b60c019c6b5afc21973eeee4dda2b35e9 url: "https://pub.dev" source: hosted - version: "2.0.27" + version: "2.2.17" path_provider_foundation: dependency: transitive description: name: path_provider_foundation - sha256: "916731ccbdce44d545414dd9961f26ba5fbaa74bcbb55237d8e65a623a8c7297" + sha256: "4843174df4d288f5e29185bd6e72a6fbdf5a4a4602717eed565497429f179942" url: "https://pub.dev" source: hosted - version: "2.2.4" + version: "2.4.1" path_provider_linux: dependency: transitive description: name: path_provider_linux - sha256: ffbb8cc9ed2c9ec0e4b7a541e56fd79b138e8f47d2fb86815f15358a349b3b57 + sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279 url: "https://pub.dev" source: hosted - version: "2.1.11" + version: "2.2.1" path_provider_platform_interface: dependency: transitive description: name: path_provider_platform_interface - sha256: "57585299a729335f1298b43245842678cb9f43a6310351b18fb577d6e33165ec" + sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334" url: "https://pub.dev" source: hosted - version: "2.0.6" + version: "2.1.2" path_provider_windows: dependency: transitive description: name: path_provider_windows - sha256: "1cb68ba4cd3a795033de62ba1b7b4564dace301f952de6bfb3cd91b202b6ee96" + sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7 url: "https://pub.dev" source: hosted - version: "2.1.7" + version: "2.3.0" platform: dependency: transitive description: name: platform - sha256: "4a451831508d7d6ca779f7ac6e212b4023dd5a7d08a27a63da33756410e32b76" + sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984" url: "https://pub.dev" source: hosted - version: "3.1.0" + version: "3.1.6" playx_core: dependency: transitive description: name: playx_core - sha256: "22366f8a8cf82230eb762858f009cf4c46616e6308c4a0ee0d6cb736264a0661" + sha256: "2ec52210e11918d2d4d86580ee9f859da434346ffb2fecbb3f903d931414f369" url: "https://pub.dev" source: hosted - version: "0.6.1" + version: "0.7.3" playx_localization: dependency: "direct main" description: path: ".." relative: true source: path - version: "0.2.2" + version: "0.3.0" plugin_platform_interface: dependency: transitive description: @@ -360,26 +344,26 @@ packages: dependency: transitive description: name: shared_preferences - sha256: a752ce92ea7540fc35a0d19722816e04d0e72828a4200e83a98cf1a1eb524c9a + sha256: "6e8bf70b7fef813df4e9a36f658ac46d107db4b4cfe1048b477d4e453a8159f5" url: "https://pub.dev" source: hosted - version: "2.3.5" + version: "2.5.3" shared_preferences_android: dependency: transitive description: name: shared_preferences_android - sha256: "02a7d8a9ef346c9af715811b01fbd8e27845ad2c41148eefd31321471b41863d" + sha256: "20cbd561f743a342c76c151d6ddb93a9ce6005751e7aa458baad3858bfbfb6ac" url: "https://pub.dev" source: hosted - version: "2.4.0" + version: "2.4.10" shared_preferences_foundation: dependency: transitive description: name: shared_preferences_foundation - sha256: c4b35f6cb8f63c147312c054ce7c2254c8066745125264f0c88739c417fc9d9f + sha256: "6a52cfcdaeac77cad8c97b539ff688ccfc458c007b4db12be584fbe5c0e49e03" url: "https://pub.dev" source: hosted - version: "2.5.2" + version: "2.5.4" shared_preferences_linux: dependency: transitive description: @@ -400,10 +384,10 @@ packages: dependency: transitive description: name: shared_preferences_web - sha256: d2ca4132d3946fec2184261726b355836a82c33d7d5b67af32692aff18a4684e + sha256: c49bd060261c9a3f0ff445892695d6212ff603ef3115edbb448509d407600019 url: "https://pub.dev" source: hosted - version: "2.4.2" + version: "2.4.3" shared_preferences_windows: dependency: transitive description: @@ -421,10 +405,10 @@ packages: dependency: transitive description: name: source_span - sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" + sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c" url: "https://pub.dev" source: hosted - version: "1.10.0" + version: "1.10.1" sprintf: dependency: transitive description: @@ -437,42 +421,50 @@ packages: dependency: transitive description: name: stack_trace - sha256: "9f47fd3630d76be3ab26f0ee06d213679aa425996925ff3feffdec504931c377" + sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" url: "https://pub.dev" source: hosted - version: "1.12.0" + version: "1.12.1" stream_channel: dependency: transitive description: name: stream_channel - sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 + sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.4" string_scanner: dependency: transitive description: name: string_scanner - sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3" + sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" url: "https://pub.dev" source: hosted - version: "1.3.0" + version: "1.4.1" + talker_logger: + dependency: transitive + description: + name: talker_logger + sha256: f1755d517e5ca8b119b65ad2fc1079746a8d03bd565e75d6b9d5aedf5c1d5b15 + url: "https://pub.dev" + source: hosted + version: "4.9.1" term_glyph: dependency: transitive description: name: term_glyph - sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" url: "https://pub.dev" source: hosted - version: "1.2.1" + version: "1.2.2" test_api: dependency: transitive description: name: test_api - sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c" + sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd url: "https://pub.dev" source: hosted - version: "0.7.3" + version: "0.7.4" vector_math: dependency: transitive description: @@ -485,42 +477,42 @@ packages: dependency: transitive description: name: vm_service - sha256: f6be3ed8bd01289b34d679c2b62226f63c0e69f9fd2e50a6b3c1c729a961041b + sha256: ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02 url: "https://pub.dev" source: hosted - version: "14.3.0" + version: "15.0.0" web: dependency: transitive description: name: web - sha256: d43c1d6b787bf0afad444700ae7f4db8827f701bc61c255ac8d328c6f4d52062 + sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a" url: "https://pub.dev" source: hosted - version: "1.0.0" + version: "1.1.1" win32: - dependency: "direct overridden" + dependency: transitive description: name: win32 - sha256: "68d1e89a91ed61ad9c370f9f8b6effed9ae5e0ede22a270bdfa6daf79fc2290a" + sha256: "66814138c3562338d05613a6e368ed8cfb237ad6d64a9e9334be3f309acfca03" url: "https://pub.dev" source: hosted - version: "5.5.4" + version: "5.14.0" worker_manager: dependency: transitive description: name: worker_manager - sha256: "0c6c4e7d246bcbe7221273ef955732dafb097347d536ebe6acd6547d0398c49c" + sha256: af3db5e6c6c8a74ab8f72e25e9d305f8ff60984ca55551397e3c8828ebf30509 url: "https://pub.dev" source: hosted - version: "7.2.2" + version: "7.2.6" xdg_directories: dependency: transitive description: name: xdg_directories - sha256: e0b1147eec179d3911f1f19b59206448f78195ca1d20514134e10641b7d7fbff + sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15" url: "https://pub.dev" source: hosted - version: "1.0.1" + version: "1.1.0" sdks: - dart: ">=3.5.0 <4.0.0" - flutter: ">=3.24.0" + dart: ">=3.8.0 <4.0.0" + flutter: ">=3.27.0" diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 96740ea..9e23c53 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -13,14 +13,12 @@ dependencies: playx_localization: path: ../ -dependency_overrides: - win32: ^5.5.4 dev_dependencies: flutter_test: sdk: flutter - flutter_lints: ^4.0.0 + flutter_lints: ^6.0.0 flutter: From 015ca8748213377cca73fc3c58243363c9bc5cb0 Mon Sep 17 00:00:00 2001 From: basemosama Date: Tue, 1 Jul 2025 14:41:18 +0300 Subject: [PATCH 08/10] refactor: Enhance localization logging and builder - Improved logging in `PlayxLocalizationController` to include locale name, string representation, and index. - Wrapped the builder in `PlayxLocalizationBuilder` with `Localizations` widget to ensure proper localization context. --- lib/src/controller/controller.dart | 6 +----- lib/src/widgets/playx_localization_builder.dart | 5 ++++- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/lib/src/controller/controller.dart b/lib/src/controller/controller.dart index af37ee2..afcc547 100644 --- a/lib/src/controller/controller.dart +++ b/lib/src/controller/controller.dart @@ -76,12 +76,8 @@ class PlayxLocaleController extends ValueNotifier { lastKnownIndex ?? -1, ); - logger.i( - 'Last Saved Locale ${lastSavedLocale?.locale.toStringWithSeparator()}'); - final locale = _getStartLocale(savedLocale: lastSavedLocale); - logger.i('Start Locale ${locale.locale.toStringWithSeparator()}'); //Load translations from assets await loadTranslations(locale); @@ -94,7 +90,7 @@ class PlayxLocaleController extends ValueNotifier { value = locale; logger.i( - 'Translation booted with ${locale.locale.toStringWithSeparator()} with index $currentIndex'); + 'Translation booted with locale ${locale.name} -> ${locale.toStringWithSeparator()} at index ${supportedXLocales.indexOf(locale)}'); } /// Retrieves the last saved theme index from preferences. diff --git a/lib/src/widgets/playx_localization_builder.dart b/lib/src/widgets/playx_localization_builder.dart index 33c4d73..640633f 100644 --- a/lib/src/widgets/playx_localization_builder.dart +++ b/lib/src/widgets/playx_localization_builder.dart @@ -28,7 +28,10 @@ class PlayxLocalizationBuilder extends StatelessWidget { } return PlayxInheritedLocalization( locale: xLocale, - child: builder(context, xLocale), + child: Localizations( + locale: xLocale.locale, + delegates: controller.delegates, + child: builder(context, xLocale)), ); }, ); From 99c8fa33dc6a5c9bf74c977815ac4d02b11d6425 Mon Sep 17 00:00:00 2001 From: basemosama Date: Tue, 1 Jul 2025 14:50:16 +0300 Subject: [PATCH 09/10] chore: Update CHANGELOG for version 0.3.0 with enhancements and new extensions --- CHANGELOG.md | 38 +++++++++++++++++++++++++++++++++++++ lib/playx_localization.dart | 1 + 2 files changed, 39 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 491c1ab..bea86bb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,43 @@ # Changelog +## 0.3.0 + +### Enhancements + +* **Improved Delegate Configuration**: + + * Added `extraDelegates` to inject custom localization delegates. + * Added `customLocalizationDelegateBuilder` to fully customize the delegate list. +* **Logging Enhancements**: + + * Added `logLocaleChanges` toggle in `PlayxLocaleConfig`. + * Improved logs to show locale name, value, and index. + +* Removed `easy_localization` dependency; replaced with a custom, flexible system. + +### New Extensions + +#### `BuildContext` Locale Helpers + +* Easily access locale info like `currentLocale`, `localeTag`, `languageCode`, `isRtl`, `fontFamily`, and more. + +#### Number Extensions + +* Enhanced currency formatting with `toFormattedCurrencyNumber` and `toLocalizedCurrencyNumber`. +* Added format options to all localized number methods. +* New `isZero` utility for floating-point comparisons. + +#### String Localization Extensions + +* Check for RTL/LTR, Arabic/English text, numbers, and diacritics. +* Convert digits between Arabic and Western formats. +* Normalize Arabic letters and clean up extra spaces. + +#### Locale Utilities + +* New extensions for `Locale`, `XLocale`, and `String` for parsing and formatting. + + ## 0.2.2 - Update packages. diff --git a/lib/playx_localization.dart b/lib/playx_localization.dart index 0d36835..4fbb02f 100644 --- a/lib/playx_localization.dart +++ b/lib/playx_localization.dart @@ -13,5 +13,6 @@ export 'package:playx_localization/src/playx_localization.dart'; export 'package:playx_localization/src/widgets/playx_localization_builder.dart'; export 'package:playx_localization/src/widgets/playx_inherited_localization.dart'; export 'package:playx_localization/src/extensions/locale_extensions.dart'; +export 'package:playx_localization/src/easy_localization/asset_loader.dart'; From b51799961cdcc250fcb0f809ec51cc1437a2e4d4 Mon Sep 17 00:00:00 2001 From: basemosama Date: Tue, 1 Jul 2025 14:52:52 +0300 Subject: [PATCH 10/10] refactor: code cleanup --- example/lib/main.dart | 46 +++++++++---------- lib/playx_localization.dart | 2 - lib/src/config/playx_locale_config.dart | 4 +- lib/src/controller/controller.dart | 10 ++-- lib/src/controller/translation_manager.dart | 16 ++++--- .../delegate/playx_localization_delegate.dart | 1 - lib/src/easy_localization/asset_loader.dart | 2 +- lib/src/extensions/locale_extensions.dart | 5 +- .../localization_string_extensions.dart | 20 ++++---- .../playx_localization_extensions.dart | 5 -- lib/src/playx_localization.dart | 2 - .../widgets/playx_localization_builder.dart | 1 - 12 files changed, 49 insertions(+), 65 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index 711d2d2..30daaf5 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -43,7 +43,8 @@ class MyHomePage extends StatelessWidget { @override Widget build(BuildContext context) { - print('Current Locale: ${PlayxLocalization.currentLocale} context :${context.locale.toStringWithSeparator()}'); + print( + 'Current Locale: ${PlayxLocalization.currentLocale} context :${context.locale.toStringWithSeparator()}'); return Scaffold( appBar: AppBar( title: Text( @@ -60,10 +61,10 @@ class MyHomePage extends StatelessWidget { style: TextStyle( fontSize: 18, color: - ('${context.tr(AppTrans.changeLanguageTitle)} : بلاي') - .isArabic - ? Colors.blueAccent - : Colors.black), + ('${context.tr(AppTrans.changeLanguageTitle)} : بلاي') + .isArabic + ? Colors.blueAccent + : Colors.black), ), const SizedBox( height: 20, @@ -73,7 +74,7 @@ class MyHomePage extends StatelessWidget { showDialog( context: context, builder: (ctx) => Center( - child: Card( + child: Card( margin: const EdgeInsets.all(8), child: Column( mainAxisSize: MainAxisSize.min, @@ -85,23 +86,22 @@ class MyHomePage extends StatelessWidget { ), ...PlayxLocalization.supportedXLocales .map((e) => ListTile( - onTap: () { - PlayxLocalization.updateById( - e.id, - forceAppUpdate: false); - Navigator.pop(ctx); - }, - title: Text(e.name), - trailing: PlayxLocalization - .currentXLocale.id == - e.id - ? const Icon( - Icons.done, - color: Colors.lightBlue, - ) - : const SizedBox.shrink(), - )) - , + onTap: () { + PlayxLocalization.updateById( + e.id, + forceAppUpdate: false); + Navigator.pop(ctx); + }, + title: Text(e.name), + trailing: PlayxLocalization + .currentXLocale.id == + e.id + ? const Icon( + Icons.done, + color: Colors.lightBlue, + ) + : const SizedBox.shrink(), + )), ], ), ))); diff --git a/lib/playx_localization.dart b/lib/playx_localization.dart index 4fbb02f..bfc8bba 100644 --- a/lib/playx_localization.dart +++ b/lib/playx_localization.dart @@ -14,5 +14,3 @@ export 'package:playx_localization/src/widgets/playx_localization_builder.dart'; export 'package:playx_localization/src/widgets/playx_inherited_localization.dart'; export 'package:playx_localization/src/extensions/locale_extensions.dart'; export 'package:playx_localization/src/easy_localization/asset_loader.dart'; - - diff --git a/lib/src/config/playx_locale_config.dart b/lib/src/config/playx_locale_config.dart index 509b782..bd17e4a 100644 --- a/lib/src/config/playx_locale_config.dart +++ b/lib/src/config/playx_locale_config.dart @@ -2,7 +2,6 @@ import 'package:flutter/cupertino.dart'; import 'package:playx_localization/src/delegate/playx_localization_delegate.dart'; import '../../playx_localization.dart'; -import '../easy_localization/asset_loader.dart'; /// Locale config : /// used to configure out app locales by providing the app with the supported locales and localization settings. @@ -67,7 +66,8 @@ class PlayxLocaleConfig { /// Custom localization delegate builder. /// This allows you to create a custom list of delegates based on the provided [PlayxLocalizationDelegate]. - final List Function(PlayxLocalizationDelegate delegate)? customLocalizationDelegateBuilder; + final List Function( + PlayxLocalizationDelegate delegate)? customLocalizationDelegateBuilder; PlayxLocaleConfig({ required this.supportedLocales, diff --git a/lib/src/controller/controller.dart b/lib/src/controller/controller.dart index afcc547..e39036c 100644 --- a/lib/src/controller/controller.dart +++ b/lib/src/controller/controller.dart @@ -4,7 +4,6 @@ import 'package:intl/intl_standalone.dart'; import 'package:playx_localization/playx_localization.dart'; import 'package:playx_localization/src/delegate/playx_localization_delegate.dart'; import 'package:playx_localization/src/easy_localization/translations.dart'; -import 'package:playx_localization/src/extensions/locale_extensions.dart'; import '../easy_localization/localization.dart'; import 'translation_manager.dart'; @@ -47,7 +46,8 @@ class PlayxLocaleController extends ValueNotifier { // Returns the device locale. Locale? deviceLocale; - static PlayxBaseLogger? get logger => PlayxLogger.getLogger('Playx Localization'); + static PlayxBaseLogger? get logger => + PlayxLogger.getLogger('Playx Localization'); /// current locale index int get currentIndex { @@ -78,7 +78,6 @@ class PlayxLocaleController extends ValueNotifier { final locale = _getStartLocale(savedLocale: lastSavedLocale); - //Load translations from assets await loadTranslations(locale); logger.i('Loaded Translation from assets'); @@ -196,7 +195,7 @@ class PlayxLocaleController extends ValueNotifier { /// if [forceAppUpdate] is true it will force the app to update. Future nextLocale({bool forceAppUpdate = false}) async { final isLastLocale = currentIndex == config.supportedLocales.length - 1; - final index= isLastLocale? 0 : currentIndex + 1; + final index = isLastLocale ? 0 : currentIndex + 1; await updateByIndex( index, @@ -211,7 +210,8 @@ class PlayxLocaleController extends ValueNotifier { final locale = config.supportedLocales.atOrNull(index); if (locale == null) { if (config.logLocaleChanges) { - logger?.error('Locale with index $index not found in supported Locales'); + logger + ?.error('Locale with index $index not found in supported Locales'); } return false; } diff --git a/lib/src/controller/translation_manager.dart b/lib/src/controller/translation_manager.dart index a1e484a..f6ab38f 100644 --- a/lib/src/controller/translation_manager.dart +++ b/lib/src/controller/translation_manager.dart @@ -4,7 +4,6 @@ import 'package:flutter/foundation.dart'; import 'package:playx_localization/playx_localization.dart'; import 'package:playx_localization/src/controller/controller.dart'; import 'package:playx_localization/src/easy_localization/translations.dart'; -import 'package:playx_localization/src/extensions/locale_extensions.dart'; class TranslationManager { TranslationManager._(); @@ -46,12 +45,14 @@ class TranslationManager { ); } return (translations: translations, fallbackTranslations: null); - } on FlutterError catch (e,s) { + } on FlutterError catch (e, s) { // onLoadError(e); - PlayxLocaleController.logger?.error('Error loading translations: ',error: e, stackTrace: s); + PlayxLocaleController.logger + ?.error('Error loading translations: ', error: e, stackTrace: s); return (translations: null, fallbackTranslations: null); - } catch (e,s) { - PlayxLocaleController.logger?.error('Error loading translations: ',error: e, stackTrace: s); + } catch (e, s) { + PlayxLocaleController.logger + ?.error('Error loading translations: ', error: e, stackTrace: s); // onLoadError(FlutterError(e.toString())); return ( translations: null, @@ -64,9 +65,10 @@ class TranslationManager { {required XLocale locale, required PlayxLocaleConfig config}) async { try { return await loadTranslationData(locale: locale, config: config); - } on FlutterError catch (e,s) { + } on FlutterError catch (e, s) { // Disregard asset not found FlutterError when attempting to load base language fallback - PlayxLocaleController.logger?.error('Error loading translations: ',error: e, stackTrace: s); + PlayxLocaleController.logger + ?.error('Error loading translations: ', error: e, stackTrace: s); } return null; } diff --git a/lib/src/delegate/playx_localization_delegate.dart b/lib/src/delegate/playx_localization_delegate.dart index b869935..8f96597 100644 --- a/lib/src/delegate/playx_localization_delegate.dart +++ b/lib/src/delegate/playx_localization_delegate.dart @@ -1,7 +1,6 @@ import 'package:flutter/material.dart'; import 'package:playx_localization/playx_localization.dart'; import 'package:playx_localization/src/controller/controller.dart'; -import 'package:playx_localization/src/extensions/locale_extensions.dart'; import '../easy_localization/localization.dart'; diff --git a/lib/src/easy_localization/asset_loader.dart b/lib/src/easy_localization/asset_loader.dart index 687b841..7858df3 100644 --- a/lib/src/easy_localization/asset_loader.dart +++ b/lib/src/easy_localization/asset_loader.dart @@ -35,4 +35,4 @@ class RootBundleAssetLoader extends AssetLoader { var localePath = getLocalePath(path, locale); return json.decode(await rootBundle.loadString(localePath)); } -} \ No newline at end of file +} diff --git a/lib/src/extensions/locale_extensions.dart b/lib/src/extensions/locale_extensions.dart index d8c1fe3..8fd7682 100644 --- a/lib/src/extensions/locale_extensions.dart +++ b/lib/src/extensions/locale_extensions.dart @@ -37,13 +37,10 @@ extension LocaleExtension on Locale { } } - extension XLocaleExtension on XLocale { Locale get locale => Locale(languageCode, countryCode); String toStringWithSeparator({String separator = '-'}) { return locale.toStringWithSeparator(separator: separator); } - - -} \ No newline at end of file +} diff --git a/lib/src/extensions/localization_string_extensions.dart b/lib/src/extensions/localization_string_extensions.dart index 1d66975..0c6ac8a 100644 --- a/lib/src/extensions/localization_string_extensions.dart +++ b/lib/src/extensions/localization_string_extensions.dart @@ -1,7 +1,5 @@ import 'dart:ui'; -import 'package:intl/intl.dart'; - import '../../playx_localization.dart'; /// Extension on [String] to help with localization and language-specific analysis. @@ -34,17 +32,16 @@ extension LocalizationStringExtensions on String { bool get isArabic => _arabicRegExp.hasMatch(this); /// Returns `true` if the string contains **only Arabic** letters (and spaces). - bool get containsOnlyArabic => _onlyArabicRegExp.hasMatch(this.trim()); + bool get containsOnlyArabic => _onlyArabicRegExp.hasMatch(trim()); /// Returns `true` if the string contains **only English** letters (and spaces). - bool get containsOnlyEnglish => _onlyEnglishRegExp.hasMatch(this.trim()); + bool get containsOnlyEnglish => _onlyEnglishRegExp.hasMatch(trim()); /// Returns `true` if the string contains **any numeric** digits. bool get hasNumbers => _numberRegExp.hasMatch(this); - /// A list of Arabic diacritics (tashkeel) used in the Arabic language. - static const List _diacritics = [ + static const List _diacritics = [ '\u064B', // fathatan '\u064C', // dammatan '\u064D', // kasratan @@ -91,7 +88,8 @@ extension LocalizationStringExtensions on String { /// Converts the string to localized digits based on the current locale. String toLocalizedDigits({String? locale, bool toArabic = true}) { - final formatLocale = locale ?? PlayxLocalization.currentLocale.toLanguageTag(); + final formatLocale = + locale ?? PlayxLocalization.currentLocale.toLanguageTag(); if (formatLocale.startsWith('ar') && toArabic) { return toArabicIndicDigits(); } @@ -110,7 +108,6 @@ extension LocalizationStringExtensions on String { return trim().replaceAll(RegExp(r'\s+'), ' '); } - /// Convert string to [Locale] object Locale toLocale({String separator = '_'}) { final localeList = split(separator); @@ -118,9 +115,9 @@ extension LocalizationStringExtensions on String { case 2: return localeList.last.length == 4 // scriptCode length is 4 ? Locale.fromSubtags( - languageCode: localeList.first, - scriptCode: localeList.last, - ) + languageCode: localeList.first, + scriptCode: localeList.last, + ) : Locale(localeList.first, localeList.last); case 3: return Locale.fromSubtags( @@ -132,5 +129,4 @@ extension LocalizationStringExtensions on String { return Locale(localeList.first); } } - } diff --git a/lib/src/extensions/playx_localization_extensions.dart b/lib/src/extensions/playx_localization_extensions.dart index fe44d73..fb8deb1 100644 --- a/lib/src/extensions/playx_localization_extensions.dart +++ b/lib/src/extensions/playx_localization_extensions.dart @@ -1,11 +1,8 @@ import 'package:flutter/material.dart'; -import 'package:intl/intl.dart'; import 'package:playx_localization/playx_localization.dart'; import 'package:playx_localization/src/easy_localization/public.dart' as ez; -import 'package:playx_localization/src/extensions/locale_extensions.dart'; import '../easy_localization/localization.dart'; -import '../widgets/playx_inherited_localization.dart'; /// Strings extension method for access to [tr] and [plural()] /// Example : @@ -208,7 +205,6 @@ extension BuildContextLocalizationExtension on BuildContext { ); } - /// Returns the current `XLocale` object with locale and font info. XLocale get currentXLocale { final locale = PlayxInheritedLocalization.of(this); @@ -238,5 +234,4 @@ extension BuildContextLocalizationExtension on BuildContext { /// Returns true if the current locale is LTR. bool get isLtr => !isRtl; - } diff --git a/lib/src/playx_localization.dart b/lib/src/playx_localization.dart index 1744f21..403a329 100644 --- a/lib/src/playx_localization.dart +++ b/lib/src/playx_localization.dart @@ -16,8 +16,6 @@ abstract class PlayxLocalization { static PlayxLocaleController get _controller => PlayxLocaleController.controller; - - ///Setup the current app locales with your configuration. ///And loads app supported translations. /// Must be called before calling any other method to initialize dependencies. diff --git a/lib/src/widgets/playx_localization_builder.dart b/lib/src/widgets/playx_localization_builder.dart index 640633f..3034a31 100644 --- a/lib/src/widgets/playx_localization_builder.dart +++ b/lib/src/widgets/playx_localization_builder.dart @@ -1,7 +1,6 @@ import 'package:flutter/material.dart'; import 'package:playx_localization/playx_localization.dart'; import 'package:playx_localization/src/controller/controller.dart'; -import 'package:playx_localization/src/widgets/playx_inherited_localization.dart'; /// PlayxLocalizationBuilder: /// It allows us to create a widget with current locale.