[feat]: Add localization support with easy_localization

This commit is contained in:
nahnah
2026-01-26 23:31:20 +00:00
parent 19fa03a286
commit 129dca1f8d
14 changed files with 551 additions and 70 deletions
+304
View File
@@ -0,0 +1,304 @@
# Contributing to Florid
Thank you for your interest in contributing to Florid! We welcome contributions from everyone. This guide will help you get started.
## Table of Contents
- [Code of Conduct](#code-of-conduct)
- [How Can I Contribute?](#how-can-i-contribute)
- [Reporting Bugs](#reporting-bugs)
- [Suggesting Features](#suggesting-features)
- [Contributing Code](#contributing-code)
- [Contributing Translations](#contributing-translations)
- [Development Setup](#development-setup)
- [Pull Request Process](#pull-request-process)
- [Style Guidelines](#style-guidelines)
- [Localization Guidelines](#localization-guidelines)
## Code of Conduct
By participating in this project, you agree to maintain a respectful and inclusive environment for everyone.
## How Can I Contribute?
### Reporting Bugs
Before creating bug reports, please check existing issues to avoid duplicates. When creating a bug report, include:
- **Clear title and description**
- **Steps to reproduce** the issue
- **Expected behavior** vs **actual behavior**
- **Screenshots** if applicable
- **Device information** (Android version, device model)
- **App version** you're using
### Suggesting Features
Feature suggestions are welcome! Please:
- **Check existing feature requests** first
- **Describe the feature** in detail
- **Explain the use case** and why it would be valuable
- **Consider implementation complexity**
### Contributing Code
1. Fork the repository
2. Create a feature branch (`git checkout -b feature/amazing-feature`)
3. Make your changes
4. Test thoroughly
5. Commit with clear messages (`git commit -m 'Add amazing feature'`)
6. Push to your branch (`git push origin feature/amazing-feature`)
7. Open a Pull Request
### Contributing Translations
We use `easy_localization` for internationalization. Contributing translations is easy and highly appreciated!
#### Adding a New Language
1. **Create a translation file:**
- Navigate to `assets/translations/`
- Create a new JSON file named with the language code (e.g., `fr.json` for French, `de.json` for German)
- Copy the structure from `en.json`
2. **Translate all keys:**
```json
{
"app_name": "Florid",
"welcome": "Your translation here",
"search": "Your translation here",
...
}
```
3. **Update main.dart:**
Add your locale to the supported locales list:
```dart
EasyLocalization(
supportedLocales: const [
Locale('en'),
Locale('es'),
Locale('fr'), // Your new language
],
// ...
)
```
4. **Test your translations:**
- Change your device language to the new language
- Launch the app and verify all strings appear correctly
- Check that text fits in UI elements (some languages use longer words)
#### Improving Existing Translations
1. Open the relevant JSON file in `assets/translations/`
2. Update the translation values
3. Ensure translations are:
- **Accurate** and contextually appropriate
- **Natural** in the target language
- **Consistent** with app terminology
4. Test the changes in the app
#### Translation Guidelines
- **Keep keys unchanged** - Only modify the values, never the keys
- **Maintain consistency** - Use the same terms throughout for repeated concepts
- **Consider context** - Some words have different meanings in different contexts
- **Test thoroughly** - Verify translations in the actual UI
- **Be concise** - Mobile UIs have limited space
- **Use native conventions** - Follow target language conventions for dates, numbers, etc.
See [LOCALIZATION.md](LOCALIZATION.md) for detailed localization documentation.
## Development Setup
### Prerequisites
- Flutter SDK (3.38.7 or higher)
- Dart SDK (3.9.2 or higher)
- Android Studio or VS Code with Flutter extensions
- Android device or emulator for testing
### Setup Steps
1. **Clone the repository:**
```bash
git clone https://github.com/yourusername/florid.git
cd florid
```
2. **Install dependencies:**
```bash
flutter pub get
```
3. **Run the app:**
```bash
flutter run
```
### Project Structure
```
lib/
├── models/ # Data models
├── providers/ # State management (Provider)
├── screens/ # UI screens
├── services/ # API and business logic
├── themes/ # App themes
├── utils/ # Utility functions
├── widgets/ # Reusable widgets
└── main.dart # App entry point
assets/
└── translations/ # Translation JSON files
```
## Pull Request Process
1. **Update documentation** if you've made changes to APIs or added features
2. **Add/update tests** for new functionality
3. **Follow the style guidelines** below
4. **Ensure the app builds** without errors
5. **Test on a real device** when possible
6. **Update CHANGELOG.md** with notable changes
7. **Link any related issues** in the PR description
### PR Checklist
- [ ] Code follows the project style guidelines
- [ ] Self-review of code completed
- [ ] Comments added for complex logic
- [ ] Documentation updated if needed
- [ ] No new warnings generated
- [ ] Translations added/updated if UI text changed
- [ ] Tested on Android device/emulator
## Style Guidelines
### Dart Code Style
- Follow [Effective Dart](https://dart.dev/guides/language/effective-dart) guidelines
- Use `flutter analyze` to check for issues
- Format code with `dart format .`
- Maximum line length: 80 characters (flexible for readability)
### Widget Organization
```dart
class MyWidget extends StatelessWidget {
// 1. Final fields
final String title;
// 2. Constructor
const MyWidget({super.key, required this.title});
// 3. Build method
@override
Widget build(BuildContext context) {
// ...
}
// 4. Helper methods
void _helperMethod() {
// ...
}
}
```
### Naming Conventions
- **Classes**: `PascalCase` (e.g., `AppDetailsScreen`)
- **Files**: `snake_case` (e.g., `app_details_screen.dart`)
- **Variables/Functions**: `camelCase` (e.g., `downloadApp`)
- **Constants**: `camelCase` (e.g., `maxRetries`)
- **Private members**: prefix with `_` (e.g., `_privateMethod`)
### Comments
- Use `///` for public API documentation
- Use `//` for inline comments
- Explain **why**, not **what** (code should be self-documenting)
```dart
// Good
/// Fetches app details from the repository.
/// Returns null if the app is not found or network error occurs.
Future<FDroidApp?> fetchAppDetails(String packageName) async { ... }
// Bad
// This function gets the app
Future<FDroidApp?> fetchAppDetails(String packageName) async { ... }
```
### UI/UX Guidelines
- **Responsive Design**: Test on different screen sizes
- **Accessibility**: Use semantic labels and ensure good contrast
- **Performance**: Avoid unnecessary rebuilds, use `const` constructors
- **Material Design**: Follow Material 3 guidelines
- **Animations**: Keep animations smooth and purposeful (avoid excessive animation)
## Localization Guidelines
### Adding New Strings
When adding new UI text:
1. **Never hardcode strings** in UI code
2. **Add to all translation files** (at minimum `en.json` and `es.json`)
3. **Use descriptive keys** with underscores:
```json
{
"error_network_title": "Network Error",
"error_network_message": "Please check your internet connection",
"button_retry": "Retry"
}
```
4. **Use the string in code:**
```dart
Text('error_network_title'.tr())
```
### Translation Key Naming
Follow this pattern: `[category]_[context]_[element]`
Examples:
- `error_network_title`
- `settings_theme_dark`
- `dialog_delete_confirm`
- `button_download`
- `label_version_name`
### Context for Translators
When adding strings that might be ambiguous, add a comment in the PR:
```
Added "bank" key - refers to river bank, not financial institution
```
## Questions?
If you have questions or need help:
- Open an issue with the `question` label
- Check existing issues and discussions
- Review the documentation in the repository
## License
By contributing to Florid, you agree that your contributions will be licensed under the same license as the project.
---
Thank you for contributing to Florid! 🎉
+31
View File
@@ -0,0 +1,31 @@
# Localization Setup with easy_localization
This project uses the `easy_localization` package for internationalization.
## Setup
The localization is already set up with the following configuration:
### Supported Languages
- English (en) - Default
### Translation Files
Translation files are located in `assets/translations/`:
- `en.json` - English translations
- `es.json` - Spanish translations (for example)
## Usage
### 1. Translations with Parameters
Add to your JSON files:
```json
{
"welcome": "YOUR_TRANSLATION",
"items_count": "YOUR_TRANSLATION"
}
```
+90
View File
@@ -0,0 +1,90 @@
{
"app_name": "Florid",
"welcome": "Welcome to Florid",
"search": "Search",
"settings": "Settings",
"home": "Home",
"categories": "Categories",
"updates": "Updates",
"installed": "Installed",
"download": "Download",
"install": "Install",
"uninstall": "Uninstall",
"open": "Open",
"cancel": "Cancel",
"update_available": "Update Available",
"downloading": "Downloading...",
"install_permission_required": "Install permission is required",
"storage_permission_required": "Storage permission is required",
"cancel_download": "Cancel Download",
"version": "Version",
"size": "Size",
"description": "Description",
"permissions": "Permissions",
"screenshots": "Screenshots",
"no_version_available": "No Version Available",
"app_information": "App Information",
"package_name": "Package Name",
"license": "License",
"added": "Added",
"last_updated": "Last Updated",
"version_information": "Version Information",
"version_name": "Version Name",
"version_code": "Version Code",
"min_sdk": "Min SDK",
"target_sdk": "Target SDK",
"all_versions": "All Versions",
"latest": "Latest",
"released": "Released",
"loading": "Loading...",
"error": "Error",
"retry": "Retry",
"share": "Share",
"website": "Website",
"source_code": "Source Code",
"issue_tracker": "Issue Tracker",
"whats_new": "What's New",
"show_more": "Show more",
"show_less": "Show less",
"downloads_stats": "Downloads stats",
"last_day": "Last day",
"last_30_days": "Last 30 days",
"last_365_days": "Last 365 days",
"not_available": "Not available",
"download_failed": "Download failed",
"installation_failed": "Installation failed",
"uninstall_failed": "Uninstall failed",
"open_failed": "Failed to open",
"device": "Device",
"recently_updated": "Recently Updated",
"refresh": "Refresh",
"about": "About",
"refreshing_data": "Refreshing data...",
"data_refreshed": "Data refreshed",
"refresh_failed": "Refresh failed",
"loading_latest_apps": "Loading latest apps...",
"latest_apps": "Latest Apps",
"no_apps_found": "No apps found",
"searching": "Searching...",
"setup_failed": "Setup failed",
"back": "Back",
"allow": "Allow",
"manage_repositories": "Manage Repositories",
"enable_disable": "Enable/Disable",
"edit": "Edit",
"delete": "Delete",
"delete_repository": "Delete Repository",
"delete_repository_confirm": "Are you sure you want to remove \"{}\"?",
"updating_repository": "Updating Repository",
"touch_grass_message": "Now is a great time to touch grass!",
"add_repository": "Add Repository",
"add": "Add",
"save": "Save",
"enter_repository_name": "Please enter a repository name",
"enter_repository_url": "Please enter a repository URL",
"edit_repository": "Edit Repository",
"loading_apps": "Loading apps...",
"no_apps_in_category": "No apps found in {}",
"loading_categories": "Loading categories...",
"no_categories_found": "No categories found"
}
+13 -1
View File
@@ -1,5 +1,6 @@
import 'dart:convert';
import 'package:easy_localization/easy_localization.dart';
import 'package:florid/providers/settings_provider.dart';
import 'package:florid/screens/florid_app.dart';
import 'package:florid/themes/app_themes.dart';
@@ -17,11 +18,19 @@ import 'services/izzy_stats_service.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await EasyLocalization.ensureInitialized();
// Initialize notification service and request permission
// await NotificationService().init();
runApp(const MainApp());
runApp(
EasyLocalization(
supportedLocales: const [Locale('en')],
path: 'assets/translations',
fallbackLocale: const Locale('en'),
child: const MainApp(),
),
);
}
class MainApp extends StatelessWidget {
@@ -88,6 +97,9 @@ class MainApp extends StatelessWidget {
return MaterialApp(
title: 'Florid - F-Droid Client',
debugShowCheckedModeBanner: false,
localizationsDelegates: context.localizationDelegates,
supportedLocales: context.supportedLocales,
locale: context.locale,
theme: settings.themeStyle == ThemeStyle.florid
? AppThemes.floridLightTheme()
: AppThemes.materialLightTheme(),
+10 -9
View File
@@ -1,3 +1,4 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_animate/flutter_animate.dart';
import 'package:material_symbols_icons/symbols.dart';
@@ -56,13 +57,13 @@ class _CategoriesScreenState extends State<CategoriesScreen>
String? error,
) {
if (state == LoadingState.loading && categories.isEmpty) {
return const Center(
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
CircularProgressIndicator(year2023: false),
SizedBox(height: 16),
Text('Loading categories...'),
const CircularProgressIndicator(year2023: false),
const SizedBox(height: 16),
Text('loading_categories'.tr()),
],
),
);
@@ -95,7 +96,7 @@ class _CategoriesScreenState extends State<CategoriesScreen>
ElevatedButton.icon(
onPressed: _loadData,
icon: const Icon(Symbols.refresh),
label: const Text('Retry'),
label: Text('retry'.tr()),
),
],
),
@@ -103,13 +104,13 @@ class _CategoriesScreenState extends State<CategoriesScreen>
}
if (categories.isEmpty) {
return const Center(
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Symbols.category, size: 64, color: Colors.grey),
SizedBox(height: 16),
Text('No categories found'),
const Icon(Symbols.category, size: 64, color: Colors.grey),
const SizedBox(height: 16),
Text('no_categories_found'.tr()),
],
),
);
+5 -4
View File
@@ -1,3 +1,4 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:florid/providers/settings_provider.dart';
import 'package:flutter/material.dart';
import 'package:material_symbols_icons/symbols.dart';
@@ -75,13 +76,13 @@ class _CategoryAppsScreenState extends State<CategoryAppsScreen> {
final error = appProvider.categoryAppsError;
if (state == LoadingState.loading && apps.isEmpty) {
return const Center(
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
CircularProgressIndicator(year2023: false),
SizedBox(height: 16),
Text('Loading apps...'),
Text('loading_apps'.tr()),
],
),
);
@@ -114,7 +115,7 @@ class _CategoryAppsScreenState extends State<CategoryAppsScreen> {
ElevatedButton.icon(
onPressed: _loadData,
icon: const Icon(Symbols.refresh),
label: const Text('Retry'),
label: Text('retry'.tr()),
),
],
),
@@ -128,7 +129,7 @@ class _CategoryAppsScreenState extends State<CategoryAppsScreen> {
children: [
const Icon(Symbols.apps, size: 64, color: Colors.grey),
const SizedBox(height: 16),
Text('No apps found in ${widget.category}'),
Text('no_apps_in_category'.tr(args: [widget.category])),
],
),
);
+36 -32
View File
@@ -1,3 +1,4 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:florid/screens/library_screen.dart';
import 'package:flutter/material.dart';
import 'package:material_symbols_icons/symbols.dart';
@@ -44,24 +45,6 @@ class _FloridAppState extends State<FloridApp> {
super.dispose();
}
final List<NavigationDestination> _destinations = const [
NavigationDestination(
icon: Icon(Symbols.newsstand_rounded),
selectedIcon: Icon(Symbols.newsstand_rounded, fill: 1, weight: 600),
label: 'Library',
),
NavigationDestination(
icon: Icon(Symbols.search),
selectedIcon: Icon(Symbols.search, fill: 1, weight: 600),
label: 'Search',
),
NavigationDestination(
icon: Icon(Symbols.mobile_3_rounded),
selectedIcon: Icon(Symbols.mobile_3_rounded, fill: 1, weight: 600),
label: 'Device',
),
];
@override
Widget build(BuildContext context) {
return Scaffold(
@@ -69,22 +52,43 @@ class _FloridAppState extends State<FloridApp> {
bottomNavigationBar: Consumer<AppProvider>(
builder: (context, appProvider, child) {
final updatableAppsCount = appProvider.getUpdatableApps().length;
final destinations = List<NavigationDestination>.from(_destinations);
// Add badge to Device tab if there are updates
if (updatableAppsCount > 0) {
destinations[2] = NavigationDestination(
icon: Badge.count(
count: updatableAppsCount,
child: Icon(Symbols.mobile_3_rounded),
// Build destinations with translations
final destinations = [
NavigationDestination(
icon: const Icon(Symbols.newsstand_rounded),
selectedIcon: const Icon(
Symbols.newsstand_rounded,
fill: 1,
weight: 600,
),
selectedIcon: Badge.count(
count: updatableAppsCount,
child: Icon(Symbols.mobile_3_rounded, fill: 1, weight: 600),
),
label: 'Device',
);
}
label: 'home'.tr(),
),
NavigationDestination(
icon: const Icon(Symbols.search),
selectedIcon: const Icon(Symbols.search, fill: 1, weight: 600),
label: 'search'.tr(),
),
NavigationDestination(
icon: updatableAppsCount > 0
? Badge.count(
count: updatableAppsCount,
child: const Icon(Symbols.mobile_3_rounded),
)
: const Icon(Symbols.mobile_3_rounded),
selectedIcon: updatableAppsCount > 0
? Badge.count(
count: updatableAppsCount,
child: const Icon(
Symbols.mobile_3_rounded,
fill: 1,
weight: 600,
),
)
: const Icon(Symbols.mobile_3_rounded, fill: 1, weight: 600),
label: 'device'.tr(),
),
];
return NavigationBar(
selectedIndex: _currentIndex,
+4 -3
View File
@@ -1,3 +1,4 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_animate/flutter_animate.dart';
import 'package:material_symbols_icons/symbols.dart';
@@ -100,7 +101,7 @@ class _HomeScreenState extends State<HomeScreen>
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Recently Updated',
'recently_updated'.tr(),
style: Theme.of(context).textTheme.titleMedium
?.copyWith(fontWeight: FontWeight.w600),
),
@@ -108,7 +109,7 @@ class _HomeScreenState extends State<HomeScreen>
onPressed: _openRecentlyUpdatedScreen,
iconAlignment: IconAlignment.end,
icon: Icon(Symbols.arrow_forward),
label: Text('More'),
label: Text('show_more'.tr()),
),
],
),
@@ -186,7 +187,7 @@ class _HomeScreenState extends State<HomeScreen>
onPressed: _openLatestScreen,
iconAlignment: IconAlignment.end,
icon: Icon(Symbols.arrow_forward),
label: Text('More'),
label: Text('show_more'.tr()),
),
],
),
+9 -8
View File
@@ -1,3 +1,4 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_animate/flutter_animate.dart';
import 'package:material_symbols_icons/symbols.dart';
@@ -59,13 +60,13 @@ class _LatestScreenState extends State<LatestScreen>
Widget _buildBody(LoadingState state, List<FDroidApp> apps, String? error) {
if (state == LoadingState.loading && apps.isEmpty) {
return const Center(
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
CircularProgressIndicator(year2023: false),
SizedBox(height: 16),
Text('Loading latest apps...'),
Text('loading_latest_apps'.tr()),
],
),
);
@@ -98,7 +99,7 @@ class _LatestScreenState extends State<LatestScreen>
ElevatedButton.icon(
onPressed: _loadData,
icon: const Icon(Symbols.refresh),
label: const Text('Retry'),
label: Text('retry'.tr()),
),
],
),
@@ -106,13 +107,13 @@ class _LatestScreenState extends State<LatestScreen>
}
if (apps.isEmpty) {
return const Center(
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Symbols.apps, size: 64, color: Colors.grey),
SizedBox(height: 16),
Text('No apps found'),
const Icon(Symbols.apps, size: 64, color: Colors.grey),
const SizedBox(height: 16),
Text('no_apps_found'.tr()),
],
),
);
@@ -120,7 +121,7 @@ class _LatestScreenState extends State<LatestScreen>
return Scaffold(
appBar: AppBar(
title: const Text('Latest Apps'),
title: Text('latest_apps'.tr()),
backgroundColor: Theme.of(context).colorScheme.surfaceContainerLow,
surfaceTintColor: Theme.of(context).colorScheme.surfaceContainerLow,
),
+10 -9
View File
@@ -1,3 +1,4 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:florid/providers/app_provider.dart';
import 'package:florid/providers/repositories_provider.dart';
import 'package:florid/screens/categories_screen.dart';
@@ -36,7 +37,7 @@ class _LibraryScreenState extends State<LibraryScreen>
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Florid'),
title: Text('app_name'.tr()),
backgroundColor: Theme.of(context).colorScheme.surfaceContainerLow,
surfaceTintColor: Theme.of(context).colorScheme.surfaceContainerLow,
actions: [
@@ -55,19 +56,19 @@ class _LibraryScreenState extends State<LibraryScreen>
}
},
itemBuilder: (context) => [
const PopupMenuItem(
PopupMenuItem(
value: 'refresh',
child: ListTile(
leading: Icon(Symbols.refresh),
title: Text('Refresh'),
leading: const Icon(Symbols.refresh),
title: Text('refresh'.tr()),
contentPadding: EdgeInsets.zero,
),
),
const PopupMenuItem(
PopupMenuItem(
value: 'settings',
child: ListTile(
leading: Icon(Symbols.settings),
title: Text('Settings'),
leading: const Icon(Symbols.settings),
title: Text('settings'.tr()),
contentPadding: EdgeInsets.zero,
),
),
@@ -88,8 +89,8 @@ class _LibraryScreenState extends State<LibraryScreen>
_tabController.animateTo(index);
},
items: [
FloridTabBarItem(icon: Symbols.home, label: 'Home'),
FloridTabBarItem(icon: Symbols.category, label: 'Categories'),
FloridTabBarItem(icon: Symbols.home, label: 'home'.tr()),
FloridTabBarItem(icon: Symbols.category, label: 'categories'.tr()),
],
),
),
+2 -1
View File
@@ -1,5 +1,6 @@
import 'dart:convert';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_animate/flutter_animate.dart';
import 'package:material_symbols_icons/symbols.dart';
@@ -227,7 +228,7 @@ class _OnboardingScreenState extends State<OnboardingScreen> {
if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Setup failed: $e'),
content: Text('${'setup_failed'.tr()}: $e'),
action: SnackBarAction(label: 'Retry', onPressed: _performSetup),
),
);
+4 -3
View File
@@ -1,3 +1,4 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:florid/utils/menu_actions.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
@@ -202,13 +203,13 @@ class _SearchScreenState extends State<SearchScreen> {
// Show loading
if (state == LoadingState.loading) {
return const Center(
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
CircularProgressIndicator(year2023: false),
SizedBox(height: 16),
Text('Searching...'),
Text('searching'.tr()),
],
),
);
@@ -242,7 +243,7 @@ class _SearchScreenState extends State<SearchScreen> {
ElevatedButton.icon(
onPressed: () => _performSearch(query),
icon: const Icon(Symbols.refresh),
label: const Text('Retry'),
label: Text('retry'.tr()),
),
],
),
+29
View File
@@ -273,6 +273,22 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.1.1"
easy_localization:
dependency: "direct main"
description:
name: easy_localization
sha256: "2ccdf9db8fe4d9c5a75c122e6275674508fd0f0d49c827354967b8afcc56bbed"
url: "https://pub.dev"
source: hosted
version: "3.0.8"
easy_logger:
dependency: transitive
description:
name: easy_logger
sha256: c764a6e024846f33405a2342caf91c62e357c24b02c04dbc712ef232bf30ffb7
url: "https://pub.dev"
source: hosted
version: "0.0.2"
fake_async:
dependency: transitive
description:
@@ -366,6 +382,11 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.0.3"
flutter_localizations:
dependency: transitive
description: flutter
source: sdk
version: "0.0.0"
flutter_native_splash:
dependency: "direct main"
description:
@@ -472,6 +493,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.1.0"
intl:
dependency: transitive
description:
name: intl
sha256: "3df61194eb431efc39c4ceba583b95633a403f46c9fd341e550ce0bfa50e9aa5"
url: "https://pub.dev"
source: hosted
version: "0.20.2"
io:
dependency: transitive
description:
+4
View File
@@ -75,6 +75,9 @@ dependencies:
flutter_native_splash: ^2.4.7
flutter_animate: ^4.5.2
# Localization
easy_localization: ^3.0.8
dev_dependencies:
flutter_test:
sdk: flutter
@@ -102,6 +105,7 @@ flutter:
- assets/Foreground.png
- assets/Splash.png
- assets/repositories.json
- assets/translations/
# - images/a_dot_burr.jpeg
# - images/a_dot_ham.jpeg