Skip to content

Commit 242bd41

Browse files
authored
Added LanguageList service
- added dependency on package `umpirsky/locale-list` - added new configuration options and options object `ListOptions` - added exception `RuntimeException` - added interface `IList` and abstract implementor `AbstractList` - added service `LanguageList`
1 parent 6e725ce commit 242bd41

File tree

7 files changed

+327
-1
lines changed

7 files changed

+327
-1
lines changed

composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@
1717
"php": "~7.1",
1818
"nette/di": "~2.4",
1919
"nette/http": "~2.4",
20-
"nette/utils": "~2.4"
20+
"nette/utils": "~2.4",
21+
"umpirsky/locale-list": "^1.0"
2122
},
2223
"require-dev": {
2324
"friendsofphp/php-cs-fixer": "^2.0",

src/DI/I18nExtension.php

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,11 @@ final class I18nExtension extends Nette\DI\CompilerExtension
1717
'enabled' => FALSE,
1818
'use_default' => FALSE,
1919
],
20+
'lists' => [
21+
'vendorDir' => '%appDir%/../vendor',
22+
'fallback_language' => 'en',
23+
'default_language' => NULL,
24+
],
2025
'storage' => SixtyEightPublishers\i18n\Storage\SessionProfileStorage::class,
2126
'detector' => SixtyEightPublishers\i18n\Detector\NetteRequestDetector::class,
2227
];
@@ -47,6 +52,11 @@ public function loadConfiguration(): void
4752
Nette\Utils\Validators::assertField($config, 'storage', 'string|' . Nette\DI\Statement::class);
4853
Nette\Utils\Validators::assertField($config, 'detector', 'string|' . Nette\DI\Statement::class);
4954

55+
Nette\Utils\Validators::assertField($config, 'lists', 'array');
56+
Nette\Utils\Validators::assertField($config['lists'], 'vendorDir', 'string');
57+
Nette\Utils\Validators::assertField($config['lists'], 'fallback_language', 'string');
58+
Nette\Utils\Validators::assertField($config['lists'], 'default_language', 'null|string');
59+
5060
if (empty($profiles)) {
5161
throw new SixtyEightPublishers\i18n\Exception\ConfigurationException('You must define almost one profile in your configuration.');
5262
}
@@ -99,6 +109,23 @@ public function loadConfiguration(): void
99109
$profileContainer,
100110
]);
101111

112+
# register lists
113+
114+
$listOptions = $builder->addDefinition($this->prefix('list_options'))
115+
->setType(SixtyEightPublishers\i18n\Lists\ListOptions::class)
116+
->setArguments([
117+
'vendorDir' => realpath($config['lists']['vendorDir']),
118+
'fallbackLanguage' => $config['lists']['fallback_language'],
119+
'defaultLanguage' => $config['lists']['default_language'],
120+
])
121+
->setAutowired(FALSE);
122+
123+
$builder->addDefinition($this->prefix('list.language'))
124+
->setType(SixtyEightPublishers\i18n\Lists\LanguageList::class)
125+
->setArguments([
126+
'options' => $listOptions,
127+
]);
128+
102129
# register kdyby/translation integration
103130
if (TRUE === $config['translations']['enabled']) {
104131
$this->registerTranslations((bool) $config['translations']['use_default']);

src/Exception/RuntimeException.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace SixtyEightPublishers\i18n\Exception;
6+
7+
final class RuntimeException extends \RuntimeException implements IException
8+
{
9+
}

src/Lists/AbstractList.php

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace SixtyEightPublishers\i18n\Lists;
6+
7+
use Nette;
8+
use SixtyEightPublishers;
9+
10+
abstract class AbstractList implements IList
11+
{
12+
use Nette\SmartObject;
13+
14+
/** @var \SixtyEightPublishers\i18n\Lists\ListOptions */
15+
private $options;
16+
17+
/** @var NULL|string */
18+
private $language;
19+
20+
/** @var array */
21+
private $cached = [];
22+
23+
/**
24+
* @param \SixtyEightPublishers\i18n\Lists\ListOptions $options
25+
*/
26+
public function __construct(ListOptions $options)
27+
{
28+
$this->options = $options;
29+
}
30+
31+
/**
32+
* First %s is vendor dir, second %s is locale
33+
*
34+
* @return string
35+
*/
36+
abstract protected function getSourcePathMask(): string;
37+
38+
/**
39+
* @param string $language
40+
*
41+
* @return string
42+
*/
43+
private function createSourcePath(string $language): string
44+
{
45+
return sprintf(
46+
$this->getSourcePathMask(),
47+
$this->options->vendorDir,
48+
$language
49+
);
50+
}
51+
52+
/************ interface \IteratorAggregate ************/
53+
54+
/**
55+
* {@inheritdoc}
56+
*/
57+
public function getIterator(): \ArrayIterator
58+
{
59+
return new \ArrayIterator($this->getList());
60+
}
61+
62+
/************ interface \ArrayAccess ************/
63+
64+
/**
65+
* {@inheritdoc}
66+
*/
67+
public function offsetExists($offset): bool
68+
{
69+
return isset($this->getList()[$offset]);
70+
}
71+
72+
/**
73+
* {@inheritdoc}
74+
*/
75+
public function offsetGet($offset): string
76+
{
77+
if (!$this->offsetExists($offset)) {
78+
throw new SixtyEightPublishers\i18n\Exception\InvalidArgumentException(sprintf(
79+
'Item %s is not defined in list.',
80+
(string) $offset
81+
));
82+
}
83+
84+
return $this->getList()[$offset];
85+
}
86+
87+
/**
88+
* {@inheritdoc}
89+
*/
90+
public function offsetSet($offset, $value)
91+
{
92+
throw new \LogicException('Changes of statically defined list is not allowed.');
93+
}
94+
95+
/**
96+
* {@inheritdoc}
97+
*/
98+
public function offsetUnset($offset): void
99+
{
100+
throw new \LogicException('Changes of statically defined list is not allowed.');
101+
}
102+
103+
/************ interface \JsonSerializable ************/
104+
105+
/**
106+
* {@inheritdoc}
107+
*/
108+
public function jsonSerialize(): array
109+
{
110+
return $this->getList();
111+
}
112+
113+
/************ interface \Countable ************/
114+
115+
/**
116+
* {@inheritdoc}
117+
*/
118+
public function count(): int
119+
{
120+
return count($this->getList());
121+
}
122+
123+
/************ interface \SixtyEightPublishers\i18n\Lists\IList ************/
124+
125+
/**
126+
* {@inheritdoc}
127+
*/
128+
public function setLanguage(string $language): void
129+
{
130+
$this->language = $language;
131+
}
132+
133+
/**
134+
* {@inheritdoc}
135+
*/
136+
public function getList(?string $language = NULL): array
137+
{
138+
$language = ($language ?? $this->language) ?? $this->options->resolvedLanguage;
139+
140+
if (isset($this->cached[$language])) {
141+
return $this->cached[$language];
142+
}
143+
144+
$path = $this->createSourcePath($language);
145+
146+
if (!file_exists($path)) {
147+
trigger_error(sprintf(
148+
'Missing lists for language %s, fallback %s is used.',
149+
$language,
150+
$this->options->fallbackLanguage
151+
), E_USER_NOTICE);
152+
153+
$language = $this->options->fallbackLanguage;
154+
$path = $this->createSourcePath($language);
155+
}
156+
157+
if (!file_exists($path)) {
158+
throw new SixtyEightPublishers\i18n\Exception\RuntimeException('Can\'t resolve language for list.');
159+
}
160+
161+
/** @noinspection PhpIncludeInspection */
162+
return $this->cached[$language] = include $path;
163+
}
164+
}

src/Lists/IList.php

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace SixtyEightPublishers\i18n\Lists;
6+
7+
interface IList extends \ArrayAccess, \IteratorAggregate, \JsonSerializable, \Countable
8+
{
9+
/**
10+
* @param string $language
11+
*
12+
* @return void
13+
*/
14+
public function setLanguage(string $language): void;
15+
16+
/**
17+
* @param string|NULL $language
18+
*
19+
* @return array
20+
*/
21+
public function getList(?string $language = NULL): array;
22+
}

src/Lists/LanguageList.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace SixtyEightPublishers\i18n\Lists;
6+
7+
final class LanguageList extends AbstractList
8+
{
9+
/**
10+
* {@inheritdoc}
11+
*/
12+
protected function getSourcePathMask(): string
13+
{
14+
return '%s/umpirsky/locale-list/data/%s/locales.php';
15+
}
16+
}

src/Lists/ListOptions.php

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace SixtyEightPublishers\i18n\Lists;
6+
7+
use Nette;
8+
use SixtyEightPublishers;
9+
10+
/**
11+
* @property-read string $vendorDir
12+
* @property-read string $fallbackLanguage
13+
* @property-read string|NULL $defaultLanguage
14+
* @property-read string $resolvedLanguage
15+
*/
16+
final class ListOptions
17+
{
18+
use Nette\SmartObject;
19+
20+
/** @var \SixtyEightPublishers\i18n\IProfileProvider */
21+
private $profileProvider;
22+
23+
/** @var string */
24+
private $vendorDir;
25+
26+
/** @var string */
27+
private $fallbackLanguage;
28+
29+
/** @var string|NULL */
30+
private $defaultLanguage;
31+
32+
/**
33+
* @param \SixtyEightPublishers\i18n\IProfileProvider $profileProvider
34+
* @param string $vendorDir
35+
* @param string $fallbackLanguage
36+
* @param string|NULL $defaultLanguage
37+
*/
38+
public function __construct(
39+
SixtyEightPublishers\i18n\IProfileProvider $profileProvider,
40+
string $vendorDir,
41+
string $fallbackLanguage,
42+
?string $defaultLanguage
43+
) {
44+
$this->profileProvider = $profileProvider;
45+
$this->vendorDir = $vendorDir;
46+
$this->fallbackLanguage = $fallbackLanguage;
47+
$this->defaultLanguage = $defaultLanguage;
48+
}
49+
50+
/**
51+
* @return string
52+
*/
53+
public function getVendorDir(): string
54+
{
55+
return $this->vendorDir;
56+
}
57+
58+
/**
59+
* @return string
60+
*/
61+
public function getFallbackLanguage(): string
62+
{
63+
return $this->fallbackLanguage;
64+
}
65+
66+
/**
67+
* @return NULL|string
68+
*/
69+
public function getDefaultLanguage(): ?string
70+
{
71+
return $this->defaultLanguage;
72+
}
73+
74+
/**
75+
* @return string
76+
*/
77+
public function getResolvedLanguage(): string
78+
{
79+
try {
80+
return $this->defaultLanguage ?? $this->profileProvider->getProfile()->language;
81+
} catch (\Throwable $e) {
82+
trigger_error($e->getMessage(), E_USER_NOTICE);
83+
84+
return $this->fallbackLanguage;
85+
}
86+
}
87+
}

0 commit comments

Comments
 (0)