Skip to content

Commit

Permalink
Add I18n support for the validators
Browse files Browse the repository at this point in the history
The PasswordStrengthValidator now also provides tips on how to
increase the password strength.
  • Loading branch information
sstok committed Feb 22, 2016
1 parent eb9436c commit de0ef66
Show file tree
Hide file tree
Showing 9 changed files with 328 additions and 129 deletions.
4 changes: 0 additions & 4 deletions phpunit.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,4 @@
<directory>./src</directory>
</whitelist>
</filter>

<php>
<ini name="mbstring.internal_encoding" value="UTF-8"/>
</php>
</phpunit>
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ public function load(array $configs, ContainerBuilder $container)
$container->setAlias('rollerworks_password_strength.blacklist_provider', $config['blacklist']['default_provider']);

$loader = new Loader\XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
$loader->load('strength_validator.xml');
$loader->load('blacklist.xml');

if (isset($config['blacklist']['providers']['sqlite'])) {
Expand Down
13 changes: 13 additions & 0 deletions src/Resources/config/strength_validator.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?xml version="1.0" ?>

<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">

<services>
<service class="Rollerworks\Bundle\PasswordStrengthBundle\Validator\Constraints\PasswordStrengthValidator" id="rollerworks_password_strength.validator.password_strength">
<argument id="translator" type="service" on-invalid="null" />
<tag name="validator.constraint_validator" alias="rollerworks_password_strength" />
</service>
</services>
</container>
79 changes: 79 additions & 0 deletions src/Resources/translations/validators.en.xlf
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
<?xml version="1.0"?>
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
<file source-language="en" datatype="plaintext" original="file.ext">
<body>
<trans-unit id="1">
<source>Your password must be at least {{length}} characters long.</source>
<target>Password must be at least {{length}} characters long.</target>
</trans-unit>
<trans-unit id="2">
<source>Your password must include at least one letter.</source>
<target>Password must include at least one letter.</target>
</trans-unit>
<trans-unit id="3">
<source>Your password must include both upper and lower case letters.</source>
<target>Password must include both upper and lower case letters.</target>
</trans-unit>
<trans-unit id="4">
<source>Your password must include at least one number.</source>
<target>Password must include at least one number.</target>
</trans-unit>
<trans-unit id="5">
<source>Your password must contain at least one special character.</source>
<target>Password must contain at least one special character.</target>
</trans-unit>
<trans-unit id="6">
<source>password_too_weak</source>
<target>Password needs to be at least at strength level "{{ min_strength }}", current level is "{{ current_strength }}", try the following {{ strength_tips }}.</target>
</trans-unit>

<!-- Strength levels -->
<trans-unit id="7">
<source>rollerworks_password.strength_level.very_weak</source>
<target>Very Weak</target>
</trans-unit>
<trans-unit id="8">
<source>rollerworks_password.strength_level.weak</source>
<target>Weak</target>
</trans-unit>
<trans-unit id="9">
<source>rollerworks_password.strength_level.medium</source>
<target>Medium</target>
</trans-unit>
<trans-unit id="10">
<source>rollerworks_password.strength_level.strong</source>
<target>Strong</target>
</trans-unit>
<trans-unit id="11">
<source>rollerworks_password.strength_level.very_strong</source>
<target>Very strong</target>
</trans-unit>

<!-- Tip translations -->
<trans-unit id="12">
<source>rollerworks_password.tip.letters</source>
<target>add (upper/lowercase) letters</target>
</trans-unit>
<trans-unit id="13">
<source>rollerworks_password.tip.numbers</source>
<target>add numbers</target>
</trans-unit>
<trans-unit id="14">
<source>rollerworks_password.tip.lowercase_letters</source>
<target>add uppercase letters</target>
</trans-unit>
<trans-unit id="15">
<source>rollerworks_password.tip.uppercase_letters</source>
<target>add uppercase letters</target>
</trans-unit>
<trans-unit id="16">
<source>rollerworks_password.tip.special_chars</source>
<target>add special characters</target>
</trans-unit>
<trans-unit id="17">
<source>rollerworks_password.tip.length</source>
<target>add more characters</target>
</trans-unit>
</body>
</file>
</xliff>
79 changes: 79 additions & 0 deletions src/Resources/translations/validators.nl.xlf
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
<?xml version="1.0"?>
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
<file source-language="en" datatype="plaintext" original="file.ext">
<body>
<trans-unit id="1">
<source>Your password must be at least {{length}} characters long.</source>
<target>Wachtwoord moet minstens {{length}} tekens lang zijn.</target>
</trans-unit>
<trans-unit id="2">
<source>Your password must include at least one letter.</source>
<target>Wachtwoord moet ten minste één letter bevatten.</target>
</trans-unit>
<trans-unit id="3">
<source>Your password must include both upper and lower case letters.</source>
<target>Wachtwoord moet ten minste één hoofdletter en kleine letter bevatten.</target>
</trans-unit>
<trans-unit id="4">
<source>Your password must include at least one number.</source>
<target>Wachtwoord moet ten minste één nummer bevatten.</target>
</trans-unit>
<trans-unit id="5">
<source>Your password must contain at least one special character.</source>
<target>Wachtwoord moet ten minste één speciaal teken of leesteken bevatten.</target>
</trans-unit>
<trans-unit id="6">
<source>password_too_weak</source>
<target>Wachtwoord moet minstens aan sterkte niveau "{{ min_strength }}" voldoen, huidig niveau is “{{ current_strength }}” probeer het volgende: {{ strength_tips }}.</target>
</trans-unit>

<!-- Strength levels -->
<trans-unit id="7">
<source>rollerworks_password.strength_level.very_weak</source>
<target>Erg zwak</target>
</trans-unit>
<trans-unit id="8">
<source>rollerworks_password.strength_level.weak</source>
<target>Zwak</target>
</trans-unit>
<trans-unit id="9">
<source>rollerworks_password.strength_level.medium</source>
<target>Gemiddeld</target>
</trans-unit>
<trans-unit id="10">
<source>rollerworks_password.strength_level.strong</source>
<target>Sterk</target>
</trans-unit>
<trans-unit id="11">
<source>rollerworks_password.strength_level.very_strong</source>
<target>Zeer sterk</target>
</trans-unit>

<!-- Tip translations -->
<trans-unit id="12">
<source>rollerworks_password.tip.letters</source>
<target>voeg (hoofd/kleine) letters toe</target>
</trans-unit>
<trans-unit id="13">
<source>rollerworks_password.tip.numbers</source>
<target>voeg nummers toe</target>
</trans-unit>
<trans-unit id="14">
<source>rollerworks_password.tip.lowercase_letters</source>
<target>voeg hoofdletters toe</target>
</trans-unit>
<trans-unit id="15">
<source>rollerworks_password.tip.uppercase_letters</source>
<target>voeg kleine letters toe</target>
</trans-unit>
<trans-unit id="16">
<source>rollerworks_password.tip.special_chars</source>
<target>voeg speciaal tekens of leestekens toe</target>
</trans-unit>
<trans-unit id="17">
<source>rollerworks_password.tip.length</source>
<target>gebruik meer tekens</target>
</trans-unit>
</body>
</file>
</xliff>
5 changes: 5 additions & 0 deletions src/Validator/Constraints/PasswordStrength.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,9 @@ public function getRequiredOptions()
{
return array('minStrength');
}

public function validatedBy()
{
return 'rollerworks_password_strength';
}
}
68 changes: 65 additions & 3 deletions src/Validator/Constraints/PasswordStrengthValidator.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@

namespace Rollerworks\Bundle\PasswordStrengthBundle\Validator\Constraints;

use Symfony\Component\Translation\Loader\XliffFileLoader;
use Symfony\Component\Translation\Translator;
use Symfony\Component\Translation\TranslatorInterface;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
Expand Down Expand Up @@ -38,6 +41,35 @@
*/
class PasswordStrengthValidator extends ConstraintValidator
{
/**
* @var TranslatorInterface
*/
private $translator;

/**
* @var array
*/
private static $levelToLabel = array(
1 => 'very_weak',
2 => 'weak',
3 => 'medium',
4 => 'strong',
5 => 'very_strong',
);

public function __construct(TranslatorInterface $translator = null)
{
// If translator is missing create a new translator.
// With the 'en' locale and 'validators' domain.
if (null === $translator) {
$translator = new Translator('en');
$translator->addLoader('xlf', new XliffFileLoader());
$translator->addResource('xlf', dirname(dirname(__DIR__)).'/Resources/translations/validators.en.xlf', 'en', 'validators');
}

$this->translator = $translator;
}

/**
* @param string $password
* @param PasswordStrength|Constraint $constraint
Expand Down Expand Up @@ -69,35 +101,65 @@ public function validate($password, Constraint $constraint)
return;
}

$tips = array();

if (preg_match('/[a-zA-Z]/', $password)) {
++$passwordStrength;
if (preg_match('/[a-z]/', $password) && preg_match('/[A-Z]/', $password)) {

if (!preg_match('/[a-z]/', $password)) {
$tips[] = 'lowercase_letters';
} elseif (preg_match('/[A-Z]/', $password)) {
++$passwordStrength;
} else {
$tips[] = 'uppercase_letters';
}
} else {
$tips[] = 'letters';
}

if (preg_match('/\d+/', $password)) {
++$passwordStrength;
} else {
$tips[] = 'numbers';
}

if (preg_match('/[^a-zA-Z0-9]/', $password)) {
++$passwordStrength;
} else {
$tips[] = 'special_chars';
}

if ($passLength > 12) {
++$passwordStrength;
} else {
$tips[] = 'length';
}

// No decrease strength on weak combinations

if ($passwordStrength < $constraint->minStrength) {
$parameters = array(
'{{ length }}' => $constraint->minLength,
'{{ min_strength }}' => $this->translator->trans('rollerworks_password.strength_level.'.self::$levelToLabel[$constraint->minStrength], array(), 'validators'),
'{{ current_strength }}' => $this->translator->trans('rollerworks_password.strength_level.'.self::$levelToLabel[$passwordStrength], array(), 'validators'),
'{{ strength_tips }}' => implode(', ', array_map(array($this, 'translateTips'), $tips)),
);

if ($this->context instanceof ExecutionContextInterface) {
$this->context->buildViolation($constraint->message)
->setParameters(array('{{ length }}' => $constraint->minLength))
->setParameters($parameters)
->addViolation();
} else {
$this->context->addViolation($constraint->message, array('{{ length }}' => $constraint->minLength));
$this->context->addViolation($constraint->message, $parameters);
}
}
}

/**
* @internal
*/
public function translateTips($tip)
{
return $this->translator->trans('rollerworks_password.tip.'.$tip, array(), 'validators');
}
}
26 changes: 26 additions & 0 deletions tests/DependencyInjection/ExtensionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@

use Rollerworks\Bundle\PasswordStrengthBundle\DependencyInjection\RollerworksPasswordStrengthExtension;
use Rollerworks\Bundle\PasswordStrengthBundle\Validator\Constraints\Blacklist as BlacklistConstraint;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddConstraintValidatorsPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
use Symfony\Component\Validator\Tests\Fixtures\Reference;

class ExtensionTest extends \PHPUnit_Framework_TestCase
{
Expand Down Expand Up @@ -107,6 +109,30 @@ public function testLoadWithChainConfiguration()
$this->assertFalse($provider->isBlacklisted('leeRoy'));
}

public function testPasswordStrengthValidatorService()
{
$container = $this->createContainer();
$container->registerExtension(new RollerworksPasswordStrengthExtension());
$container->loadFromExtension('rollerworks_password_strength');

$container->addCompilerPass(new AddConstraintValidatorsPass());
$container->register(
'validator.validator_factory',
'Symfony\Bundle\FrameworkBundle\Validator\ConstraintValidatorFactory'
)->setArguments(array(new Reference('service_container'), array()));

$this->compileContainer($container);

$validatorFactory = $container->getDefinition('validator.validator_factory');
$factoryArguments = $validatorFactory->getArguments();

$this->assertArrayHasKey('rollerworks_password_strength', $factoryArguments[1]);
$this->assertEquals(
'rollerworks_password_strength.validator.password_strength',
$factoryArguments[1]['rollerworks_password_strength']
);
}

/**
* @return ContainerBuilder
*/
Expand Down
Loading

0 comments on commit de0ef66

Please sign in to comment.