Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
wellgenio committed Aug 28, 2024
2 parents 5346842 + 59730bb commit ca421eb
Show file tree
Hide file tree
Showing 19 changed files with 383 additions and 38 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 1.0.0

* Production release

## 0.0.7

* Added `when` and `setValidator`
Expand Down
105 changes: 105 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,111 @@ After that, execute a validation normaly:
expect(result.isValid, isTrue);
```

You can use `byField` using nested params syntax:

```dart
final validator = CustomerValidator();
final postCodeValidator = validator.byField(customer, 'address.postcode')();
expect(postCodeValidator, null); // is valid
```

There are several ways to customize or internationalize the failure message in validation.

All validations have the `message` parameter for customization, with the possibility of receiving arguments to make the message more dynamic.

```dart
ruleFor((entity) => entity.name, key: 'name')
.isEmpty(message: "'{PropertyName}' can not be empty." )
```

Please note that the `{PropertyName}` is an exclusive parameter of the `isEmpty` validation that will be internally changed to the validation's `key`, which in this case is `name`.
Each validation can have different parameters such as `{PropertyValue}` or `{ComparisonValue}`, so please check the documentation of each one to know the available parameters.

### Default Messages

By default, validation messages are in English, but you can change the language in the global properties of `LucidValidation`.


```dart
LucidValidation.global.culture = Culture('pt', 'BR');
```

If you’d like to contribute a translation of `LucidValidation’s` default messages, please open a pull request that adds a language file to the project.


You can also customize the default messages by overriding the `LanguageManager`:

```dart
class CustomLanguageManager extends LanguageManager {
CustomLanguageManager(){
addTranslation(Culture('pt', 'PR'), Language.code.equalTo, 'Custom message here');
}
}
...
// change manager
LucidValidation.global.languageManager = CustomLanguageManager();
```

## Flutter Configuration

Podemos criar um `Delegate` para automatizar a internacionalização diretamente no Flutter.

Para criar um `Delegate` siga esses passos:

```dart
class LucidLocalizationDelegate extends LocalizationsDelegate<Culture> {
const LucidLocalizationDelegate();
static final delegate = LucidLocalizationDelegate();
@override
bool isSupported(Locale locale) {
return LucidValidation.global.languageManager.isSupported(
locale.languageCode,
locale.countryCode,
);
}
@override
Future<Culture> load(Locale locale) async {
print(locale);
final culture = Culture(locale.languageCode, locale.countryCode ?? '');
LucidValidation.global.culture = culture;
return culture;
}
@override
bool shouldReload(LocalizationsDelegate<Culture> old) {
return true;
}
}
```

Agora basta adicionar no `MaterialApp` ou `CupertinoApp`:

```dart
@override
Widget build(BuildContext context) {
return MaterialApp(
supportedLocales: const [
Locale('en', 'US'),
Locale('pt', 'BR'),
],
localizationsDelegates: [
LucidLocalizationDelegate.delegate,
//
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
],
...
);
}
```


## Creating Custom Rules

Expand Down
5 changes: 2 additions & 3 deletions example/lib/domain/validations/extensions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,10 @@ extension CustomValidPasswordValidator on SimpleValidationBuilder<String> {
}

extension CustomValidPhoneValidator on SimpleValidationBuilder<String> {
SimpleValidationBuilder<String> customValidPhone(String message) {
SimpleValidationBuilder<String> customValidPhone() {
return matchesPattern(
r'^\(?(\d{2})\)?\s?9?\d{4}-?\d{4}$',
message: message,
code: 'invalid_phone',
code: 'validPhone',
);
}
}
10 changes: 10 additions & 0 deletions example/lib/domain/validations/language_manager.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import 'package:lucid_validation/lucid_validation.dart';

class CustomLanguageManager extends LanguageManager {
CustomLanguageManager() {
addTranslation(Culture('pt', 'BR'), 'passwordEqualTo', "'{PropertyName}' deve ser igual.");
addTranslation(Culture('pt'), 'passwordEqualTo', "'{PropertyName}' deve ser igual.");
addTranslation(Culture('en', 'US'), 'passwordEqualTo', "'{PropertyName}' must be equal.");
addTranslation(Culture('en'), 'passwordEqualTo', "'{PropertyName}' must be equal.");
}
}
4 changes: 2 additions & 2 deletions example/lib/domain/validations/register_param_validation.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ class RegisterParamValidation extends LucidValidator<RegisterParamDto> {

ruleFor((registerParamDto) => registerParamDto.confirmPassword, key: 'confirmPassword') //
.customValidPassword()
.equalTo((registerParamDto) => registerParamDto.password, message: 'Password and confirm password must match');
.equalTo((registerParamDto) => registerParamDto.password, code: 'passwordEqualTo');

ruleFor((registerParamDto) => registerParamDto.phone, key: 'phone') //
.customValidPhone('Phone invalid format');
.customValidPhone();
}
}
66 changes: 59 additions & 7 deletions example/lib/main.dart
Original file line number Diff line number Diff line change
@@ -1,22 +1,74 @@
import 'package:example/presentation/login_page/login_page.dart';
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:lucid_validation/lucid_validation.dart';

import 'domain/validations/language_manager.dart';

void main() {
LucidValidation.global.languageManager = CustomLanguageManager();

runApp(const MyApp());
}

final globalLocale = ValueNotifier(Locale('en'));

class MyApp extends StatelessWidget {
const MyApp({super.key});

@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const LoginPage(),
return ValueListenableBuilder<Locale>(
valueListenable: globalLocale,
builder: (context, value, child) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
locale: value,
supportedLocales: const [
Locale('en', 'US'),
Locale('pt', 'BR'),
],
localizationsDelegates: [
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
LucidLocalizationDelegate.delegate,
],
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const LoginPage(),
);
},
);
}
}

class LucidLocalizationDelegate extends LocalizationsDelegate<Culture> {
const LucidLocalizationDelegate();

static final delegate = LucidLocalizationDelegate();

@override
bool isSupported(Locale locale) {
return LucidValidation.global.languageManager.isSupported(
locale.languageCode,
locale.countryCode,
);
}

@override
Future<Culture> load(Locale locale) async {
print(locale);
final culture = Culture(locale.languageCode, locale.countryCode ?? '');
LucidValidation.global.culture = culture;
return culture;
}

@override
bool shouldReload(LocalizationsDelegate<Culture> old) {
return true;
}
}
22 changes: 22 additions & 0 deletions example/lib/presentation/login_page/login_page.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'package:example/domain/dtos/login_param_dto.dart';
import 'package:example/domain/validations/login_param_validation.dart';
import 'package:example/main.dart';
import 'package:example/presentation/register_page/register_page.dart';
import 'package:flutter/material.dart';

Expand Down Expand Up @@ -35,6 +36,27 @@ class _LoginPageState extends State<LoginPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Login'),
actions: [
Row(
mainAxisSize: MainAxisSize.min,
children: [
Text('Is English'),
ValueListenableBuilder<Locale>(
valueListenable: globalLocale,
builder: (context, _, __) {
return Switch(
value: globalLocale.value.languageCode == 'en',
onChanged: (value) {
globalLocale.value = value ? Locale('en', 'US') : Locale('pt', 'BR');
},
);
}),
],
)
],
),
body: Form(
key: formKey,
child: Padding(
Expand Down
22 changes: 22 additions & 0 deletions example/lib/presentation/register_page/register_page.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'package:example/domain/dtos/register_param_dto.dart';
import 'package:example/domain/validations/register_param_validation.dart';
import 'package:example/main.dart';
import 'package:flutter/material.dart';

class RegisterPage extends StatefulWidget {
Expand Down Expand Up @@ -53,6 +54,27 @@ class _RegisterPageState extends State<RegisterPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Login'),
actions: [
Row(
mainAxisSize: MainAxisSize.min,
children: [
Text('Is English'),
ValueListenableBuilder<Locale>(
valueListenable: globalLocale,
builder: (context, _, __) {
return Switch(
value: globalLocale.value.languageCode == 'en',
onChanged: (value) {
globalLocale.value = value ? Locale('en', 'US') : Locale('pt', 'BR');
},
);
}),
],
)
],
),
body: Padding(
padding: const EdgeInsets.all(12.0),
child: Column(
Expand Down
19 changes: 16 additions & 3 deletions example/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,24 @@ packages:
url: "https://pub.dev"
source: hosted
version: "3.0.2"
flutter_localizations:
dependency: "direct main"
description: flutter
source: sdk
version: "0.0.0"
flutter_test:
dependency: "direct dev"
description: flutter
source: sdk
version: "0.0.0"
intl:
dependency: transitive
description:
name: intl
sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf
url: "https://pub.dev"
source: hosted
version: "0.19.0"
leak_tracker:
dependency: transitive
description:
Expand Down Expand Up @@ -113,7 +126,7 @@ packages:
path: ".."
relative: true
source: path
version: "0.0.6"
version: "0.0.7"
matcher:
dependency: transitive
description:
Expand Down Expand Up @@ -211,10 +224,10 @@ packages:
dependency: transitive
description:
name: vm_service
sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d"
sha256: f652077d0bdf60abe4c1f6377448e8655008eef28f128bc023f7b5e8dfeb48fc
url: "https://pub.dev"
source: hosted
version: "14.2.5"
version: "14.2.4"
sdks:
dart: ">=3.4.3 <4.0.0"
flutter: ">=3.18.0-18.0.pre.54"
2 changes: 2 additions & 0 deletions example/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ environment:
dependencies:
flutter:
sdk: flutter
flutter_localizations:
sdk: flutter
lucid_validation:
path: ../

Expand Down
6 changes: 3 additions & 3 deletions lib/lucid_validation.dart
Original file line number Diff line number Diff line change
Expand Up @@ -65,20 +65,20 @@ export 'src/validations/validations.dart';

sealed class LucidValidation {
static final global = _GlobalConfig(
language: EnglishLanguage(),
languageManager: DefaultLanguageManager(),
cascadeMode: CascadeMode.continueExecution,
culture: Culture('en'),
);
}

class _GlobalConfig {
LanguageManager languageManager;
Culture culture;
CascadeMode cascadeMode;
Language language;

_GlobalConfig({
required this.languageManager,
required this.cascadeMode,
required this.language,
required this.culture,
});
}
Loading

0 comments on commit ca421eb

Please sign in to comment.