downgrade to kirby v3
This commit is contained in:
@@ -4,8 +4,6 @@ namespace Kirby\Cms;
|
||||
|
||||
use Kirby\Data\Data;
|
||||
use Kirby\Exception\Exception;
|
||||
use Kirby\Exception\InvalidArgumentException;
|
||||
use Kirby\Exception\LogicException;
|
||||
use Kirby\Exception\PermissionException;
|
||||
use Kirby\Filesystem\F;
|
||||
use Kirby\Toolkit\Locale;
|
||||
@@ -28,54 +26,80 @@ use Throwable;
|
||||
* @copyright Bastian Allgeier
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
class Language
|
||||
class Language extends Model
|
||||
{
|
||||
use HasSiblings;
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $code;
|
||||
|
||||
/**
|
||||
* The parent Kirby instance
|
||||
* @var bool
|
||||
*/
|
||||
public static App|null $kirby;
|
||||
protected $default;
|
||||
|
||||
protected string $code;
|
||||
protected bool $default;
|
||||
protected string $direction;
|
||||
protected array $locale;
|
||||
protected string $name;
|
||||
protected array $slugs;
|
||||
protected array $smartypants;
|
||||
protected array $translations;
|
||||
protected string|null $url;
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $direction;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $locale;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $name;
|
||||
|
||||
/**
|
||||
* @var array|null
|
||||
*/
|
||||
protected $slugs;
|
||||
|
||||
/**
|
||||
* @var array|null
|
||||
*/
|
||||
protected $smartypants;
|
||||
|
||||
/**
|
||||
* @var array|null
|
||||
*/
|
||||
protected $translations;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $url;
|
||||
|
||||
/**
|
||||
* Creates a new language object
|
||||
*
|
||||
* @param array $props
|
||||
*/
|
||||
public function __construct(array $props)
|
||||
{
|
||||
if (isset($props['code']) === false) {
|
||||
throw new InvalidArgumentException('The property "code" is required');
|
||||
}
|
||||
$this->setRequiredProperties($props, [
|
||||
'code'
|
||||
]);
|
||||
|
||||
static::$kirby = $props['kirby'] ?? null;
|
||||
$this->code = trim($props['code']);
|
||||
$this->default = ($props['default'] ?? false) === true;
|
||||
$this->direction = ($props['direction'] ?? null) === 'rtl' ? 'rtl' : 'ltr';
|
||||
$this->name = trim($props['name'] ?? $this->code);
|
||||
$this->slugs = $props['slugs'] ?? [];
|
||||
$this->smartypants = $props['smartypants'] ?? [];
|
||||
$this->translations = $props['translations'] ?? [];
|
||||
$this->url = $props['url'] ?? null;
|
||||
|
||||
if ($locale = $props['locale'] ?? null) {
|
||||
$this->locale = Locale::normalize($locale);
|
||||
} else {
|
||||
$this->locale = [LC_ALL => $this->code];
|
||||
}
|
||||
$this->setOptionalProperties($props, [
|
||||
'default',
|
||||
'direction',
|
||||
'locale',
|
||||
'name',
|
||||
'slugs',
|
||||
'smartypants',
|
||||
'translations',
|
||||
'url',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Improved `var_dump` output
|
||||
* @codeCoverageIgnore
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function __debugInfo(): array
|
||||
{
|
||||
@@ -85,6 +109,8 @@ class Language
|
||||
/**
|
||||
* Returns the language code
|
||||
* when the language is converted to a string
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __toString(): string
|
||||
{
|
||||
@@ -94,6 +120,8 @@ class Language
|
||||
/**
|
||||
* Returns the base Url for the language
|
||||
* without the path or other cruft
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function baseUrl(): string
|
||||
{
|
||||
@@ -111,29 +139,12 @@ class Language
|
||||
return Url::base($languageUrl) ?? $kirbyUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance with the same
|
||||
* initial properties.
|
||||
*/
|
||||
public function clone(array $props = []): static
|
||||
{
|
||||
return new static(array_replace_recursive([
|
||||
'code' => $this->code,
|
||||
'default' => $this->default,
|
||||
'direction' => $this->direction,
|
||||
'locale' => $this->locale,
|
||||
'name' => $this->name,
|
||||
'slugs' => $this->slugs,
|
||||
'smartypants' => $this->smartypants,
|
||||
'translations' => $this->translations,
|
||||
'url' => $this->url,
|
||||
], $props));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the language code/id.
|
||||
* The language code is used in
|
||||
* text file names as appendix.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function code(): string
|
||||
{
|
||||
@@ -141,10 +152,54 @@ class Language
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new language object
|
||||
* @internal
|
||||
* Internal converter to create or remove
|
||||
* translation files.
|
||||
*
|
||||
* @param string $from
|
||||
* @param string $to
|
||||
* @return bool
|
||||
*/
|
||||
public static function create(array $props): static
|
||||
protected static function converter(string $from, string $to): bool
|
||||
{
|
||||
$kirby = App::instance();
|
||||
$site = $kirby->site();
|
||||
|
||||
// convert site
|
||||
foreach ($site->files() as $file) {
|
||||
F::move($file->contentFile($from, true), $file->contentFile($to, true));
|
||||
}
|
||||
|
||||
F::move($site->contentFile($from, true), $site->contentFile($to, true));
|
||||
|
||||
// convert all pages
|
||||
foreach ($kirby->site()->index(true) as $page) {
|
||||
foreach ($page->files() as $file) {
|
||||
F::move($file->contentFile($from, true), $file->contentFile($to, true));
|
||||
}
|
||||
|
||||
F::move($page->contentFile($from, true), $page->contentFile($to, true));
|
||||
}
|
||||
|
||||
// convert all users
|
||||
foreach ($kirby->users() as $user) {
|
||||
foreach ($user->files() as $file) {
|
||||
F::move($file->contentFile($from, true), $file->contentFile($to, true));
|
||||
}
|
||||
|
||||
F::move($user->contentFile($from, true), $user->contentFile($to, true));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new language object
|
||||
*
|
||||
* @internal
|
||||
* @param array $props
|
||||
* @return static
|
||||
*/
|
||||
public static function create(array $props)
|
||||
{
|
||||
$kirby = App::instance();
|
||||
$user = $kirby->user();
|
||||
@@ -157,6 +212,7 @@ class Language
|
||||
}
|
||||
|
||||
$props['code'] = Str::slug($props['code'] ?? null);
|
||||
$kirby = App::instance();
|
||||
$languages = $kirby->languages();
|
||||
|
||||
// make the first language the default language
|
||||
@@ -166,40 +222,17 @@ class Language
|
||||
|
||||
$language = new static($props);
|
||||
|
||||
// trigger before hook
|
||||
$kirby->trigger(
|
||||
'language.create:before',
|
||||
[
|
||||
'input' => $props,
|
||||
'language' => $language
|
||||
]
|
||||
);
|
||||
|
||||
// validate the new language
|
||||
LanguageRules::create($language);
|
||||
|
||||
$language->save();
|
||||
|
||||
if ($languages->count() === 0) {
|
||||
foreach ($kirby->models() as $model) {
|
||||
$model->storage()->convertLanguage(
|
||||
'default',
|
||||
$language->code()
|
||||
);
|
||||
}
|
||||
static::converter('', $language->code());
|
||||
}
|
||||
|
||||
// update the main languages collection in the app instance
|
||||
$kirby->languages(false)->append($language->code(), $language);
|
||||
|
||||
// trigger after hook
|
||||
$kirby->trigger(
|
||||
'language.create:after',
|
||||
[
|
||||
'input' => $props,
|
||||
'language' => $language
|
||||
]
|
||||
);
|
||||
App::instance()->languages(false)->append($language->code(), $language);
|
||||
|
||||
return $language;
|
||||
}
|
||||
@@ -207,15 +240,18 @@ class Language
|
||||
/**
|
||||
* Delete the current language and
|
||||
* all its translation files
|
||||
* @internal
|
||||
*
|
||||
* @internal
|
||||
* @return bool
|
||||
* @throws \Kirby\Exception\Exception
|
||||
*/
|
||||
public function delete(): bool
|
||||
{
|
||||
$kirby = App::instance();
|
||||
$user = $kirby->user();
|
||||
$code = $this->code();
|
||||
$kirby = App::instance();
|
||||
$user = $kirby->user();
|
||||
$languages = $kirby->languages();
|
||||
$code = $this->code();
|
||||
$isLast = $languages->count() === 1;
|
||||
|
||||
if (
|
||||
$user === null ||
|
||||
@@ -224,40 +260,59 @@ class Language
|
||||
throw new PermissionException(['key' => 'language.delete.permission']);
|
||||
}
|
||||
|
||||
if ($this->isDeletable() === false) {
|
||||
throw new Exception('The language cannot be deleted');
|
||||
}
|
||||
|
||||
// trigger before hook
|
||||
$kirby->trigger('language.delete:before', [
|
||||
'language' => $this
|
||||
]);
|
||||
|
||||
if (F::remove($this->root()) !== true) {
|
||||
throw new Exception('The language could not be deleted');
|
||||
}
|
||||
|
||||
foreach ($kirby->models() as $model) {
|
||||
if ($this->isLast() === true) {
|
||||
$model->storage()->convertLanguage($code, 'default');
|
||||
} else {
|
||||
$model->storage()->deleteLanguage($code);
|
||||
}
|
||||
if ($isLast === true) {
|
||||
$this->converter($code, '');
|
||||
} else {
|
||||
$this->deleteContentFiles($code);
|
||||
}
|
||||
|
||||
// get the original language collection and remove the current language
|
||||
$kirby->languages(false)->remove($code);
|
||||
|
||||
// trigger after hook
|
||||
$kirby->trigger('language.delete:after', [
|
||||
'language' => $this
|
||||
]);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* When the language is deleted, all content files with
|
||||
* the language code must be removed as well.
|
||||
*
|
||||
* @param mixed $code
|
||||
* @return bool
|
||||
*/
|
||||
protected function deleteContentFiles($code): bool
|
||||
{
|
||||
$kirby = App::instance();
|
||||
$site = $kirby->site();
|
||||
|
||||
F::remove($site->contentFile($code, true));
|
||||
|
||||
foreach ($kirby->site()->index(true) as $page) {
|
||||
foreach ($page->files() as $file) {
|
||||
F::remove($file->contentFile($code, true));
|
||||
}
|
||||
|
||||
F::remove($page->contentFile($code, true));
|
||||
}
|
||||
|
||||
foreach ($kirby->users() as $user) {
|
||||
foreach ($user->files() as $file) {
|
||||
F::remove($file->contentFile($code, true));
|
||||
}
|
||||
|
||||
F::remove($user->contentFile($code, true));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reading direction of this language
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function direction(): string
|
||||
{
|
||||
@@ -266,6 +321,8 @@ class Language
|
||||
|
||||
/**
|
||||
* Check if the language file exists
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function exists(): bool
|
||||
{
|
||||
@@ -275,54 +332,31 @@ class Language
|
||||
/**
|
||||
* Checks if this is the default language
|
||||
* for the site.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isDefault(): bool
|
||||
{
|
||||
return $this->default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the language can be deleted
|
||||
*/
|
||||
public function isDeletable(): bool
|
||||
{
|
||||
// the default language can only be deleted if it's the last
|
||||
if ($this->isDefault() === true && $this->isLast() === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this is the last language
|
||||
*/
|
||||
public function isLast(): bool
|
||||
{
|
||||
return App::instance()->languages()->count() === 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* The id is required for collections
|
||||
* to work properly. The code is used as id
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function id(): string
|
||||
{
|
||||
return $this->code;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the parent Kirby instance
|
||||
*/
|
||||
public function kirby(): App
|
||||
{
|
||||
return static::$kirby ??= App::instance();
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the language rules for provided locale code
|
||||
*
|
||||
* @param string $code
|
||||
*/
|
||||
public static function loadRules(string $code): array
|
||||
public static function loadRules(string $code)
|
||||
{
|
||||
$kirby = App::instance();
|
||||
$code = Str::contains($code, '.') ? Str::before($code, '.') : $code;
|
||||
@@ -334,7 +368,7 @@ class Language
|
||||
|
||||
try {
|
||||
return Data::read($file);
|
||||
} catch (\Exception) {
|
||||
} catch (\Exception $e) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -343,19 +377,22 @@ class Language
|
||||
* Returns the PHP locale setting array
|
||||
*
|
||||
* @param int $category If passed, returns the locale for the specified category (e.g. LC_ALL) as string
|
||||
* @return array|string
|
||||
*/
|
||||
public function locale(int $category = null): array|string|null
|
||||
public function locale(int $category = null)
|
||||
{
|
||||
if ($category !== null) {
|
||||
return $this->locale[$category] ?? $this->locale[LC_ALL] ?? null;
|
||||
} else {
|
||||
return $this->locale;
|
||||
}
|
||||
|
||||
return $this->locale;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the human-readable name
|
||||
* of the language
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function name(): string
|
||||
{
|
||||
@@ -364,6 +401,8 @@ class Language
|
||||
|
||||
/**
|
||||
* Returns the URL path for the language
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function path(): string
|
||||
{
|
||||
@@ -376,6 +415,8 @@ class Language
|
||||
|
||||
/**
|
||||
* Returns the routing pattern for the language
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function pattern(): string
|
||||
{
|
||||
@@ -390,6 +431,8 @@ class Language
|
||||
|
||||
/**
|
||||
* Returns the absolute path to the language file
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function root(): string
|
||||
{
|
||||
@@ -400,15 +443,19 @@ class Language
|
||||
* Returns the LanguageRouter instance
|
||||
* which is used to handle language specific
|
||||
* routes.
|
||||
*
|
||||
* @return \Kirby\Cms\LanguageRouter
|
||||
*/
|
||||
public function router(): LanguageRouter
|
||||
public function router()
|
||||
{
|
||||
return new LanguageRouter($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get slug rules for language
|
||||
*
|
||||
* @internal
|
||||
* @return array
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
@@ -419,15 +466,15 @@ class Language
|
||||
|
||||
/**
|
||||
* Saves the language settings in the languages folder
|
||||
* @internal
|
||||
*
|
||||
* @internal
|
||||
* @return $this
|
||||
*/
|
||||
public function save(): static
|
||||
public function save()
|
||||
{
|
||||
try {
|
||||
$existingData = Data::read($this->root());
|
||||
} catch (Throwable) {
|
||||
} catch (Throwable $e) {
|
||||
$existingData = [];
|
||||
}
|
||||
|
||||
@@ -451,15 +498,104 @@ class Language
|
||||
}
|
||||
|
||||
/**
|
||||
* Private siblings collector
|
||||
* @param string $code
|
||||
* @return $this
|
||||
*/
|
||||
protected function siblingsCollection(): Collection
|
||||
protected function setCode(string $code)
|
||||
{
|
||||
return App::instance()->languages();
|
||||
$this->code = trim($code);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $default
|
||||
* @return $this
|
||||
*/
|
||||
protected function setDefault(bool $default = false)
|
||||
{
|
||||
$this->default = $default;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $direction
|
||||
* @return $this
|
||||
*/
|
||||
protected function setDirection(string $direction = 'ltr')
|
||||
{
|
||||
$this->direction = $direction === 'rtl' ? 'rtl' : 'ltr';
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|array $locale
|
||||
* @return $this
|
||||
*/
|
||||
protected function setLocale($locale = null)
|
||||
{
|
||||
if ($locale === null) {
|
||||
$this->locale = [LC_ALL => $this->code];
|
||||
} else {
|
||||
$this->locale = Locale::normalize($locale);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @return $this
|
||||
*/
|
||||
protected function setName(string $name = null)
|
||||
{
|
||||
$this->name = trim($name ?? $this->code);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $slugs
|
||||
* @return $this
|
||||
*/
|
||||
protected function setSlugs(array $slugs = null)
|
||||
{
|
||||
$this->slugs = $slugs ?? [];
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $smartypants
|
||||
* @return $this
|
||||
*/
|
||||
protected function setSmartypants(array $smartypants = null)
|
||||
{
|
||||
$this->smartypants = $smartypants ?? [];
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $translations
|
||||
* @return $this
|
||||
*/
|
||||
protected function setTranslations(array $translations = null)
|
||||
{
|
||||
$this->translations = $translations ?? [];
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $url
|
||||
* @return $this
|
||||
*/
|
||||
protected function setUrl(string $url = null)
|
||||
{
|
||||
$this->url = $url;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the custom slug rules for this language
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function slugs(): array
|
||||
{
|
||||
@@ -468,6 +604,8 @@ class Language
|
||||
|
||||
/**
|
||||
* Returns the custom SmartyPants options for this language
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function smartypants(): array
|
||||
{
|
||||
@@ -477,6 +615,8 @@ class Language
|
||||
/**
|
||||
* Returns the most important
|
||||
* properties as array
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function toArray(): array
|
||||
{
|
||||
@@ -493,6 +633,8 @@ class Language
|
||||
|
||||
/**
|
||||
* Returns the translation strings for this language
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function translations(): array
|
||||
{
|
||||
@@ -501,19 +643,28 @@ class Language
|
||||
|
||||
/**
|
||||
* Returns the absolute Url for the language
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function url(): string
|
||||
{
|
||||
$url = $this->url;
|
||||
$url ??= '/' . $this->code;
|
||||
$url = $this->url;
|
||||
|
||||
if ($url === null) {
|
||||
$url = '/' . $this->code;
|
||||
}
|
||||
|
||||
return Url::makeAbsolute($url, $this->kirby()->url());
|
||||
}
|
||||
|
||||
/**
|
||||
* Update language properties and save them
|
||||
*
|
||||
* @internal
|
||||
* @param array $props
|
||||
* @return static
|
||||
*/
|
||||
public function update(array $props = null): static
|
||||
public function update(array $props = null)
|
||||
{
|
||||
$kirby = App::instance();
|
||||
$user = $kirby->user();
|
||||
@@ -533,67 +684,38 @@ class Language
|
||||
|
||||
$updated = $this->clone($props);
|
||||
|
||||
if (isset($props['translations']) === true) {
|
||||
$updated->translations = $props['translations'];
|
||||
}
|
||||
|
||||
// validate the updated language
|
||||
LanguageRules::update($updated);
|
||||
|
||||
// trigger before hook
|
||||
$kirby->trigger('language.update:before', [
|
||||
'language' => $this,
|
||||
'input' => $props
|
||||
]);
|
||||
|
||||
// if language just got promoted to be the new default language…
|
||||
if ($this->isDefault() === false && $updated->isDefault() === true) {
|
||||
// convert the current default to a non-default language
|
||||
$previous = $kirby->defaultLanguage()?->clone(['default' => false])->save();
|
||||
$kirby->languages(false)->set($previous->code(), $previous);
|
||||
|
||||
foreach ($kirby->models() as $model) {
|
||||
$model->storage()->touchLanguage($this);
|
||||
// convert the current default to a non-default language
|
||||
if ($updated->isDefault() === true) {
|
||||
if ($oldDefault = $kirby->defaultLanguage()) {
|
||||
$oldDefault->clone(['default' => false])->save();
|
||||
}
|
||||
}
|
||||
|
||||
// if language was the default language and got demoted…
|
||||
if (
|
||||
$this->isDefault() === true &&
|
||||
$updated->isDefault() === false &&
|
||||
$kirby->defaultLanguage()->code() === $this->code()
|
||||
) {
|
||||
// ensure another language has already been set as default
|
||||
throw new LogicException('Please select another language to be the primary language');
|
||||
$code = $this->code();
|
||||
$site = $kirby->site();
|
||||
|
||||
touch($site->contentFile($code));
|
||||
|
||||
foreach ($kirby->site()->index(true) as $page) {
|
||||
$files = $page->files();
|
||||
|
||||
foreach ($files as $file) {
|
||||
touch($file->contentFile($code));
|
||||
}
|
||||
|
||||
touch($page->contentFile($code));
|
||||
}
|
||||
} elseif ($this->isDefault() === true) {
|
||||
throw new PermissionException('Please select another language to be the primary language');
|
||||
}
|
||||
|
||||
$language = $updated->save();
|
||||
|
||||
// make sure the language is also updated in the languages collection
|
||||
$kirby->languages(false)->set($language->code(), $language);
|
||||
|
||||
// trigger after hook
|
||||
$kirby->trigger('language.update:after', [
|
||||
'newLanguage' => $language,
|
||||
'oldLanguage' => $this,
|
||||
'input' => $props
|
||||
]);
|
||||
// make sure the language is also updated in the Kirby language collection
|
||||
App::instance()->languages(false)->set($language->code(), $language);
|
||||
|
||||
return $language;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a language variable object
|
||||
* for the key in the translations array
|
||||
*/
|
||||
public function variable(string $key, bool $decode = false): LanguageVariable
|
||||
{
|
||||
// allows decoding if base64-url encoded url is sent
|
||||
// for compatibility of different environments
|
||||
if ($decode === true) {
|
||||
$key = rawurldecode(base64_decode($key));
|
||||
}
|
||||
|
||||
return new LanguageVariable($this, $key);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user