mirror of
https://github.com/Lastorder-DC/rhymix.git
synced 2026-01-03 08:41:39 +09:00
417 lines
8.7 KiB
PHP
417 lines
8.7 KiB
PHP
<?php
|
|
|
|
namespace Rhymix\Framework;
|
|
|
|
/**
|
|
* The language class.
|
|
*/
|
|
class Lang
|
|
{
|
|
/**
|
|
* Instances are stored here.
|
|
*/
|
|
protected static $_instances = array();
|
|
|
|
/**
|
|
* Configuration.
|
|
*/
|
|
protected $_language;
|
|
protected $_loaded_directories = array();
|
|
protected $_loaded_plugins = array();
|
|
protected $_search_priority = array();
|
|
|
|
/**
|
|
* This method returns the cached instance of a language.
|
|
*
|
|
* @param string $language
|
|
* @return self
|
|
*/
|
|
public static function getInstance(string $language): self
|
|
{
|
|
if ($language === 'jp')
|
|
{
|
|
$language = 'ja';
|
|
}
|
|
if (!isset(self::$_instances[$language]))
|
|
{
|
|
self::$_instances[$language] = new self($language);
|
|
}
|
|
return self::$_instances[$language];
|
|
}
|
|
|
|
/**
|
|
* The constructor should not be called from outside.
|
|
*
|
|
* @param string $language
|
|
*/
|
|
protected function __construct(string $language)
|
|
{
|
|
$this->_language = preg_replace('/[^a-z0-9_-]/i', '', $language);
|
|
$this->_loaded_plugins['_custom_'] = new \stdClass();
|
|
}
|
|
|
|
/**
|
|
* Return language type.
|
|
*
|
|
* @return string
|
|
*/
|
|
public function langType(): string
|
|
{
|
|
return $this->_language;
|
|
}
|
|
|
|
/**
|
|
* Load translations from a plugin (module, addon).
|
|
*
|
|
* @param string $name
|
|
* @return bool
|
|
*/
|
|
public function loadPlugin(string $name): bool
|
|
{
|
|
if (isset($this->_loaded_plugins[$name]))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if ($name === 'common')
|
|
{
|
|
$this->loadDirectory(\RX_BASEDIR . 'common/lang', 'common');
|
|
}
|
|
elseif (file_exists(\RX_BASEDIR . "modules/$name/lang"))
|
|
{
|
|
$this->loadDirectory(\RX_BASEDIR . "modules/$name/lang", $name);
|
|
}
|
|
elseif (file_exists(\RX_BASEDIR . "plugins/$name/lang"))
|
|
{
|
|
$this->loadDirectory(\RX_BASEDIR . "plugins/$name/lang", $name);
|
|
}
|
|
elseif (file_exists(\RX_BASEDIR . "addons/$name/lang"))
|
|
{
|
|
$this->loadDirectory(\RX_BASEDIR . "addons/$name/lang", $name);
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Load translations from a directory.
|
|
*
|
|
* @param string $dir
|
|
* @param string $plugin_name
|
|
* @return bool
|
|
*/
|
|
public function loadDirectory(string $dir, ?string $plugin_name = null): bool
|
|
{
|
|
// Do not load the same directory twice.
|
|
$dir = rtrim($dir, '/');
|
|
$plugin_name = $plugin_name ?: $dir;
|
|
if (isset($this->_loaded_directories[$dir]) || isset($this->_loaded_plugins[$plugin_name]))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
// Initialize variables.
|
|
$filename = null;
|
|
$lang = new \stdClass;
|
|
$result = true;
|
|
|
|
// Find a suitable language file in the given directory.
|
|
if (file_exists($dir . '/' . $this->_language . '.php'))
|
|
{
|
|
$filename = $dir . '/' . $this->_language . '.php';
|
|
}
|
|
elseif (($hyphen = strpos($this->_language, '-')) !== false && file_exists($dir . '/' . substr($this->_language, 0, $hyphen) . '.php'))
|
|
{
|
|
$filename = $dir . '/' . substr($this->_language, 0, $hyphen) . '.php';
|
|
}
|
|
elseif (file_exists("$dir/lang.xml"))
|
|
{
|
|
$filename = Parsers\LangParser::compileXMLtoPHP("$dir/lang.xml", $this->_language === 'ja' ? 'jp' : $this->_language);
|
|
}
|
|
elseif (file_exists($dir . '/' . ($this->_language === 'ja' ? 'jp' : $this->_language) . '.lang.php'))
|
|
{
|
|
$filename = $dir . '/' . ($this->_language === 'ja' ? 'jp' : $this->_language) . '.lang.php';
|
|
}
|
|
|
|
// Load the language file.
|
|
if ($filename)
|
|
{
|
|
include $filename;
|
|
array_unshift($this->_search_priority, $plugin_name);
|
|
$result = true;
|
|
}
|
|
else
|
|
{
|
|
$result = false;
|
|
}
|
|
|
|
// Mark this directory and plugin as loaded.
|
|
$this->_loaded_directories[$dir] = true;
|
|
$this->_loaded_plugins[$plugin_name] = $lang;
|
|
|
|
// Load the same directory in the default language, too.
|
|
if ($this->_language !== 'en')
|
|
{
|
|
self::getInstance('en')->loadDirectory($dir, $plugin_name);
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* Get the list of supported languages.
|
|
*
|
|
* @return array
|
|
*/
|
|
public static function getSupportedList(): array
|
|
{
|
|
static $list = null;
|
|
if ($list === null)
|
|
{
|
|
$list = (include \RX_BASEDIR . 'common/defaults/locales.php');
|
|
}
|
|
return $list;
|
|
}
|
|
|
|
/**
|
|
* Generic getter.
|
|
*
|
|
* @param string $key
|
|
* @return string|\ArrayObject
|
|
*/
|
|
public function get(string $key)
|
|
{
|
|
$args = func_get_args();
|
|
array_shift($args);
|
|
if (count($args) === 1 && is_array($args[0]))
|
|
{
|
|
$args = $args[0];
|
|
}
|
|
|
|
// Get the translation.
|
|
$translation = $this->__get($key);
|
|
|
|
// If there are no arguments, return the translation.
|
|
if (!count($args)) return $translation;
|
|
|
|
// If there are arguments, interpolate them into the translation and return the result.
|
|
return vsprintf($translation, $args);
|
|
}
|
|
|
|
/**
|
|
* Generic setter.
|
|
*
|
|
* @param string $key
|
|
* @param mixed $value
|
|
* @return void
|
|
*/
|
|
public function set(string $key, $value): void
|
|
{
|
|
$this->__set($key, $value);
|
|
}
|
|
|
|
/**
|
|
* Fallback method for getting the default translation.
|
|
*
|
|
* @param string $key
|
|
* @return string|\ArrayObject
|
|
*/
|
|
public function getFromDefaultLang(string $key)
|
|
{
|
|
if ($this->_language === 'en')
|
|
{
|
|
return $key;
|
|
}
|
|
else
|
|
{
|
|
return self::getInstance('en')->__get($key);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Magic method for translations without arguments.
|
|
*
|
|
* @param string $key
|
|
* @return string|\ArrayObject
|
|
*/
|
|
public function __get(string $key)
|
|
{
|
|
// Load a dot-separated key (prefixed by plugin name).
|
|
if (preg_match('/^[a-z0-9_.-]+$/i', $key) && ($keys = explode('.', $key)) && count($keys) >= 2)
|
|
{
|
|
// Attempt to load the plugin.
|
|
$plugin_name = array_shift($keys);
|
|
if (!isset($this->_loaded_plugins[$plugin_name]))
|
|
{
|
|
$this->loadPlugin($plugin_name);
|
|
}
|
|
if (!isset($this->_loaded_plugins[$plugin_name]))
|
|
{
|
|
return $this->getFromDefaultLang($key);
|
|
}
|
|
|
|
// Find the given key.
|
|
$lang = $this->_loaded_plugins[$plugin_name];
|
|
foreach ($keys as $subkey)
|
|
{
|
|
if (is_object($lang) && isset($lang->{$subkey}))
|
|
{
|
|
$lang = $lang->{$subkey};
|
|
}
|
|
elseif (is_array($lang) && isset($lang[$subkey]))
|
|
{
|
|
$lang = $lang[$subkey];
|
|
}
|
|
else
|
|
{
|
|
return $this->getFromDefaultLang($key);
|
|
}
|
|
}
|
|
return is_array($lang) ? new \ArrayObject($lang, 3) : $lang;
|
|
}
|
|
|
|
// Search custom translations first.
|
|
if (isset($this->_loaded_plugins['_custom_']->{$key}))
|
|
{
|
|
$lang = $this->_loaded_plugins['_custom_']->{$key};
|
|
return is_array($lang) ? new \ArrayObject($lang, 3) : $lang;
|
|
}
|
|
|
|
// Search other plugins.
|
|
foreach ($this->_search_priority as $plugin_name)
|
|
{
|
|
if (isset($this->_loaded_plugins[$plugin_name]->{$key}))
|
|
{
|
|
$lang = $this->_loaded_plugins[$plugin_name]->{$key};
|
|
return is_array($lang) ? new \ArrayObject($lang, 3) : $lang;
|
|
}
|
|
}
|
|
|
|
// If no translation is found, return the default language.
|
|
return $this->getFromDefaultLang($key);
|
|
}
|
|
|
|
/**
|
|
* Magic method for setting a new custom translation.
|
|
*
|
|
* @param string $key
|
|
* @param mixed $value
|
|
* @return void
|
|
*/
|
|
public function __set(string $key, $value): void
|
|
{
|
|
// Set a dot-separated key (prefixed by plugin name).
|
|
if (preg_match('/^[a-z0-9_.-]+$/i', $key) && ($keys = explode('.', $key)) && count($keys) >= 2)
|
|
{
|
|
// Attempt to load the plugin.
|
|
$plugin_name = array_shift($keys);
|
|
if (!isset($this->_loaded_plugins[$plugin_name]))
|
|
{
|
|
$this->loadPlugin($plugin_name);
|
|
}
|
|
if (!isset($this->_loaded_plugins[$plugin_name]))
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Set the given key.
|
|
$count = count($keys);
|
|
$lang = $this->_loaded_plugins[$plugin_name];
|
|
foreach ($keys as $i => $subkey)
|
|
{
|
|
if (is_object($lang) && isset($lang->{$subkey}))
|
|
{
|
|
if ($i === $count - 1)
|
|
{
|
|
$lang->{$subkey} = $value;
|
|
break;
|
|
}
|
|
elseif (is_array($lang->{$subkey}))
|
|
{
|
|
$lang = &$lang->{$subkey};
|
|
}
|
|
else
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
elseif (is_array($lang) && isset($lang[$subkey]))
|
|
{
|
|
if ($i === $count - 1)
|
|
{
|
|
$lang[$subkey] = $value;
|
|
break;
|
|
}
|
|
elseif (is_array($lang[$subkey]))
|
|
{
|
|
$lang = &$lang[$subkey];
|
|
}
|
|
else
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (is_object($lang))
|
|
{
|
|
$lang->{$subkey} = $value;
|
|
}
|
|
else
|
|
{
|
|
$lang[$subkey] = $value;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Set a regular key.
|
|
$this->_loaded_plugins['_custom_']->{$key} = $value;
|
|
}
|
|
|
|
/**
|
|
* Magic method for checking whether a translation exists.
|
|
*
|
|
* @param string $key
|
|
* @return bool
|
|
*/
|
|
public function __isset(string $key): bool
|
|
{
|
|
foreach ($this->_loaded_plugins as $plugin_name => $translations)
|
|
{
|
|
if (isset($translations->{$key}))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Magic method for unsetting a translation.
|
|
*
|
|
* @param string $key
|
|
* @return void
|
|
*/
|
|
public function __unset(string $key): void
|
|
{
|
|
$this->set($key, null);
|
|
}
|
|
|
|
/**
|
|
* Magic method for translations with arguments.
|
|
*
|
|
* @param string $key
|
|
* @param mixed $args
|
|
* @return mixed
|
|
*/
|
|
public function __call(string $key, $args = array())
|
|
{
|
|
return $this->get($key, $args);
|
|
}
|
|
}
|