From b70ed2e21d82a6f2b8c438d293af938927d92989 Mon Sep 17 00:00:00 2001 From: Dean Wunder Date: Sun, 19 Nov 2023 01:56:53 +1100 Subject: [PATCH 1/7] Add the ability to handle missing translation strings with a user-defined callback to facilitate customising missing translation behaviour. Callback can return a string which is subsequently returned by the Translator get method. --- src/Illuminate/Translation/Translator.php | 42 +++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/src/Illuminate/Translation/Translator.php b/src/Illuminate/Translation/Translator.php index e29ba93a2dca..2798b51ce481 100755 --- a/src/Illuminate/Translation/Translator.php +++ b/src/Illuminate/Translation/Translator.php @@ -65,6 +65,13 @@ class Translator extends NamespacedItemResolver implements TranslatorContract */ protected $stringableHandlers = []; + /** + * The callback that is responsible for handling missing translation keys. + * + * @var callable|null + */ + protected static $missingTranslationKeyCallback; + /** * Create a new translator instance. * @@ -153,6 +160,10 @@ public function get($key, array $replace = [], $locale = null, $fallback = true) return $line; } } + + // If we can't find a translation in neither JSON nor typical translation + // file, then this is considered a missing translation, handle it accordingly. + $key = $this->handleMissingTranslationKey($key, $replace, $locale, $fallback); } // If the line doesn't exist, we will return back the key which was requested as @@ -161,6 +172,37 @@ public function get($key, array $replace = [], $locale = null, $fallback = true) return $this->makeReplacements($line ?: $key, $replace); } + /** + * Handle a missing translation key. + * + * @param string $key + * @param array $replace + * @param string|null $locale + * @param bool $fallback + * @return string + */ + protected function handleMissingTranslationKey($key, $replace, $locale, $fallback) + { + // Call user defined missing translation handler callback if set. + if (isset(static::$missingTranslationKeyCallback)) { + return call_user_func(static::$missingTranslationKeyCallback, + $key, $replace, $locale, $fallback + ); + } + return $key; + } + + /** + * Register a callback that is responsible for handling missing translation keys. + * + * @param callable|null $callback + * @return void + */ + public static function handleMissingTranslationKeyUsing(?callable $callback) + { + static::$missingTranslationKeyCallback = $callback; + } + /** * Get a translation according to an integer value. * From 9f8eb094dd85a2765c6344a68a0fdb50b96706ea Mon Sep 17 00:00:00 2001 From: Dean Wunder Date: Sun, 19 Nov 2023 02:48:57 +1100 Subject: [PATCH 2/7] Add functionality to avoid infinite loops when the handle missing translation callback itself tries to translation a missing translation. --- src/Illuminate/Translation/Translator.php | 29 +++++++++++++++++++---- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/src/Illuminate/Translation/Translator.php b/src/Illuminate/Translation/Translator.php index 2798b51ce481..565cc32e72f9 100755 --- a/src/Illuminate/Translation/Translator.php +++ b/src/Illuminate/Translation/Translator.php @@ -65,6 +65,13 @@ class Translator extends NamespacedItemResolver implements TranslatorContract */ protected $stringableHandlers = []; + /** + * Whether missing translation keys should be handled. + * + * @var bool + */ + protected $handleMissingTranslationKeys = true; + /** * The callback that is responsible for handling missing translation keys. * @@ -183,12 +190,24 @@ public function get($key, array $replace = [], $locale = null, $fallback = true) */ protected function handleMissingTranslationKey($key, $replace, $locale, $fallback) { - // Call user defined missing translation handler callback if set. - if (isset(static::$missingTranslationKeyCallback)) { - return call_user_func(static::$missingTranslationKeyCallback, - $key, $replace, $locale, $fallback - ); + // Avoid infinite loops: don't handle any missing translations which are in + // the user defined callback. + if (! $this->handleMissingTranslationKeys) { + return $key; } + + // Return the key unchanged if there is no user defined callback set. + if (! isset(static::$missingTranslationKeyCallback)) { + return $key; + } + + // Call user defined missing translation handler callback, prevent infinite loops. + $this->handleMissingTranslationKeys = false; + $key = call_user_func(static::$missingTranslationKeyCallback, + $key, $replace, $locale, $fallback + ); + $this->handleMissingTranslationKeys = true; + return $key; } From 049f74178fe996773180804f47837ac0d5df30dd Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Mon, 20 Nov 2023 13:35:56 -0600 Subject: [PATCH 3/7] formatting --- src/Illuminate/Translation/Translator.php | 102 +++++++++++----------- 1 file changed, 50 insertions(+), 52 deletions(-) diff --git a/src/Illuminate/Translation/Translator.php b/src/Illuminate/Translation/Translator.php index 565cc32e72f9..13b129f5d549 100755 --- a/src/Illuminate/Translation/Translator.php +++ b/src/Illuminate/Translation/Translator.php @@ -66,18 +66,18 @@ class Translator extends NamespacedItemResolver implements TranslatorContract protected $stringableHandlers = []; /** - * Whether missing translation keys should be handled. + * The callback that is responsible for handling missing translation keys. * - * @var bool + * @var callable|null */ - protected $handleMissingTranslationKeys = true; + protected static $missingTranslationKeyCallback; /** - * The callback that is responsible for handling missing translation keys. + * Indicates whether missing translation keys should be handled. * - * @var callable|null + * @var bool */ - protected static $missingTranslationKeyCallback; + protected $handleMissingTranslationKeys = true; /** * Create a new translator instance. @@ -168,9 +168,9 @@ public function get($key, array $replace = [], $locale = null, $fallback = true) } } - // If we can't find a translation in neither JSON nor typical translation - // file, then this is considered a missing translation, handle it accordingly. - $key = $this->handleMissingTranslationKey($key, $replace, $locale, $fallback); + $key = $this->handleMissingTranslationKey( + $key, $replace, $locale, $fallback + ); } // If the line doesn't exist, we will return back the key which was requested as @@ -179,49 +179,6 @@ public function get($key, array $replace = [], $locale = null, $fallback = true) return $this->makeReplacements($line ?: $key, $replace); } - /** - * Handle a missing translation key. - * - * @param string $key - * @param array $replace - * @param string|null $locale - * @param bool $fallback - * @return string - */ - protected function handleMissingTranslationKey($key, $replace, $locale, $fallback) - { - // Avoid infinite loops: don't handle any missing translations which are in - // the user defined callback. - if (! $this->handleMissingTranslationKeys) { - return $key; - } - - // Return the key unchanged if there is no user defined callback set. - if (! isset(static::$missingTranslationKeyCallback)) { - return $key; - } - - // Call user defined missing translation handler callback, prevent infinite loops. - $this->handleMissingTranslationKeys = false; - $key = call_user_func(static::$missingTranslationKeyCallback, - $key, $replace, $locale, $fallback - ); - $this->handleMissingTranslationKeys = true; - - return $key; - } - - /** - * Register a callback that is responsible for handling missing translation keys. - * - * @param callable|null $callback - * @return void - */ - public static function handleMissingTranslationKeyUsing(?callable $callback) - { - static::$missingTranslationKeyCallback = $callback; - } - /** * Get a translation according to an integer value. * @@ -369,6 +326,47 @@ protected function isLoaded($namespace, $group, $locale) return isset($this->loaded[$namespace][$group][$locale]); } + /** + * Handle a missing translation key. + * + * @param string $key + * @param array $replace + * @param string|null $locale + * @param bool $fallback + * @return string + */ + protected function handleMissingTranslationKey($key, $replace, $locale, $fallback) + { + if (! $this->handleMissingTranslationKeys || + ! isset($this->missingTranslationKeyCallback)) { + return $key; + } + + // Prevent infinite loops... + $this->handleMissingTranslationKeys = false; + + $key = call_user_func($this->missingTranslationKeyCallback, + $key, $replace, $locale, $fallback + ); + + $this->handleMissingTranslationKeys = true; + + return $key; + } + + /** + * Register a callback that is responsible for handling missing translation keys. + * + * @param callable|null $callback + * @return static + */ + public function handleMissingTranslationKeyUsing(?callable $callback) + { + $this->missingTranslationKeyCallback = $callback; + + return $this; + } + /** * Add a new namespace to the loader. * From 828f4660abc0de9856f7f75cc9a3ef6ca441c43d Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Mon, 20 Nov 2023 13:36:29 -0600 Subject: [PATCH 4/7] formatting --- src/Illuminate/Translation/Translator.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Translation/Translator.php b/src/Illuminate/Translation/Translator.php index 13b129f5d549..d329f2dda29b 100755 --- a/src/Illuminate/Translation/Translator.php +++ b/src/Illuminate/Translation/Translator.php @@ -70,7 +70,7 @@ class Translator extends NamespacedItemResolver implements TranslatorContract * * @var callable|null */ - protected static $missingTranslationKeyCallback; + protected $missingTranslationKeyCallback; /** * Indicates whether missing translation keys should be handled. From 1e84b65236439b210374697d210533c292353c40 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Mon, 20 Nov 2023 13:40:10 -0600 Subject: [PATCH 5/7] add test --- src/Illuminate/Translation/Translator.php | 2 +- tests/Integration/Translation/TranslatorTest.php | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Translation/Translator.php b/src/Illuminate/Translation/Translator.php index d329f2dda29b..262656c36521 100755 --- a/src/Illuminate/Translation/Translator.php +++ b/src/Illuminate/Translation/Translator.php @@ -360,7 +360,7 @@ protected function handleMissingTranslationKey($key, $replace, $locale, $fallbac * @param callable|null $callback * @return static */ - public function handleMissingTranslationKeyUsing(?callable $callback) + public function handleMissingTranslationKeysUsing(?callable $callback) { $this->missingTranslationKeyCallback = $callback; diff --git a/tests/Integration/Translation/TranslatorTest.php b/tests/Integration/Translation/TranslatorTest.php index bb84bb5c17f9..38bfc4c72944 100644 --- a/tests/Integration/Translation/TranslatorTest.php +++ b/tests/Integration/Translation/TranslatorTest.php @@ -40,4 +40,19 @@ public function testItCanCheckLanguageExistsHasFromLocaleForJson() $this->assertFalse($this->app['translator']->hasForLocale('1 Day')); $this->assertTrue($this->app['translator']->hasForLocale('30 Days')); } + + public function testItCanHandleMissingKeysUsingCallback() + { + $this->app['translator']->handleMissingTranslationKeysUsing(function ($key) { + $_SERVER['__missing_translation_key'] = $key; + return 'callback key'; + }); + + $key = $this->app['translator']->get('some missing key'); + + $this->assertSame('callback key', $key); + $this->assertSame('some missing key', $_SERVER['__missing_translation_key']); + + $this->app['translator']->handleMissingTranslationKeysUsing(null); + } } From 9beaf4ed6d1cd4f40ca624529fd745bf52b44cbc Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Mon, 20 Nov 2023 13:40:43 -0600 Subject: [PATCH 6/7] formatting --- src/Illuminate/Translation/Translator.php | 2 +- tests/Integration/Translation/TranslatorTest.php | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Translation/Translator.php b/src/Illuminate/Translation/Translator.php index 262656c36521..ef61dabb3b73 100755 --- a/src/Illuminate/Translation/Translator.php +++ b/src/Illuminate/Translation/Translator.php @@ -360,7 +360,7 @@ protected function handleMissingTranslationKey($key, $replace, $locale, $fallbac * @param callable|null $callback * @return static */ - public function handleMissingTranslationKeysUsing(?callable $callback) + public function handleMissingKeysUsing(?callable $callback) { $this->missingTranslationKeyCallback = $callback; diff --git a/tests/Integration/Translation/TranslatorTest.php b/tests/Integration/Translation/TranslatorTest.php index 38bfc4c72944..4ebf8dcecaae 100644 --- a/tests/Integration/Translation/TranslatorTest.php +++ b/tests/Integration/Translation/TranslatorTest.php @@ -43,7 +43,7 @@ public function testItCanCheckLanguageExistsHasFromLocaleForJson() public function testItCanHandleMissingKeysUsingCallback() { - $this->app['translator']->handleMissingTranslationKeysUsing(function ($key) { + $this->app['translator']->handleMissingKeysUsing(function ($key) { $_SERVER['__missing_translation_key'] = $key; return 'callback key'; }); @@ -53,6 +53,6 @@ public function testItCanHandleMissingKeysUsingCallback() $this->assertSame('callback key', $key); $this->assertSame('some missing key', $_SERVER['__missing_translation_key']); - $this->app['translator']->handleMissingTranslationKeysUsing(null); + $this->app['translator']->handleMissingKeysUsing(null); } } From d4fa514ee86af5cb32925a6249bb29fe37cef85a Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Mon, 20 Nov 2023 13:44:57 -0600 Subject: [PATCH 7/7] Update Translator.php --- src/Illuminate/Translation/Translator.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Translation/Translator.php b/src/Illuminate/Translation/Translator.php index ef61dabb3b73..41fb2c94922b 100755 --- a/src/Illuminate/Translation/Translator.php +++ b/src/Illuminate/Translation/Translator.php @@ -345,7 +345,8 @@ protected function handleMissingTranslationKey($key, $replace, $locale, $fallbac // Prevent infinite loops... $this->handleMissingTranslationKeys = false; - $key = call_user_func($this->missingTranslationKeyCallback, + $key = call_user_func( + $this->missingTranslationKeyCallback, $key, $replace, $locale, $fallback );