├── example ├── ios │ ├── Runner │ │ ├── ar-DZ.lproj │ │ │ ├── Main.strings │ │ │ └── LaunchScreen.strings │ │ ├── ru.lproj │ │ │ ├── Main.strings │ │ │ └── LaunchScreen.strings │ │ ├── Runner-Bridging-Header.h │ │ ├── Assets.xcassets │ │ │ ├── LaunchImage.imageset │ │ │ │ ├── LaunchImage.png │ │ │ │ ├── LaunchImage@2x.png │ │ │ │ ├── LaunchImage@3x.png │ │ │ │ ├── README.md │ │ │ │ └── Contents.json │ │ │ └── AppIcon.appiconset │ │ │ │ ├── Icon-App-20x20@1x.png │ │ │ │ ├── Icon-App-20x20@2x.png │ │ │ │ ├── Icon-App-20x20@3x.png │ │ │ │ ├── Icon-App-29x29@1x.png │ │ │ │ ├── Icon-App-29x29@2x.png │ │ │ │ ├── Icon-App-29x29@3x.png │ │ │ │ ├── Icon-App-40x40@1x.png │ │ │ │ ├── Icon-App-40x40@2x.png │ │ │ │ ├── Icon-App-40x40@3x.png │ │ │ │ ├── Icon-App-60x60@2x.png │ │ │ │ ├── Icon-App-60x60@3x.png │ │ │ │ ├── Icon-App-76x76@1x.png │ │ │ │ ├── Icon-App-76x76@2x.png │ │ │ │ ├── Icon-App-1024x1024@1x.png │ │ │ │ ├── Icon-App-83.5x83.5@2x.png │ │ │ │ └── Contents.json │ │ ├── AppDelegate.swift │ │ ├── Base.lproj │ │ │ ├── Main.storyboard │ │ │ └── LaunchScreen.storyboard │ │ └── Info.plist │ ├── Flutter │ │ ├── .last_build_id │ │ ├── Debug.xcconfig │ │ ├── Release.xcconfig │ │ └── AppFrameworkInfo.plist │ ├── Runner.xcodeproj │ │ ├── project.xcworkspace │ │ │ ├── contents.xcworkspacedata │ │ │ └── xcshareddata │ │ │ │ ├── WorkspaceSettings.xcsettings │ │ │ │ └── IDEWorkspaceChecks.plist │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ └── Runner.xcscheme │ ├── Runner.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ ├── WorkspaceSettings.xcsettings │ │ │ └── IDEWorkspaceChecks.plist │ ├── .gitignore │ └── Podfile ├── linux │ ├── .gitignore │ ├── main.cc │ ├── flutter │ │ ├── generated_plugin_registrant.cc │ │ ├── generated_plugin_registrant.h │ │ ├── generated_plugins.cmake │ │ └── CMakeLists.txt │ ├── my_application.h │ ├── CMakeLists.txt │ └── my_application.cc ├── assets │ ├── lang │ │ ├── en.json │ │ └── ar.json │ └── fonts │ │ └── MyFlutterApp.ttf ├── web │ ├── favicon.png │ ├── icons │ │ ├── Icon-192.png │ │ └── Icon-512.png │ ├── manifest.json │ └── index.html ├── android │ ├── gradle.properties │ ├── app │ │ ├── src │ │ │ ├── main │ │ │ │ ├── res │ │ │ │ │ ├── mipmap-hdpi │ │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ ├── mipmap-mdpi │ │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ ├── mipmap-xhdpi │ │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ ├── drawable │ │ │ │ │ │ └── launch_background.xml │ │ │ │ │ ├── drawable-v21 │ │ │ │ │ │ └── launch_background.xml │ │ │ │ │ ├── values │ │ │ │ │ │ └── styles.xml │ │ │ │ │ └── values-night │ │ │ │ │ │ └── styles.xml │ │ │ │ ├── kotlin │ │ │ │ │ └── net │ │ │ │ │ │ └── msayed │ │ │ │ │ │ └── example │ │ │ │ │ │ └── example │ │ │ │ │ │ └── MainActivity.kt │ │ │ │ └── AndroidManifest.xml │ │ │ ├── debug │ │ │ │ └── AndroidManifest.xml │ │ │ └── profile │ │ │ │ └── AndroidManifest.xml │ │ └── build.gradle │ ├── gradle │ │ └── wrapper │ │ │ └── gradle-wrapper.properties │ ├── .gitignore │ ├── build.gradle │ └── settings.gradle ├── macos │ ├── Runner │ │ ├── Configs │ │ │ ├── Debug.xcconfig │ │ │ ├── Release.xcconfig │ │ │ ├── Warnings.xcconfig │ │ │ └── AppInfo.xcconfig │ │ ├── Assets.xcassets │ │ │ └── AppIcon.appiconset │ │ │ │ ├── app_icon_128.png │ │ │ │ ├── app_icon_16.png │ │ │ │ ├── app_icon_256.png │ │ │ │ ├── app_icon_32.png │ │ │ │ ├── app_icon_512.png │ │ │ │ ├── app_icon_64.png │ │ │ │ ├── app_icon_1024.png │ │ │ │ └── Contents.json │ │ ├── AppDelegate.swift │ │ ├── Release.entitlements │ │ ├── DebugProfile.entitlements │ │ ├── MainFlutterWindow.swift │ │ ├── Info.plist │ │ └── Base.lproj │ │ │ └── MainMenu.xib │ ├── .gitignore │ ├── Flutter │ │ ├── Flutter-Debug.xcconfig │ │ ├── Flutter-Release.xcconfig │ │ └── GeneratedPluginRegistrant.swift │ ├── Runner.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ ├── Runner.xcodeproj │ │ ├── project.xcworkspace │ │ │ └── xcshareddata │ │ │ │ └── IDEWorkspaceChecks.plist │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ └── Runner.xcscheme │ └── Podfile ├── pubspec.yaml ├── .gitignore ├── .metadata ├── analysis_options.yaml ├── lib │ └── main.dart ├── README.md └── pubspec.lock ├── logo.png ├── lang ├── ar.json ├── ar-EG.json ├── en.json └── en-US.json ├── linux └── flutter │ ├── generated_plugin_registrant.cc │ ├── generated_plugin_registrant.h │ └── generated_plugins.cmake ├── windows └── flutter │ ├── generated_plugin_registrant.cc │ ├── generated_plugin_registrant.h │ └── generated_plugins.cmake ├── lib ├── src │ ├── mappers │ │ ├── json_mapper_base.dart │ │ └── nested_json_mapper.dart │ ├── constants │ │ ├── enums.dart │ │ ├── error_messages.dart │ │ └── db_keys.dart │ ├── extensions │ │ ├── string_extensions.dart │ │ └── context_extensions.dart │ ├── exceptions │ │ └── not_found_exception.dart │ ├── assets │ │ ├── asset_loader_base.dart │ │ ├── asset_loader_root_bundle_json.dart │ │ └── asset_loader_network.dart │ ├── db │ │ ├── db_box.dart │ │ └── usecases.dart │ ├── widgets │ │ ├── localized_app.dart │ │ └── localized_app_exception.dart │ └── core │ │ └── localize_and_translate.dart └── localize_and_translate.dart ├── macos └── Flutter │ ├── GeneratedPluginRegistrant.swift │ └── ephemeral │ ├── Flutter-Generated.xcconfig │ └── flutter_export_environment.sh ├── .metadata ├── .github ├── workflows │ ├── cd.yml │ └── ci.yml └── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md ├── pubspec.yaml ├── LICENSE ├── .all-contributorsrc ├── localize_and_translate.iml ├── .gitignore ├── CHANGELOG.md ├── README.md ├── analysis_options.yaml └── pubspec.lock /example/ios/Runner/ar-DZ.lproj/Main.strings: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /example/ios/Runner/ru.lproj/Main.strings: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /example/linux/.gitignore: -------------------------------------------------------------------------------- 1 | flutter/ephemeral 2 | -------------------------------------------------------------------------------- /example/ios/Runner/ru.lproj/LaunchScreen.strings: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /example/ios/Runner/ar-DZ.lproj/LaunchScreen.strings: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /example/ios/Flutter/.last_build_id: -------------------------------------------------------------------------------- 1 | 95aad2d4f53601773338c4ce51791765 -------------------------------------------------------------------------------- /example/ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" -------------------------------------------------------------------------------- /example/assets/lang/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "change": "Change", 3 | "name": "Test App" 4 | } -------------------------------------------------------------------------------- /logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msayed-net/localize_and_translate/HEAD/logo.png -------------------------------------------------------------------------------- /example/assets/lang/ar.json: -------------------------------------------------------------------------------- 1 | { 2 | "change": "تغيير", 3 | "name": "تطبيق تجريبي" 4 | } -------------------------------------------------------------------------------- /example/web/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msayed-net/localize_and_translate/HEAD/example/web/favicon.png -------------------------------------------------------------------------------- /example/android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | -------------------------------------------------------------------------------- /example/macos/Runner/Configs/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "../../Flutter/Flutter-Debug.xcconfig" 2 | #include "Warnings.xcconfig" 3 | -------------------------------------------------------------------------------- /example/macos/.gitignore: -------------------------------------------------------------------------------- 1 | # Flutter-related 2 | **/Flutter/ephemeral/ 3 | **/Pods/ 4 | 5 | # Xcode-related 6 | **/xcuserdata/ 7 | -------------------------------------------------------------------------------- /example/macos/Runner/Configs/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "../../Flutter/Flutter-Release.xcconfig" 2 | #include "Warnings.xcconfig" 3 | -------------------------------------------------------------------------------- /example/web/icons/Icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msayed-net/localize_and_translate/HEAD/example/web/icons/Icon-192.png -------------------------------------------------------------------------------- /example/web/icons/Icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msayed-net/localize_and_translate/HEAD/example/web/icons/Icon-512.png -------------------------------------------------------------------------------- /example/assets/fonts/MyFlutterApp.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msayed-net/localize_and_translate/HEAD/example/assets/fonts/MyFlutterApp.ttf -------------------------------------------------------------------------------- /example/macos/Flutter/Flutter-Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "ephemeral/Flutter-Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /example/macos/Flutter/Flutter-Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "ephemeral/Flutter-Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msayed-net/localize_and_translate/HEAD/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msayed-net/localize_and_translate/HEAD/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msayed-net/localize_and_translate/HEAD/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msayed-net/localize_and_translate/HEAD/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msayed-net/localize_and_translate/HEAD/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msayed-net/localize_and_translate/HEAD/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msayed-net/localize_and_translate/HEAD/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png -------------------------------------------------------------------------------- /example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msayed-net/localize_and_translate/HEAD/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png -------------------------------------------------------------------------------- /example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msayed-net/localize_and_translate/HEAD/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png -------------------------------------------------------------------------------- /example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msayed-net/localize_and_translate/HEAD/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png -------------------------------------------------------------------------------- /example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msayed-net/localize_and_translate/HEAD/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png -------------------------------------------------------------------------------- /example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msayed-net/localize_and_translate/HEAD/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msayed-net/localize_and_translate/HEAD/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msayed-net/localize_and_translate/HEAD/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msayed-net/localize_and_translate/HEAD/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msayed-net/localize_and_translate/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msayed-net/localize_and_translate/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msayed-net/localize_and_translate/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msayed-net/localize_and_translate/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msayed-net/localize_and_translate/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msayed-net/localize_and_translate/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msayed-net/localize_and_translate/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msayed-net/localize_and_translate/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msayed-net/localize_and_translate/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msayed-net/localize_and_translate/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msayed-net/localize_and_translate/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msayed-net/localize_and_translate/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msayed-net/localize_and_translate/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msayed-net/localize_and_translate/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msayed-net/localize_and_translate/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /example/linux/main.cc: -------------------------------------------------------------------------------- 1 | #include "my_application.h" 2 | 3 | int main(int argc, char** argv) { 4 | g_autoptr(MyApplication) app = my_application_new(); 5 | return g_application_run(G_APPLICATION(app), argc, argv); 6 | } 7 | -------------------------------------------------------------------------------- /example/android/app/src/main/kotlin/net/msayed/example/example/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package net.msayed.example.example 2 | 3 | import io.flutter.embedding.android.FlutterActivity 4 | 5 | class MainActivity: FlutterActivity() { 6 | } 7 | -------------------------------------------------------------------------------- /example/ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 3 | #include "Generated.xcconfig" 4 | -------------------------------------------------------------------------------- /lang/ar.json: -------------------------------------------------------------------------------- 1 | { 2 | "test": "اختبار", 3 | "day": { 4 | "zero": "{} يوم", 5 | "one": "{} يوم", 6 | "two": "{} أيام", 7 | "few": "{} أيام", 8 | "many": "{} يوم", 9 | "other": "{} يوم" 10 | } 11 | } -------------------------------------------------------------------------------- /example/ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 3 | #include "Generated.xcconfig" 4 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/macos/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /lang/ar-EG.json: -------------------------------------------------------------------------------- 1 | { 2 | "test": "اختبار", 3 | "day": { 4 | "zero": "{} يوم", 5 | "one": "{} يوم", 6 | "two": "{} أيام", 7 | "few": "{} أيام", 8 | "many": "{} يوم", 9 | "other": "{} يوم" 10 | } 11 | } -------------------------------------------------------------------------------- /lang/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "test": "test", 3 | "day": { 4 | "zero": "{} days", 5 | "one": "{} day", 6 | "two": "{} days", 7 | "few": "{} few days", 8 | "many": "{} many days", 9 | "other": "{} other days" 10 | } 11 | } -------------------------------------------------------------------------------- /lang/en-US.json: -------------------------------------------------------------------------------- 1 | { 2 | "test": "test", 3 | "day": { 4 | "zero": "{} days", 5 | "one": "{} day", 6 | "two": "{} days", 7 | "few": "{} few days", 8 | "many": "{} many days", 9 | "other": "{} other days" 10 | } 11 | } -------------------------------------------------------------------------------- /linux/flutter/generated_plugin_registrant.cc: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // clang-format off 6 | 7 | #include "generated_plugin_registrant.h" 8 | 9 | 10 | void fl_register_plugins(FlPluginRegistry* registry) { 11 | } 12 | -------------------------------------------------------------------------------- /windows/flutter/generated_plugin_registrant.cc: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // clang-format off 6 | 7 | #include "generated_plugin_registrant.h" 8 | 9 | 10 | void RegisterPlugins(flutter::PluginRegistry* registry) { 11 | } 12 | -------------------------------------------------------------------------------- /example/linux/flutter/generated_plugin_registrant.cc: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // clang-format off 6 | 7 | #include "generated_plugin_registrant.h" 8 | 9 | 10 | void fl_register_plugins(FlPluginRegistry* registry) { 11 | } 12 | -------------------------------------------------------------------------------- /example/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | zipStoreBase=GRADLE_USER_HOME 4 | zipStorePath=wrapper/dists 5 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip 6 | -------------------------------------------------------------------------------- /example/macos/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | import FlutterMacOS 3 | 4 | @NSApplicationMain 5 | class AppDelegate: FlutterAppDelegate { 6 | override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { 7 | return true 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /example/macos/Runner/Release.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /lib/src/mappers/json_mapper_base.dart: -------------------------------------------------------------------------------- 1 | /// Base class for JSON mappers. 2 | abstract class JsonMapperBase { 3 | /// Flattens a nested JSON structure into a single-level map. 4 | Map flattenJson(Map json, 5 | {String parentKey = '', String? separator = '.'}); 6 | } 7 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /lib/src/constants/enums.dart: -------------------------------------------------------------------------------- 1 | /// [LocalizationDefaultType] is used to define the default type of localization 2 | enum LocalizationDefaultType { 3 | /// [device] is used to define the default type of localization as device 4 | device, 5 | 6 | /// [asDefined] is used to define the default type of localization as manual 7 | asDefined, 8 | } 9 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | 9 | # Remember to never publicly share your keystore. 10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app 11 | key.properties 12 | **/*.keystore 13 | **/*.jks 14 | -------------------------------------------------------------------------------- /macos/Flutter/GeneratedPluginRegistrant.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | import FlutterMacOS 6 | import Foundation 7 | 8 | import path_provider_foundation 9 | 10 | func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { 11 | PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) 12 | } 13 | -------------------------------------------------------------------------------- /.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: 18cd7a3601bcffb36fdf2f679f763b5e827c2e8e 8 | channel: v1.12.13-hotfixes 9 | 10 | project_type: package 11 | -------------------------------------------------------------------------------- /example/macos/Flutter/GeneratedPluginRegistrant.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | import FlutterMacOS 6 | import Foundation 7 | 8 | import path_provider_foundation 9 | 10 | func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { 11 | PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) 12 | } 13 | -------------------------------------------------------------------------------- /.github/workflows/cd.yml: -------------------------------------------------------------------------------- 1 | name: Publish to pub.dev 2 | 3 | on: 4 | push: 5 | tags: 6 | - 'v[0-9]+.[0-9]+.[0-9]+*' 7 | 8 | jobs: 9 | publish: 10 | permissions: 11 | id-token: write # Required for authentication using OIDC 12 | uses: dart-lang/setup-dart/.github/workflows/publish.yml@v1 13 | # with: 14 | # working-directory: path/to/package/within/repository -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. -------------------------------------------------------------------------------- /linux/flutter/generated_plugin_registrant.h: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // clang-format off 6 | 7 | #ifndef GENERATED_PLUGIN_REGISTRANT_ 8 | #define GENERATED_PLUGIN_REGISTRANT_ 9 | 10 | #include 11 | 12 | // Registers Flutter plugins. 13 | void fl_register_plugins(FlPluginRegistry* registry); 14 | 15 | #endif // GENERATED_PLUGIN_REGISTRANT_ 16 | -------------------------------------------------------------------------------- /windows/flutter/generated_plugin_registrant.h: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // clang-format off 6 | 7 | #ifndef GENERATED_PLUGIN_REGISTRANT_ 8 | #define GENERATED_PLUGIN_REGISTRANT_ 9 | 10 | #include 11 | 12 | // Registers Flutter plugins. 13 | void RegisterPlugins(flutter::PluginRegistry* registry); 14 | 15 | #endif // GENERATED_PLUGIN_REGISTRANT_ 16 | -------------------------------------------------------------------------------- /example/linux/flutter/generated_plugin_registrant.h: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // clang-format off 6 | 7 | #ifndef GENERATED_PLUGIN_REGISTRANT_ 8 | #define GENERATED_PLUGIN_REGISTRANT_ 9 | 10 | #include 11 | 12 | // Registers Flutter plugins. 13 | void fl_register_plugins(FlPluginRegistry* registry); 14 | 15 | #endif // GENERATED_PLUGIN_REGISTRANT_ 16 | -------------------------------------------------------------------------------- /lib/src/constants/error_messages.dart: -------------------------------------------------------------------------------- 1 | /// [ErrorMessages] contains all the error messages used in the app. 2 | class ErrorMessages { 3 | /// [ErrorMessages] constructor 4 | factory ErrorMessages() => _instance; 5 | ErrorMessages._(); 6 | static final ErrorMessages _instance = ErrorMessages._(); 7 | 8 | /// [keyNotFound] is the error message when 9 | static String keyNotFound(String key) => '$key - 404'; 10 | } 11 | -------------------------------------------------------------------------------- /example/android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/macos/Runner/DebugProfile.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | com.apple.security.cs.allow-jit 8 | 9 | com.apple.security.network.server 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /lib/src/extensions/string_extensions.dart: -------------------------------------------------------------------------------- 1 | import 'package:localize_and_translate/src/core/localize_and_translate.dart'; 2 | 3 | /// [Translation] is the extension of the [String] class. 4 | extension Translation on String { 5 | /// [tr] is the extension method that translates the string. 6 | String tr({String? defaultValue}) => LocalizeAndTranslate.translate( 7 | this, 8 | defaultValue: defaultValue, 9 | ); 10 | } 11 | -------------------------------------------------------------------------------- /lib/src/exceptions/not_found_exception.dart: -------------------------------------------------------------------------------- 1 | /// [NotFoundException] is thrown when the language code is not found in the 2 | class NotFoundException implements Exception { 3 | /// [NotFoundException] is thrown when the language code is not found in the 4 | /// [message] is the message to be shown when the exception is thrown. 5 | NotFoundException(this.message); 6 | 7 | /// [message] is the message to be shown when the exception is thrown. 8 | final String message; 9 | } 10 | -------------------------------------------------------------------------------- /example/ios/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Flutter 3 | 4 | @UIApplicationMain 5 | @objc class AppDelegate: FlutterAppDelegate { 6 | override func application( 7 | _ application: UIApplication, 8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? 9 | ) -> Bool { 10 | GeneratedPluginRegistrant.register(with: self) 11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /example/linux/my_application.h: -------------------------------------------------------------------------------- 1 | #ifndef FLUTTER_MY_APPLICATION_H_ 2 | #define FLUTTER_MY_APPLICATION_H_ 3 | 4 | #include 5 | 6 | G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, 7 | GtkApplication) 8 | 9 | /** 10 | * my_application_new: 11 | * 12 | * Creates a new Flutter-based application. 13 | * 14 | * Returns: a new #MyApplication. 15 | */ 16 | MyApplication* my_application_new(); 17 | 18 | #endif // FLUTTER_MY_APPLICATION_H_ 19 | -------------------------------------------------------------------------------- /example/macos/Runner/MainFlutterWindow.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | import FlutterMacOS 3 | 4 | class MainFlutterWindow: NSWindow { 5 | override func awakeFromNib() { 6 | let flutterViewController = FlutterViewController.init() 7 | let windowFrame = self.frame 8 | self.contentViewController = flutterViewController 9 | self.setFrame(windowFrame, display: true) 10 | 11 | RegisterGeneratedPlugins(registry: flutterViewController) 12 | 13 | super.awakeFromNib() 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /macos/Flutter/ephemeral/Flutter-Generated.xcconfig: -------------------------------------------------------------------------------- 1 | // This is a generated file; do not edit or check into version control. 2 | FLUTTER_ROOT=/opt/flutter 3 | FLUTTER_APPLICATION_PATH=/Users/msayed/Documents/projects/palestine/localize_and_translate 4 | COCOAPODS_PARALLEL_CODE_SIGN=true 5 | FLUTTER_BUILD_DIR=build 6 | FLUTTER_BUILD_NAME=4.1.3 7 | FLUTTER_BUILD_NUMBER=4.1.3 8 | DART_OBFUSCATION=false 9 | TRACK_WIDGET_CREATION=true 10 | TREE_SHAKE_ICONS=false 11 | PACKAGE_CONFIG=.dart_tool/package_config.json 12 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/drawable-v21/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchImage.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchImage@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "LaunchImage@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /example/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: localize_and_translate_example 2 | description: Example for how to use the localize_and_translate plugin. 3 | publish_to: "none" 4 | version: 1.0.0+1 5 | 6 | environment: 7 | sdk: ">=2.17.0-0 <3.0.0" 8 | 9 | dependencies: 10 | flutter: 11 | sdk: flutter 12 | cupertino_icons: ^1.0.5 13 | # print_color: any 14 | localize_and_translate: 15 | path: ../ 16 | 17 | 18 | 19 | dev_dependencies: 20 | flutter_test: 21 | sdk: flutter 22 | flutter_lints: ^3.0.1 23 | 24 | flutter: 25 | uses-material-design: true 26 | assets: 27 | - assets/lang/ 28 | -------------------------------------------------------------------------------- /macos/Flutter/ephemeral/flutter_export_environment.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # This is a generated file; do not edit or check into version control. 3 | export "FLUTTER_ROOT=/opt/flutter" 4 | export "FLUTTER_APPLICATION_PATH=/Users/msayed/Documents/projects/palestine/localize_and_translate" 5 | export "COCOAPODS_PARALLEL_CODE_SIGN=true" 6 | export "FLUTTER_BUILD_DIR=build" 7 | export "FLUTTER_BUILD_NAME=4.1.3" 8 | export "FLUTTER_BUILD_NUMBER=4.1.3" 9 | export "DART_OBFUSCATION=false" 10 | export "TRACK_WIDGET_CREATION=true" 11 | export "TREE_SHAKE_ICONS=false" 12 | export "PACKAGE_CONFIG=.dart_tool/package_config.json" 13 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: localize_and_translate 2 | description: Flutter localization in easy steps, simple ways to localize and translate your app 3 | version: 6.0.8 4 | homepage: https://github.com/msayed-net/localize_and_translate 5 | issue_tracker: https://github.com/msayed-net/localize_and_translate/issues 6 | 7 | environment: 8 | sdk: ">=2.18.0 <4.0.0" 9 | 10 | dependencies: 11 | flutter: 12 | sdk: flutter 13 | flutter_localizations: 14 | sdk: flutter 15 | 16 | hive: ^2.2.3 17 | hive_flutter: ^1.1.0 18 | 19 | dio: ^5.7.0 20 | 21 | dev_dependencies: 22 | flutter_test: 23 | sdk: flutter 24 | flutter_lints: ^2.0.1 25 | -------------------------------------------------------------------------------- /example/macos/Runner/Configs/Warnings.xcconfig: -------------------------------------------------------------------------------- 1 | WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings 2 | GCC_WARN_UNDECLARED_SELECTOR = YES 3 | CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES 4 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE 5 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES 6 | CLANG_WARN_PRAGMA_PACK = YES 7 | CLANG_WARN_STRICT_PROTOTYPES = YES 8 | CLANG_WARN_COMMA = YES 9 | GCC_WARN_STRICT_SELECTOR_MATCH = YES 10 | CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES 11 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES 12 | GCC_WARN_SHADOW = YES 13 | CLANG_WARN_UNREACHABLE_CODE = YES 14 | -------------------------------------------------------------------------------- /example/web/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "example", 3 | "short_name": "example", 4 | "start_url": ".", 5 | "display": "minimal-ui", 6 | "background_color": "#0175C2", 7 | "theme_color": "#0175C2", 8 | "description": "A new Flutter project.", 9 | "orientation": "portrait-primary", 10 | "prefer_related_applications": false, 11 | "icons": [ 12 | { 13 | "src": "icons/Icon-192.png", 14 | "sizes": "192x192", 15 | "type": "image/png" 16 | }, 17 | { 18 | "src": "icons/Icon-512.png", 19 | "sizes": "512x512", 20 | "type": "image/png" 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /example/ios/.gitignore: -------------------------------------------------------------------------------- 1 | *.mode1v3 2 | *.mode2v3 3 | *.moved-aside 4 | *.pbxuser 5 | *.perspectivev3 6 | **/*sync/ 7 | .sconsign.dblite 8 | .tags* 9 | **/.vagrant/ 10 | **/DerivedData/ 11 | Icon? 12 | **/Pods/ 13 | **/.symlinks/ 14 | profile 15 | xcuserdata 16 | **/.generated/ 17 | Flutter/App.framework 18 | Flutter/Flutter.framework 19 | Flutter/Flutter.podspec 20 | Flutter/Generated.xcconfig 21 | Flutter/app.flx 22 | Flutter/app.zip 23 | Flutter/flutter_assets/ 24 | Flutter/flutter_export_environment.sh 25 | ServiceDefinitions.json 26 | Runner/GeneratedPluginRegistrant.* 27 | 28 | # Exceptions to above rules. 29 | !default.mode1v3 30 | !default.mode2v3 31 | !default.pbxuser 32 | !default.perspectivev3 33 | -------------------------------------------------------------------------------- /example/macos/Runner/Configs/AppInfo.xcconfig: -------------------------------------------------------------------------------- 1 | // Application-level settings for the Runner target. 2 | // 3 | // This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the 4 | // future. If not, the values below would default to using the project name when this becomes a 5 | // 'flutter create' template. 6 | 7 | // The application's name. By default this is also the title of the Flutter window. 8 | PRODUCT_NAME = example 9 | 10 | // The application's bundle identifier 11 | PRODUCT_BUNDLE_IDENTIFIER = net.msayed.example.example 12 | 13 | // The copyright displayed in application information 14 | PRODUCT_COPYRIGHT = Copyright © 2020 net.msayed.example. All rights reserved. 15 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /lib/src/assets/asset_loader_base.dart: -------------------------------------------------------------------------------- 1 | import 'package:localize_and_translate/src/mappers/json_mapper_base.dart'; 2 | 3 | /// [AssetLoaderBase] abstract class used to building your Custom AssetLoader 4 | /// Example: 5 | /// ``` 6 | ///class FileAssetLoader extends AssetLoader { 7 | /// @override 8 | /// Future> load(String path) async { 9 | /// final file = File(path); 10 | /// return json.decode(await file.readAsString()); 11 | /// } 12 | ///} 13 | /// ``` 14 | abstract class AssetLoaderBase { 15 | /// [AssetLoaderBase] constructor 16 | const AssetLoaderBase(); 17 | 18 | /// [load] method used to load the json file from the path 19 | Future> load([JsonMapperBase? base]); 20 | } 21 | -------------------------------------------------------------------------------- /lib/src/db/db_box.dart: -------------------------------------------------------------------------------- 1 | import 'package:hive/hive.dart'; 2 | import 'package:localize_and_translate/src/constants/db_keys.dart'; 3 | 4 | /// [DBBox] is the data source for the names of allah. 5 | class DBBox { 6 | /// [DBBox] constructor 7 | factory DBBox() => _instance; 8 | DBBox._(); 9 | static final DBBox _instance = DBBox._(); 10 | 11 | static late Box _box; 12 | 13 | /// [boxName] is the name of the box. 14 | static const String boxName = DBKeys.boxName; 15 | 16 | /// [box] is the getter for the box. 17 | static Box get box => _box; 18 | 19 | /// [openBox] is used to open the box. 20 | static Future openBox() async { 21 | _box = await Hive.openBox(boxName); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /example/android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlin_version = '1.7.10' 3 | repositories { 4 | google() 5 | mavenCentral() 6 | } 7 | 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:7.3.0' 10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 11 | } 12 | } 13 | 14 | allprojects { 15 | repositories { 16 | google() 17 | mavenCentral() 18 | } 19 | } 20 | 21 | rootProject.buildDir = '../build' 22 | subprojects { 23 | project.buildDir = "${rootProject.buildDir}/${project.name}" 24 | } 25 | subprojects { 26 | project.evaluationDependsOn(':app') 27 | } 28 | 29 | tasks.register("clean", Delete) { 30 | delete rootProject.buildDir 31 | } 32 | -------------------------------------------------------------------------------- /example/android/settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | def flutterSdkPath = { 3 | def properties = new Properties() 4 | file("local.properties").withInputStream { properties.load(it) } 5 | def flutterSdkPath = properties.getProperty("flutter.sdk") 6 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties" 7 | return flutterSdkPath 8 | } 9 | settings.ext.flutterSdkPath = flutterSdkPath() 10 | 11 | includeBuild("${settings.ext.flutterSdkPath}/packages/flutter_tools/gradle") 12 | 13 | plugins { 14 | id "dev.flutter.flutter-gradle-plugin" version "1.0.0" apply false 15 | } 16 | } 17 | 18 | include ":app" 19 | 20 | apply from: "${settings.ext.flutterSdkPath}/packages/flutter_tools/gradle/app_plugin_loader.gradle" 21 | -------------------------------------------------------------------------------- /example/.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # The .vscode folder contains launch configuration and tasks you configure in 19 | # VS Code which you may wish to be included in version control, so this line 20 | # is commented out by default. 21 | #.vscode/ 22 | #*.lock 23 | 24 | # Flutter/Dart/Pub related 25 | **/doc/api/ 26 | .dart_tool/ 27 | .flutter-plugins 28 | .flutter-plugins-dependencies 29 | .packages 30 | .pub-cache/ 31 | .pub/ 32 | /build/ 33 | 34 | # Web related 35 | lib/generated_plugin_registrant.dart 36 | 37 | # Exceptions to above rules. 38 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages 39 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | #name: Dart CI 2 | #on: 3 | # push: 4 | # branches: [main] 5 | # pull_request: 6 | # branches: [main] 7 | #jobs: 8 | # test: 9 | # defaults: 10 | # run: 11 | # working-directory: ./ 12 | # runs-on: ubuntu-latest 13 | # steps: 14 | # - name: Start Job 15 | # uses: actions/checkout@v1 16 | # - name: Install Flutter 17 | # uses: subosito/flutter-action@v1 18 | # with: 19 | # flutter-version: "2.8.1" 20 | # channel: "stable" 21 | # - name: Get Packages 22 | # run: flutter pub get 23 | # - name: Test Coverage 24 | # run: flutter test --coverage 25 | # - name: Insall VeryGoodCoverage 26 | # uses: codecov/codecov-action@v1.0.7 27 | # - name: Very Good Coverage 28 | # uses: VeryGoodOpenSource/very_good_coverage@v1.2.0 29 | -------------------------------------------------------------------------------- /linux/flutter/generated_plugins.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Generated file, do not edit. 3 | # 4 | 5 | list(APPEND FLUTTER_PLUGIN_LIST 6 | ) 7 | 8 | list(APPEND FLUTTER_FFI_PLUGIN_LIST 9 | ) 10 | 11 | set(PLUGIN_BUNDLED_LIBRARIES) 12 | 13 | foreach(plugin ${FLUTTER_PLUGIN_LIST}) 14 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) 15 | target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) 16 | list(APPEND PLUGIN_BUNDLED_LIBRARIES $) 17 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) 18 | endforeach(plugin) 19 | 20 | foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) 21 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin}) 22 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) 23 | endforeach(ffi_plugin) 24 | -------------------------------------------------------------------------------- /windows/flutter/generated_plugins.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Generated file, do not edit. 3 | # 4 | 5 | list(APPEND FLUTTER_PLUGIN_LIST 6 | ) 7 | 8 | list(APPEND FLUTTER_FFI_PLUGIN_LIST 9 | ) 10 | 11 | set(PLUGIN_BUNDLED_LIBRARIES) 12 | 13 | foreach(plugin ${FLUTTER_PLUGIN_LIST}) 14 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin}) 15 | target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) 16 | list(APPEND PLUGIN_BUNDLED_LIBRARIES $) 17 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) 18 | endforeach(plugin) 19 | 20 | foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) 21 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin}) 22 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) 23 | endforeach(ffi_plugin) 24 | -------------------------------------------------------------------------------- /example/linux/flutter/generated_plugins.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Generated file, do not edit. 3 | # 4 | 5 | list(APPEND FLUTTER_PLUGIN_LIST 6 | ) 7 | 8 | list(APPEND FLUTTER_FFI_PLUGIN_LIST 9 | ) 10 | 11 | set(PLUGIN_BUNDLED_LIBRARIES) 12 | 13 | foreach(plugin ${FLUTTER_PLUGIN_LIST}) 14 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) 15 | target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) 16 | list(APPEND PLUGIN_BUNDLED_LIBRARIES $) 17 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) 18 | endforeach(plugin) 19 | 20 | foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) 21 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin}) 22 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) 23 | endforeach(ffi_plugin) 24 | -------------------------------------------------------------------------------- /lib/localize_and_translate.dart: -------------------------------------------------------------------------------- 1 | export 'package:localize_and_translate/src/assets/asset_loader_base.dart'; 2 | export 'package:localize_and_translate/src/assets/asset_loader_network.dart'; 3 | export 'package:localize_and_translate/src/assets/asset_loader_root_bundle_json.dart'; 4 | export 'package:localize_and_translate/src/constants/enums.dart'; 5 | export 'package:localize_and_translate/src/core/localize_and_translate.dart'; 6 | export 'package:localize_and_translate/src/extensions/context_extensions.dart'; 7 | export 'package:localize_and_translate/src/extensions/string_extensions.dart'; 8 | export 'package:localize_and_translate/src/mappers/json_mapper_base.dart'; 9 | export 'package:localize_and_translate/src/mappers/nested_json_mapper.dart'; 10 | export 'package:localize_and_translate/src/widgets/localized_app.dart'; 11 | export 'package:localize_and_translate/src/widgets/localized_app_exception.dart'; 12 | -------------------------------------------------------------------------------- /example/ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 11.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /example/.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: "ff5b5b5fa6f35b717667719ddfdb1521d8bdd05a" 8 | channel: "stable" 9 | 10 | project_type: app 11 | 12 | # Tracks metadata for the flutter migrate command 13 | migration: 14 | platforms: 15 | - platform: root 16 | create_revision: ff5b5b5fa6f35b717667719ddfdb1521d8bdd05a 17 | base_revision: ff5b5b5fa6f35b717667719ddfdb1521d8bdd05a 18 | - platform: android 19 | create_revision: ff5b5b5fa6f35b717667719ddfdb1521d8bdd05a 20 | base_revision: ff5b5b5fa6f35b717667719ddfdb1521d8bdd05a 21 | 22 | # User provided section 23 | 24 | # List of Local paths (relative to this file) that should be 25 | # ignored by the migrate tool. 26 | # 27 | # Files that are not part of the templates will be ignored by default. 28 | unmanaged_files: 29 | - 'lib/main.dart' 30 | - 'ios/Runner.xcodeproj/project.pbxproj' 31 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/values-night/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Mohamed Sayed 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /lib/src/widgets/localized_app.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:localize_and_translate/src/core/localize_and_translate.dart'; 3 | 4 | /// [LocalizedApp] is the widget that is used to localize the app. 5 | class LocalizedApp extends StatefulWidget { 6 | /// [LocalizedApp] constructor 7 | const LocalizedApp({ 8 | required this.child, 9 | super.key, 10 | }); 11 | 12 | /// [child] is the child widget. 13 | final Widget child; 14 | 15 | @override 16 | State createState() => _LocalizedAppState(); 17 | } 18 | 19 | class _LocalizedAppState extends State { 20 | @override 21 | void initState() { 22 | LocalizeAndTranslate.notifyUI = _onLocaleChange; 23 | super.initState(); 24 | } 25 | 26 | void _onLocaleChange() { 27 | WidgetsBinding.instance.addPostFrameCallback((_) { 28 | (context as Element).visitChildren(_rebuildElement); 29 | }); 30 | } 31 | 32 | void _rebuildElement(Element element) { 33 | element 34 | ..markNeedsBuild() 35 | ..visitChildren(_rebuildElement); 36 | } 37 | 38 | @override 39 | Widget build(BuildContext context) { 40 | return widget.child; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /example/macos/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | $(FLUTTER_BUILD_NAME) 21 | CFBundleVersion 22 | $(FLUTTER_BUILD_NUMBER) 23 | LSMinimumSystemVersion 24 | $(MACOSX_DEPLOYMENT_TARGET) 25 | NSHumanReadableCopyright 26 | $(PRODUCT_COPYRIGHT) 27 | NSMainNibFile 28 | MainMenu 29 | NSPrincipalClass 30 | NSApplication 31 | 32 | 33 | -------------------------------------------------------------------------------- /lib/src/mappers/nested_json_mapper.dart: -------------------------------------------------------------------------------- 1 | import 'package:localize_and_translate/src/mappers/json_mapper_base.dart'; 2 | 3 | /// Helper class to flatten nested JSON structures. 4 | class NestedJsonMapper implements JsonMapperBase { 5 | /// Flattens a nested JSON structure into a single-level map. 6 | /// 7 | /// - `json`: The input JSON map. 8 | /// - `parentKey`: The parent key used for recursive calls (leave empty for the root). 9 | /// - `separator`: The separator to use between nested keys (default is '.'). 10 | @override 11 | Map flattenJson(Map json, 12 | {String parentKey = '', String? separator = '.'}) { 13 | final Map flattened = {}; 14 | 15 | json.forEach((String key, value) { 16 | final String newKey = 17 | parentKey.isNotEmpty ? '$parentKey$separator$key' : key; 18 | 19 | if (value is Map) { 20 | // Recursively flatten nested JSON 21 | flattened.addAll( 22 | flattenJson(value, parentKey: newKey, separator: separator)); 23 | } else { 24 | flattened[newKey] = value; 25 | } 26 | }); 27 | 28 | return flattened; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /.all-contributorsrc: -------------------------------------------------------------------------------- 1 | { 2 | "files": [ 3 | "README.md" 4 | ], 5 | "imageSize": 100, 6 | "commit": false, 7 | "contributors": [ 8 | { 9 | "login": "msayed-net", 10 | "name": "Mohamed Sayed", 11 | "avatar_url": "https://avatars.githubusercontent.com/u/25801517?s=40&v=4", 12 | "profile": "https://www.linkedin.com/in/msayed-net/", 13 | "contributions": [ 14 | "code" 15 | ] 16 | }, 17 | { 18 | "login": "mo-ah-dawood", 19 | "name": "Mohamed Dawood", 20 | "avatar_url": "https://avatars.githubusercontent.com/u/31937782?v=4", 21 | "profile": "https://www.linkedin.com/in/mohamed-ahmed-2220b6121/", 22 | "contributions": [ 23 | "code" 24 | ] 25 | }, 26 | { 27 | "login": "RYOKSEC", 28 | "name": "Eyad Al-Khatib", 29 | "avatar_url": "https://avatars.githubusercontent.com/u/31315805?v=4", 30 | "profile": "https://github.com/RYOKSEC", 31 | "contributions": [ 32 | "code" 33 | ] 34 | }, 35 | ], 36 | "contributorsPerLine": 7, 37 | "projectName": "localize_and_translate", 38 | "projectOwner": "msayed-net", 39 | "repoType": "github", 40 | "repoHost": "https://github.com", 41 | "skipCi": true 42 | } 43 | -------------------------------------------------------------------------------- /example/web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | example 18 | 19 | 20 | 21 | 24 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /lib/src/extensions/context_extensions.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:localize_and_translate/localize_and_translate.dart'; 3 | 4 | /// [ContextExtensions] is the extension class for the [BuildContext]. 5 | extension ContextExtensions on BuildContext { 6 | /// [locale] is the getter for the localization delegates. 7 | Locale get locale => LocalizeAndTranslate.getLocale(); 8 | 9 | /// [supportedLocales] is the getter for the supported locales. 10 | List get supportedLocales => LocalizeAndTranslate.getLocals(); 11 | 12 | /// [languageCode] is the getter for the language code. 13 | String get languageCode => locale.languageCode; 14 | 15 | /// [isRTL] is the getter for the right to left. 16 | bool get isRTL => LocalizeAndTranslate.isRTL(); 17 | 18 | /// [delegates] is the getter for the localization delegates. 19 | Iterable> get delegates => 20 | LocalizeAndTranslate.delegates; 21 | 22 | /// [setLocale] is the setter for the locale. 23 | void setLocale(Locale locale) => LocalizeAndTranslate.setLocale(locale); 24 | 25 | /// [setLanguageCode] is the setter for the language code. 26 | void setLanguageCode(String languageCode) => 27 | LocalizeAndTranslate.setLanguageCode(languageCode); 28 | 29 | /// [countryCode] is the setter for the language code. 30 | void countryCode() => LocalizeAndTranslate.getCountryCode(); 31 | } 32 | -------------------------------------------------------------------------------- /localize_and_translate.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /example/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | # This file configures the analyzer, which statically analyzes Dart code to 2 | # check for errors, warnings, and lints. 3 | # 4 | # The issues identified by the analyzer are surfaced in the UI of Dart-enabled 5 | # IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be 6 | # invoked from the command line by running `flutter analyze`. 7 | 8 | # The following line activates a set of recommended lints for Flutter apps, 9 | # packages, and plugins designed to encourage good coding practices. 10 | include: package:flutter_lints/flutter.yaml 11 | 12 | linter: 13 | # The lint rules applied to this project can be customized in the 14 | # section below to disable rules from the `package:flutter_lints/flutter.yaml` 15 | # included above or to enable additional rules. A list of all available lints 16 | # and their documentation is published at https://dart.dev/lints. 17 | # 18 | # Instead of disabling a lint rule for the entire project in the 19 | # section below, it can also be suppressed for a single line of code 20 | # or a specific dart file by using the `// ignore: name_of_lint` and 21 | # `// ignore_for_file: name_of_lint` syntax on the line or in the file 22 | # producing the lint. 23 | rules: 24 | # avoid_print: false # Uncomment to disable the `avoid_print` rule 25 | # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule 26 | 27 | # Additional information about this file can be found at 28 | # https://dart.dev/guides/language/analysis-options 29 | -------------------------------------------------------------------------------- /lib/src/constants/db_keys.dart: -------------------------------------------------------------------------------- 1 | import 'package:localize_and_translate/src/core/localize_and_translate.dart'; 2 | 3 | /// [DBKeys] is a singleton class that contains all the keys used in the database. 4 | class DBKeys { 5 | /// [DBKeys] constructor 6 | factory DBKeys() => _appTranslator; 7 | DBKeys._internal(); 8 | static final DBKeys _appTranslator = DBKeys._internal(); 9 | 10 | /// [boxName] is the name of the box. 11 | static const String boxName = 'localize_and_translate_config_box'; 12 | 13 | /// [languageCode] is the key for the language code. 14 | static const String languageCode = 'language_code'; 15 | 16 | /// [countryCode] is the key for the country code. 17 | static const String countryCode = 'country_code'; 18 | 19 | /// [isRTL] is the key for the isRTL. 20 | static const String isRTL = 'is_rtl'; 21 | 22 | /// [locales] is the key for the isRTL. 23 | static const String locales = 'locales'; 24 | 25 | /// [hivePath] is the path of the hive database. 26 | static const String hivePath = 'localize_and_translate_hive_db_path'; 27 | 28 | /// [appendPrefix] is the prefix for the translations. 29 | static String appendPrefix(String key) { 30 | return 'tr__${LocalizeAndTranslate.getLanguageCode()}_${LocalizeAndTranslate.getCountryCode()}_$key'; 31 | } 32 | 33 | /// [appendPrefix] is the prefix for the translations. 34 | static String buildPrefix({ 35 | required String key, 36 | required String languageCode, 37 | required String? countryCode, 38 | }) { 39 | return 'tr__${languageCode}_${countryCode ?? ''}_$key'; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /lib/src/widgets/localized_app_exception.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | /// [LocalizedAppException] is the widget that is shown when there is an error in the future. 4 | class LocalizedAppException extends StatelessWidget { 5 | /// [LocalizedAppException] constructor 6 | const LocalizedAppException({ 7 | this.msg = 'Loading ...', 8 | super.key, 9 | }); 10 | 11 | /// [msg] is the message to be shown. 12 | final String msg; 13 | 14 | @override 15 | Widget build(BuildContext context) { 16 | return ColoredBox( 17 | color: Colors.white, 18 | child: Column( 19 | mainAxisAlignment: MainAxisAlignment.center, 20 | children: [ 21 | const Icon( 22 | Icons.error_outline, 23 | color: Colors.red, 24 | size: 64, 25 | textDirection: TextDirection.ltr, 26 | ), 27 | const SizedBox(height: 20), 28 | const Text( 29 | 'Localize And Translate:', 30 | textAlign: TextAlign.center, 31 | textDirection: TextDirection.ltr, 32 | style: TextStyle(fontWeight: FontWeight.w700, color: Colors.red, fontSize: 25), 33 | ), 34 | const SizedBox(height: 10), 35 | Text( 36 | '"$msg"', 37 | textAlign: TextAlign.center, 38 | textDirection: TextDirection.ltr, 39 | style: const TextStyle(fontWeight: FontWeight.w500, color: Colors.red, fontSize: 14), 40 | ), 41 | const SizedBox(height: 30), 42 | ], 43 | ), 44 | ); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /example/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "16x16", 5 | "idiom" : "mac", 6 | "filename" : "app_icon_16.png", 7 | "scale" : "1x" 8 | }, 9 | { 10 | "size" : "16x16", 11 | "idiom" : "mac", 12 | "filename" : "app_icon_32.png", 13 | "scale" : "2x" 14 | }, 15 | { 16 | "size" : "32x32", 17 | "idiom" : "mac", 18 | "filename" : "app_icon_32.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "32x32", 23 | "idiom" : "mac", 24 | "filename" : "app_icon_64.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "128x128", 29 | "idiom" : "mac", 30 | "filename" : "app_icon_128.png", 31 | "scale" : "1x" 32 | }, 33 | { 34 | "size" : "128x128", 35 | "idiom" : "mac", 36 | "filename" : "app_icon_256.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "256x256", 41 | "idiom" : "mac", 42 | "filename" : "app_icon_256.png", 43 | "scale" : "1x" 44 | }, 45 | { 46 | "size" : "256x256", 47 | "idiom" : "mac", 48 | "filename" : "app_icon_512.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "512x512", 53 | "idiom" : "mac", 54 | "filename" : "app_icon_512.png", 55 | "scale" : "1x" 56 | }, 57 | { 58 | "size" : "512x512", 59 | "idiom" : "mac", 60 | "filename" : "app_icon_1024.png", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /lib/src/db/usecases.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ui'; 2 | 3 | import 'package:localize_and_translate/src/db/db_box.dart'; 4 | 5 | /// [DBUseCases] is a use case that localize and translate a text. 6 | class DBUseCases { 7 | /// [DBUseCases] constructor 8 | const DBUseCases(); 9 | 10 | /// [getKeys] is used to get all keys in the database. 11 | static List getKeys() => DBBox.box.keys.cast().toList(); 12 | 13 | /// [read] is used to retrieve a data from the database. 14 | static String read(String key) => DBBox.box.get(key) ?? key; 15 | 16 | /// [readNullable] is used to retrieve a data from the database. 17 | static String? readNullable(String key) => DBBox.box.get(key); 18 | 19 | /// [write] is used to write a data to the database. 20 | static Future write(String key, String value) async { 21 | await DBBox.box.put(key, value); 22 | } 23 | 24 | /// [writeMap] is used to write a map to the database. 25 | static Future writeMap(Map map) async { 26 | await DBBox.box.putAll(map); 27 | } 28 | 29 | /// [delete] is used to delete a data from the database. 30 | static Future delete(String key) async { 31 | await DBBox.box.delete(key); 32 | } 33 | 34 | /// [dbStringFromLocales] 35 | static String dbStringFromLocales(List data) { 36 | return data.map((Locale e) => '${e.languageCode}-${e.countryCode}').join('==='); 37 | } 38 | 39 | /// [localesFromDBString] 40 | static List localesFromDBString(String data) { 41 | return data.split('===').map((String e) { 42 | final List parts = e.split('-'); 43 | return Locale(parts[0], parts[1]); 44 | }).toList(); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /example/ios/Runner/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /example/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 14 | 18 | 22 | 23 | 24 | 25 | 26 | 27 | 29 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | # *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # The .vscode folder contains launch configuration and tasks you configure in 19 | # VS Code which you may wish to be included in version control, so this line 20 | # is commented out by default. 21 | #.vscode/ 22 | 23 | # Flutter/Dart/Pub related 24 | **/doc/api/ 25 | .dart_tool/ 26 | .flutter-plugins 27 | .flutter-plugins-dependencies 28 | .packages 29 | .pub-cache/ 30 | .pub/ 31 | build/ 32 | 33 | # Android related 34 | **/android/**/gradle-wrapper.jar 35 | **/android/.gradle 36 | **/android/captures/ 37 | **/android/gradlew 38 | **/android/gradlew.bat 39 | **/android/local.properties 40 | **/android/**/GeneratedPluginRegistrant.java 41 | 42 | # iOS/XCode related 43 | **/ios/**/*.mode1v3 44 | **/ios/**/*.mode2v3 45 | **/ios/**/*.moved-aside 46 | **/ios/**/*.pbxuser 47 | **/ios/**/*.perspectivev3 48 | **/ios/**/*sync/ 49 | **/ios/**/.sconsign.dblite 50 | **/ios/**/.tags* 51 | **/ios/**/.vagrant/ 52 | **/ios/**/DerivedData/ 53 | **/ios/**/Icon? 54 | **/ios/**/Pods/ 55 | **/ios/**/.symlinks/ 56 | **/ios/**/profile 57 | **/ios/**/xcuserdata 58 | **/ios/.generated/ 59 | **/ios/Flutter/App.framework 60 | **/ios/Flutter/Flutter.framework 61 | **/ios/Flutter/Flutter.podspec 62 | **/ios/Flutter/Generated.xcconfig 63 | **/ios/Flutter/app.flx 64 | **/ios/Flutter/app.zip 65 | **/ios/Flutter/flutter_assets/ 66 | **/ios/Flutter/flutter_export_environment.sh 67 | **/ios/ServiceDefinitions.json 68 | **/ios/Runner/GeneratedPluginRegistrant.* 69 | 70 | # Exceptions to above rules. 71 | !**/ios/**/default.mode1v3 72 | !**/ios/**/default.mode2v3 73 | !**/ios/**/default.pbxuser 74 | !**/ios/**/default.perspectivev3 75 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages 76 | 77 | -------------------------------------------------------------------------------- /example/ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleAllowMixedLocalizations 6 | 7 | CFBundleDevelopmentRegion 8 | $(DEVELOPMENT_LANGUAGE) 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | example 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | $(FLUTTER_BUILD_NAME) 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | $(FLUTTER_BUILD_NUMBER) 25 | LSRequiresIPhoneOS 26 | 27 | UILaunchStoryboardName 28 | LaunchScreen 29 | UIMainStoryboardFile 30 | Main 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | UIViewControllerBasedStatusBarAppearance 45 | 46 | CADisableMinimumFrameDurationOnPhone 47 | 48 | UIApplicationSupportsIndirectInputEvents 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /example/lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:localize_and_translate/localize_and_translate.dart'; 3 | 4 | void main() async { 5 | WidgetsFlutterBinding.ensureInitialized(); 6 | 7 | await LocalizeAndTranslate.init( 8 | assetLoader: const AssetLoaderRootBundleJson('assets/lang'), 9 | supportedLanguageCodes: const ['ar', 'en'], 10 | ); 11 | 12 | runApp( 13 | const MyApp(), 14 | ); 15 | } 16 | 17 | class MyApp extends StatelessWidget { 18 | const MyApp({super.key}); 19 | 20 | @override 21 | Widget build(BuildContext context) { 22 | return LocalizedApp( 23 | child: MaterialApp( 24 | localizationsDelegates: context.delegates, 25 | supportedLocales: context.supportedLocales, 26 | locale: context.locale, 27 | builder: (BuildContext context, Widget? child) { 28 | child = LocalizeAndTranslate.directionBuilder(context, child); 29 | 30 | return child; 31 | }, 32 | theme: ThemeData( 33 | primarySwatch: Colors.indigo, 34 | ), 35 | home: const MyHomePage(), 36 | ), 37 | ); 38 | } 39 | } 40 | 41 | class MyHomePage extends StatelessWidget { 42 | const MyHomePage({super.key}); 43 | 44 | @override 45 | Widget build(BuildContext context) { 46 | return Scaffold( 47 | appBar: AppBar( 48 | title: Text('name'.tr()), 49 | ), 50 | body: Center( 51 | child: ElevatedButton( 52 | onPressed: () { 53 | if (LocalizeAndTranslate.getLanguageCode() == 'ar') { 54 | LocalizeAndTranslate.setLanguageCode('en'); 55 | debugPrint('new lang: en -- context.locale: ${context.locale}'); 56 | } else { 57 | LocalizeAndTranslate.setLanguageCode('ar'); 58 | debugPrint('new lang: ar -- context.locale: ${context.locale}'); 59 | } 60 | }, 61 | child: Text('change'.tr()), 62 | ), 63 | ), 64 | ); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /example/android/app/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id "com.android.application" 3 | id "kotlin-android" 4 | id "dev.flutter.flutter-gradle-plugin" 5 | } 6 | 7 | def localProperties = new Properties() 8 | def localPropertiesFile = rootProject.file('local.properties') 9 | if (localPropertiesFile.exists()) { 10 | localPropertiesFile.withReader('UTF-8') { reader -> 11 | localProperties.load(reader) 12 | } 13 | } 14 | 15 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode') 16 | if (flutterVersionCode == null) { 17 | flutterVersionCode = '1' 18 | } 19 | 20 | def flutterVersionName = localProperties.getProperty('flutter.versionName') 21 | if (flutterVersionName == null) { 22 | flutterVersionName = '1.0' 23 | } 24 | 25 | android { 26 | namespace "net.msayed.example.example" 27 | compileSdkVersion flutter.compileSdkVersion 28 | ndkVersion flutter.ndkVersion 29 | 30 | compileOptions { 31 | sourceCompatibility JavaVersion.VERSION_1_8 32 | targetCompatibility JavaVersion.VERSION_1_8 33 | } 34 | 35 | kotlinOptions { 36 | jvmTarget = '1.8' 37 | } 38 | 39 | sourceSets { 40 | main.java.srcDirs += 'src/main/kotlin' 41 | } 42 | 43 | defaultConfig { 44 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 45 | applicationId "net.msayed.example.example" 46 | // You can update the following values to match your application needs. 47 | // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration. 48 | minSdkVersion flutter.minSdkVersion 49 | targetSdkVersion flutter.targetSdkVersion 50 | versionCode flutterVersionCode.toInteger() 51 | versionName flutterVersionName 52 | } 53 | 54 | buildTypes { 55 | release { 56 | // TODO: Add your own signing config for the release build. 57 | // Signing with the debug keys for now, so `flutter run --release` works. 58 | signingConfig signingConfigs.debug 59 | } 60 | } 61 | } 62 | 63 | flutter { 64 | source '../..' 65 | } 66 | 67 | dependencies {} 68 | -------------------------------------------------------------------------------- /example/ios/Runner/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /lib/src/assets/asset_loader_root_bundle_json.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:flutter/cupertino.dart'; 4 | import 'package:flutter/services.dart'; 5 | import 'package:localize_and_translate/src/assets/asset_loader_base.dart'; 6 | import 'package:localize_and_translate/src/constants/db_keys.dart'; 7 | import 'package:localize_and_translate/src/mappers/json_mapper_base.dart'; 8 | import 'package:localize_and_translate/src/mappers/nested_json_mapper.dart'; 9 | 10 | /// [AssetLoaderRootBundleJson] is the asset loader for root bundle. 11 | /// It loads the assets from the root bundle. 12 | class AssetLoaderRootBundleJson implements AssetLoaderBase { 13 | /// [AssetLoaderRootBundleJson] constructor 14 | /// [directory] is the path of the json directory 15 | const AssetLoaderRootBundleJson(this.directory); 16 | 17 | /// [directory] is the path of the json directory 18 | final String directory; 19 | 20 | @override 21 | Future> load([JsonMapperBase? base]) async { 22 | base ??= NestedJsonMapper(); 23 | 24 | final AssetManifest assetManifest = await AssetManifest.loadFromAssetBundle(rootBundle); 25 | final Iterable paths = assetManifest.listAssets().where( 26 | (String element) => element.contains(directory), 27 | ); 28 | 29 | final Map result = {}; 30 | 31 | for (final String path in paths) { 32 | final String fileName = path.split('/').last; 33 | final String fileNameNoExtension = fileName.split('.').first; 34 | String languageCode = ''; 35 | String? countryCode; 36 | 37 | if (fileNameNoExtension.contains('-')) { 38 | languageCode = fileNameNoExtension.split('-').first; 39 | countryCode = fileNameNoExtension.split('-').length > 2 ? fileNameNoExtension.split('-').elementAt(1) : null; 40 | } else { 41 | languageCode = fileNameNoExtension; 42 | } 43 | 44 | final String valuesStr = await rootBundle.loadString(path); 45 | final dynamic values = json.decode(valuesStr); 46 | 47 | if (values is Map) { 48 | final Map flattenedValues = base.flattenJson(values); 49 | 50 | for (final String key in flattenedValues.keys) { 51 | result[DBKeys.buildPrefix( 52 | key: key, 53 | languageCode: languageCode, 54 | countryCode: countryCode, 55 | )] = flattenedValues[key]; 56 | } 57 | } 58 | } 59 | 60 | debugPrint('--LocalizeAndTranslate - (AssetLoaderRootBundleJson) -- Translated Strings: ${result.length}'); 61 | return result; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Next 2 | 3 | * Add more features 4 | 5 | ## 6.0.8 6 | 7 | * Hotfix for web 8 | 9 | ## 6.0.7 10 | 11 | * init() : add `assetLoadersExtra` parameter to change the default assetLoadersExtra 12 | * add getKey() method 13 | 14 | ## 6.0.5 15 | 16 | * Fix exports 17 | 18 | ## 6.0.4 19 | 20 | * init() : add `assetLoaderSecondary` parameter to change the default assetLoaderSecondary 21 | 22 | ## 6.0.3 23 | 24 | * init() : add `mapper` parameter to change the default mapper 25 | 26 | ## 6.0.2 27 | 28 | * Enhance Docs 29 | 30 | ## 6.0.1 31 | 32 | * remove intl package 33 | * add AssetLoaderNetwork adapter 34 | * add NestedJsonMapper adapter 35 | * add separator to assetLoaders 36 | 37 | ## 6.0.0 38 | 39 | * remove intl package 40 | * add AssetLoaderNetwork adapter 41 | * add NestedJsonMapper adapter 42 | 43 | ## 5.1.2 44 | 45 | * enable hive path and prefs change through params 46 | * disable resetLocale for now 47 | 48 | ## 5.1.1 49 | 50 | * Enhance docs 51 | 52 | ## 5.0.21-dev 53 | 54 | * Code analysis 55 | 56 | ## 5.0.20-dev 57 | 58 | * Bug Fix 59 | * Auto state change after change lang 60 | * Enhance Performance 61 | 62 | ## 5.0.7-dev 63 | 64 | * New Architecture 65 | * New Methods 66 | * New Features 67 | * New Docs 68 | 69 | ## 5.0.0-dev 70 | 71 | * Re-Structure Package 72 | 73 | ## 4.1.2-dev 74 | 75 | * Re-Structure Package 76 | * Rebuild after change language .. same screen (state) 77 | 78 | ## 4.1.0, 4.1.1 79 | 80 | * Remove Google Translate 81 | * Add String Extension .tr() 82 | * Enhance Performance 83 | 84 | ## 4.0.0, 4.0.1 85 | 86 | * Migrate To Null-Safe 87 | 88 | ## 3.0.3 89 | 90 | * Bug Fix 91 | * Upgrade Packages 92 | * Remove intl 93 | 94 | ## 3.0.2 95 | 96 | * Bug Fix 97 | * Remove `LIST_OF_LANGS` & `LANGS_DIR` 98 | * `init()` now takes all needed parameters 99 | * Google Translate : added with developer-based api key -> NOT YET TESTED 100 | 101 | ## 2.2.1 102 | 103 | * `googleTranslate()` : Remove 104 | 105 | ## 2.1.2 106 | 107 | * Plugin -> Package 108 | 109 | ## 2.0.0 : 2.1.1 110 | 111 | * translate() enhance 112 | * translate() with keys 113 | * googleTranslate() added 114 | * in error, return given key 115 | * in not found case return given key 116 | * FIXs, docs, video docs 117 | 118 | ## 1.2.0 | 1.2.1 119 | 120 | * Performance Improvements 121 | * Docs Improvements 122 | 123 | ## 1.1.1+6 124 | 125 | * add isDirectionRTL method 126 | 127 | ## 1.0.1+5 128 | 129 | * Documentation Enhancements 130 | * iOS Delegates 131 | 132 | ## 1.0.1 133 | 134 | * first lanuch 135 | * added main methods 136 | 137 | ## 0.0.1 138 | 139 | * init 140 | * add description 141 | -------------------------------------------------------------------------------- /example/macos/Podfile: -------------------------------------------------------------------------------- 1 | platform :osx, '10.11' 2 | 3 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 4 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 5 | 6 | project 'Runner', { 7 | 'Debug' => :debug, 8 | 'Profile' => :release, 9 | 'Release' => :release, 10 | } 11 | 12 | def parse_KV_file(file, separator='=') 13 | file_abs_path = File.expand_path(file) 14 | if !File.exists? file_abs_path 15 | return []; 16 | end 17 | pods_ary = [] 18 | skip_line_start_symbols = ["#", "/"] 19 | File.foreach(file_abs_path) { |line| 20 | next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ } 21 | plugin = line.split(pattern=separator) 22 | if plugin.length == 2 23 | podname = plugin[0].strip() 24 | path = plugin[1].strip() 25 | podpath = File.expand_path("#{path}", file_abs_path) 26 | pods_ary.push({:name => podname, :path => podpath}); 27 | else 28 | puts "Invalid plugin specification: #{line}" 29 | end 30 | } 31 | return pods_ary 32 | end 33 | 34 | def pubspec_supports_macos(file) 35 | file_abs_path = File.expand_path(file) 36 | if !File.exists? file_abs_path 37 | return false; 38 | end 39 | File.foreach(file_abs_path) { |line| 40 | return true if line =~ /^\s*macos:/ 41 | } 42 | return false 43 | end 44 | 45 | target 'Runner' do 46 | use_frameworks! 47 | use_modular_headers! 48 | 49 | # Prepare symlinks folder. We use symlinks to avoid having Podfile.lock 50 | # referring to absolute paths on developers' machines. 51 | ephemeral_dir = File.join('Flutter', 'ephemeral') 52 | symlink_dir = File.join(ephemeral_dir, '.symlinks') 53 | symlink_plugins_dir = File.join(symlink_dir, 'plugins') 54 | system("rm -rf #{symlink_dir}") 55 | system("mkdir -p #{symlink_plugins_dir}") 56 | 57 | # Flutter Pods 58 | generated_xcconfig = parse_KV_file(File.join(ephemeral_dir, 'Flutter-Generated.xcconfig')) 59 | if generated_xcconfig.empty? 60 | puts "Flutter-Generated.xcconfig must exist. If you're running pod install manually, make sure flutter packages get is executed first." 61 | end 62 | generated_xcconfig.map { |p| 63 | if p[:name] == 'FLUTTER_FRAMEWORK_DIR' 64 | symlink = File.join(symlink_dir, 'flutter') 65 | File.symlink(File.dirname(p[:path]), symlink) 66 | pod 'FlutterMacOS', :path => File.join(symlink, File.basename(p[:path])) 67 | end 68 | } 69 | 70 | # Plugin Pods 71 | plugin_pods = parse_KV_file('../.flutter-plugins') 72 | plugin_pods.map { |p| 73 | symlink = File.join(symlink_plugins_dir, p[:name]) 74 | File.symlink(p[:path], symlink) 75 | if pubspec_supports_macos(File.join(symlink, 'pubspec.yaml')) 76 | pod p[:name], :path => File.join(symlink, 'macos') 77 | end 78 | } 79 | end 80 | 81 | # Prevent Cocoapods from embedding a second Flutter framework and causing an error with the new Xcode build system. 82 | install! 'cocoapods', :disable_input_output_paths => true 83 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-App-20x20@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-App-20x20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-App-29x29@1x.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-App-29x29@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "29x29", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-App-29x29@3x.png", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-App-40x40@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "40x40", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-App-40x40@3x.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "Icon-App-60x60@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "60x60", 53 | "idiom" : "iphone", 54 | "filename" : "Icon-App-60x60@3x.png", 55 | "scale" : "3x" 56 | }, 57 | { 58 | "size" : "20x20", 59 | "idiom" : "ipad", 60 | "filename" : "Icon-App-20x20@1x.png", 61 | "scale" : "1x" 62 | }, 63 | { 64 | "size" : "20x20", 65 | "idiom" : "ipad", 66 | "filename" : "Icon-App-20x20@2x.png", 67 | "scale" : "2x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "Icon-App-29x29@1x.png", 73 | "scale" : "1x" 74 | }, 75 | { 76 | "size" : "29x29", 77 | "idiom" : "ipad", 78 | "filename" : "Icon-App-29x29@2x.png", 79 | "scale" : "2x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "Icon-App-40x40@1x.png", 85 | "scale" : "1x" 86 | }, 87 | { 88 | "size" : "40x40", 89 | "idiom" : "ipad", 90 | "filename" : "Icon-App-40x40@2x.png", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "size" : "76x76", 95 | "idiom" : "ipad", 96 | "filename" : "Icon-App-76x76@1x.png", 97 | "scale" : "1x" 98 | }, 99 | { 100 | "size" : "76x76", 101 | "idiom" : "ipad", 102 | "filename" : "Icon-App-76x76@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "83.5x83.5", 107 | "idiom" : "ipad", 108 | "filename" : "Icon-App-83.5x83.5@2x.png", 109 | "scale" : "2x" 110 | }, 111 | { 112 | "size" : "1024x1024", 113 | "idiom" : "ios-marketing", 114 | "filename" : "Icon-App-1024x1024@1x.png", 115 | "scale" : "1x" 116 | } 117 | ], 118 | "info" : { 119 | "version" : 1, 120 | "author" : "xcode" 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /example/linux/flutter/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | 3 | set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") 4 | 5 | # Configuration provided via flutter tool. 6 | include(${EPHEMERAL_DIR}/generated_config.cmake) 7 | 8 | # TODO: Move the rest of this into files in ephemeral. See 9 | # https://github.com/flutter/flutter/issues/57146. 10 | 11 | # Serves the same purpose as list(TRANSFORM ... PREPEND ...), 12 | # which isn't available in 3.10. 13 | function(list_prepend LIST_NAME PREFIX) 14 | set(NEW_LIST "") 15 | foreach(element ${${LIST_NAME}}) 16 | list(APPEND NEW_LIST "${PREFIX}${element}") 17 | endforeach(element) 18 | set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE) 19 | endfunction() 20 | 21 | # === Flutter Library === 22 | # System-level dependencies. 23 | find_package(PkgConfig REQUIRED) 24 | pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) 25 | pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) 26 | pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) 27 | pkg_check_modules(BLKID REQUIRED IMPORTED_TARGET blkid) 28 | pkg_check_modules(LZMA REQUIRED IMPORTED_TARGET liblzma) 29 | 30 | set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so") 31 | 32 | # Published to parent scope for install step. 33 | set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) 34 | set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) 35 | set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) 36 | set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE) 37 | 38 | list(APPEND FLUTTER_LIBRARY_HEADERS 39 | "fl_basic_message_channel.h" 40 | "fl_binary_codec.h" 41 | "fl_binary_messenger.h" 42 | "fl_dart_project.h" 43 | "fl_engine.h" 44 | "fl_json_message_codec.h" 45 | "fl_json_method_codec.h" 46 | "fl_message_codec.h" 47 | "fl_method_call.h" 48 | "fl_method_channel.h" 49 | "fl_method_codec.h" 50 | "fl_method_response.h" 51 | "fl_plugin_registrar.h" 52 | "fl_plugin_registry.h" 53 | "fl_standard_message_codec.h" 54 | "fl_standard_method_codec.h" 55 | "fl_string_codec.h" 56 | "fl_value.h" 57 | "fl_view.h" 58 | "flutter_linux.h" 59 | ) 60 | list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/") 61 | add_library(flutter INTERFACE) 62 | target_include_directories(flutter INTERFACE 63 | "${EPHEMERAL_DIR}" 64 | ) 65 | target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}") 66 | target_link_libraries(flutter INTERFACE 67 | PkgConfig::GTK 68 | PkgConfig::GLIB 69 | PkgConfig::GIO 70 | PkgConfig::BLKID 71 | PkgConfig::LZMA 72 | ) 73 | add_dependencies(flutter flutter_assemble) 74 | 75 | # === Flutter tool backend === 76 | # _phony_ is a non-existent file to force this command to run every time, 77 | # since currently there's no way to get a full input/output list from the 78 | # flutter tool. 79 | add_custom_command( 80 | OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} 81 | ${CMAKE_CURRENT_BINARY_DIR}/_phony_ 82 | COMMAND ${CMAKE_COMMAND} -E env 83 | ${FLUTTER_TOOL_ENVIRONMENT} 84 | "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" 85 | linux-x64 ${CMAKE_BUILD_TYPE} 86 | VERBATIM 87 | ) 88 | add_custom_target(flutter_assemble DEPENDS 89 | "${FLUTTER_LIBRARY}" 90 | ${FLUTTER_LIBRARY_HEADERS} 91 | ) 92 | -------------------------------------------------------------------------------- /example/ios/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment this line to define a global platform for your project 2 | # platform :ios, '11.0' 3 | 4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 6 | 7 | project 'Runner', { 8 | 'Debug' => :debug, 9 | 'Profile' => :release, 10 | 'Release' => :release, 11 | } 12 | 13 | def parse_KV_file(file, separator='=') 14 | file_abs_path = File.expand_path(file) 15 | if !File.exists? file_abs_path 16 | return []; 17 | end 18 | generated_key_values = {} 19 | skip_line_start_symbols = ["#", "/"] 20 | File.foreach(file_abs_path) do |line| 21 | next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ } 22 | plugin = line.split(pattern=separator) 23 | if plugin.length == 2 24 | podname = plugin[0].strip() 25 | path = plugin[1].strip() 26 | podpath = File.expand_path("#{path}", file_abs_path) 27 | generated_key_values[podname] = podpath 28 | else 29 | puts "Invalid plugin specification: #{line}" 30 | end 31 | end 32 | generated_key_values 33 | end 34 | 35 | target 'Runner' do 36 | use_frameworks! 37 | use_modular_headers! 38 | 39 | # Flutter Pod 40 | 41 | copied_flutter_dir = File.join(__dir__, 'Flutter') 42 | copied_framework_path = File.join(copied_flutter_dir, 'Flutter.framework') 43 | copied_podspec_path = File.join(copied_flutter_dir, 'Flutter.podspec') 44 | unless File.exist?(copied_framework_path) && File.exist?(copied_podspec_path) 45 | # Copy Flutter.framework and Flutter.podspec to Flutter/ to have something to link against if the xcode backend script has not run yet. 46 | # That script will copy the correct debug/profile/release version of the framework based on the currently selected Xcode configuration. 47 | # CocoaPods will not embed the framework on pod install (before any build phases can generate) if the dylib does not exist. 48 | 49 | generated_xcode_build_settings_path = File.join(copied_flutter_dir, 'Generated.xcconfig') 50 | unless File.exist?(generated_xcode_build_settings_path) 51 | raise "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter pub get is executed first" 52 | end 53 | generated_xcode_build_settings = parse_KV_file(generated_xcode_build_settings_path) 54 | cached_framework_dir = generated_xcode_build_settings['FLUTTER_FRAMEWORK_DIR']; 55 | 56 | unless File.exist?(copied_framework_path) 57 | FileUtils.cp_r(File.join(cached_framework_dir, 'Flutter.framework'), copied_flutter_dir) 58 | end 59 | unless File.exist?(copied_podspec_path) 60 | FileUtils.cp(File.join(cached_framework_dir, 'Flutter.podspec'), copied_flutter_dir) 61 | end 62 | end 63 | 64 | # Keep pod path relative so it can be checked into Podfile.lock. 65 | pod 'Flutter', :path => 'Flutter' 66 | 67 | # Plugin Pods 68 | 69 | # Prepare symlinks folder. We use symlinks to avoid having Podfile.lock 70 | # referring to absolute paths on developers' machines. 71 | system('rm -rf .symlinks') 72 | system('mkdir -p .symlinks/plugins') 73 | plugin_pods = parse_KV_file('../.flutter-plugins') 74 | plugin_pods.each do |name, path| 75 | symlink = File.join('.symlinks', 'plugins', name) 76 | File.symlink(path, symlink) 77 | pod name, :path => File.join(symlink, 'ios') 78 | end 79 | end 80 | 81 | post_install do |installer| 82 | installer.pods_project.targets.each do |target| 83 | target.build_configurations.each do |config| 84 | config.build_settings['ENABLE_BITCODE'] = 'NO' 85 | end 86 | end 87 | end 88 | -------------------------------------------------------------------------------- /lib/src/assets/asset_loader_network.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:dio/dio.dart'; 4 | import 'package:flutter/material.dart'; 5 | import 'package:localize_and_translate/src/assets/asset_loader_base.dart'; 6 | import 'package:localize_and_translate/src/constants/db_keys.dart'; 7 | import 'package:localize_and_translate/src/mappers/json_mapper_base.dart'; 8 | import 'package:localize_and_translate/src/mappers/nested_json_mapper.dart'; 9 | 10 | /// [AssetLoaderNetwork] loads translation assets from a network source using a user-defined URL map. 11 | class AssetLoaderNetwork implements AssetLoaderBase { 12 | /// Creates an instance of [AssetLoaderNetwork]. 13 | /// 14 | /// - `urlMap`: A map where the key is the language code (e.g., 'en', 'en_US') and the value is the full URL for the translation file. 15 | /// - `headers`: An optional map of headers to include in the HTTP request. 16 | /// - `dio`: An optional Dio instance for customization (e.g., adding interceptors). 17 | AssetLoaderNetwork( 18 | this.urlMap, { 19 | Dio? dio, 20 | Map? headers, 21 | }) : _dio = dio ?? Dio() { 22 | if (headers != null) { 23 | _dio.options.headers.addAll(headers); 24 | } 25 | } 26 | 27 | /// A map of language codes to their corresponding translation file URLs. 28 | final Map urlMap; 29 | 30 | /// Dio instance for making HTTP requests. 31 | final Dio _dio; 32 | 33 | @override 34 | Future> load([JsonMapperBase? base]) async { 35 | base ??= NestedJsonMapper(); 36 | 37 | final Map result = {}; 38 | 39 | for (final MapEntry entry in urlMap.entries) { 40 | // Normalize the language code to a consistent format (e.g., en_US) 41 | final String normalizedLanguageCode = _normalizeLanguageCode(entry.key); 42 | final String url = entry.value; 43 | 44 | try { 45 | final Response response = await _dio.get(url); 46 | 47 | if (response.statusCode == 200) { 48 | final dynamic values = jsonDecode(jsonEncode(response.data)); 49 | 50 | if (values is Map) { 51 | final Map flattenedValues = base.flattenJson(values); 52 | 53 | for (final String key in flattenedValues.keys) { 54 | final String prefix = DBKeys.buildPrefix( 55 | key: key, 56 | languageCode: normalizedLanguageCode.split('_').first, 57 | countryCode: normalizedLanguageCode.contains('_') ? normalizedLanguageCode.split('_').last : null, 58 | ); 59 | 60 | result[prefix] = flattenedValues[key]; 61 | } 62 | } 63 | 64 | debugPrint( 65 | '--LocalizeAndTranslate - (AssetLoaderNetwork) -- Translated Strings: ${result.length}', 66 | ); 67 | } else { 68 | throw Exception( 69 | '--LocalizeAndTranslate-- Failed to load translations for $normalizedLanguageCode: HTTP ${response.statusCode}', 70 | ); 71 | } 72 | } catch (e, stackTrace) { 73 | debugPrint( 74 | '--LocalizeAndTranslate-- Failed to load translations for $normalizedLanguageCode: $e\n$stackTrace', 75 | ); 76 | } 77 | } 78 | 79 | return result; 80 | } 81 | 82 | /// Normalizes a language code to the format `en_US` (underscore-separated). 83 | String _normalizeLanguageCode(String languageCode) { 84 | // Replace hyphens (-) with underscores (_), e.g., en-US -> en_US 85 | return languageCode.replaceAll('-', '_'); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /example/linux/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | project(runner LANGUAGES CXX) 3 | 4 | set(BINARY_NAME "example") 5 | set(APPLICATION_ID "net.msayed.example.example") 6 | 7 | cmake_policy(SET CMP0063 NEW) 8 | 9 | set(CMAKE_INSTALL_RPATH "$ORIGIN/lib") 10 | 11 | # Configure build options. 12 | if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) 13 | set(CMAKE_BUILD_TYPE "Debug" CACHE 14 | STRING "Flutter build mode" FORCE) 15 | set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS 16 | "Debug" "Profile" "Release") 17 | endif() 18 | 19 | # Compilation settings that should be applied to most targets. 20 | function(APPLY_STANDARD_SETTINGS TARGET) 21 | target_compile_features(${TARGET} PUBLIC cxx_std_14) 22 | target_compile_options(${TARGET} PRIVATE -Wall -Werror) 23 | target_compile_options(${TARGET} PRIVATE "$<$>:-O3>") 24 | target_compile_definitions(${TARGET} PRIVATE "$<$>:NDEBUG>") 25 | endfunction() 26 | 27 | set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") 28 | 29 | # Flutter library and tool build rules. 30 | add_subdirectory(${FLUTTER_MANAGED_DIR}) 31 | 32 | # System-level dependencies. 33 | find_package(PkgConfig REQUIRED) 34 | pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) 35 | 36 | add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") 37 | 38 | # Application build 39 | add_executable(${BINARY_NAME} 40 | "main.cc" 41 | "my_application.cc" 42 | "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" 43 | ) 44 | apply_standard_settings(${BINARY_NAME}) 45 | target_link_libraries(${BINARY_NAME} PRIVATE flutter) 46 | target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) 47 | add_dependencies(${BINARY_NAME} flutter_assemble) 48 | # Only the install-generated bundle's copy of the executable will launch 49 | # correctly, since the resources must in the right relative locations. To avoid 50 | # people trying to run the unbundled copy, put it in a subdirectory instead of 51 | # the default top-level location. 52 | set_target_properties(${BINARY_NAME} 53 | PROPERTIES 54 | RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run" 55 | ) 56 | 57 | # Generated plugin build rules, which manage building the plugins and adding 58 | # them to the application. 59 | include(flutter/generated_plugins.cmake) 60 | 61 | 62 | # === Installation === 63 | # By default, "installing" just makes a relocatable bundle in the build 64 | # directory. 65 | set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle") 66 | if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) 67 | set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) 68 | endif() 69 | 70 | # Start with a clean build bundle directory every time. 71 | install(CODE " 72 | file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") 73 | " COMPONENT Runtime) 74 | 75 | set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") 76 | set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib") 77 | 78 | install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" 79 | COMPONENT Runtime) 80 | 81 | install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" 82 | COMPONENT Runtime) 83 | 84 | install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" 85 | COMPONENT Runtime) 86 | 87 | if(PLUGIN_BUNDLED_LIBRARIES) 88 | install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" 89 | DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" 90 | COMPONENT Runtime) 91 | endif() 92 | 93 | # Fully re-copy the assets directory on each build to avoid having stale files 94 | # from a previous install. 95 | set(FLUTTER_ASSET_DIR_NAME "flutter_assets") 96 | install(CODE " 97 | file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") 98 | " COMPONENT Runtime) 99 | install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" 100 | DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) 101 | 102 | # Install the AOT library on non-Debug builds only. 103 | if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") 104 | install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" 105 | COMPONENT Runtime) 106 | endif() 107 | -------------------------------------------------------------------------------- /example/linux/my_application.cc: -------------------------------------------------------------------------------- 1 | #include "my_application.h" 2 | 3 | #include 4 | #ifdef GDK_WINDOWING_X11 5 | #include 6 | #endif 7 | 8 | #include "flutter/generated_plugin_registrant.h" 9 | 10 | struct _MyApplication { 11 | GtkApplication parent_instance; 12 | char** dart_entrypoint_arguments; 13 | }; 14 | 15 | G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) 16 | 17 | // Implements GApplication::activate. 18 | static void my_application_activate(GApplication* application) { 19 | MyApplication* self = MY_APPLICATION(application); 20 | GtkWindow* window = 21 | GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application))); 22 | 23 | // Use a header bar when running in GNOME as this is the common style used 24 | // by applications and is the setup most users will be using (e.g. Ubuntu 25 | // desktop). 26 | // If running on X and not using GNOME then just use a traditional title bar 27 | // in case the window manager does more exotic layout, e.g. tiling. 28 | // If running on Wayland assume the header bar will work (may need changing 29 | // if future cases occur). 30 | gboolean use_header_bar = TRUE; 31 | #ifdef GDK_WINDOWING_X11 32 | GdkScreen *screen = gtk_window_get_screen(window); 33 | if (GDK_IS_X11_SCREEN(screen)) { 34 | const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen); 35 | if (g_strcmp0(wm_name, "GNOME Shell") != 0) { 36 | use_header_bar = FALSE; 37 | } 38 | } 39 | #endif 40 | if (use_header_bar) { 41 | GtkHeaderBar *header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); 42 | gtk_widget_show(GTK_WIDGET(header_bar)); 43 | gtk_header_bar_set_title(header_bar, "example"); 44 | gtk_header_bar_set_show_close_button(header_bar, TRUE); 45 | gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); 46 | } 47 | else { 48 | gtk_window_set_title(window, "example"); 49 | } 50 | 51 | gtk_window_set_default_size(window, 1280, 720); 52 | gtk_widget_show(GTK_WIDGET(window)); 53 | 54 | g_autoptr(FlDartProject) project = fl_dart_project_new(); 55 | fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments); 56 | 57 | FlView* view = fl_view_new(project); 58 | gtk_widget_show(GTK_WIDGET(view)); 59 | gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); 60 | 61 | fl_register_plugins(FL_PLUGIN_REGISTRY(view)); 62 | 63 | gtk_widget_grab_focus(GTK_WIDGET(view)); 64 | } 65 | 66 | // Implements GApplication::local_command_line. 67 | static gboolean my_application_local_command_line(GApplication* application, gchar ***arguments, int *exit_status) { 68 | MyApplication* self = MY_APPLICATION(application); 69 | // Strip out the first argument as it is the binary name. 70 | self->dart_entrypoint_arguments = g_strdupv(*arguments + 1); 71 | 72 | g_autoptr(GError) error = nullptr; 73 | if (!g_application_register(application, nullptr, &error)) { 74 | g_warning("Failed to register: %s", error->message); 75 | *exit_status = 1; 76 | return TRUE; 77 | } 78 | 79 | g_application_activate(application); 80 | *exit_status = 0; 81 | 82 | return TRUE; 83 | } 84 | 85 | // Implements GObject::dispose. 86 | static void my_application_dispose(GObject *object) { 87 | MyApplication* self = MY_APPLICATION(object); 88 | g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev); 89 | G_OBJECT_CLASS(my_application_parent_class)->dispose(object); 90 | } 91 | 92 | static void my_application_class_init(MyApplicationClass* klass) { 93 | G_APPLICATION_CLASS(klass)->activate = my_application_activate; 94 | G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line; 95 | G_OBJECT_CLASS(klass)->dispose = my_application_dispose; 96 | } 97 | 98 | static void my_application_init(MyApplication* self) {} 99 | 100 | MyApplication* my_application_new() { 101 | return MY_APPLICATION(g_object_new(my_application_get_type(), 102 | "application-id", APPLICATION_ID, 103 | "flags", G_APPLICATION_NON_UNIQUE, 104 | nullptr)); 105 | } 106 | -------------------------------------------------------------------------------- /example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 64 | 66 | 72 | 73 | 74 | 75 | 76 | 77 | 83 | 85 | 91 | 92 | 93 | 94 | 96 | 97 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # localize_and_translate 2 | 3 | Flutter localization in easy steps, eas 4 | 5 | [![License](https://img.shields.io/github/license/msayed-net/localize_and_translate?style=for-the-badge)](https://github.com/msayed-net) 6 | [![Pub](https://img.shields.io/badge/PUB-pub-blue?style=for-the-badge)](https://pub.dev/packages/localize_and_translate) 7 | [![Example](https://img.shields.io/badge/Example-Ex-success?style=for-the-badge)](https://pub.dev/packages/localize_and_translate/example) 8 | 9 | [![PUB](https://img.shields.io/pub/v/localize_and_translate.svg?style=for-the-badge)](https://pub.dev/packages/localize_and_translate) 10 | [![GitHub stars](https://img.shields.io/github/stars/msayed-net/localize_and_translate?style=for-the-badge)](https://github.com/msayed-net/localize_and_translate) 11 | [![GitHub forks](https://img.shields.io/github/forks/msayed-net/localize_and_translate?style=for-the-badge)](https://github.com/msayed-net/localize_and_translate) 12 | 13 | ## Getting Started 14 | 15 | ### 🔩 Installation 16 | 17 | Add to your `pubspec.yaml`: 18 | 19 | ```yaml 20 | dependencies: 21 | localize_and_translate: 22 | ``` 23 | 24 | Create folder and add translation files like this 25 | 26 | ``` 27 | assets 28 | └── lang 29 | ├── {languageCode}.{ext} //only language code 30 | └── {languageCode}-{countryCode}.{ext} //or full locale code 31 | ``` 32 | 33 | Example: 34 | 35 | ``` 36 | assets 37 | └── lang 38 | ├── en.json 39 | └── en-US.json 40 | ``` 41 | 42 | Declare your assets localization directory in `pubspec.yaml`: 43 | 44 | ```yaml 45 | flutter: 46 | assets: 47 | - assets/lang/ 48 | ``` 49 | 50 | ### ⚠️ Note on **iOS** 51 | 52 | For translation to work on **iOS** you need to add supported locales to 53 | `ios/Runner/Info.plist` as described [here](https://flutter.dev/docs/development/accessibility-and-localization/internationalization#specifying-supportedlocales). 54 | 55 | Example: 56 | 57 | ```xml 58 | CFBundleLocalizations 59 | 60 | en 61 | nb 62 | 63 | ``` 64 | 65 | ### ⚙️ Configuration 66 | 67 | Add LocalizedApp widget like in example 68 | 69 | ```dart 70 | import 'package:flutter/material.dart'; 71 | import 'package:localize_and_translate/localize_and_translate.dart'; 72 | 73 | void main() async { 74 | WidgetsFlutterBinding.ensureInitialized(); 75 | await LocalizeAndTranslate.init( 76 | assetLoader: const AssetLoaderRootBundleJson('assets/lang/'), // <-- change the path of the translation files 77 | supportedLanguageCodes: ['ar', 'en'], // <-- or supportedLocales: [Locale('ar', 'EG'), Locale('en', 'US')], 78 | ); 79 | 80 | runApp( 81 | LocalizedApp( 82 | child: MaterialApp( 83 | // style 1 84 | builder: LocalizeAndTranslate.directionBuilder, 85 | // style 2 86 | builder: (BuildContext context, Widget? child) { 87 | child = LocalizeAndTranslate.directionBuilder(context, child); 88 | 89 | return child; 90 | }, 91 | home: const MyHomePage(), 92 | locale: context.locale, 93 | localizationsDelegates: context.delegates, 94 | supportedLocales: context.supportedLocales, 95 | ), 96 | ), 97 | ); 98 | } 99 | ``` 100 | 101 | [**Full example**](https://github.com/msayed-net/localize_and_translate/tree/main/example) 102 | 103 | ### 📜 Localize And Translate init properties 104 | 105 | | Properties | Required | Description | 106 | | ---------------------- | -------- | -------------------------------------------------------------------- | 107 | | supportedLanguageCodes | or next | List of supported languages to be converted to locales. | 108 | | supportedLocales | or prev | List of supported locales. | 109 | | assetLoader | true | Class loader for localization values. You can create your own class. | 110 | | assetLoadersExtra | true | Class loader for localization values. You can create your own class. | 111 | | defaultType | false | Path to your folder with localization files. | 112 | | mapper | false | Mapper for localization values. You can create your own class. | 113 | | hivePath | false | Path to hive box. | 114 | | hiveBackendPreference | false | Hive backend preference. | 115 | 116 | ## Usage 117 | 118 | ### Init 119 | 120 | Call `LocalizeAndTranslate.init(params)` in your main before runApp. 121 | 122 | ```dart 123 | void main() async{ 124 | // ... 125 | // Needs to be called so that we can await for LocalizeAndTranslate.init(); 126 | WidgetsFlutterBinding.ensureInitialized(); 127 | 128 | await LocalizeAndTranslate.init( 129 | assetLoader: const AssetLoaderRootBundleJson('assets/lang/'), // <-- change the path of the translation files 130 | supportedLocales: [Locale('ar', 'EG'), Locale('en', 'US')], // <-- or supportedLanguageCodes: ['ar', 'en'], 131 | defaultType: LocalizationDefaultType.asDefined, // <-- change the default type 132 | ); 133 | // ... 134 | runApp( 135 | // ... 136 | ); 137 | // ... 138 | } 139 | ``` 140 | 141 | or over network 142 | 143 | ```dart 144 | void main() async{ 145 | // ... 146 | // Needs to be called so that we can await for LocalizeAndTranslate.init(); 147 | WidgetsFlutterBinding.ensureInitialized(); 148 | 149 | await LocalizeAndTranslate.init( 150 | assetLoader: const AssetLoaderNetwork({ 151 | 'ar': 'https://raw.githubusercontent.com/msayed-net/localize_and_translate/main/example/assets/lang/ar.json', 152 | 'en': 'https://raw.githubusercontent.com/msayed-net/localize_and_translate/main/example/assets/lang/en.json', 153 | }), 154 | supportedLocales: [Locale('ar', 'EG'), Locale('en', 'US')], 155 | defaultType: LocalizationDefaultType.asDefined, 156 | ); 157 | // ... 158 | runApp( 159 | // ... 160 | ); 161 | // ... 162 | } 163 | ``` 164 | 165 | ### context extensions 166 | 167 | LocalizeAndTranslate uses extension methods [BuildContext] for access to some values. 168 | 169 | Example: 170 | 171 | ```dart 172 | // set locale 173 | context.setLocale(Locale('en', 'US')); 174 | 175 | // set language code 176 | context.setLanguageCode('en'); 177 | 178 | // get locale 179 | context.locale; // en_US 180 | 181 | // get language code 182 | context.languageCode; // en 183 | ``` 184 | 185 | ### Translate `tr()` 186 | 187 | Main function for translate your language keys 188 | 189 | ```dart 190 | print('title'.tr(defaultValue: 'Awesome App')); //String 191 | ``` 192 | 193 | ### Translations 194 | 195 | as json values pair 196 | 197 | ```json 198 | { 199 | "title": "Awesome App", 200 | "hello": "Hello", 201 | "world": "World!", 202 | } 203 | ``` 204 | 205 | ### API Reference 206 | 207 | | Properties | Extension | Type | Description | 208 | | ------------------ | --------- | -------- | ------------------------------------------------------------- | 209 | | `countryCode` | context | Property | Gets the country code of the current locale. | 210 | | `delegates` | context | Property | Gets the list of localization delegates used for translation. | 211 | | `init` | no | Method | Initializes the plugin with the desired configuration values. | 212 | | `locale` | context | Property | Gets the current locale being used for localization. | 213 | | `resetLocale` | context | Method | Resets the current locale to its default value. | 214 | | `setLanguageCode` | context | Method | Sets the language code for localization. | 215 | | `setLocale` | context | Method | Sets the current locale to one of the supported locales. | 216 | | `supportedLocales` | context | Property | Gets the list of supported locales for the app. | 217 | | `getKeys` | context | Method | Retrieves the list of keys for the current localization file. | 218 | | `tr` | string | Method | Retrieves the translated string for a given localization key. | 219 | 220 | Reset everything to default values passed through `init()`. 221 | 222 | Example: 223 | 224 | ```dart 225 | RaisedButton( 226 | onPressed: (){ 227 | context.resetLocale(); 228 | }, 229 | child: Text(LocaleKeys.reset_locale).tr(), 230 | ) 231 | ``` 232 | -------------------------------------------------------------------------------- /lib/src/core/localize_and_translate.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | import 'dart:ui' as ui; 3 | 4 | import 'package:flutter/cupertino.dart'; 5 | import 'package:flutter/foundation.dart'; 6 | import 'package:flutter_localizations/flutter_localizations.dart'; 7 | import 'package:hive_flutter/hive_flutter.dart'; 8 | import 'package:localize_and_translate/src/assets/asset_loader_base.dart'; 9 | import 'package:localize_and_translate/src/constants/db_keys.dart'; 10 | import 'package:localize_and_translate/src/constants/enums.dart'; 11 | import 'package:localize_and_translate/src/constants/error_messages.dart'; 12 | import 'package:localize_and_translate/src/db/db_box.dart'; 13 | import 'package:localize_and_translate/src/db/usecases.dart'; 14 | import 'package:localize_and_translate/src/exceptions/not_found_exception.dart'; 15 | import 'package:localize_and_translate/src/mappers/json_mapper_base.dart'; 16 | 17 | /// [LocalizeAndTranslate] is the main class of the package. 18 | /// It is used to initialize the package and to translate the words. 19 | /// It is a singleton class. 20 | /// It is used as follows: 21 | /// ```dart 22 | class LocalizeAndTranslate { 23 | /// [LocalizeAndTranslate] constructor 24 | factory LocalizeAndTranslate() => _instance; 25 | LocalizeAndTranslate._internal(); 26 | static final LocalizeAndTranslate _instance = LocalizeAndTranslate._internal(); 27 | 28 | /// [notifyUI] is the function that is used to notify the UI. 29 | static void Function()? notifyUI; 30 | 31 | ///--- 32 | /// ### setLocale 33 | /// --- 34 | static Future setLocale(Locale locale) async { 35 | await DBUseCases.write(DBKeys.languageCode, locale.languageCode); 36 | 37 | if (locale.countryCode == 'null') { 38 | await DBUseCases.write(DBKeys.countryCode, ''); 39 | } else { 40 | await DBUseCases.write(DBKeys.countryCode, locale.countryCode ?? ''); 41 | } 42 | 43 | await DBUseCases.write( 44 | DBKeys.isRTL, 45 | isRtlLanguage(locale.languageCode) ? 'true' : 'false', 46 | ); 47 | 48 | notifyUI?.call(); 49 | } 50 | 51 | /// --- 52 | /// ### setHivePath 53 | /// --- 54 | static Future setHivePath(String path) async { 55 | await DBUseCases.write(DBKeys.hivePath, path); 56 | } 57 | 58 | ///--- 59 | /// ### setLanguageCode 60 | /// --- 61 | static Future setLanguageCode(String languageCode) async { 62 | await setLocale( 63 | Locale(languageCode), 64 | ); 65 | } 66 | 67 | ///--- 68 | /// ### Returns app locales. 69 | /// 70 | /// used in app entry point e.g. MaterialApp() 71 | /// --- 72 | static List getLocals() { 73 | return DBUseCases.localesFromDBString( 74 | DBUseCases.readNullable(DBKeys.locales) ?? _getDeviceLanguageCode(), 75 | ); 76 | } 77 | 78 | /// --- 79 | /// ### Ensures that the package is initialized. 80 | /// --- 81 | static Future init({ 82 | required AssetLoaderBase assetLoader, 83 | List? assetLoadersExtra, 84 | List? supportedLocales, 85 | List? supportedLanguageCodes, 86 | LocalizationDefaultType defaultType = LocalizationDefaultType.device, 87 | String? hivePath, 88 | HiveStorageBackendPreference? hiveBackendPreference, 89 | JsonMapperBase? mapper, 90 | }) async { 91 | if (hivePath != null && hiveBackendPreference != null) { 92 | Hive.init(hivePath, backendPreference: hiveBackendPreference); 93 | } else if (hivePath != null && hiveBackendPreference == null) { 94 | Hive.init(hivePath); 95 | } else { 96 | await Hive.initFlutter(); 97 | } 98 | 99 | await DBBox.openBox(); 100 | 101 | await _writeSettings( 102 | supportedLocales: supportedLocales, 103 | supportedLanguageCodes: supportedLanguageCodes, 104 | type: defaultType, 105 | ); 106 | 107 | Map primaryTranslations = {}; 108 | Map fallbackTranslations = {}; 109 | Map finalTranslations = {}; 110 | 111 | try { 112 | // Attempt to load translations using the primary asset loader 113 | primaryTranslations = await assetLoader.load(mapper); 114 | debugPrint('--LocalizeAndTranslate-- Primary asset loader succeeded'); 115 | } catch (e) { 116 | debugPrint('--LocalizeAndTranslate-- Primary asset loader failed: $e'); 117 | } 118 | 119 | if (assetLoadersExtra != null) { 120 | for (final AssetLoaderBase loader in assetLoadersExtra) { 121 | try { 122 | // Attempt to load translations using the secondary asset loader 123 | final Map secondaryTranslations = await loader.load(mapper); 124 | debugPrint('--LocalizeAndTranslate-- Secondary asset loader succeeded'); 125 | fallbackTranslations = secondaryTranslations; 126 | break; 127 | } catch (e) { 128 | debugPrint('--LocalizeAndTranslate-- Secondary asset loader failed: $e'); 129 | } 130 | } 131 | } 132 | 133 | // Merge primary and fallback translations 134 | finalTranslations = {...fallbackTranslations, ...primaryTranslations}; 135 | 136 | await _writeTranslations(data: finalTranslations); 137 | 138 | debugPrint( 139 | '--LocalizeAndTranslate-- init | LanguageCode: ${getLanguageCode()}' 140 | ' | CountryCode: ${getCountryCode()} | isRTL: ${isRTL()}', 141 | ); 142 | } 143 | 144 | /// --- 145 | /// ### Returns Locale 146 | /// --- 147 | static Locale getLocale() { 148 | return Locale( 149 | getLanguageCode(), 150 | getCountryCode(), 151 | ); 152 | } 153 | 154 | /// --- 155 | /// ### Returns language code 156 | /// --- 157 | static String? getCountryCode() => DBUseCases.readNullable(DBKeys.countryCode); 158 | 159 | /// --- 160 | /// ### Returns language code 161 | /// --- 162 | static String getLanguageCode() { 163 | final String? langCode = DBUseCases.readNullable(DBKeys.languageCode); 164 | 165 | if (langCode == null) { 166 | return _getDeviceLocale().split('-').first; 167 | } 168 | 169 | return langCode; 170 | } 171 | 172 | /// --- 173 | /// ### Returns boolean value for isRTL 174 | /// --- 175 | static bool isRTL() { 176 | return DBUseCases.read(DBKeys.isRTL) == 'true'; 177 | } 178 | 179 | /// --- 180 | /// ### Returns translated string 181 | /// 182 | /// It takes the key and the default value. 183 | /// It returns the translated string. 184 | /// If the key is not found, it returns the default value. 185 | /// 186 | /// --- 187 | static String translate(String key, {String? defaultValue}) { 188 | final String? text = DBUseCases.readNullable(DBKeys.appendPrefix(key)); 189 | 190 | return text ?? defaultValue ?? ErrorMessages.keyNotFound(key); 191 | } 192 | 193 | ///--- 194 | /// ### Returns app delegates. 195 | /// 196 | /// used in app entry point e.g. MaterialApp() 197 | /// --- 198 | static Iterable> get delegates => >[ 199 | GlobalMaterialLocalizations.delegate, 200 | GlobalWidgetsLocalizations.delegate, 201 | GlobalCupertinoLocalizations.delegate, 202 | DefaultCupertinoLocalizations.delegate, 203 | ]; 204 | 205 | ///--- 206 | /// ### builder directionality 207 | /// --- 208 | static Widget directionBuilder(BuildContext context, Widget? child) { 209 | return Directionality( 210 | textDirection: isRTL() ? TextDirection.rtl : TextDirection.ltr, 211 | child: child ?? const SizedBox(), 212 | ); 213 | } 214 | 215 | ///--- 216 | /// ### Sets app locales. 217 | /// It takes the list of locales. 218 | /// It saves the list of locales to the database. 219 | /// --- 220 | static Future _setLocales(List locales) async { 221 | await DBUseCases.write( 222 | DBKeys.locales, 223 | DBUseCases.dbStringFromLocales(locales), 224 | ); 225 | } 226 | 227 | /// --- 228 | /// ### Ensures that the package is initialized. 229 | /// --- 230 | static Future _writeSettings({ 231 | List? supportedLocales, 232 | List? supportedLanguageCodes, 233 | LocalizationDefaultType? type = LocalizationDefaultType.device, 234 | String? hivePath, 235 | }) async { 236 | final List? locales = supportedLocales ?? supportedLanguageCodes?.map(Locale.new).toList(); 237 | 238 | if (locales == null) { 239 | throw NotFoundException('Locales not provided'); 240 | } 241 | 242 | if (hivePath != null) { 243 | await setHivePath(hivePath); 244 | } 245 | 246 | await _setLocales(locales); 247 | 248 | if (_getSavedLanguageCode() != null) { 249 | await setLocale(getLocale()); 250 | return; 251 | } 252 | 253 | if (type == LocalizationDefaultType.device) { 254 | await setLanguageCode( 255 | _getDeviceLanguageCode(), 256 | ); 257 | return; 258 | } 259 | 260 | if (locales.isNotEmpty) { 261 | await setLocale(locales.first); 262 | return; 263 | } 264 | } 265 | 266 | /// --- 267 | /// ### Writes translations to the database. 268 | /// --- 269 | static Future _writeTranslations({ 270 | required Map data, 271 | }) async { 272 | await DBUseCases.writeMap( 273 | data.map((String key, dynamic value) { 274 | return MapEntry(key, value.toString()); 275 | }), 276 | ); 277 | } 278 | 279 | static String? _getSavedLanguageCode() { 280 | return DBUseCases.readNullable(DBKeys.languageCode); 281 | } 282 | 283 | /// --- 284 | /// ### Returns device locale. 285 | /// --- 286 | static String _getDeviceLocale() { 287 | if (kIsWeb) { 288 | // Use `window.locale` for web 289 | return ui.window.locale.toString(); 290 | } 291 | // Fallback for non-web platforms 292 | return Platform.localeName; 293 | } 294 | 295 | /// --- 296 | /// ### Returns device language code. 297 | /// --- 298 | static String _getDeviceLanguageCode() { 299 | // split on - or _ to support locales like en-US or en_US 300 | return _getDeviceLocale().split(RegExp('[-_]+')).first; 301 | } 302 | 303 | /// --- 304 | /// ### Determines if a language is written right-to-left based on its language code. 305 | /// --- 306 | static List getKeys() { 307 | return DBUseCases.getKeys(); 308 | } 309 | 310 | /// Determines if a language is written right-to-left based on its language code. 311 | static bool isRtlLanguage(String languageCode) { 312 | const Set rtlLanguages = { 313 | 'ar', // Arabic 314 | 'fa', // Persian 315 | 'he', // Hebrew 316 | 'ur', // Urdu 317 | 'ps', // Pashto 318 | 'sd', // Sindhi 319 | }; 320 | 321 | return rtlLanguages.contains(languageCode); 322 | } 323 | } 324 | -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | # example 2 | 3 | ## example/assets/lang/ar-EG.json 4 | 5 | ```json 6 | { 7 | "title": "السلام", 8 | "msg":"السلام عليكم يا {} في عالم {}", 9 | "clickMe":"إضغط هنا", 10 | "profile": { 11 | "reset_password": { 12 | "label": "اعادة تعين كلمة السر", 13 | "username": "المستخدم", 14 | "password": "كلمة السر" 15 | } 16 | }, 17 | "clicked": { 18 | "zero": "{} نقرة!", 19 | "one": "{} نقرة!", 20 | "two":"{} نقرات!", 21 | "few":"{} نقرات!", 22 | "many":"{} نقرة!", 23 | "other": "{} نقرة!" 24 | }, 25 | "gender":{ 26 | "male": " مرحبا يا رجل", 27 | "female": " مرحبا بك يا فتاة", 28 | "with_arg":{ 29 | "male": "{} مرحبا يا رجل", 30 | "female": "{} مرحبا بك يا فتاة" 31 | } 32 | } 33 | } 34 | ``` 35 | 36 | ## example/assets/lang/en-US.json 37 | 38 | ```json 39 | { 40 | "title": "Hello", 41 | "msg": "Hello {} in the {} world ", 42 | "clickMe": "Click me", 43 | "profile": { 44 | "reset_password": { 45 | "label": "Reset Password", 46 | "username": "Username", 47 | "password": "password" 48 | } 49 | }, 50 | "clicked": { 51 | "zero": "You clicked {} times!", 52 | "one": "You clicked {} time!", 53 | "two":"You clicked {} times!", 54 | "few":"You clicked {} times!", 55 | "many":"You clicked {} times!", 56 | "other": "You clicked {} times!" 57 | }, 58 | "gender":{ 59 | "male": "Hi man ;) ", 60 | "female": "Hello girl :)", 61 | "with_arg":{ 62 | "male": "Hi man ;) {}", 63 | "female": "Hello girl :) {}" 64 | } 65 | } 66 | } 67 | 68 | ``` 69 | 70 | ### [example/lib/main.dart](https://github.com/aissat/localize_and_translate/blob/master/example/lib/main.dart) 71 | 72 | ```dart 73 | import 'dart:developer'; 74 | 75 | import 'package:example/lang_view.dart'; 76 | import 'package:example/my_flutter_app_icons.dart'; 77 | import 'package:flutter/material.dart'; 78 | import 'package:flutter_localizations/flutter_localizations.dart'; 79 | import 'package:localize_and_translate/localize_and_translate.dart'; 80 | 81 | void main() async{ 82 | 83 | // WidgetsFlutterBinding.ensureInitialized(); 84 | await LocalizeAndTranslate.ensureInitialized(); 85 | 86 | runApp(LocalizeAndTranslate( 87 | child: MyApp(), 88 | supportedLocales: [Locale('en', 'US'), Locale('ar', 'EG')], 89 | path: 'assets/lang', 90 | // fallbackLocale: Locale('en', 'US'), 91 | // saveLocale: false, 92 | // useOnlyLangCode: true, 93 | 94 | // optional assetLoader default used is RootBundleAssetLoader which uses flutter's assetloader 95 | // install localize_and_translate_loader for enable custom loaders 96 | // assetLoader: RootBundleAssetLoader() 97 | // assetLoader: HttpAssetLoader() 98 | // assetLoader: FileAssetLoader() 99 | assetLoader: CsvAssetLoader() 100 | // assetLoader: YamlAssetLoader() //multiple files 101 | // assetLoader: YamlSingleAssetLoader() //single file 102 | // assetLoader: XmlAssetLoader() //multiple files 103 | // assetLoader: XmlSingleAssetLoader() //single file 104 | 105 | // assetLoader: CodegenLoader() 106 | )); 107 | } 108 | 109 | class MyApp extends StatelessWidget { 110 | @override 111 | Widget build(BuildContext context) { 112 | log( LocalizeAndTranslate.of(context).locale.toString(), name: this.toString()+"# locale" ); 113 | log( Intl.defaultLocale.toString(), name: this.toString()+"# Intl.defaultLocale" ); 114 | return MaterialApp( 115 | title: 'Flutter Demo', 116 | localizationsDelegates: [ 117 | GlobalMaterialLocalizations.delegate, 118 | GlobalWidgetsLocalizations.delegate, 119 | LocalizeAndTranslate.of(context).delegate, 120 | ], 121 | supportedLocales: LocalizeAndTranslate.of(context).supportedLocales, 122 | locale: LocalizeAndTranslate.of(context).locale, 123 | theme: ThemeData( 124 | primarySwatch: Colors.blue, 125 | ), 126 | home: MyHomePage(title: 'Localize And Translate'), 127 | ); 128 | } 129 | } 130 | 131 | class MyHomePage extends StatefulWidget { 132 | MyHomePage({Key key, this.title}) : super(key: key); 133 | 134 | final String title; 135 | 136 | @override 137 | _MyHomePageState createState() => _MyHomePageState(); 138 | } 139 | 140 | class _MyHomePageState extends State { 141 | int counter = 0; 142 | bool _gender = true; 143 | 144 | incrementCounter() { 145 | setState(() { 146 | counter++; 147 | }); 148 | } 149 | 150 | switchGender(bool val) { 151 | setState(() { 152 | _gender = val; 153 | }); 154 | } 155 | 156 | @override 157 | Widget build(BuildContext context) { 158 | log(tr("title"), name: this.toString() ); 159 | return Scaffold( 160 | appBar: AppBar( 161 | title: Text("title").tr(context: context), 162 | //Text(AppLocalizations.of(context).tr('title')), 163 | actions: [ 164 | FlatButton( 165 | child: Icon(Icons.language), 166 | onPressed: () { 167 | Navigator.push( 168 | context, 169 | MaterialPageRoute( 170 | builder: (_) => LanguageView(), fullscreenDialog: true), 171 | ); 172 | }, 173 | ), 174 | ], 175 | ), 176 | body: Center( 177 | child: Column( 178 | mainAxisAlignment: MainAxisAlignment.center, 179 | children: [ 180 | Spacer( 181 | flex: 1, 182 | ), 183 | Text( 184 | 'switch.with_arg', 185 | style: TextStyle( 186 | color: Colors.grey.shade600, 187 | fontSize: 19, 188 | fontWeight: FontWeight.bold), 189 | ).tr(args: ["aissat"], gender: _gender ? "female" : "male"), 190 | Text( 191 | tr('switch', gender: _gender ? "female" : "male"), 192 | style: TextStyle( 193 | color: Colors.grey.shade600, 194 | fontSize: 15, 195 | fontWeight: FontWeight.bold), 196 | ), 197 | Row( 198 | mainAxisAlignment: MainAxisAlignment.center, 199 | children: [ 200 | Icon(MyFlutterApp.male_1), 201 | Switch(value: _gender, onChanged: switchGender), 202 | Icon(MyFlutterApp.female_1), 203 | ], 204 | ), 205 | Spacer( 206 | flex: 1, 207 | ), 208 | Text('msg').tr(args: ['aissat', 'Flutter']), 209 | Text('clicked').plural(counter), 210 | FlatButton( 211 | onPressed: () { 212 | incrementCounter(); 213 | }, 214 | child: Text('clickMe').tr(), 215 | ), 216 | SizedBox( 217 | height: 15, 218 | ), 219 | Text( 220 | plural('amount', counter, 221 | format: NumberFormat.currency( 222 | locale: Intl.defaultLocale, 223 | symbol: "€")), 224 | style: TextStyle( 225 | color: Colors.grey.shade900, 226 | fontSize: 18, 227 | fontWeight: FontWeight.bold)), 228 | SizedBox( 229 | height: 20, 230 | ), 231 | Text('profile.reset_password.title').tr(), 232 | Spacer( 233 | flex: 2, 234 | ), 235 | ], 236 | ), 237 | ), 238 | floatingActionButton: FloatingActionButton( 239 | onPressed: incrementCounter, 240 | child: Text('+1'), 241 | ), 242 | ); 243 | } 244 | } 245 | 246 | ``` 247 | 248 | ### [example/lib/lang_view.dart](https://github.com/aissat/localize_and_translate/blob/master/example/lib/lang_view.dart) 249 | 250 | ```dart 251 | import 'dart:developer'; 252 | 253 | import 'package:flutter/material.dart'; 254 | import 'package:localize_and_translate/localize_and_translate.dart'; 255 | 256 | class LanguageView extends StatelessWidget { 257 | @override 258 | Widget build(BuildContext context) { 259 | return Scaffold( 260 | appBar: AppBar( 261 | title: Text( 262 | "", 263 | style: TextStyle(color: Colors.black), 264 | ), 265 | backgroundColor: Colors.white, 266 | iconTheme: IconThemeData(color: Colors.black), 267 | elevation: 0, 268 | ), 269 | body: Container( 270 | color: Colors.white, 271 | child: Column( 272 | crossAxisAlignment: CrossAxisAlignment.start, 273 | children: [ 274 | Container( 275 | padding: EdgeInsets.only(top: 26), 276 | margin: EdgeInsets.symmetric( 277 | horizontal: 24, 278 | ), 279 | child: Text( 280 | "Language Menu", 281 | style: TextStyle( 282 | color: Color.fromARGB(255, 166, 166, 166), 283 | fontFamily: "Montserrat", 284 | fontWeight: FontWeight.w700, 285 | fontSize: 10, 286 | ), 287 | ), 288 | ), 289 | Container( 290 | padding: EdgeInsets.only(top: 10, bottom: 25), 291 | margin: EdgeInsets.symmetric( 292 | horizontal: 24, 293 | ), 294 | child: Text( 295 | "language", 296 | ), 297 | ), 298 | buildDivider(), 299 | buildSwitchListTileMenuItem( 300 | context: context, 301 | title: "عربي", 302 | subtitle: "عربي", 303 | locale: Locale("ar", "EG")), 304 | buildDivider(), 305 | buildSwitchListTileMenuItem( 306 | context: context, 307 | title: "English", 308 | subtitle: "English", 309 | locale: Locale("en", "US")), 310 | buildDivider(), 311 | ], 312 | ), 313 | ), 314 | ); 315 | } 316 | 317 | Container buildDivider() => Container( 318 | margin: EdgeInsets.symmetric( 319 | horizontal: 24, 320 | ), 321 | child: Divider( 322 | color: Colors.grey, 323 | ), 324 | ); 325 | 326 | Container buildSwitchListTileMenuItem( 327 | {BuildContext context, String title, String subtitle, Locale locale}) { 328 | return Container( 329 | margin: EdgeInsets.only( 330 | left: 10, 331 | right: 10, 332 | top: 5, 333 | ), 334 | child: ListTile( 335 | dense: true, 336 | // isThreeLine: true, 337 | title: Text( 338 | title, 339 | ), 340 | subtitle: Text( 341 | subtitle, 342 | ), 343 | onTap: () { 344 | log(locale.toString(), name: this.toString()); 345 | LocalizeAndTranslate.of(context).locale = locale; 346 | }), 347 | ); 348 | } 349 | } 350 | ``` 351 | -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | # Specify analysis options. 2 | # 3 | # This file is a copy of analysis_options.yaml from flutter repo 4 | # as of 2023-03-22, but with some modifications marked with 5 | # "DIFFERENT FROM FLUTTER/FLUTTER" below. 6 | 7 | analyzer: 8 | language: 9 | strict-casts: true 10 | strict-inference: true 11 | strict-raw-types: true 12 | errors: 13 | # allow self-reference to deprecated members (we do this because otherwise we have 14 | # to annotate every member in every test, assert, etc, when we deprecate something) 15 | deprecated_member_use_from_same_package: ignore 16 | exclude: # DIFFERENT FROM FLUTTER/FLUTTER 17 | # Fixture depends on dart:ui and raises false positives. 18 | - flutter_frontend_server/test/fixtures/lib/main.dart 19 | 20 | linter: 21 | rules: 22 | # This list is derived from the list of all available lints located at 23 | # https://github.com/dart-lang/linter/blob/master/example/all.yaml 24 | - always_declare_return_types 25 | - always_put_control_body_on_new_line 26 | # - always_put_required_named_parameters_first # we prefer having parameters in the same order as fields https://github.com/flutter/flutter/issues/10219 27 | - always_specify_types 28 | # - always_use_package_imports # we do this commonly 29 | - annotate_overrides 30 | # - avoid_annotating_with_dynamic # conflicts with always_specify_types 31 | - avoid_bool_literals_in_conditional_expressions 32 | # - avoid_catches_without_on_clauses # blocked on https://github.com/dart-lang/linter/issues/3023 33 | # - avoid_catching_errors # blocked on https://github.com/dart-lang/linter/issues/3023 34 | # - avoid_classes_with_only_static_members # we do this commonly 35 | - avoid_double_and_int_checks 36 | - avoid_dynamic_calls 37 | - avoid_empty_else 38 | # - avoid_equals_and_hash_code_on_mutable_classes # DIFFERENT FROM FLUTTER/FLUTTER (can't import the meta package here) 39 | - avoid_escaping_inner_quotes 40 | - avoid_field_initializers_in_const_classes 41 | # - avoid_final_parameters # incompatible with prefer_final_parameters 42 | - avoid_function_literals_in_foreach_calls 43 | - avoid_implementing_value_types 44 | - avoid_init_to_null 45 | - avoid_js_rounded_ints 46 | # - avoid_multiple_declarations_per_line # seems to be a stylistic choice we don't subscribe to 47 | - avoid_null_checks_in_equality_operators 48 | # - avoid_positional_boolean_parameters # would have been nice to enable this but by now there's too many places that break it 49 | - avoid_print 50 | # - avoid_private_typedef_functions # we prefer having typedef (discussion in https://github.com/flutter/flutter/pull/16356) 51 | - avoid_redundant_argument_values 52 | - avoid_relative_lib_imports 53 | - avoid_renaming_method_parameters 54 | - avoid_return_types_on_setters 55 | - avoid_returning_null_for_void 56 | # - avoid_returning_this # there are enough valid reasons to return `this` that this lint ends up with too many false positives 57 | - avoid_setters_without_getters 58 | - avoid_shadowing_type_parameters 59 | - avoid_single_cascade_in_expression_statements 60 | - avoid_slow_async_io 61 | - avoid_type_to_string 62 | - avoid_types_as_parameter_names 63 | # - avoid_types_on_closure_parameters # conflicts with always_specify_types 64 | - avoid_unnecessary_containers 65 | - avoid_unused_constructor_parameters 66 | - avoid_void_async 67 | # - avoid_web_libraries_in_flutter # we use web libraries in web-specific code, and our tests prevent us from using them elsewhere 68 | - await_only_futures 69 | - camel_case_extensions 70 | - camel_case_types 71 | - cancel_subscriptions 72 | # - cascade_invocations # doesn't match the typical style of this repo 73 | - cast_nullable_to_non_nullable 74 | # - close_sinks # not reliable enough 75 | - collection_methods_unrelated_type 76 | - combinators_ordering 77 | # - comment_references # blocked on https://github.com/dart-lang/linter/issues/1142 78 | - conditional_uri_does_not_exist 79 | # - constant_identifier_names # needs an opt-out https://github.com/dart-lang/linter/issues/204 80 | - control_flow_in_finally 81 | - curly_braces_in_flow_control_structures 82 | - dangling_library_doc_comments 83 | - depend_on_referenced_packages 84 | - deprecated_consistency 85 | # - diagnostic_describe_all_properties # enabled only at the framework level (packages/flutter/lib) 86 | - directives_ordering 87 | # - discarded_futures # too many false positives, similar to unawaited_futures 88 | # - do_not_use_environment # there are appropriate times to use the environment, especially in our tests and build logic 89 | - empty_catches 90 | - empty_constructor_bodies 91 | - empty_statements 92 | - eol_at_end_of_file 93 | - exhaustive_cases 94 | - file_names 95 | - flutter_style_todos 96 | - hash_and_equals 97 | - implementation_imports 98 | - implicit_call_tearoffs 99 | - invalid_case_patterns 100 | # - join_return_with_assignment # not required by flutter style 101 | - leading_newlines_in_multiline_strings 102 | - library_annotations 103 | - library_names 104 | - library_prefixes 105 | - library_private_types_in_public_api 106 | # - lines_longer_than_80_chars # not required by flutter style 107 | # - literal_only_boolean_expressions # too many false positives: https://github.com/dart-lang/linter/issues/453 108 | # - missing_whitespace_between_adjacent_strings # DIFFERENT FROM FLUTTER/FLUTTER (too many false positives) 109 | - no_adjacent_strings_in_list 110 | - no_default_cases 111 | - no_duplicate_case_values 112 | - no_leading_underscores_for_library_prefixes 113 | - no_leading_underscores_for_local_identifiers 114 | - no_logic_in_create_state 115 | # - no_runtimeType_toString # ok in tests; we enable this only in packages/ 116 | - non_constant_identifier_names 117 | - noop_primitive_operations 118 | - null_check_on_nullable_type_parameter 119 | - null_closures 120 | # - omit_local_variable_types # opposite of always_specify_types 121 | # - one_member_abstracts # too many false positives 122 | - only_throw_errors # this does get disabled in a few places where we have legacy code that uses strings et al 123 | - overridden_fields 124 | - package_api_docs 125 | - package_names 126 | - package_prefixed_library_names 127 | # - parameter_assignments # we do this commonly 128 | - prefer_adjacent_string_concatenation 129 | - prefer_asserts_in_initializer_lists 130 | # - prefer_asserts_with_message # not required by flutter style 131 | - prefer_collection_literals 132 | - prefer_conditional_assignment 133 | - prefer_const_constructors 134 | - prefer_const_constructors_in_immutables 135 | - prefer_const_declarations 136 | - prefer_const_literals_to_create_immutables 137 | # - prefer_constructors_over_static_methods # far too many false positives 138 | - prefer_contains 139 | # - prefer_double_quotes # opposite of prefer_single_quotes 140 | # - prefer_expression_function_bodies # conflicts with https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#consider-using--for-short-functions-and-methods 141 | - prefer_final_fields 142 | - prefer_final_in_for_each 143 | - prefer_final_locals 144 | # - prefer_final_parameters # we should enable this one day when it can be auto-fixed (https://github.com/dart-lang/linter/issues/3104), see also parameter_assignments 145 | - prefer_for_elements_to_map_fromIterable 146 | - prefer_foreach 147 | - prefer_function_declarations_over_variables 148 | - prefer_generic_function_type_aliases 149 | - prefer_if_elements_to_conditional_expressions 150 | - prefer_if_null_operators 151 | - prefer_initializing_formals 152 | - prefer_inlined_adds 153 | # - prefer_int_literals # conflicts with https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#use-double-literals-for-double-constants 154 | - prefer_interpolation_to_compose_strings 155 | - prefer_is_empty 156 | - prefer_is_not_empty 157 | - prefer_is_not_operator 158 | - prefer_iterable_whereType 159 | - prefer_mixin 160 | # - prefer_null_aware_method_calls # "call()" is confusing to people new to the language since it's not documented anywhere 161 | - prefer_null_aware_operators 162 | - prefer_single_quotes 163 | - prefer_spread_collections 164 | - prefer_typing_uninitialized_variables 165 | - prefer_void_to_null 166 | - provide_deprecation_message 167 | - public_member_api_docs # DIFFERENT FROM FLUTTER/FLUTTER 168 | - recursive_getters 169 | # - require_trailing_commas # would be nice, but requires a lot of manual work: 10,000+ code locations would need to be reformatted by hand after bulk fix is applied 170 | - secure_pubspec_urls 171 | - sized_box_for_whitespace 172 | - sized_box_shrink_expand 173 | - slash_for_doc_comments 174 | - sort_child_properties_last 175 | - sort_constructors_first 176 | # - sort_pub_dependencies # prevents separating pinned transitive dependencies 177 | - sort_unnamed_constructors_first 178 | - test_types_in_equals 179 | - throw_in_finally 180 | - tighten_type_of_initializing_formals 181 | # - type_annotate_public_apis # subset of always_specify_types 182 | - type_init_formals 183 | # - unawaited_futures # too many false positives, especially with the way AnimationController works 184 | - unnecessary_await_in_return 185 | - unnecessary_brace_in_string_interps 186 | - unnecessary_breaks 187 | - unnecessary_const 188 | - unnecessary_constructor_name 189 | # - unnecessary_final # conflicts with prefer_final_locals 190 | - unnecessary_getters_setters 191 | # - unnecessary_lambdas # has false positives: https://github.com/dart-lang/linter/issues/498 192 | - unnecessary_late 193 | - unnecessary_library_directive 194 | - unnecessary_new 195 | - unnecessary_null_aware_assignments 196 | - unnecessary_null_aware_operator_on_extension_on_nullable 197 | - unnecessary_null_checks 198 | - unnecessary_null_in_if_null_operators 199 | - unnecessary_nullable_for_final_variable_declarations 200 | - unnecessary_overrides 201 | - unnecessary_parenthesis 202 | # - unnecessary_raw_strings # what's "necessary" is a matter of opinion; consistency across strings can help readability more than this lint 203 | - unnecessary_statements 204 | - unnecessary_string_escapes 205 | - unnecessary_string_interpolations 206 | - unnecessary_this 207 | - unnecessary_to_list_in_spreads 208 | # - unreachable_from_main # Do not enable this rule until it is un-marked as "experimental" and carefully re-evaluated. 209 | - unrelated_type_equality_checks 210 | - unsafe_html 211 | - use_build_context_synchronously 212 | - use_colored_box 213 | # - use_decorated_box # leads to bugs: DecoratedBox and Container are not equivalent (Container inserts extra padding) 214 | - use_enums 215 | - use_full_hex_values_for_flutter_colors 216 | - use_function_type_syntax_for_parameters 217 | - use_if_null_to_convert_nulls_to_bools 218 | - use_is_even_rather_than_modulo 219 | - use_key_in_widget_constructors 220 | - use_late_for_private_fields_and_variables 221 | - use_named_constants 222 | - use_raw_strings 223 | - use_rethrow_when_possible 224 | - use_setters_to_change_properties 225 | # - use_string_buffers # has false positives: https://github.com/dart-lang/sdk/issues/34182 226 | # - use_string_in_part_of_directives # DIFFERENT FROM FLUTTER/FLUTTER (needs to be evaluated, dart:ui does this frequently) 227 | - use_super_parameters 228 | - use_test_throws_matchers 229 | # - use_to_and_as_if_applicable # has false positives, so we prefer to catch this by code-review 230 | - valid_regexps 231 | - void_checks 232 | -------------------------------------------------------------------------------- /pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://dart.dev/tools/pub/glossary#lockfile 3 | packages: 4 | async: 5 | dependency: transitive 6 | description: 7 | name: async 8 | sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" 9 | url: "https://pub.dev" 10 | source: hosted 11 | version: "2.11.0" 12 | boolean_selector: 13 | dependency: transitive 14 | description: 15 | name: boolean_selector 16 | sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" 17 | url: "https://pub.dev" 18 | source: hosted 19 | version: "2.1.1" 20 | characters: 21 | dependency: transitive 22 | description: 23 | name: characters 24 | sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" 25 | url: "https://pub.dev" 26 | source: hosted 27 | version: "1.3.0" 28 | clock: 29 | dependency: transitive 30 | description: 31 | name: clock 32 | sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf 33 | url: "https://pub.dev" 34 | source: hosted 35 | version: "1.1.1" 36 | collection: 37 | dependency: transitive 38 | description: 39 | name: collection 40 | sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a 41 | url: "https://pub.dev" 42 | source: hosted 43 | version: "1.18.0" 44 | crypto: 45 | dependency: transitive 46 | description: 47 | name: crypto 48 | sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855" 49 | url: "https://pub.dev" 50 | source: hosted 51 | version: "3.0.6" 52 | dio: 53 | dependency: "direct main" 54 | description: 55 | name: dio 56 | sha256: "5598aa796bbf4699afd5c67c0f5f6e2ed542afc956884b9cd58c306966efc260" 57 | url: "https://pub.dev" 58 | source: hosted 59 | version: "5.7.0" 60 | dio_web_adapter: 61 | dependency: transitive 62 | description: 63 | name: dio_web_adapter 64 | sha256: "33259a9276d6cea88774a0000cfae0d861003497755969c92faa223108620dc8" 65 | url: "https://pub.dev" 66 | source: hosted 67 | version: "2.0.0" 68 | fake_async: 69 | dependency: transitive 70 | description: 71 | name: fake_async 72 | sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" 73 | url: "https://pub.dev" 74 | source: hosted 75 | version: "1.3.1" 76 | ffi: 77 | dependency: transitive 78 | description: 79 | name: ffi 80 | sha256: "7bf0adc28a23d395f19f3f1eb21dd7cfd1dd9f8e1c50051c069122e6853bc878" 81 | url: "https://pub.dev" 82 | source: hosted 83 | version: "2.1.0" 84 | flutter: 85 | dependency: "direct main" 86 | description: flutter 87 | source: sdk 88 | version: "0.0.0" 89 | flutter_lints: 90 | dependency: "direct dev" 91 | description: 92 | name: flutter_lints 93 | sha256: a25a15ebbdfc33ab1cd26c63a6ee519df92338a9c10f122adda92938253bef04 94 | url: "https://pub.dev" 95 | source: hosted 96 | version: "2.0.3" 97 | flutter_localizations: 98 | dependency: "direct main" 99 | description: flutter 100 | source: sdk 101 | version: "0.0.0" 102 | flutter_test: 103 | dependency: "direct dev" 104 | description: flutter 105 | source: sdk 106 | version: "0.0.0" 107 | hive: 108 | dependency: "direct main" 109 | description: 110 | name: hive 111 | sha256: "8dcf6db979d7933da8217edcec84e9df1bdb4e4edc7fc77dbd5aa74356d6d941" 112 | url: "https://pub.dev" 113 | source: hosted 114 | version: "2.2.3" 115 | hive_flutter: 116 | dependency: "direct main" 117 | description: 118 | name: hive_flutter 119 | sha256: dca1da446b1d808a51689fb5d0c6c9510c0a2ba01e22805d492c73b68e33eecc 120 | url: "https://pub.dev" 121 | source: hosted 122 | version: "1.1.0" 123 | http_parser: 124 | dependency: transitive 125 | description: 126 | name: http_parser 127 | sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" 128 | url: "https://pub.dev" 129 | source: hosted 130 | version: "4.0.2" 131 | intl: 132 | dependency: transitive 133 | description: 134 | name: intl 135 | sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf 136 | url: "https://pub.dev" 137 | source: hosted 138 | version: "0.19.0" 139 | leak_tracker: 140 | dependency: transitive 141 | description: 142 | name: leak_tracker 143 | sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05" 144 | url: "https://pub.dev" 145 | source: hosted 146 | version: "10.0.5" 147 | leak_tracker_flutter_testing: 148 | dependency: transitive 149 | description: 150 | name: leak_tracker_flutter_testing 151 | sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806" 152 | url: "https://pub.dev" 153 | source: hosted 154 | version: "3.0.5" 155 | leak_tracker_testing: 156 | dependency: transitive 157 | description: 158 | name: leak_tracker_testing 159 | sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" 160 | url: "https://pub.dev" 161 | source: hosted 162 | version: "3.0.1" 163 | lints: 164 | dependency: transitive 165 | description: 166 | name: lints 167 | sha256: "0a217c6c989d21039f1498c3ed9f3ed71b354e69873f13a8dfc3c9fe76f1b452" 168 | url: "https://pub.dev" 169 | source: hosted 170 | version: "2.1.1" 171 | matcher: 172 | dependency: transitive 173 | description: 174 | name: matcher 175 | sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb 176 | url: "https://pub.dev" 177 | source: hosted 178 | version: "0.12.16+1" 179 | material_color_utilities: 180 | dependency: transitive 181 | description: 182 | name: material_color_utilities 183 | sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec 184 | url: "https://pub.dev" 185 | source: hosted 186 | version: "0.11.1" 187 | meta: 188 | dependency: transitive 189 | description: 190 | name: meta 191 | sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 192 | url: "https://pub.dev" 193 | source: hosted 194 | version: "1.15.0" 195 | path: 196 | dependency: transitive 197 | description: 198 | name: path 199 | sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" 200 | url: "https://pub.dev" 201 | source: hosted 202 | version: "1.9.0" 203 | path_provider: 204 | dependency: transitive 205 | description: 206 | name: path_provider 207 | sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd" 208 | url: "https://pub.dev" 209 | source: hosted 210 | version: "2.1.5" 211 | path_provider_android: 212 | dependency: transitive 213 | description: 214 | name: path_provider_android 215 | sha256: "8c4967f8b7cb46dc914e178daa29813d83ae502e0529d7b0478330616a691ef7" 216 | url: "https://pub.dev" 217 | source: hosted 218 | version: "2.2.14" 219 | path_provider_foundation: 220 | dependency: transitive 221 | description: 222 | name: path_provider_foundation 223 | sha256: f234384a3fdd67f989b4d54a5d73ca2a6c422fa55ae694381ae0f4375cd1ea16 224 | url: "https://pub.dev" 225 | source: hosted 226 | version: "2.4.0" 227 | path_provider_linux: 228 | dependency: transitive 229 | description: 230 | name: path_provider_linux 231 | sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279 232 | url: "https://pub.dev" 233 | source: hosted 234 | version: "2.2.1" 235 | path_provider_platform_interface: 236 | dependency: transitive 237 | description: 238 | name: path_provider_platform_interface 239 | sha256: "94b1e0dd80970c1ce43d5d4e050a9918fce4f4a775e6142424c30a29a363265c" 240 | url: "https://pub.dev" 241 | source: hosted 242 | version: "2.1.1" 243 | path_provider_windows: 244 | dependency: transitive 245 | description: 246 | name: path_provider_windows 247 | sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170" 248 | url: "https://pub.dev" 249 | source: hosted 250 | version: "2.2.1" 251 | platform: 252 | dependency: transitive 253 | description: 254 | name: platform 255 | sha256: ae68c7bfcd7383af3629daafb32fb4e8681c7154428da4febcff06200585f102 256 | url: "https://pub.dev" 257 | source: hosted 258 | version: "3.1.2" 259 | plugin_platform_interface: 260 | dependency: transitive 261 | description: 262 | name: plugin_platform_interface 263 | sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" 264 | url: "https://pub.dev" 265 | source: hosted 266 | version: "2.1.8" 267 | sky_engine: 268 | dependency: transitive 269 | description: flutter 270 | source: sdk 271 | version: "0.0.99" 272 | source_span: 273 | dependency: transitive 274 | description: 275 | name: source_span 276 | sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" 277 | url: "https://pub.dev" 278 | source: hosted 279 | version: "1.10.0" 280 | stack_trace: 281 | dependency: transitive 282 | description: 283 | name: stack_trace 284 | sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" 285 | url: "https://pub.dev" 286 | source: hosted 287 | version: "1.11.1" 288 | stream_channel: 289 | dependency: transitive 290 | description: 291 | name: stream_channel 292 | sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 293 | url: "https://pub.dev" 294 | source: hosted 295 | version: "2.1.2" 296 | string_scanner: 297 | dependency: transitive 298 | description: 299 | name: string_scanner 300 | sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" 301 | url: "https://pub.dev" 302 | source: hosted 303 | version: "1.2.0" 304 | term_glyph: 305 | dependency: transitive 306 | description: 307 | name: term_glyph 308 | sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 309 | url: "https://pub.dev" 310 | source: hosted 311 | version: "1.2.1" 312 | test_api: 313 | dependency: transitive 314 | description: 315 | name: test_api 316 | sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" 317 | url: "https://pub.dev" 318 | source: hosted 319 | version: "0.7.2" 320 | typed_data: 321 | dependency: transitive 322 | description: 323 | name: typed_data 324 | sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 325 | url: "https://pub.dev" 326 | source: hosted 327 | version: "1.4.0" 328 | vector_math: 329 | dependency: transitive 330 | description: 331 | name: vector_math 332 | sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" 333 | url: "https://pub.dev" 334 | source: hosted 335 | version: "2.1.4" 336 | vm_service: 337 | dependency: transitive 338 | description: 339 | name: vm_service 340 | sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d" 341 | url: "https://pub.dev" 342 | source: hosted 343 | version: "14.2.5" 344 | web: 345 | dependency: transitive 346 | description: 347 | name: web 348 | sha256: cd3543bd5798f6ad290ea73d210f423502e71900302dde696f8bff84bf89a1cb 349 | url: "https://pub.dev" 350 | source: hosted 351 | version: "1.1.0" 352 | win32: 353 | dependency: transitive 354 | description: 355 | name: win32 356 | sha256: "464f5674532865248444b4c3daca12bd9bf2d7c47f759ce2617986e7229494a8" 357 | url: "https://pub.dev" 358 | source: hosted 359 | version: "5.2.0" 360 | xdg_directories: 361 | dependency: transitive 362 | description: 363 | name: xdg_directories 364 | sha256: "589ada45ba9e39405c198fe34eb0f607cddb2108527e658136120892beac46d2" 365 | url: "https://pub.dev" 366 | source: hosted 367 | version: "1.0.3" 368 | sdks: 369 | dart: ">=3.5.0 <4.0.0" 370 | flutter: ">=3.24.0" 371 | -------------------------------------------------------------------------------- /example/pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://dart.dev/tools/pub/glossary#lockfile 3 | packages: 4 | async: 5 | dependency: transitive 6 | description: 7 | name: async 8 | sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" 9 | url: "https://pub.dev" 10 | source: hosted 11 | version: "2.11.0" 12 | boolean_selector: 13 | dependency: transitive 14 | description: 15 | name: boolean_selector 16 | sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" 17 | url: "https://pub.dev" 18 | source: hosted 19 | version: "2.1.1" 20 | characters: 21 | dependency: transitive 22 | description: 23 | name: characters 24 | sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" 25 | url: "https://pub.dev" 26 | source: hosted 27 | version: "1.3.0" 28 | clock: 29 | dependency: transitive 30 | description: 31 | name: clock 32 | sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf 33 | url: "https://pub.dev" 34 | source: hosted 35 | version: "1.1.1" 36 | collection: 37 | dependency: transitive 38 | description: 39 | name: collection 40 | sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a 41 | url: "https://pub.dev" 42 | source: hosted 43 | version: "1.18.0" 44 | crypto: 45 | dependency: transitive 46 | description: 47 | name: crypto 48 | sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab 49 | url: "https://pub.dev" 50 | source: hosted 51 | version: "3.0.3" 52 | cupertino_icons: 53 | dependency: "direct main" 54 | description: 55 | name: cupertino_icons 56 | sha256: e35129dc44c9118cee2a5603506d823bab99c68393879edb440e0090d07586be 57 | url: "https://pub.dev" 58 | source: hosted 59 | version: "1.0.5" 60 | dio: 61 | dependency: transitive 62 | description: 63 | name: dio 64 | sha256: "5598aa796bbf4699afd5c67c0f5f6e2ed542afc956884b9cd58c306966efc260" 65 | url: "https://pub.dev" 66 | source: hosted 67 | version: "5.7.0" 68 | dio_web_adapter: 69 | dependency: transitive 70 | description: 71 | name: dio_web_adapter 72 | sha256: "33259a9276d6cea88774a0000cfae0d861003497755969c92faa223108620dc8" 73 | url: "https://pub.dev" 74 | source: hosted 75 | version: "2.0.0" 76 | fake_async: 77 | dependency: transitive 78 | description: 79 | name: fake_async 80 | sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" 81 | url: "https://pub.dev" 82 | source: hosted 83 | version: "1.3.1" 84 | ffi: 85 | dependency: transitive 86 | description: 87 | name: ffi 88 | sha256: "7bf0adc28a23d395f19f3f1eb21dd7cfd1dd9f8e1c50051c069122e6853bc878" 89 | url: "https://pub.dev" 90 | source: hosted 91 | version: "2.1.0" 92 | flutter: 93 | dependency: "direct main" 94 | description: flutter 95 | source: sdk 96 | version: "0.0.0" 97 | flutter_lints: 98 | dependency: "direct dev" 99 | description: 100 | name: flutter_lints 101 | sha256: e2a421b7e59244faef694ba7b30562e489c2b489866e505074eb005cd7060db7 102 | url: "https://pub.dev" 103 | source: hosted 104 | version: "3.0.1" 105 | flutter_localizations: 106 | dependency: transitive 107 | description: flutter 108 | source: sdk 109 | version: "0.0.0" 110 | flutter_test: 111 | dependency: "direct dev" 112 | description: flutter 113 | source: sdk 114 | version: "0.0.0" 115 | hive: 116 | dependency: transitive 117 | description: 118 | name: hive 119 | sha256: "8dcf6db979d7933da8217edcec84e9df1bdb4e4edc7fc77dbd5aa74356d6d941" 120 | url: "https://pub.dev" 121 | source: hosted 122 | version: "2.2.3" 123 | hive_flutter: 124 | dependency: transitive 125 | description: 126 | name: hive_flutter 127 | sha256: dca1da446b1d808a51689fb5d0c6c9510c0a2ba01e22805d492c73b68e33eecc 128 | url: "https://pub.dev" 129 | source: hosted 130 | version: "1.1.0" 131 | http_parser: 132 | dependency: transitive 133 | description: 134 | name: http_parser 135 | sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" 136 | url: "https://pub.dev" 137 | source: hosted 138 | version: "4.0.2" 139 | intl: 140 | dependency: transitive 141 | description: 142 | name: intl 143 | sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf 144 | url: "https://pub.dev" 145 | source: hosted 146 | version: "0.19.0" 147 | leak_tracker: 148 | dependency: transitive 149 | description: 150 | name: leak_tracker 151 | sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05" 152 | url: "https://pub.dev" 153 | source: hosted 154 | version: "10.0.5" 155 | leak_tracker_flutter_testing: 156 | dependency: transitive 157 | description: 158 | name: leak_tracker_flutter_testing 159 | sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806" 160 | url: "https://pub.dev" 161 | source: hosted 162 | version: "3.0.5" 163 | leak_tracker_testing: 164 | dependency: transitive 165 | description: 166 | name: leak_tracker_testing 167 | sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" 168 | url: "https://pub.dev" 169 | source: hosted 170 | version: "3.0.1" 171 | lints: 172 | dependency: transitive 173 | description: 174 | name: lints 175 | sha256: cbf8d4b858bb0134ef3ef87841abdf8d63bfc255c266b7bf6b39daa1085c4290 176 | url: "https://pub.dev" 177 | source: hosted 178 | version: "3.0.0" 179 | localize_and_translate: 180 | dependency: "direct main" 181 | description: 182 | path: ".." 183 | relative: true 184 | source: path 185 | version: "6.0.0-dev.4" 186 | matcher: 187 | dependency: transitive 188 | description: 189 | name: matcher 190 | sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb 191 | url: "https://pub.dev" 192 | source: hosted 193 | version: "0.12.16+1" 194 | material_color_utilities: 195 | dependency: transitive 196 | description: 197 | name: material_color_utilities 198 | sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec 199 | url: "https://pub.dev" 200 | source: hosted 201 | version: "0.11.1" 202 | meta: 203 | dependency: transitive 204 | description: 205 | name: meta 206 | sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 207 | url: "https://pub.dev" 208 | source: hosted 209 | version: "1.15.0" 210 | path: 211 | dependency: transitive 212 | description: 213 | name: path 214 | sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" 215 | url: "https://pub.dev" 216 | source: hosted 217 | version: "1.9.0" 218 | path_provider: 219 | dependency: transitive 220 | description: 221 | name: path_provider 222 | sha256: a1aa8aaa2542a6bc57e381f132af822420216c80d4781f7aa085ca3229208aaa 223 | url: "https://pub.dev" 224 | source: hosted 225 | version: "2.1.1" 226 | path_provider_android: 227 | dependency: transitive 228 | description: 229 | name: path_provider_android 230 | sha256: "6b8b19bd80da4f11ce91b2d1fb931f3006911477cec227cce23d3253d80df3f1" 231 | url: "https://pub.dev" 232 | source: hosted 233 | version: "2.2.0" 234 | path_provider_foundation: 235 | dependency: transitive 236 | description: 237 | name: path_provider_foundation 238 | sha256: "19314d595120f82aca0ba62787d58dde2cc6b5df7d2f0daf72489e38d1b57f2d" 239 | url: "https://pub.dev" 240 | source: hosted 241 | version: "2.3.1" 242 | path_provider_linux: 243 | dependency: transitive 244 | description: 245 | name: path_provider_linux 246 | sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279 247 | url: "https://pub.dev" 248 | source: hosted 249 | version: "2.2.1" 250 | path_provider_platform_interface: 251 | dependency: transitive 252 | description: 253 | name: path_provider_platform_interface 254 | sha256: "94b1e0dd80970c1ce43d5d4e050a9918fce4f4a775e6142424c30a29a363265c" 255 | url: "https://pub.dev" 256 | source: hosted 257 | version: "2.1.1" 258 | path_provider_windows: 259 | dependency: transitive 260 | description: 261 | name: path_provider_windows 262 | sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170" 263 | url: "https://pub.dev" 264 | source: hosted 265 | version: "2.2.1" 266 | platform: 267 | dependency: transitive 268 | description: 269 | name: platform 270 | sha256: ae68c7bfcd7383af3629daafb32fb4e8681c7154428da4febcff06200585f102 271 | url: "https://pub.dev" 272 | source: hosted 273 | version: "3.1.2" 274 | plugin_platform_interface: 275 | dependency: transitive 276 | description: 277 | name: plugin_platform_interface 278 | sha256: da3fdfeccc4d4ff2da8f8c556704c08f912542c5fb3cf2233ed75372384a034d 279 | url: "https://pub.dev" 280 | source: hosted 281 | version: "2.1.6" 282 | sky_engine: 283 | dependency: transitive 284 | description: flutter 285 | source: sdk 286 | version: "0.0.99" 287 | source_span: 288 | dependency: transitive 289 | description: 290 | name: source_span 291 | sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" 292 | url: "https://pub.dev" 293 | source: hosted 294 | version: "1.10.0" 295 | stack_trace: 296 | dependency: transitive 297 | description: 298 | name: stack_trace 299 | sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" 300 | url: "https://pub.dev" 301 | source: hosted 302 | version: "1.11.1" 303 | stream_channel: 304 | dependency: transitive 305 | description: 306 | name: stream_channel 307 | sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 308 | url: "https://pub.dev" 309 | source: hosted 310 | version: "2.1.2" 311 | string_scanner: 312 | dependency: transitive 313 | description: 314 | name: string_scanner 315 | sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" 316 | url: "https://pub.dev" 317 | source: hosted 318 | version: "1.2.0" 319 | term_glyph: 320 | dependency: transitive 321 | description: 322 | name: term_glyph 323 | sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 324 | url: "https://pub.dev" 325 | source: hosted 326 | version: "1.2.1" 327 | test_api: 328 | dependency: transitive 329 | description: 330 | name: test_api 331 | sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" 332 | url: "https://pub.dev" 333 | source: hosted 334 | version: "0.7.2" 335 | typed_data: 336 | dependency: transitive 337 | description: 338 | name: typed_data 339 | sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c 340 | url: "https://pub.dev" 341 | source: hosted 342 | version: "1.3.2" 343 | vector_math: 344 | dependency: transitive 345 | description: 346 | name: vector_math 347 | sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" 348 | url: "https://pub.dev" 349 | source: hosted 350 | version: "2.1.4" 351 | vm_service: 352 | dependency: transitive 353 | description: 354 | name: vm_service 355 | sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d" 356 | url: "https://pub.dev" 357 | source: hosted 358 | version: "14.2.5" 359 | web: 360 | dependency: transitive 361 | description: 362 | name: web 363 | sha256: cd3543bd5798f6ad290ea73d210f423502e71900302dde696f8bff84bf89a1cb 364 | url: "https://pub.dev" 365 | source: hosted 366 | version: "1.1.0" 367 | win32: 368 | dependency: transitive 369 | description: 370 | name: win32 371 | sha256: "9e82a402b7f3d518fb9c02d0e9ae45952df31b9bf34d77baf19da2de03fc2aaa" 372 | url: "https://pub.dev" 373 | source: hosted 374 | version: "5.0.7" 375 | xdg_directories: 376 | dependency: transitive 377 | description: 378 | name: xdg_directories 379 | sha256: "589ada45ba9e39405c198fe34eb0f607cddb2108527e658136120892beac46d2" 380 | url: "https://pub.dev" 381 | source: hosted 382 | version: "1.0.3" 383 | sdks: 384 | dart: ">=3.4.0 <4.0.0" 385 | flutter: ">=3.18.0-18.0.pre.54" 386 | -------------------------------------------------------------------------------- /example/macos/Runner/Base.lproj/MainMenu.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | --------------------------------------------------------------------------------