- First working version of Tell
- JsonReader and PhpReader added
This commit is contained in:
parent
a58efcdef4
commit
026126be76
175
src/I18n.php
175
src/I18n.php
|
@ -2,105 +2,144 @@
|
||||||
|
|
||||||
namespace Tell;
|
namespace Tell;
|
||||||
|
|
||||||
class I18n
|
class I18n implements MissingKeyInterface
|
||||||
{
|
{
|
||||||
const DELIMITER = '.';
|
const DELIMITER = '.';
|
||||||
|
|
||||||
protected bool $updatedData = false;
|
protected string $locale = "en_US";
|
||||||
|
|
||||||
protected array $data = [];
|
protected string $language = "";
|
||||||
|
|
||||||
protected array $cache = [];
|
protected array $data = [];
|
||||||
|
|
||||||
protected array $engine = [];
|
|
||||||
|
|
||||||
protected string $currentLanguage = "";
|
|
||||||
|
|
||||||
protected array $fileStack = [];
|
protected array $fileStack = [];
|
||||||
|
|
||||||
protected function __construct(bool $enableCache = false) {
|
protected string $currentLanguage = "";
|
||||||
|
|
||||||
# $this->persistent = new Persistent(static::class);
|
protected Reader\ReaderInterface $dataReader;
|
||||||
if ( $enableCache ) {
|
|
||||||
# $data = $this->persistent->load();
|
protected ? Reader\ReaderInterface $cacheReader = null;
|
||||||
# $this->data = $data['data'];
|
|
||||||
# $this->fileStack = $data['fileStack'];
|
protected ? MissingKeyInterface $missingKey = null;
|
||||||
}
|
|
||||||
|
public function __construct(
|
||||||
|
Reader\ReaderInterface $dataReader,
|
||||||
|
? Reader\ReaderInterface $cacheReader = null,
|
||||||
|
? MissingKeyInterface $missingKey = null
|
||||||
|
)
|
||||||
|
{
|
||||||
|
$this->dataReader = $dataReader;
|
||||||
|
$this->cacheReader = $cacheReader;
|
||||||
|
$this->missingKey = $missingKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __destruct() {
|
public function initialize(bool $useCache) : bool
|
||||||
# $this->update_data() && $this->persistent->save([
|
{
|
||||||
# 'fileStack' => $this->fileStack,
|
$loaded = $useCache && $this->fromReader($this->cacheReader) ?: $this->fromReader($this->dataReader);
|
||||||
# 'data' => $this->data
|
|
||||||
# ]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function updateData() {
|
if ( ! $useCache ) {
|
||||||
return $this->updatedData;
|
$this->cacheReader->save($this->locale, $this->data);
|
||||||
}
|
|
||||||
|
|
||||||
public static function get(?string $key = null) {
|
|
||||||
if ( $key === null ) {
|
|
||||||
return $this->data;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return isset( $this->cache[$key] ) ? $this->cache[$key] : $this->cache[$key] = Iterate::arrayGet($this->data, ( $this->currentLanguage ? $this->currentLanguage."." : "").$key, static::DELIMITER);
|
return $loaded;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function set(string $key, $value) {
|
public function fromKey(string $key, array $variables) : ?string
|
||||||
|
{
|
||||||
|
if ( null === ( $string = $this->get($key) ) ) {
|
||||||
|
$string = $this->missingKey ? $this->missingKey->get($key) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_array($string)) {
|
||||||
|
$string = json_encode($string);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $string && $variables ? $this->placeVariables($string, $variables) : $string;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function get(string $key)
|
||||||
|
{
|
||||||
|
# Testing full locale key first
|
||||||
|
if ( null === ( $string = Iterate::arrayGet($this->data, "{$this->locale}.$key", static::DELIMITER)) ) {
|
||||||
|
# Fallback on language only
|
||||||
|
$string = Iterate::arrayGet($this->data, "{$this->language}.$key", static::DELIMITER);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $string;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function set(string $key, $value)
|
||||||
|
{
|
||||||
$cache = explode(static::DELIMITER, $key);
|
$cache = explode(static::DELIMITER, $key);
|
||||||
|
|
||||||
while ( !empty($cache) ) {
|
while ( ! empty($cache) ) {
|
||||||
$imp = implode(static::DELIMITER, $cache);
|
$imp = implode(static::DELIMITER, $cache);
|
||||||
array_pop($cache);
|
array_pop($cache);
|
||||||
unset( $this->cache[$imp] );
|
unset( $this->cache[$imp] );
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->cache[$key] = $value ;
|
$this->cache[$key] = $value;
|
||||||
|
|
||||||
return Iterate::arraySet($this->data, $key, $value, static::DELIMITER);
|
return Iterate::arraySet($this->data, $key, $value, static::DELIMITER);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function addEngine($engine) {
|
public function locale(?string $set = null)
|
||||||
$this->engine[] = $engine;
|
{
|
||||||
}
|
$locale = $set === null ? ( $this->locale ?? null ) : $this->locale = strtolower(explode(".", $this->locale)[0]);
|
||||||
|
|
||||||
public function load(string $path, bool $filenameAsKey = false) {
|
if ( $set !== null ) {
|
||||||
if ( !in_array($path, $this->fileStack) ) {
|
$this->language = explode('_', $locale)[0];
|
||||||
$this->updatedData = true;
|
|
||||||
$this->fileStack[] = $path;
|
|
||||||
|
|
||||||
foreach(Iterate::files($path) as $item) {
|
|
||||||
foreach($this->engine as $engine) {
|
|
||||||
if ( $engine->accept($item )) {
|
|
||||||
|
|
||||||
if ( $array = $engine->translate( $item ) ){
|
|
||||||
if ($filenameAsKey ) {
|
|
||||||
$base = basename($item);
|
|
||||||
|
|
||||||
$key = substr($base,0, strrpos($base, "."));
|
|
||||||
$keysplit = explode(".", $key);
|
|
||||||
$key = array_pop($keysplit);
|
|
||||||
|
|
||||||
$this->mergeData([ $keysplit ? "{".implode(".", array_merge([ $key ], $keysplit))."}" : $key => $array ]);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$this->mergeData($array);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
continue 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return $locale;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function currentLanguage($set = null) {
|
protected function mergeData($data) : void
|
||||||
return $set === null ? $this->currentLanguage : $this->currentLanguage = $set;
|
{
|
||||||
}
|
|
||||||
|
|
||||||
protected function mergeData($data) {
|
|
||||||
$this->data = array_replace_recursive($this->data, Iterate::splitKeys($data));
|
$this->data = array_replace_recursive($this->data, Iterate::splitKeys($data));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function fromReader(Reader\ReaderInterface $reader) : bool
|
||||||
|
{
|
||||||
|
foreach($reader->pathList as $path) {
|
||||||
|
foreach(Iterate::files($path) as $item) {
|
||||||
|
if ( $reader->accept($item->getExtension() )) {
|
||||||
|
if ( null !== ( $data = $reader->load( $item ) )) {
|
||||||
|
|
||||||
|
if ( $reader->filenameAsKey ) {
|
||||||
|
# Adding folder to full key
|
||||||
|
$filekey = ltrim(substr($item->getPathname(), strlen($path)), DIRECTORY_SEPARATOR);
|
||||||
|
|
||||||
|
# Removing extension
|
||||||
|
$filekey = substr($filekey, 0, strrpos($filekey, '.'));
|
||||||
|
|
||||||
|
# Replacing directory separator with dots
|
||||||
|
$filekey = str_replace(DIRECTORY_SEPARATOR, '.', $filekey);
|
||||||
|
|
||||||
|
$this->mergeData([ '{' . $filekey . '}' => $data ]);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$this->mergeData($data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function placeVariables(string $string, array $parameters) {
|
||||||
|
if ( preg_match_all('~{$(.*?)}~si', $string, $matches, PREG_SET_ORDER) ) {
|
||||||
|
$search = [];
|
||||||
|
|
||||||
|
foreach($matches as $item) {
|
||||||
|
$search[ $item[0] ] = Iterate::arrayGet($parameters, $item[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return str_replace(array_keys($search), array_values($search), $string);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $string;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,9 +3,7 @@
|
||||||
namespace Tell;
|
namespace Tell;
|
||||||
|
|
||||||
use RecursiveDirectoryIterator,
|
use RecursiveDirectoryIterator,
|
||||||
RecursiveIteratorIterator,
|
RecursiveIteratorIterator;
|
||||||
RecursiveRegexIterator,
|
|
||||||
RegexIterator;
|
|
||||||
|
|
||||||
class Iterate
|
class Iterate
|
||||||
{
|
{
|
||||||
|
@ -15,7 +13,7 @@ class Iterate
|
||||||
* @param string $path - path like 'person.name.first'
|
* @param string $path - path like 'person.name.first'
|
||||||
* @param string $value - value to set
|
* @param string $value - value to set
|
||||||
*/
|
*/
|
||||||
public static function arraySet(array &$array, string $path, string $value = '', string $delimiter = '.') {
|
public static function arraySet(?array &$array, string $path, $value, string $delimiter = '.') {
|
||||||
$pathArr = explode($delimiter, $path);
|
$pathArr = explode($delimiter, $path);
|
||||||
|
|
||||||
// Go to next node
|
// Go to next node
|
||||||
|
@ -28,6 +26,29 @@ class Iterate
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function arrayKeysSet($key_list, &$array, $value, $append = false) {
|
||||||
|
$current_key = array_shift($key_list);
|
||||||
|
|
||||||
|
if ($key_list) {
|
||||||
|
return static::arrayKeysSet($key_list, $array[$current_key], $value, $append);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if ( $append && isset($array[$current_key]) ) {
|
||||||
|
if (is_array($array[$current_key])) {
|
||||||
|
return $array[$current_key] = array_merge_recursive($value, $array[$current_key]); #: array_replace_recursive($value, $array[$current_key]);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return $array[$current_key] = $array[$current_key] . $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return $array[$current_key] = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public static function arrayGet(array $array, string $path, string $delimiter = '.') {
|
public static function arrayGet(array $array, string $path, string $delimiter = '.') {
|
||||||
$pathArr = explode($delimiter, $path);
|
$pathArr = explode($delimiter, $path);
|
||||||
|
|
||||||
|
@ -65,8 +86,7 @@ class Iterate
|
||||||
$tmp = [];
|
$tmp = [];
|
||||||
$keylist = explode($delimiter, $key);
|
$keylist = explode($delimiter, $key);
|
||||||
$finalKey = array_shift($keylist);
|
$finalKey = array_shift($keylist);
|
||||||
# Arrayobj::iterate_set($keylist, $tmp, $value);
|
static::arrayKeysSet($keylist, $tmp, $value);
|
||||||
static::arraySet($tmp, $key, $value);
|
|
||||||
$swap[$finalKey] = static::splitKeys($tmp, $delimiter);
|
$swap[$finalKey] = static::splitKeys($tmp, $delimiter);
|
||||||
|
|
||||||
unset($array[isset($oldKey) ? $oldKey : $key]);
|
unset($array[isset($oldKey) ? $oldKey : $key]);
|
||||||
|
@ -90,28 +110,22 @@ class Iterate
|
||||||
return $array;
|
return $array;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function files(string $path, string $fileExtension = "") {
|
public static function files(string $path, string $fileExtension = "") : \Generator
|
||||||
$retval = [];
|
{
|
||||||
|
|
||||||
if ( \file_exists($path) ) {
|
if ( \file_exists($path) ) {
|
||||||
$iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::SKIP_DOTS), RecursiveIteratorIterator::SELF_FIRST, RecursiveIteratorIterator::CATCH_GET_CHILD);
|
$iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::SKIP_DOTS), RecursiveIteratorIterator::SELF_FIRST, RecursiveIteratorIterator::CATCH_GET_CHILD);
|
||||||
|
|
||||||
if ($fileExtension) {
|
|
||||||
$iterator = new RegexIterator($iterator, '/^.+\.'.$fileExtension.'$/i', RecursiveRegexIterator::GET_MATCH);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($iterator as $file) {
|
foreach ($iterator as $file) {
|
||||||
if ($fileExtension) {
|
if ( $file->isFile() || $file->isDir() ) {
|
||||||
$retval[] = $file[0];
|
if ($fileExtension && ( $file->getExtension() === $fileExtension )) {
|
||||||
}
|
yield $file;
|
||||||
else {
|
}
|
||||||
if ( $file->isFile() || $file->isDir() ) {
|
else {
|
||||||
$retval[] = $file->getRealPath();
|
yield $file;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return $retval;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
<?php declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace Tell;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description of MissingKeyInterface
|
||||||
|
*
|
||||||
|
* @author mcnd
|
||||||
|
*/
|
||||||
|
interface MissingKeyInterface {
|
||||||
|
|
||||||
|
public function get(string $key);
|
||||||
|
|
||||||
|
public function set(string $key, $value);
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Tell;
|
||||||
|
|
||||||
|
class PrintMissingKey implements MissingKeyInterface {
|
||||||
|
|
||||||
|
public function get(string $key) {
|
||||||
|
return $key;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function set(string $key, $value) { }
|
||||||
|
}
|
|
@ -0,0 +1,52 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Tell\Reader;
|
||||||
|
|
||||||
|
class JsonReader implements ReaderInterface {
|
||||||
|
|
||||||
|
protected string $name = "json";
|
||||||
|
|
||||||
|
protected array $accept = [ "json" ];
|
||||||
|
|
||||||
|
protected int $saveFlag = 0;
|
||||||
|
|
||||||
|
public array $pathList;
|
||||||
|
|
||||||
|
public bool $filenameAsKey = false;
|
||||||
|
|
||||||
|
public function __construct(array $pathList, bool $filenameAsKey = false, int $saveFlag = \JSON_PRETTY_PRINT)
|
||||||
|
{
|
||||||
|
$this->pathList = $pathList;
|
||||||
|
$this->filenameAsKey = $filenameAsKey;
|
||||||
|
$this->saveFlag = $saveFlag;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function accept(string $extension) : bool
|
||||||
|
{
|
||||||
|
return in_array($extension, $this->accept);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function load(string $filepath) : ?array
|
||||||
|
{
|
||||||
|
if ( ! file_exists($filepath) ) {
|
||||||
|
throw new \Exception("Given file path is not existing or is inaccessible.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( null === ( $content = json_decode(file_get_contents($filepath), true) ) ) {
|
||||||
|
throw new \Exception("An error occured trying to parse configuration file: given json file [ $filepath ] seems to be invalid");
|
||||||
|
}
|
||||||
|
|
||||||
|
return $content;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function save(string $filepath, array $content) : bool
|
||||||
|
{
|
||||||
|
$path = $this->pathList[0];
|
||||||
|
|
||||||
|
if ( !file_exists($path) ) {
|
||||||
|
mkdir($path, 0750, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ( file_put_contents($path . DIRECTORY_SEPARATOR . "$filepath." . $this->accept[0], json_encode($content, $this->saveFlag)) !== false );
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Tell\Reader;
|
||||||
|
|
||||||
|
class PhpReader implements ReaderInterface {
|
||||||
|
|
||||||
|
protected string $name = "php";
|
||||||
|
|
||||||
|
protected array $accept = [ "php" ];
|
||||||
|
|
||||||
|
public array $pathList = [];
|
||||||
|
|
||||||
|
public bool $filenameAsKey;
|
||||||
|
|
||||||
|
public function __construct(array $pathList, bool $filenameAsKey = false)
|
||||||
|
{
|
||||||
|
$this->pathList = $pathList;
|
||||||
|
$this->filenameAsKey = $filenameAsKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function accept(string $extension) : bool
|
||||||
|
{
|
||||||
|
return in_array($extension, $this->accept);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function load(string $filepath) : ?array
|
||||||
|
{
|
||||||
|
if ( ! file_exists($filepath) ) {
|
||||||
|
throw new \Exception("Given file path is not existing or is inaccessible.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( null === ( $content = include($filepath) ?? false ) ) {
|
||||||
|
throw new \Exception("An error occured trying to parse configuration file: given php file [ $filepath ] seems to be invalid");
|
||||||
|
}
|
||||||
|
|
||||||
|
return $content;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function save(string $filepath, array $content) : bool
|
||||||
|
{
|
||||||
|
$path = $this->pathList[0];
|
||||||
|
return (bool) file_put_contents($path . DIRECTORY_SEPARATOR . "$filepath." . $this->accept[0], "return " . var_export($content, true) . ";");
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Tell\Reader;
|
||||||
|
|
||||||
|
interface ReaderInterface {
|
||||||
|
|
||||||
|
public function load(string $filepath) : ?array;
|
||||||
|
|
||||||
|
public function save(string $filepath, array $content): bool;
|
||||||
|
|
||||||
|
public function accept(string $extension) : bool;
|
||||||
|
}
|
Loading…
Reference in New Issue