Navigation: Validations | Conditional Validation | Rules & Schemas | Custom Strategies | Error Handling | Internationalization(INTERNATIONALIZATION.md) | Benchmarks
DataVerify includes a built-in translation system for validation error messages. Built-in languages (English, French) are automatically loaded - just set the locale.
- Quick Start
- Built-in Languages
- Custom Translation Files
- Inline Custom Translations
- Translation Placeholders
- Custom Translator
- Best Practices
use Gravity\DataVerify;
$data = new stdClass();
$data->email = 'invalid';
$dv = new DataVerify($data);
$dv->setLocale('fr'); // Switch to French
$dv->field('email')->required->email;
if (!$dv->verify()) {
echo $dv->getErrors()[0]['message'];
// "Le champ email doit être une adresse email valide"
}Available Built-in Locales
DataVerify comes with built-in translations that are automatically loaded:
- English (
en) - Default locale - French (
fr) - Ready to use
$dv = new DataVerify($data);
// English (default)
$dv->field('email')->required;
// "The field email is required"
// French
$dv->setLocale('fr');
$dv->field('email')->required;
// "Le champ email est requis"Note: Built-in translations are in src/Locales/ (no dependencies).
PHP Translation Files (Recommended)
<?php
// locales/es/validations.php
return [
'validation.required' => 'El campo {field} es obligatorio',
'validation.email' => 'El campo {field} debe ser un email válido',
'validation.minLength' => 'El campo {field} debe tener al menos {min} caracteres',
];Load and use:
$dv->loadLocale('es', __DIR__ . '/locales/es/validations.php');
$dv->setLocale('es');Why PHP files? Fast, zero dependencies, native support.
YAML Files (Requires symfony/yaml)
# locales/es/validations.yml
validation.required: "El campo {field} es obligatorio"
validation.email: "El campo {field} debe ser un email válido"$dv->loadLocale('es', __DIR__ . '/locales/es/validations.yml');
$dv->setLocale('es');Note: Requires composer require symfony/yaml
Recommended File Structure
app/locales/
├── en/validations.php
├── fr/validations.php
└── es/validations.php
Load multiple files per locale:
$dv
->loadLocale('es', __DIR__ . '/locales/es/validations.php')
->loadLocale('es', __DIR__ . '/locales/es/custom.php')
->setLocale('es');Adding Translations Directly in Code
$dv->addTranslations([
'validation.strong_password' => 'The {field} must be at least {minLength} characters with uppercase, lowercase, number, and special character'
], 'en');
$dv->addTranslations([
'validation.strong_password' => 'Le {field} doit contenir au moins {minLength} caractères avec majuscule, minuscule, chiffre et caractère spécial'
], 'fr');Use for: Custom strategies, quick prototyping, one-off translations.
Overriding Built-in Messages
$dv->addTranslations([
'validation.required' => '{field} is absolutely mandatory!'
], 'en');
$dv->field('email')->required;
// "email is absolutely mandatory!"Built-in Placeholders
| Placeholder | Used In | Example |
|---|---|---|
{field} |
All validations | Field name or alias |
{min} |
minLength, between, greaterThan |
Minimum value |
{max} |
maxLength, between, lowerThan |
Maximum value |
{mime} |
fileMime |
MIME type(s) |
{value} |
Custom messages | Actual field value |
$dv->field('password')->minLength(8);
// "The field password must be at least 8 characters"
// ^ {min} auto-replacedAutomatic Parameter Mapping
DataVerify automatically discovers parameter names from handler() methods and makes them available as placeholders.
use Gravity\Validations\ValidationStrategy;
class RangeStrategy extends ValidationStrategy
{
public function getName(): string
{
return 'in_range';
}
protected function handler(
mixed $value,
int $min, // Becomes {min} placeholder
int $max // Becomes {max} placeholder
): bool {
return $value >= $min && $value <= $max;
}
}
// Translation automatically recognizes {min} and {max}
$dv->addTranslations([
'validation.in_range' => 'The {field} must be between {min} and {max}'
], 'en');
// Usage
$dv->field('age')->in_range(18, 65);
// Error: "The field age must be between 18 and 65"
// {min} and {max} auto-populated from parametersHow it works:
- Reflection extracts parameter names from your
handler()method - Parameter names become placeholders (e.g.,
$threshold→{threshold}) - Values are automatically mapped when validation is called
Best practice - Use standard names:
// ✅ Good - Matches conventions
protected function handler(mixed $value, int $min, int $max): bool
{
// {min} and {max} in translations
}
// ❌ Works but unclear
protected function handler(mixed $value, int $firstLimit, int $secondLimit): bool
{
// {firstLimit} and {secondLimit} - less intuitive
}Standard names: {min}, {max}, {mime}, {format}, {allowed}, {forbidden}
Using Aliases
// Without alias
$dv->field('user_email')->required;
// "The field user_email is required"
// With alias
$dv->field('user_email')->alias('Email Address')->required;
// "The field Email Address is required"Custom Error Messages (Bypass Translations)
$dv->field('email')
->required
->email
->errorMessage('Please provide a valid professional email address');Extending Translator Class
For advanced needs (database, API, cache):
use Gravity\Translation\Translator;
class DatabaseTranslator extends Translator
{
private PDO $pdo;
public function __construct(PDO $pdo, string $locale = 'en')
{
parent::__construct($locale);
$this->pdo = $pdo;
}
public function trans(string $id, array $parameters = [], ?string $domain = null, ?string $locale = null): string
{
$locale = $locale ?? $this->getLocale();
$domain = $domain ?? 'messages';
// Load from database
$message = $this->loadFromDb($id, $locale, $domain);
if ($message === null) {
// Fallback to parent (handles fallback locale)
return parent::trans($id, $parameters, $domain, $locale);
}
// Use parent's placeholder replacement
return $this->replacePlaceholders($message, $parameters);
}
private function loadFromDb(string $id, string $locale, string $domain): ?string
{
$stmt = $this->pdo->prepare(
'SELECT message FROM translations WHERE id = ? AND locale = ? AND domain = ?'
);
$stmt->execute([$id, $locale, $domain]);
return $stmt->fetchColumn() ?: null;
}
}
$dv->setTranslator(new DatabaseTranslator($pdo, 'fr'));Performance Tips
Load at bootstrap, switch on demand:
// bootstrap.php - Load once
$dv->loadLocale('es', __DIR__ . '/locales/es.php');
$dv->loadLocale('de', __DIR__ . '/locales/de.php');
// Later - instant switch (no I/O)
$dv->setLocale('es');Organization
Use translation files over inline:
// ✅ Organized, reusable
$dv->loadLocale('es', __DIR__ . '/locales/es.php');
// ❌ Scattered, hard to maintain
$dv->addTranslations([...], 'es');Leverage placeholders:
// ✅ Dynamic
'validation.between' => 'Between {min} and {max}'
// ❌ Hardcoded
'validation.between' => 'Between 1 and 100'Custom Strategies
Use named parameters in handler():
use Gravity\Validations\ValidationStrategy;
// ✅ Clean - parameter names become placeholders
class MyStrategy extends ValidationStrategy
{
protected function handler(mixed $value, int $min, int $max): bool
{
return $value >= $min && $value <= $max;
}
}
// Translation
'validation.my_validation' => 'Between {min} and {max}' // Clear and automatic- Custom Strategies - Parameter mapping for custom validations
- Error Handling - Working with translated errors
- Validation Rules - All validation rules
Navigation: Validations | Conditional Validation | Rules & Schemas | Custom Strategies | Error Handling | Internationalization | Benchmarks