Skip to content

Commit

Permalink
feature #59 Add I18n support for the validators (sstok)
Browse files Browse the repository at this point in the history
This PR was merged into the master branch.

Discussion
----------

|Q            |A          |
|---          |---        |
|Bug Fix?     |no         |
|New Feature? |yes        |
|BC Breaks?   |yes (minor)|
|Deprecations?|no         |
|Fixed Tickets|#27        |
|License      |MIT        |

There is a minor BC break for the translation strings (removed the 'Your' part from the translated string).

Commits
-------

de0ef66 Add I18n support for the validators
  • Loading branch information
sstok committed Feb 22, 2016
2 parents eb9436c + de0ef66 commit 387b985
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 387b985

Please sign in to comment.