Skip to content

Commit

Permalink
update doc and example
Browse files Browse the repository at this point in the history
  • Loading branch information
jacobaraujo7 committed Aug 27, 2024
1 parent e13ff73 commit 80d1be4
Show file tree
Hide file tree
Showing 14 changed files with 217 additions and 35 deletions.
50 changes: 50 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,56 @@ 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();
```




## 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',
);
}
}
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);

ruleFor((registerParamDto) => registerParamDto.phone, key: 'phone') //
.customValidPhone('Phone invalid format');
.customValidPhone();
}
}
62 changes: 55 additions & 7 deletions example/lib/main.dart
Original file line number Diff line number Diff line change
@@ -1,22 +1,70 @@
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';

void main() {
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
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,
});
}
17 changes: 17 additions & 0 deletions lib/src/localization/culture.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// ignore_for_file: public_member_api_docs, sort_constructors_first
class Culture {
final String languageCode;
final String countryCode;

Culture(this.languageCode, [this.countryCode = '']);

@override
bool operator ==(covariant Culture other) {
if (identical(this, other)) return true;

return other.languageCode == languageCode && other.countryCode == countryCode;
}

@override
int get hashCode => languageCode.hashCode ^ countryCode.hashCode;
}
4 changes: 1 addition & 3 deletions lib/src/localization/language.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
abstract class Language {
final String culture;

static const code = (
equalTo: 'equalTo',
greaterThan: 'greaterThan',
Expand All @@ -27,7 +25,7 @@ abstract class Language {
validEmail: 'validEmail',
);

Language(this.culture, [Map<String, String> translations = const {}]) {
Language([Map<String, String> translations = const {}]) {
_translations.addAll(translations);
}

Expand Down
31 changes: 19 additions & 12 deletions lib/src/localization/language_manager.dart
Original file line number Diff line number Diff line change
@@ -1,27 +1,34 @@
import '../../lucid_validation.dart';
import 'languages/portuguese_brazillian_language.dart';

final _avaliableLanguages = <String, Language>{
'pt_BR': PortugueseBrasillianLanguage(),
'pt': PortugueseBrasillianLanguage(),
'en': EnglishLanguage(),
'en_US': EnglishLanguage(),
final _avaliableLanguages = <Culture, Language>{
Culture('pt', 'BR'): PortugueseBrasillianLanguage(),
Culture('pt'): PortugueseBrasillianLanguage(),
Culture('en'): EnglishLanguage(),
Culture('en', 'US'): EnglishLanguage(),
};

abstract class LanguageManager {
final _globalTranslations = <String, Map<String, String>>{};
final _globalTranslations = <Culture, Map<String, String>>{};

Language get currentLanguage => LucidValidation.global.language;

void addTranslation(String culture, String code, String value) {
void addTranslation(Culture culture, String code, String value) {
if (!_globalTranslations.containsKey(culture)) {
_globalTranslations[culture] = {};
}
_globalTranslations[culture]![code] = value;
}

List<Culture> avaliableCultures() {
return _avaliableLanguages.keys.toList();
}

bool isSupported(String languageCode, String? countryCode) {
return _avaliableLanguages.containsKey(Culture(languageCode, countryCode ?? ''));
}

String translate(String key, {Map<String, String> parameters = const {}, String? defaultMessage}) {
final culture = currentLanguage.culture;
final culture = LucidValidation.global.culture;
final currentLanguage = getLanguage(culture);
final translations = _globalTranslations[culture] ?? {};
var message = defaultMessage ?? translations[key] ?? currentLanguage.getTranslation(key) ?? key;
for (var key in parameters.keys) {
Expand All @@ -31,8 +38,8 @@ abstract class LanguageManager {
return message;
}

Language getLanguage(String culture) {
return _avaliableLanguages[culture] ?? LucidValidation.global.language;
Language getLanguage(Culture culture) {
return _avaliableLanguages[culture] ?? _avaliableLanguages[Culture('en')]!;
}
}

Expand Down
2 changes: 1 addition & 1 deletion lib/src/localization/languages/english_language.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import '../language.dart';

class EnglishLanguage extends Language {
EnglishLanguage() : super('en');
EnglishLanguage();
}
Loading

0 comments on commit 80d1be4

Please sign in to comment.