Add miniPaint as new frontend base
This commit is contained in:
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
$SOURCE_DIRS = [
|
||||
__DIR__ . '/../../index.html',
|
||||
__DIR__ . '/../../src/js/core/',
|
||||
__DIR__ . '/../../src/js/modules/',
|
||||
__DIR__ . '/../../src/js/tools/',
|
||||
__DIR__ . '/../../src/js/config.js',
|
||||
__DIR__ . '/../../src/js/config-menu.js',
|
||||
__DIR__ . '/../../src/js/main.js',
|
||||
__DIR__ . '/../../src/js/libs/popup.js',
|
||||
];
|
||||
|
||||
$LANGUAGES = [
|
||||
'ar',
|
||||
'de',
|
||||
'es',
|
||||
'fr',
|
||||
'it',
|
||||
'ja',
|
||||
'ko',
|
||||
'lt',
|
||||
'pt',
|
||||
'ru',
|
||||
'tr',
|
||||
'zh',
|
||||
'el',
|
||||
'nl',
|
||||
];
|
||||
|
||||
$LANG_DIR = __DIR__ . '/../../src/js/languages/';
|
||||
$LANG_DIR_EMPTY = __DIR__ . '/../../src/js/languages/empty.json'; //leave empty to skip
|
||||
@@ -0,0 +1,90 @@
|
||||
<?php
|
||||
global $LANGUAGES;
|
||||
|
||||
require_once(__DIR__ . '/libs/translator.php');
|
||||
$translator = new Translator();
|
||||
?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-US">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<title>Translator</title>
|
||||
</head>
|
||||
<body>
|
||||
<h3 style="margin: 10px 0;"><a href="">Translator</a></h3>
|
||||
<form action="" method="post">
|
||||
<b>Helpers</b>:
|
||||
<input type="submit" name="action" value="Import" />
|
||||
<input type="submit" name="action" value="Filter" />
|
||||
<input type="submit" name="action" value="Translate manually" />
|
||||
<input type="submit" name="action" value="Merge" />
|
||||
<br /><br />
|
||||
<b>Actions</b>:
|
||||
<input type="submit" name="action" value="Generate empty.json" />
|
||||
<input type="submit" name="action" value="Auto Translate: all" /> or
|
||||
|
||||
<?php
|
||||
foreach ($LANGUAGES as $lang) {
|
||||
echo '<button type="submit" name="action" value="Auto Translate: '.strtolower($lang).'">'.strtoupper($lang).'</button> ';
|
||||
}
|
||||
?>
|
||||
<br /><br />
|
||||
<?php
|
||||
if (count($_POST) > 0) {
|
||||
try {
|
||||
if ($_POST['action'] == 'Import') {
|
||||
$translator->scan();
|
||||
$translator->extract();
|
||||
echo "<pre>"; print_r($translator->strings); echo "</pre>\n";
|
||||
}
|
||||
if ($_POST['action'] == 'Filter') {
|
||||
$translator->scan();
|
||||
$translator->extract();
|
||||
$translator->filter();
|
||||
echo "<pre>"; print_r($translator->strings); echo "</pre>\n";
|
||||
}
|
||||
if ($_POST['action'] == 'Translate manually') {
|
||||
//show form
|
||||
$translator->prepare();
|
||||
|
||||
//translate
|
||||
if (isset($_POST['in'])) {
|
||||
$translation = $_POST['in'];
|
||||
|
||||
$translator->scan();
|
||||
$translator->extract();
|
||||
$translator->filter();
|
||||
$translator->add_translation($translation);
|
||||
$translator->show_merged();
|
||||
}
|
||||
}
|
||||
if ($_POST['action'] == 'Merge') {
|
||||
$translator->merge();
|
||||
}
|
||||
if (stripos($_POST['action'], 'Auto Translate') !== false) {
|
||||
//prepare
|
||||
$translator->scan();
|
||||
$translator->extract();
|
||||
$translator->filter();
|
||||
|
||||
$translator->auto_translate($_POST['action']);
|
||||
}
|
||||
if ($_POST['action'] == 'Generate empty.json') {
|
||||
//prepare
|
||||
$translator->scan();
|
||||
$translator->extract();
|
||||
$translator->filter();
|
||||
|
||||
$translator->save_empty();
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception $exc) {
|
||||
echo '<div style="margin-top:10px;color:red;">ERROR: ' . $exc->getMessage() . '</div>';
|
||||
}
|
||||
}
|
||||
?>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,137 @@
|
||||
<?php
|
||||
/**
|
||||
* PHP GoogleTranslate free
|
||||
* https://github.com/statickidz/php-google-translate-free
|
||||
*/
|
||||
namespace Statickidz;
|
||||
|
||||
/**
|
||||
* GoogleTranslate.class.php
|
||||
*
|
||||
* Class to talk with Google Translator for free.
|
||||
*
|
||||
* @package PHP Google Translate Free;
|
||||
* @category Translation
|
||||
* @author Adrián Barrio Andrés
|
||||
* @author Paris N. Baltazar Salguero <sieg.sb@gmail.com>
|
||||
* @copyright 2016 Adrián Barrio Andrés
|
||||
* @license https://opensource.org/licenses/GPL-3.0 GNU General Public License 3.0
|
||||
* @version 2.0
|
||||
* @link https://statickidz.com/
|
||||
*/
|
||||
|
||||
/**
|
||||
* Main class GoogleTranslate
|
||||
*
|
||||
* @package GoogleTranslate
|
||||
*
|
||||
*/
|
||||
class GoogleTranslate
|
||||
{
|
||||
|
||||
/**
|
||||
* Retrieves the translation of a text
|
||||
*
|
||||
* @param string $source
|
||||
* Original language of the text on notation xx. For example: es, en, it, fr...
|
||||
* @param string $target
|
||||
* Language to which you want to translate the text in format xx. For example: es, en, it, fr...
|
||||
* @param string $text
|
||||
* Text that you want to translate
|
||||
*
|
||||
* @return string a simple string with the translation of the text in the target language
|
||||
*/
|
||||
public static function translate($source, $target, $text)
|
||||
{
|
||||
// Request translation
|
||||
$response = self::requestTranslation($source, $target, $text);
|
||||
|
||||
// Get translation text
|
||||
// $response = self::getStringBetween("onmouseout=\"this.style.backgroundColor='#fff'\">", "</span></div>", strval($response));
|
||||
|
||||
// Clean translation
|
||||
$translation = self::getSentencesFromJSON($response);
|
||||
|
||||
return $translation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal function to make the request to the translator service
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @param string $source
|
||||
* Original language taken from the 'translate' function
|
||||
* @param string $target
|
||||
* Target language taken from the ' translate' function
|
||||
* @param string $text
|
||||
* Text to translate taken from the 'translate' function
|
||||
*
|
||||
* @return object[] The response of the translation service in JSON format
|
||||
*/
|
||||
protected static function requestTranslation($source, $target, $text)
|
||||
{
|
||||
|
||||
// Google translate URL
|
||||
$url = "https://translate.google.com/translate_a/single?client=at&dt=t&dt=ld&dt=qca&dt=rm&dt=bd&dj=1&hl=es-ES&ie=UTF-8&oe=UTF-8&inputm=2&otf=2&iid=1dd3b944-fa62-4b55-b330-74909a99969e";
|
||||
|
||||
$fields = array(
|
||||
'sl' => urlencode($source),
|
||||
'tl' => urlencode($target),
|
||||
'q' => urlencode($text)
|
||||
);
|
||||
|
||||
$max = 9000;
|
||||
if(strlen($fields['q']) >= $max)
|
||||
throw new \Exception("Maximum number of characters exceeded: ".strlen($fields['q'])."/$max");
|
||||
|
||||
// URL-ify the data for the POST
|
||||
$fields_string = "";
|
||||
foreach ($fields as $key => $value) {
|
||||
$fields_string .= $key . '=' . $value . '&';
|
||||
}
|
||||
|
||||
rtrim($fields_string, '&');
|
||||
|
||||
// Open connection
|
||||
$ch = curl_init();
|
||||
|
||||
// Set the url, number of POST vars, POST data
|
||||
curl_setopt($ch, CURLOPT_URL, $url);
|
||||
curl_setopt($ch, CURLOPT_POST, count($fields));
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, $fields_string);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_ENCODING, 'UTF-8');
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
|
||||
curl_setopt($ch, CURLOPT_USERAGENT, 'AndroidTranslate/5.3.0.RC02.130475354-53000263 5.1 phone TRANSLATE_OPM5_TEST_1');
|
||||
|
||||
// Execute post
|
||||
$result = curl_exec($ch);
|
||||
|
||||
// Close connection
|
||||
curl_close($ch);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dump of the JSON's response in an array
|
||||
*
|
||||
* @param string $json
|
||||
* The JSON object returned by the request function
|
||||
*
|
||||
* @return string A single string with the translation
|
||||
*/
|
||||
protected static function getSentencesFromJSON($json)
|
||||
{
|
||||
$sentencesArray = json_decode($json, true);
|
||||
$sentences = "";
|
||||
|
||||
foreach ($sentencesArray["sentences"] as $s) {
|
||||
$sentences .= isset($s["trans"]) ? $s["trans"] : '';
|
||||
}
|
||||
|
||||
return $sentences;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,416 @@
|
||||
<?php
|
||||
|
||||
require_once(__DIR__ . '/../config.php');
|
||||
require_once(__DIR__ . '/GoogleTranslate.php');
|
||||
|
||||
use \Statickidz\GoogleTranslate;
|
||||
|
||||
/**
|
||||
* translator scans javascript, html files, extracts strings and generate translation with json format.
|
||||
*/
|
||||
class Translator {
|
||||
|
||||
public $files;
|
||||
public $strings;
|
||||
public $translations;
|
||||
|
||||
/**
|
||||
* scan external resources
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function scan() {
|
||||
global $SOURCE_DIRS;
|
||||
if (count($SOURCE_DIRS) == 0)
|
||||
throw new Exception('empty settings: $SOURCE_DIRS');
|
||||
|
||||
foreach ($SOURCE_DIRS as $dir) {
|
||||
if (strpos($dir, '\\') !== false) {
|
||||
//windows url
|
||||
$dir = str_replace('/', '\\', $dir);
|
||||
}
|
||||
$dir = realpath($dir);
|
||||
|
||||
if (is_dir($dir)) {
|
||||
//directory
|
||||
$rii = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir));
|
||||
foreach ($rii as $file) {
|
||||
if ($file->isDir()) {
|
||||
continue;
|
||||
}
|
||||
$this->files[] = $file->getPathname();
|
||||
}
|
||||
}
|
||||
else if (is_file($dir)) {
|
||||
$this->files[] = $dir;
|
||||
}
|
||||
else {
|
||||
throw new Exception('can not import object: ' . $dir);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* extracts strings from files
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function extract() {
|
||||
$this->strings = array();
|
||||
foreach ($this->files as $file) {
|
||||
$content = file_get_contents($file);
|
||||
if ($content == '')
|
||||
throw new Exception('can not get file content: ' . $content);
|
||||
|
||||
$strings = array();
|
||||
|
||||
//drop svg
|
||||
$content = preg_replace('|<path.*/>|i', '', $content);
|
||||
|
||||
//drop exceptions
|
||||
$content = preg_replace('|\/\/no-translate BEGIN[\s\S]+?\/\/no-translate END|mi', '', $content);
|
||||
|
||||
//drop
|
||||
$content = stripslashes($content);
|
||||
|
||||
if (stripos($file, '.js') !== false) {
|
||||
//json
|
||||
|
||||
$ignore_matches = [
|
||||
'\.addEventListener',
|
||||
'\.style\.',
|
||||
'aria-label',
|
||||
'\.font',
|
||||
'Path2D\(',
|
||||
];
|
||||
foreach ($ignore_matches as $ignore_match) {
|
||||
$content = preg_replace('/' . $ignore_match . '.*/', '', $content);
|
||||
}
|
||||
|
||||
$content = preg_replace('|[\r\n][ \t]*//.*|', "\n", $content);
|
||||
|
||||
//extract between ' '
|
||||
$out = array();
|
||||
preg_match_all("/[']([^']*)[']/", $content, $out);
|
||||
$strings = array_merge($strings, $out[1]);
|
||||
|
||||
//extract between " "
|
||||
$out = array();
|
||||
preg_match_all('/["]([^"]*)["]/', $content, $out);
|
||||
$strings = array_merge($strings, $out[1]);
|
||||
}
|
||||
if (stripos($file, '.htm') !== false || true) {
|
||||
//html
|
||||
$ignore_attributes = [
|
||||
'dir',
|
||||
'lang',
|
||||
'http-equiv',
|
||||
'content',
|
||||
'name',
|
||||
'rel',
|
||||
'style',
|
||||
'onclick',
|
||||
'type',
|
||||
'class',
|
||||
'id',
|
||||
'href',
|
||||
'onchange',
|
||||
'onKeyUp',
|
||||
'oninput',
|
||||
'src',
|
||||
'aria-label',
|
||||
];
|
||||
foreach ($ignore_attributes as $ignore_attribute) {
|
||||
$content = preg_replace('/' . $ignore_attribute . '="[^"]*"/', '', $content);
|
||||
}
|
||||
|
||||
//extract between " "
|
||||
$out = array();
|
||||
preg_match_all('/["]([^"]*)["]/', $content, $out);
|
||||
//$strings = array_merge($strings, $out[1]);
|
||||
//extract between > <
|
||||
$out = array();
|
||||
preg_match_all('|>([^<]{1,200})<[^ ]|', $content, $out);
|
||||
$strings = array_merge($strings, $out[1]);
|
||||
}
|
||||
|
||||
foreach ($strings as $string) {
|
||||
if (trim($string) == '' || substr($string, 0, 2) == './')
|
||||
continue;
|
||||
|
||||
//remove tags
|
||||
$string = preg_replace('/<[^>]*>/', ' ', $string);
|
||||
$string = trim($string);
|
||||
|
||||
$this->strings[] = $string;
|
||||
}
|
||||
}
|
||||
|
||||
$this->strings = array_unique($this->strings);
|
||||
sort($this->strings);
|
||||
}
|
||||
|
||||
/**
|
||||
* filters out some strings
|
||||
*/
|
||||
public function filter() {
|
||||
$copy = $this->strings;
|
||||
$this->strings = array();
|
||||
foreach ($copy as $string) {
|
||||
$string = trim($string);
|
||||
if (is_numeric($string)) {
|
||||
//number
|
||||
continue;
|
||||
}
|
||||
if (strlen($string) < 2) {
|
||||
//too short
|
||||
continue;
|
||||
}
|
||||
if (preg_replace("/[^A-Z0-9]+/", "", $string[0]) == '') {
|
||||
//first letter must be common uppercase letter or number
|
||||
continue;
|
||||
}
|
||||
if (is_numeric($string[0]) && strpos($string, ' ') === false) {
|
||||
//if first letter is number - try to skip some
|
||||
continue;
|
||||
}
|
||||
if (strpos($string, '(') !== false && strpos($string, ')') !== false && strpos($string, '.') !== false) {
|
||||
//function, not string
|
||||
continue;
|
||||
}
|
||||
if (strpos($string, "\n") !== false || strpos($string, "\r") !== false) {
|
||||
//multi-line
|
||||
continue;
|
||||
}
|
||||
if (preg_replace("/[^a-z]+/", "", $string) == '') {
|
||||
//all caps - not translatable
|
||||
continue;
|
||||
}
|
||||
if (strlen($string) > 30 && strpos($string, " ") === false) {
|
||||
//long word without spaces
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->strings[] = $string;
|
||||
}
|
||||
$this->strings = array_unique($this->strings);
|
||||
$this->strings = array_values($this->strings);
|
||||
}
|
||||
|
||||
/**
|
||||
* prepare strings for translating for user
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function prepare() {
|
||||
$this->scan();
|
||||
$this->extract();
|
||||
$this->filter();
|
||||
|
||||
$data = $this->strings;
|
||||
|
||||
$in_content = '';
|
||||
if (isset($_POST['in']))
|
||||
$in_content = $_POST['in'];
|
||||
|
||||
echo '<textarea name="out" style="width:100%;height:25vh;">' . implode("\n", $data) . '</textarea><br /><br />';
|
||||
echo 'Translate text above with <a href="https://translate.google.com/">translator</a> and paste result below:<br /><br />';
|
||||
echo '<textarea name="in" style="width:100%;height:25vh;">' . $in_content . '</textarea><br />';
|
||||
echo '<input type="submit" name="action" value="Translate manually" />';
|
||||
}
|
||||
|
||||
/**
|
||||
* combines source strings and manually translated strings to json format
|
||||
*
|
||||
* @param string $translation
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function add_translation($translation) {
|
||||
$translation = trim($translation);
|
||||
if ($translation != '')
|
||||
$translation = explode("\n", $translation);
|
||||
else
|
||||
$translation = array();
|
||||
|
||||
if (count($this->strings) == 0)
|
||||
throw new Exception('0 translations found in files.');
|
||||
if (count($this->strings) != count($translation))
|
||||
throw new Exception(count($this->strings) . ' translations imported from file, but you provided ' . count($translation) . ', it must match');
|
||||
|
||||
$this->translations = new stdClass();
|
||||
foreach ($this->strings as $key => $value) {
|
||||
$translated = trim($translation[$key]);
|
||||
|
||||
$this->translations->$value = $translated;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* translates everything automatically
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function auto_translate($action_string) {
|
||||
global $LANGUAGES, $LANG_DIR;
|
||||
|
||||
$action_string = str_replace('Auto Translate: ', '', $action_string);
|
||||
if($action_string == 'all'){
|
||||
$action_string = '';
|
||||
}
|
||||
|
||||
$service = new GoogleTranslate();
|
||||
$text = implode("\n", $this->strings);
|
||||
|
||||
foreach ($LANGUAGES as $lang) {
|
||||
if($action_string != '' && $action_string != $lang){
|
||||
continue;
|
||||
}
|
||||
|
||||
echo "<br />$lang: ";
|
||||
|
||||
$file_path = $LANG_DIR . strtolower($lang) . ".json";
|
||||
|
||||
//read old translations
|
||||
$old = array();
|
||||
if (file_exists($file_path)) {
|
||||
$old = file_get_contents($file_path);
|
||||
if ($old === false)
|
||||
throw new Exception('can not open file: ' . $file_path);
|
||||
$old = json_decode($old);
|
||||
if ($old === null)
|
||||
throw new Exception($file_path . ' data is not json');
|
||||
}
|
||||
|
||||
$translation = $service->translate('en', $lang, $text);
|
||||
if ($translation == '') {
|
||||
throw new Exception('empty response from translation service');
|
||||
}
|
||||
$translation = str_replace("\r", '', $translation);
|
||||
$translation = explode("\n", $translation);
|
||||
if (count($this->strings) != count($translation)) {
|
||||
throw new Exception(count($this->strings) . ' translations imported from file, but service gave: ' . count($translation) . ', it must match');
|
||||
}
|
||||
|
||||
//generate array
|
||||
$this->translations = new stdClass();
|
||||
foreach ($this->strings as $key => $value) {
|
||||
$translated = trim($translation[$key]);
|
||||
|
||||
$this->translations->$value = $translated;
|
||||
}
|
||||
|
||||
//merge
|
||||
$merged = (object) array_merge((array) $this->translations, (array) $old);
|
||||
|
||||
//remove not use elements
|
||||
foreach ($merged as $k => $v) {
|
||||
if (isset($this->translations->$k) == false) {
|
||||
$v = null;
|
||||
unset($merged->$k);
|
||||
}
|
||||
}
|
||||
$this->translations = $merged;
|
||||
|
||||
//generate JSON
|
||||
$html = json_encode($this->translations, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
|
||||
|
||||
//save
|
||||
$written = file_put_contents($file_path, $html);
|
||||
if ($written == 0) {
|
||||
throw new Exception('can not write to: ' . $file_path);
|
||||
}
|
||||
else {
|
||||
echo 'OK';
|
||||
}
|
||||
|
||||
//sleep 05-1s
|
||||
usleep(rand(500, 1000) * 1000);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* saves current data as empty file
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function save_empty() {
|
||||
global $LANG_DIR_EMPTY;
|
||||
|
||||
if ($LANG_DIR_EMPTY == '')
|
||||
return;
|
||||
|
||||
$data = new stdClass();
|
||||
foreach($this->strings as $value){
|
||||
$data->$value = '';
|
||||
}
|
||||
|
||||
$data_encoded = json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
|
||||
|
||||
$written = file_put_contents($LANG_DIR_EMPTY, $data_encoded);
|
||||
if ($written == 0) {
|
||||
throw new Exception('can not write to: ' . $LANG_DIR_EMPTY);
|
||||
}
|
||||
else {
|
||||
echo '<p><b>File updated: <b>' . $LANG_DIR_EMPTY . '</b></p>';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* show formatted translation, use json. parameters are only for testing mode
|
||||
*/
|
||||
public function show_merged() {
|
||||
echo '<textarea style="width:100%;height:30vh;margin-top:10px;">';
|
||||
echo json_encode($this->translations, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
|
||||
echo '</textarea>';
|
||||
}
|
||||
|
||||
/**
|
||||
* merge two translations
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function merge() {
|
||||
echo 'Old translations: <b>(priority on same keys)</b><br />';
|
||||
$value = '';
|
||||
if (isset($_POST['merge_old']))
|
||||
$value = $_POST['merge_old'];
|
||||
echo '<textarea style="width:100%;height:20vh;" name="merge_old">' . $value . '</textarea>';
|
||||
|
||||
echo '<br /><br />';
|
||||
|
||||
echo 'New translations:<br />';
|
||||
$value = '';
|
||||
if (isset($_POST['merge_new']))
|
||||
$value = $_POST['merge_new'];
|
||||
echo '<textarea style="width:100%;height:20vh;" name="merge_new">' . $value . '</textarea>';
|
||||
echo '<input type="submit" name="action" value="Merge" /><br /><br />';
|
||||
|
||||
if (isset($_POST['merge_old']) == false)
|
||||
return;
|
||||
|
||||
$old = json_decode($_POST['merge_old']);
|
||||
$new = json_decode($_POST['merge_new']);
|
||||
|
||||
if ($old === null)
|
||||
throw new Exception('Old data is not json');
|
||||
if ($new === null)
|
||||
throw new Exception('New data is not json');
|
||||
|
||||
//merge
|
||||
$merged = (object) array_merge((array) $new, (array) $old);
|
||||
|
||||
//remove not use elements
|
||||
foreach ($merged as $k => $v) {
|
||||
if (isset($new->$k) == false) {
|
||||
$v = null;
|
||||
unset($merged->$k);
|
||||
}
|
||||
}
|
||||
|
||||
echo '<textarea style="width:100%;height:30vh;">';
|
||||
echo json_encode($merged, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
|
||||
echo '</textarea>';
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user