Skip to content

Commit a5e6dd9

Browse files
committed
allow fluent functions registration
resolves #3
1 parent 0186b7f commit a5e6dd9

3 files changed

Lines changed: 85 additions & 1 deletion

File tree

src/FluentTranslator.php

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,24 @@
22

33
namespace Major\Fluent\Laravel;
44

5+
use Closure;
56
use Countable;
67
use Illuminate\Contracts\Translation\Loader;
78
use Illuminate\Contracts\Translation\Translator as TranslatorContract;
89
use Illuminate\Filesystem\Filesystem;
910
use Illuminate\Translation\MessageSelector;
1011
use Illuminate\Translation\Translator as BaseTranslator;
1112
use Major\Fluent\Bundle\FluentBundle;
13+
use Major\Fluent\Exceptions\Bundle\FunctionExistsException;
1214

1315
final class FluentTranslator implements TranslatorContract
1416
{
1517
/** @var array<string, array<string, FluentBundle|false>> */
1618
private array $loaded = [];
1719

20+
/** @var array<string, Closure> */
21+
private array $functions = [];
22+
1823
public function __construct(
1924
protected BaseTranslator $baseTranslator,
2025
protected Filesystem $files,
@@ -62,6 +67,23 @@ public function get($key, array $replace = [], $locale = null, bool $fallback =
6267
return $message ?? $this->baseTranslator->get(...func_get_args());
6368
}
6469

70+
public function addFunction(string $name, Closure $function): void
71+
{
72+
if (array_key_exists($name, $this->functions)) {
73+
throw new FunctionExistsException($name);
74+
}
75+
76+
$this->functions[$name] = $function;
77+
78+
foreach ($this->loaded as $locale) {
79+
foreach ($locale as $bundle) {
80+
if ($bundle !== false) {
81+
$bundle->addFunction($name, $function);
82+
}
83+
}
84+
}
85+
}
86+
6587
private function getBundle(string $locale, string $group): ?FluentBundle
6688
{
6789
if (! isset($this->loaded[$locale][$group])) {
@@ -80,7 +102,8 @@ private function loadFtl(string $locale, string $group): ?FluentBundle
80102
}
81103

82104
return (new FluentBundle($locale, ...$this->bundleOptions))
83-
->addFtl($this->files->get($path));
105+
->addFtl($this->files->get($path))
106+
->addFunctions($this->functions);
84107
}
85108

86109
/**

tests/FunctionsTest.php

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
<?php
2+
3+
namespace Major\Fluent\Laravel\Tests;
4+
5+
use Major\Fluent\Exceptions\Bundle\FunctionExistsException;
6+
use Major\Fluent\Exceptions\Resolver\ReferenceException;
7+
8+
final class FunctionsTest extends TestCase
9+
{
10+
/**
11+
* @testdox function can be used
12+
*/
13+
public function testUsage(): void
14+
{
15+
$this->translator->addFunction('CONCAT', fn (string ...$args) => implode($args));
16+
17+
$this->assertSame('FooBar', __('functions.strings'));
18+
}
19+
20+
/**
21+
* @testdox arguments can be passed to function
22+
*/
23+
public function testArguments(): void
24+
{
25+
$this->translator->addFunction('CONCAT', fn (string ...$args) => implode($args));
26+
27+
$this->assertSame('BarBaz', __('functions.args', ['foo' => 'Bar', 'bar' => 'Baz']));
28+
}
29+
30+
/**
31+
* @testdox function can not be registered twice
32+
*/
33+
public function testRegisterTwice(): void
34+
{
35+
$this->expectException(FunctionExistsException::class);
36+
$this->expectExceptionMessage('Attempt to override an existing function: CONCAT().');
37+
38+
$this->translator->addFunction('CONCAT', fn (string ...$args) => implode($args));
39+
$this->translator->addFunction('CONCAT', fn (string ...$args) => implode(', ', $args));
40+
}
41+
42+
/**
43+
* @testdox function can be registered after bundle is resolved
44+
*/
45+
public function testLateRegistration(): void
46+
{
47+
try {
48+
$this->assertSame('FooBar', __('functions.strings'));
49+
50+
$this->fail('Exception should have been thrown.');
51+
} catch (ReferenceException $e) {
52+
$this->assertSame('Unknown function: CONCAT().', $e->getMessage());
53+
}
54+
55+
$this->translator->addFunction('CONCAT', fn (string ...$args) => implode($args));
56+
57+
$this->assertSame('FooBar', __('functions.strings'));
58+
}
59+
}

tests/lang/pl/functions.ftl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
strings = { CONCAT("Foo", "Bar") }
2+
args = { CONCAT($foo, $bar) }

0 commit comments

Comments
 (0)