Plugin Directory

Changeset 3475723


Ignore:
Timestamp:
03/05/2026 02:35:35 PM (4 weeks ago)
Author:
autoglot
Message:

Improved translation of inline JSON arrays

Location:
autoglot
Files:
66 added
7 edited

Legend:

Unmodified
Added
Removed
  • autoglot/trunk/admin/autoglot_admin.php

    r3471673 r3475723  
    15321532                ),
    15331533                array(
     1534                    'uid' => 'autoglot_translation_force_selfclosing',
     1535                    'label' => __('Force slash in self-closing tags', 'autoglot'),
     1536                    'section' => 'section_adv_out',
     1537                    'page' => 'autoglot_translation_advanced',
     1538                    'helper' => '',
     1539                    'supplemental' => __('Some local PHP setups may omit closing slashes in self-closing tags such as <meta ... />. This option forces adding a slash to these tags.', 'autoglot'),
     1540                    'type' => 'radio',
     1541                    'options' => array(
     1542                        '1' => __('Add slash to self-closing tags', 'autoglot'),
     1543                        '0' => __('Do not add slash', 'autoglot'),
     1544                    ),
     1545                    'default' => array(AUTOGLOT_DEFAULT_FORCE_SELFCLOSING),
     1546                    'sanitize_callback' => array($this, 'sanitize_radio'),
     1547                ),
     1548                array(
    15341549                    'uid' => 'autoglot_translation_widget_signature',
    15351550                    'label' => __('Show Widget Signature', 'autoglot'),
  • autoglot/trunk/autoglot.php

    r3471673 r3475723  
    44Plugin URI: https://autoglot.com/download/
    55Description: Fully automatic SEO-friendly plugin for multilingual WordPress translation. Translate your website and boost your traffic in minutes! No coding, no subscription, no recurring payments, no hurdles!
    6 Version: 2.10.8
     6Version: 2.10.9
    77Text Domain: autoglot
    88Author: Autoglot WordPress Team
     
    838838
    839839            $arraycontent = $this->dom->HTML2Array($buffer);//mb_convert_encoding($buffer, 'HTML-ENTITIES', 'UTF-8'));
    840 //            return nl2br(htmlspecialchars(print_r($arraycontent, true)));
    841840
    842841            $arraycontent = array_merge($this->orgcontent, $arraycontent);
    843842           
    844843            $arraytranslated = $this->translate_content($arraycontent, $this->langURL, "content", get_the_ID());
    845 //debug echo nl2br(htmlspecialchars(print_r($arraytranslated, true)));
    846844
    847845            $this->page_links_translated = $this->translate_urls($this->page_links, $this->langURL);                       
     
    850848//if($_GET["debug"] == "original") return nl2br(htmlspecialchars(print_r($arraycontent,true)));
    851849//elseif($_GET["debug"] == "translated") return nl2br(htmlspecialchars(print_r($arraytranslated,true)));
     850//elseif($_GET["debug"] == "urls") return nl2br(htmlspecialchars(print_r($this->page_links,true)));
     851//elseif($_GET["debug"] == "turls") return nl2br(htmlspecialchars(print_r($this->page_links_translated,true)));
    852852//debug echo htmlspecialchars($html);
    853853
     
    867867            if(isset($this->options->replace_text) && @count($this->options->replace_text)) $buffer_translated = strtr($buffer_translated, $this->options->replace_text);
    868868
    869             return $buffer_translated/*.print_r($this->page_links_translated,true)."<br /><br />".print_r($this->page_links,true)*/;
     869            //return $buffer_translated/*.print_r($this->page_links_translated,true)."<br /><br />".print_r($this->page_links,true)*/;
     870            return $buffer_translated;
    870871        }
    871872       
  • autoglot/trunk/readme.txt

    r3471673 r3475723  
    55Tested up to: 6.9
    66Requires PHP: 7.0
    7 Stable tag: 2.10.8
     7Stable tag: 2.10.9
    88License: GPLv2 or later
    99License URI: https://www.gnu.org/licenses/gpl-2.0.html
     
    408408== Upgrade Notice ==
    409409
     410= 2.10.9 =
     411Improved translation of inline JSON arrays
     412
    410413= 2.10.8 =
    411414Improved URL translation
     
    458461
    459462== Changelog ==
     463
     464= 2.10.9 (05/03/2026) =
     465* Improved translation of common keys in inline JSON arrays such as "name", "message", "description"
     466* Autoglot now updates URLs inside inline JSON arrays for keys such as "url"
     467* Small modification: Autoglot no longer escapes slashes in output JSON arrays
     468* Added an option to format HTML and force adding closing slashes to self-closing tags such as "br" or "meta"
    460469
    461470= 2.10.8 (28/02/2026) =
  • autoglot/trunk/utils/autoglot_constants.php

    r3471673 r3475723  
    174174       
    175175    /**
    176      * Default callbacks for processing JSON objects
     176     * Default callbacks for processing JSON+AJAX objects
    177177     * Used by process_json_callbacks function
    178178     */
     
    183183        'url' => 'update_url',
    184184    );
     185
     186    /**
     187     * Default keys for translating inline JS+JSON objects
     188     */
     189    const JSON_KEYS_TRANSLATE = array('name', 'html', 'content', 'message', 'description', 'caption');
     190
     191    /**
     192     * Default keys for URLs in inline JS+JSON objects
     193     */
     194    const JSON_KEYS_URL = array('url', 'urlTemplate');
    185195       
    186196    const ADMIN_ALLOWED_TAGS = array(
     
    223233                /*"ul", "li", */"g",
    224234                "style", "script"
    225                 );
     235            );
    226236
    227237    const SKIP_TAGS = array("style", "script"
    228                 );
     238            );
     239               
     240    const SELF_CLOSING_TAGS = array('area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'link', 'meta', 'param', 'source', 'track', 'wbr'
     241            );
    229242
    230243    const REPEAT_BALANCE_NOTIFICATIONS = array(60=>"1m", 600=>"10m", 1800=>"30m", 3600=>"1h", 43200=>"12h", 86400=>"1d", 604800=>"1w", 2592000=>"1month");
     
    299312                'wp-config.php',
    300313                'wp-config-sample.php',
     314                'wp-json',
    301315            ];
    302316}
    303317
    304318//Define for autoglot plugin version
    305 define('AUTOGLOT_PLUGIN_VER', '2.10.8');
     319define('AUTOGLOT_PLUGIN_VER', '2.10.9');
    306320
    307321//Define for autoglot plugin name
     
    405419//skip caching of translated pages
    406420define('AUTOGLOT_DEFAULT_SKIP_CACHING', 0);//2.2.1
     421
     422//skip caching of translated pages
     423define('AUTOGLOT_DEFAULT_FORCE_SELFCLOSING', 0);//2.10.9
    407424
    408425//always translate comments
  • autoglot/trunk/utils/autoglot_dom.php

    r3471673 r3475723  
    221221            $metaarray[autoglot_utils::gettexthash($mvalue)] = $mvalue;
    222222        }
    223         if(count($this->autoglot->third_party->json_data_strings)) {
     223       
     224        if(count($this->autoglot->third_party->json_data_strings)) {// look for specific json strings for Woo etc.
    224225           
    225226            $find = $this->autoglot->third_party->json_data_strings;
     
    254255            $metaarray = array_merge($metaarray, $json_array);
    255256        }
     257       
     258        $json_array = array();
     259        $json_urls = array();
     260        $scripts = $xpath->query("//script[@type='application/ld+json' or @type='application/json']");
     261        if ($scripts->length) foreach($scripts as $node)
     262        {
     263            if (substr(trim($node->textContent), 0, 1) === "{") {
     264//file_put_contents(__DIR__."/debug.txt", $node->textContent."\r\n", FILE_APPEND);
     265                $jsonContent = $node->textContent;
     266                $decodedArray = json_decode($jsonContent, true);
     267
     268                if (json_last_error() === JSON_ERROR_NONE) {
     269                    // Collect the values of the keys in the decoded array
     270                    $json_array = array_merge($json_array, autoglot_utils::get_json_values($decodedArray, autoglot_consts::JSON_KEYS_TRANSLATE));
     271                    if($this->autoglot->options->translate_urls) $json_urls = array_merge($json_urls, autoglot_utils::get_json_urls($decodedArray, autoglot_consts::JSON_KEYS_URL, $this->autoglot->homeURL));
     272//                    file_put_contents(__DIR__."/debug.txt", print_r($json_urls, true)."\r\n", FILE_APPEND);
     273                }
     274            }
     275        }
     276        $metaarray = array_merge($metaarray, $json_array);
     277        if($this->autoglot->options->translate_urls) $this->autoglot->page_links = array_merge($this->autoglot->page_links, $json_urls);
    256278       
    257279        $array = $this->DOM2Array($this->dom_content->getElementsByTagName('body')->item(0));
     
    628650        }
    629651       
     652        $json_out = array();
     653        $updatedJsonContent = "";
     654        $scripts = $xpath->query("//script[@type='application/ld+json' or @type='application/json']");
     655        if ($scripts->length) foreach($scripts as $node)
     656        {
     657            if (substr(trim($node->textContent), 0, 1) === "{") {
     658                $jsonContent = $node->textContent;
     659                $decodedArray = json_decode($jsonContent, true);
     660
     661                if (json_last_error() === JSON_ERROR_NONE) {
     662                    // Collect the values of the keys in the decoded array
     663                    $json_out = autoglot_utils::set_json_values($decodedArray, autoglot_consts::JSON_KEYS_TRANSLATE, $this->array_translated);
     664                    $json_out = autoglot_utils::set_json_urls($json_out, autoglot_consts::JSON_KEYS_URL, $this->autoglot->page_links_translated, $this->autoglot->homeURL, $this->autoglot->options->translate_urls, $this->autoglot->langURL);
     665                    $updatedJsonContent = json_encode($json_out, JSON_UNESCAPED_SLASHES);
     666                    $node->textContent = $updatedJsonContent;
     667                }
     668            }
     669        }
     670
    630671        $translatedHTML = $this->DOM2HTML();
    631672
     
    633674           
    634675            $find = $this->autoglot->third_party->json_data_strings;
    635             $json_out = "";
     676            $json_out = array();
    636677             
    637678            // Iterate over the $find array to search for JavaScript variables
     
    647688                        // Collect the values of the keys in the decoded array
    648689                        $json_out = autoglot_utils::set_json_values($decodedArray, $keysToCheck, $this->array_translated);
    649                         $updatedJsonContent = json_encode($json_out);
     690                        $updatedJsonContent = json_encode($json_out, JSON_UNESCAPED_SLASHES);
    650691                        $translatedHTML = preg_replace($pattern, "var $variable = $updatedJsonContent;", $translatedHTML);
    651692                    }
     
    660701                        // Collect the values of the keys in the decoded array
    661702                        $json_out = autoglot_utils::set_json_values($decodedArray, $keysToCheck, $this->array_translated);
    662                         $updatedJsonContent = rawurlencode(json_encode($json_out));
     703                        $updatedJsonContent = rawurlencode(json_encode($json_out, JSON_UNESCAPED_SLASHES));
    663704                        $translatedHTML = preg_replace($pattern, $matches[1]."$variable( '$updatedJsonContent' )", $translatedHTML);
    664705                    }
     
    845886                        if($attr->nodeName!=AUTOGLOT_EXCLUDE_TRANSLATION) $node->setAttribute($attr->nodeName, $attr->nodeValue);
    846887                    }
    847                 }
    848                 /*if(isset($this->savecontent[$blockcounter][$nodenum]["content"])) {
    849                     //$this->appendHTML($node,"<ag_tag>".$this->savecontent[$blockcounter][$nodenum]["content"]."</ag_tag>");
    850                     $node->nodeValue = $this->savecontent[$blockcounter][$nodenum]["content"];
    851                 }     */           
     888                }       
    852889            }
    853890        }
     
    856893    function DOM2HTML(){
    857894        // Generate final output
     895       
    858896        $output = "";
    859897        if($this->autoglot->custom_ajax_request || wp_is_json_request() || $this->autoglot->response_content_type == "json" || (is_admin() && wp_doing_ajax())){
     
    863901            }
    864902        }
    865         else $output = $this->dom_translated->saveHTML($this->dom_translated);
     903        else {
     904            $output = $this->dom_translated->saveHTML($this->dom_translated);
     905            if($this->autoglot->options->force_selfclosing) $output = autoglot_utils::add_selfclosing_slash($output, autoglot_consts::SELF_CLOSING_TAGS);
     906        }
    866907        return $output;   
    867908    }
  • autoglot/trunk/utils/autoglot_options.php

    r3459057 r3475723  
    3131    public $custom_titles;
    3232    public $skip_caching;
     33    public $force_selfclosing;
    3334    public $widget_signature;
    3435    public $reduce_sitemap_priority;
     
    126127        $this->skip_caching = $this->validate_checkbox($option[0], AUTOGLOT_DEFAULT_SKIP_CACHING);
    127128
     129        $option = get_option('autoglot_translation_force_selfclosing', array(AUTOGLOT_DEFAULT_FORCE_SELFCLOSING));
     130        $this->force_selfclosing = $this->validate_checkbox($option[0], AUTOGLOT_DEFAULT_FORCE_SELFCLOSING);
     131
    128132        $option = get_option('autoglot_translation_widget_signature', array(AUTOGLOT_DEFAULT_WIDGET_SIGNATURE));
    129133        $this->widget_signature = $this->validate_checkbox($option[0], AUTOGLOT_DEFAULT_WIDGET_SIGNATURE);
  • autoglot/trunk/utils/autoglot_utils.php

    r3471673 r3475723  
    304304        return $string;
    305305    }
     306   
     307    /**
     308     * Add slash to self-closing tags
     309     */
     310
     311    function add_selfclosing_slash($html, $selfClosingTags)
     312    {
     313        $tagsList = implode('|', $selfClosingTags);
     314   
     315        /**
     316         * Regex Breakdown:
     317         * <($tagsList)  -> Match the opening bracket and the tag name
     318         * ([^>]*?)      -> Capture any attributes (non-greedy)
     319         * (?<!\/)       -> Negative Lookbehind: Ensure the character before > is not a slash
     320         * \s*>          -> Match optional whitespace and the closing bracket
     321         */
     322        $pattern = '/<(' . $tagsList . ')([^>]*?)(?<!\/)\s*>/i';
     323       
     324        // Replace with the tag name, attributes, and the new " />"
     325        $html = preg_replace($pattern, '<$1$2 />', $html);
     326   
     327        return $html;
     328    }
    306329
    307330    /**
     
    453476                }
    454477
    455             }elseif (strlen($key) && in_array($key, $keysToCheck, true)) {
     478            } elseif (strlen($key) && in_array($key, $keysToCheck, true)) {
    456479                $value = autoglot_utils::prepare_HTML_translation(autoglot_utils::remove_outer_tags($value));
    457480                // Save the value of the matched key
     
    475498                $arrvalue = json_decode($value, true);
    476499                if(json_last_error() === JSON_ERROR_NONE && is_array($arrvalue)) {
    477                     $value = autoglot_utils::set_json_values($arrvalue, $keysToCheck, $translated_strings);
    478                     $value = json_encode($value);
    479                 }
    480 
    481             }elseif (strlen($key) && in_array($key, $keysToCheck, true)) {
     500                    $valuearr = autoglot_utils::set_json_values($arrvalue, $keysToCheck, $translated_strings);
     501                    $value = json_encode($valuearr);
     502                }
     503
     504            } elseif (strlen($key) && in_array($key, $keysToCheck, true)) {
    482505                // Check and update the value of the matched key
    483506                $value = autoglot_utils::prepare_HTML_translation(autoglot_utils::remove_outer_tags($value));
     
    490513    }
    491514
     515    public static function get_json_urls($array, $keysToCheck, $home) {
     516        $foundValues = [];
     517        foreach ($array as $key => $value) {
     518            if (is_array($value)) {
     519
     520                // Recursively search nested arrays
     521                $foundValues = array_merge($foundValues, autoglot_utils::get_json_urls($value, $keysToCheck, $home));
     522
     523            } elseif (substr($value, 0, 1) == "{") {
     524               
     525                //WTF some values can be json-encoded strings, OK let's decode them
     526                $arrvalue = json_decode($value, true);
     527                if(json_last_error() === JSON_ERROR_NONE && is_array($arrvalue)) {
     528                    $foundValues = array_merge($foundValues, autoglot_utils::get_json_urls($arrvalue, $keysToCheck, $home));
     529                }
     530
     531            } elseif (strlen($key) && in_array($key, $keysToCheck, true)) {
     532                $href = autoglot_utils::make_link_absolute($value, $home);
     533//                file_put_contents(__DIR__."/debug.txt", autoglot_utils::check_not_admin_link($href) . " - " . $href."\r\n", FILE_APPEND);
     534                if (strpos($href, $home) !== FALSE && autoglot_utils::check_not_admin_link($href) && autoglot_utils::check_not_core_script($href) && autoglot_utils::check_not_downloadable_file($href) ) {
     535                    // Save the value of the matched key
     536                    $foundValues[] = $value;
     537                }
     538            }
     539        }
     540        return $foundValues;
     541    }
     542   
     543    public static function set_json_urls($array, $keysToCheck, $translated_links, $home, $translate_urls, $lang) {
     544        foreach ($array as $key => &$value) {
     545            if (is_array($value)) {
     546
     547                // Recursively search nested arrays
     548                $value = autoglot_utils::set_json_urls($value, $keysToCheck, $translated_links, $home, $translate_urls, $lang);
     549
     550            } elseif (substr($value, 0, 1) == "{") {
     551
     552                //some values can be json-encoded strings, OK let's decode them
     553                $arrvalue = json_decode($value, true);
     554                if(json_last_error() === JSON_ERROR_NONE && is_array($arrvalue)) {
     555                    $valuearr = autoglot_utils::set_json_urls($arrvalue, $keysToCheck, $translated_links, $home, $translate_urls, $lang);
     556                    $value = json_encode($valuearr);
     557                }
     558
     559            } elseif (strlen($key) && in_array($key, $keysToCheck, true)) {
     560                $href = autoglot_utils::make_link_absolute($value, $home);
     561                if (strpos($href, $home) !== FALSE && autoglot_utils::check_not_admin_link($href) && autoglot_utils::check_not_core_script($href) && autoglot_utils::check_not_downloadable_file($href) ) {
     562                    // Save the value of the matched key
     563                    if($translate_urls && isset($translated_links[hash("md5", $href)]) && strlen($translated_links[hash("md5", $href)])) {
     564                        $value = $translated_links[hash("md5", $href)];
     565                    } else {
     566                        $value = autoglot_utils::add_language_to_url($href, $home, $lang);
     567                    }
     568                }
     569            }
     570        }
     571        return $array;
     572    }
    492573    /**
    493574     * Return capabilities for translation editors
Note: See TracChangeset for help on using the changeset viewer.