Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add plural interval #11

Merged
merged 3 commits into from Jul 15, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
11 changes: 11 additions & 0 deletions src/I18Next/Exception/TranslationSyntaxError.php
@@ -0,0 +1,11 @@
<?php

declare(strict_types=1);

namespace I18Next\Exception;

use atk4\core\Exception;

class TranslationSyntaxError extends Exception
{
}
3 changes: 1 addition & 2 deletions src/I18Next/Locale/Processor.php
Expand Up @@ -51,8 +51,7 @@ public function process(string $key, ?array $parameters = null, ?string $context

$found_key = $this->processorValue->processValue($found_key, $parameters);

if ($found_key !== $key)
{
if ($found_key !== $key) {
return $found_key;
}

Expand Down
71 changes: 71 additions & 0 deletions src/I18Next/Locale/Translations.php
Expand Up @@ -7,6 +7,7 @@
use atk4\core\ConfigTrait;
use atk4\core\Exception;
use DirectoryIterator;
use I18Next\Exception\TranslationSyntaxError;

/**
* @internal
Expand Down Expand Up @@ -54,6 +55,7 @@ public function load(string $path, bool $use_filename_as_namespace, ?string ...$
// normalizing
$this->afterReadProcessForKeyCounters();
$this->afterReadProcessForKeyDeepInline();

$this->afterReadAddNamespaceIfNeeded($configs, $fileInfo->getBasename('.'.$this->loader_format_ext));

// always reset config after every load
Expand Down Expand Up @@ -105,6 +107,10 @@ private function afterReadProcessForKeyCounters(): void
if ('plural' === $key_plural_definition || is_numeric($key_plural_definition)) {
$this->processForCounterKey($key_plural_definition, $key, $value);
}

if ('interval' === $key_plural_definition) {
$this->processForIntervalKey($key_plural_definition, $key, $value);
}
}
}

Expand Down Expand Up @@ -132,6 +138,71 @@ private function processForCounterKey(string $key_plural_definition, string $key
$this->setConfig($cleared_key.'/'.(string) $counter, $value);
}

private function processForIntervalKey(string $key_plural_definition, string $key, string $value): void
{
$cleared_key = substr(
$key,
0,
(strlen($key_plural_definition) + 1 /* the extra undescore before the plural_definition */) * -1
);

$check_last = substr($value, -1) === ';';

if (! $check_last) {
throw new TranslationSyntaxError([
'Interval declaration must end with ";" ('.$key.' => '.$value.')',
'key' => $key,
'value' => $value,
]);
}

$count_intervals = count(explode(';', trim($value, ';')));

$re = '/\((\S*)\)\{(.[^\}]*)\}/m';
//$str = '(1){one item};(2-7){a few items};(7-inf){a lot of items};';

preg_match_all($re, $value, $matches, PREG_SET_ORDER, 0);

if (count($matches) !== $count_intervals) {
throw new TranslationSyntaxError([
'Interval declaration syntax error ('.$key.' => '.$value.')',
'key' => $key,
'value' => $value,
]);
}

foreach ($matches as $match) {
if (count($match) < 3) {
throw new TranslationSyntaxError([
'Interval value syntax incorrect : '.$value,
'key' => $key,
'value' => $value,
'matches' => $matches,
'error_match' => $match,
]);
}

$interval = explode('-', $match[1]);

$interval_start = $interval[0];
$interval_end = $interval[1] ?? $interval[0];
if ($interval_end === 'inf') {
$interval_end = $interval_start;
}

$translation = $match[2];

if ($interval_start === $interval_end) {
$this->setConfig($cleared_key.'/'.(string) $interval_start, $translation);
continue;
}

for ($i = $interval_start; $i < $interval_end; $i++) {
$this->setConfig($cleared_key.'/'.(string) $i, $translation);
}
}
}

private function afterReadProcessForKeyDeepInline(): void
{
$filtered = array_filter($this->config, function ($key) {
Expand Down
5 changes: 2 additions & 3 deletions tests/Translator_Atk4Trait_Test.php
Expand Up @@ -22,12 +22,12 @@ public function testBase()

$app->add($child = new ATK4ChildMock());

$result = $child->_('friend', NULL, NULL, 'en');
$result = $child->_('friend', null, null, 'en');
$this->assertEquals('A friend', $result);

$this->translator->addLanguage('ro');

$result = $child->_('friend', NULL, NULL, 'ro');
$result = $child->_('friend', null, null, 'ro');
$this->assertEquals('Un prieten', $result);
}

Expand All @@ -47,7 +47,6 @@ public function testDirect()

$result = $app->_('Ho trovato, $t(friend)');
$this->assertEquals('Ho trovato, Un conoscente', $result);

}
}

Expand Down
89 changes: 89 additions & 0 deletions tests/Translator_CasePluralInterval_Test.php
@@ -0,0 +1,89 @@
<?php

namespace I18Next\Tests;

use I18Next\Exception\TranslationSyntaxError;
use I18Next\Translator;

class Translator_CasePluralInterval_Test extends TranslatorBaseCase
{
/**
* Testing this :
* "key4_interval": "(1){one item};(2-7){a few items};(7-inf){a lot of items};".
*
* "key4_interval": "(1){one item};(2-7){a few items};(7-inf){a lot of items};"
*/
public function testNoCount()
{
$this->setupTranslatorLanguages('en');

$result = $this->translator->_('key4');
$this->assertEquals('one item', $result);
}

public function testCount0()
{
$this->setupTranslatorLanguages('en');

$result = $this->translator->_('key4', ['count' => 0]);
$this->assertEquals('key4', $result);
}

public function testCount1()
{
$this->setupTranslatorLanguages('en');

$result = $this->translator->_('key4', ['count' => 1]);
$this->assertEquals('one item', $result);
}

public function testCount3()
{
$this->setupTranslatorLanguages('en');

$result = $this->translator->_('key4', ['count' => 3]);
$this->assertEquals('a few items', $result);
}

public function testCount8()
{
$this->setupTranslatorLanguages('en');

$result = $this->translator->_('key4', ['count' => 8]);
$this->assertEquals('a lot of items', $result);
}

public function testException1()
{
$this->expectException(TranslationSyntaxError::class);

$path = '/tmp/locale_exception';
@mkdir($path.'/en', 0777, true);

file_put_contents(
$path.'/en/exception.json',
json_encode(['key4_interval' => '(1){one item};2-7){a few items};(7-inf){a lot of items};'])
);

$this->translator = new Translator();
$this->translator->setTranslationsPath($path);
$this->translator->setLanguagePrimary('en');
}

public function testException2()
{
$this->expectException(TranslationSyntaxError::class);

$path = '/tmp/locale_exception';
@mkdir($path.'/en', 0777, true);

file_put_contents(
$path.'/en/exception.json',
json_encode(['key4_interval' => '(1){one item};(2-7){a few items};(7-inf){a lot of items}'])
);

$this->translator = new Translator();
$this->translator->setTranslationsPath($path);
$this->translator->setLanguagePrimary('en');
}
}
3 changes: 2 additions & 1 deletion tests/data/locales/en/key.json
Expand Up @@ -23,5 +23,6 @@
"key_4": "many",
"key_5": "other",
"key_nesting_interpolate1": "hello world",
"key_nesting_interpolate2": "say {{val}}"
"key_nesting_interpolate2": "say {{val}}",
"key4_interval": "(1){one item};(2-7){a few items};(7-inf){a lot of items};"
}
3 changes: 3 additions & 0 deletions tests/data/utils/cases.php
Expand Up @@ -131,6 +131,9 @@
'en' => 'user : {{user.first_name}} {{user.last_name}} with email : {{address.email}}',
'it' => 'utente : {{user.first_name}} {{user.last_name}} con email : {{address.email}}',
],
'key4_interval' => [
'en' => '(1){one item};(2-7){a few items};(7-inf){a lot of items};',
],
];

$path_def = [];
Expand Down