1
0
Fork 0
mirror of https://github.com/archtechx/gloss.git synced 2025-12-12 19:24:03 +00:00

Initial commit

This commit is contained in:
Samuel Štancl 2020-12-13 03:05:55 +01:00
commit f73d6e2dce
14 changed files with 838 additions and 0 deletions

40
src/Gloss.php Normal file
View file

@ -0,0 +1,40 @@
<?php
declare(strict_types=1);
namespace Lean\Gloss;
use Illuminate\Support\Facades\Facade;
/**
* 🔍 Gloss Brilliant localization for Laravel.
*
* @method static void key(string $shortKey, string $newKey) Set a key override.
* @method static void value(string $shortKey, string $value) Set a value override.
* @method static void values(string $shortKey, string $value) Set multiple value overrides.
* @method static ?string get($key, $replace = [], $locale = null) Get a translation string.
* @method static ?string choice($key, $replace = [], $locale = null) Get a translation according to an integer value.
* @method static void extend(string $shortKey, callable(string, callable): string $value) Extend a translation string.
*/
class Gloss extends Facade
{
/**
* The key used to bind Gloss to the service container.
*/
public static string $containerKey = 'gloss';
/**
* Should ___() be used as a helper?
*/
public static bool $underscoreHelper = true;
/**
* Should the Translator instance be replaced by Gloss?
*/
public static bool $shouldReplaceTranslator = false;
protected static function getFacadeAccessor()
{
return static::$containerKey;
}
}

View file

@ -0,0 +1,33 @@
<?php
declare(strict_types=1);
namespace Lean\Gloss;
use Illuminate\Contracts\Container\Container;
use Illuminate\Support\ServiceProvider;
class GlossServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->singleton(Gloss::$containerKey, function ($app) {
$loader = $app['translation.loader'];
// When registering the translator component, we'll need to set the default
// locale as well as the fallback locale. So, we'll grab the application
// configuration so we can easily get both of these values from there.
$locale = $app['config']['app.locale'];
$trans = new GlossTranslator($loader, $locale);
$trans->setFallback($app['config']['app.fallback_locale']);
return $trans;
});
if (Gloss::$shouldReplaceTranslator) {
$this->app->extend('translator', fn () => $this->app->make(Gloss::$containerKey));
}
}
}

155
src/GlossTranslator.php Normal file
View file

@ -0,0 +1,155 @@
<?php
declare(strict_types=1);
namespace Lean\Gloss;
use Countable;
use Illuminate\Translation\Translator;
class GlossTranslator extends Translator
{
/** Overrides that refer to a different key. */
public array $keyOverrides = [];
/** Overrides with new values. */
public array $valueOverrides = [];
/** Extensions executed after the string is built. */
public array $extensions = [];
/**
* Register an override that returns a different key name.
*
* @param string $shortKey
* @param string $newKey
* @return void
*/
public function key(string $shortKey, string $newKey)
{
$this->keyOverrides[$shortKey] = $newKey;
}
/**
* Register an override that returns a value.
*
* @param string $shortKey
* @param string $value
* @return void
*/
public function value(string $shortKey, string $value)
{
$this->valueOverrides[$shortKey] = $value;
}
/**
* Register multiple value overrides.
*
* @param array $values
* @return void
*/
public function values(array $values)
{
foreach ($values as $key => $value) {
$this->valueOverrides[$key] = $value;
}
}
/**
* Customize a translation string's value using a callback.
*
* @param string $shortKey
* @param callable $value
* @return void
*/
public function extend(string $shortKey, callable $value)
{
$this->extensions[$shortKey][] = $value;
}
public function get($key, array $replace = [], $locale = null, $fallback = true)
{
if (array_key_exists($key, $this->extensions)) {
// We recursively call the same method, but we make sure to skip this branch.
$stringWithoutReplacedVariables = $this->getWithoutExtensions($key, [], $locale, $fallback);
$replacer = function (string $string, array $replacements) {
foreach ($replacements as $from => $to) {
$string = str_replace($from, $to, $string);
}
return $string;
};
// We run all of the extend() callbacks
$extendedString = $key;
foreach ($this->extensions[$key] as $extension) {
$extendedString = $extension($stringWithoutReplacedVariables, $replacer);
}
// Finally, we run the string through trans() once again
// to do the replacements in Laravel and potentially
// catch edge case overrides for values in Gloss.
$key = $extendedString;
}
return $this->getWithoutExtensions($key, $replace, $locale, $fallback);
}
protected function getWithoutExtensions($key, $replace = [], $locale = null, $fallback = true)
{
return array_key_exists($key, $this->keyOverrides)
? $this->get($this->keyOverrides[$key])
: $this->valueOverrides[$key]
?? parent::get($key, $replace, $locale, $fallback);
}
public function choice($key, $number, array $replace = [], $locale = null)
{
if (array_key_exists($key, $this->extensions)) {
// We recursively call the same method, but we make sure to skip this branch.
$stringWithoutReplacedVariables = $this->getWithoutExtensions($key, [], $locale);
$replacer = function (string $string, array $replacements) {
foreach ($replacements as $from => $to) {
$string = str_replace($from, $to, $string);
}
return $string;
};
// We run all of the extend() callbacks
$extendedString = $key;
foreach ($this->extensions[$key] as $extension) {
$extendedString = $extension($stringWithoutReplacedVariables, $replacer);
}
// Finally, we run the string through trans() once again
// to do the replacements in Laravel and potentially
// catch edge case overrides for values in Gloss.
$key = $extendedString;
}
return $this->choiceWithoutExtensions($key, $number, $replace, $locale);
}
protected function choiceWithoutExtensions($key, $number, array $replace = [], $locale = null)
{
$line = $this->getWithoutExtensions(
$key, $replace, $locale = $this->localeForChoice($locale)
);
// If the given "number" is actually an array or countable we will simply count the
// number of elements in an instance. This allows developers to pass an array of
// items without having to count it on their end first which gives bad syntax.
if (is_array($number) || $number instanceof Countable) {
$number = count($number);
}
$replace['count'] = $number;
return $this->makeReplacements(
$this->getSelector()->choose($line, $number, $locale), $replace
);
}
}

45
src/helpers.php Normal file
View file

@ -0,0 +1,45 @@
<?php
declare(strict_types=1);
use Lean\Gloss\Gloss;
if (! function_exists('gloss')) {
/**
* Resolve a translation string or Gloss instance.
*
* @param string|array|null $key
* @param array $replace
* @param string|null $locale
* @return void|string|null|\Lean\Gloss\GlossTranslator
*/
function gloss($key = null, array $replace = [], string $locale = null)
{
if (is_array($key)) {
Gloss::values($key);
return;
}
if (is_string($key)) {
return Gloss::get($key, $replace, $locale);
}
return Gloss::getFacadeRoot();
}
}
if (! function_exists('___') && Gloss::$underscoreHelper) {
/**
* Resolve a translation string or Gloss instance.
*
* @param string|array|null $key
* @param array $replace
* @param string|null $locale
* @return void|string|null|\Lean\Gloss\GlossTranslator
*/
function ___($key = null, array $replace = [], string $locale = null)
{
return gloss($key, $replace, $locale);
}
}