Plugin Directory

Changeset 3393354


Ignore:
Timestamp:
11/11/2025 04:03:23 AM (5 months ago)
Author:
linguise
Message:

Updating to version 2.2.3

Location:
linguise
Files:
14 edited
1 copied

Legend:

Unmodified
Added
Removed
  • linguise/tags/2.2.3/linguise.php

    r3388557 r3393354  
    55 * Plugin URI: https://www.linguise.com/
    66 * Description: Linguise translation plugin
    7  * Version:2.2.2
     7 * Version:2.2.3
    88 * Text Domain: linguise
    99 * Domain Path: /languages
  • linguise/tags/2.2.3/readme.txt

    r3391718 r3393354  
    44Requires at least: 4.0
    55Tested up to: 6.8
    6 Stable tag: 2.2.2
     6Stable tag: 2.2.3
    77Requires PHP: 7.0
    88License: GPLv2 or later
     
    107107
    108108== Changelog ==
     109= 2.2.3 =
     110- Fix: i18n not replaced as intended
     111
    109112= 2.2.2 =
    110113- Fix: Unable to change language order
  • linguise/tags/2.2.3/src/FragmentHandler.php

    r3381590 r3393354  
    2121     * @var string
    2222     */
    23     protected static $frag_html_match = '/<(div|a|linguise-main|img) class="linguise-fragment" data-fragment-name="([^"]*)" data-fragment-param="([^"]*)" data-fragment-key="([^"]*)" data-fragment-format="((?:link|html|html-main|text|media-img|media-imgset)(?:-skip)?)" data-fragment-mode="(auto|override|skip|attribute)"(?: data-fragment-extra-id="([^"]*)")?(?: (?:href|src|srcset)="([^"]*)")?>(.*?)<\/\1>/si';
     23    protected static $frag_html_match = '/<(div|a|linguise-main|img) class="linguise-fragment" data-fragment-name="([^"]*)" data-fragment-param="([^"]*)" data-fragment-key="([^"]*)" data-fragment-format="((?:link|html|html-main|text|media-img|media-imgset)(?:-skip)?)" data-fragment-mode="(auto|override|skip|i18n|attribute)"(?: data-fragment-extra-id="([^"]*)")?(?: (?:href|src|srcset)="([^"]*)")?>(.*?)<\/\1>/si';
    2424    /**
    2525     * Regex/matcher for our custom HTML fragment
     
    2929     * @var string
    3030     */
    31     protected static $frag_html_match_self_close = '/<(img) class="linguise-fragment" data-fragment-name="([^"]*)" data-fragment-param="([^"]*)" data-fragment-key="([^"]*)" data-fragment-format="((?:link|html|html-main|text|media-img|media-imgset)(?:-skip)?)" data-fragment-mode="(auto|override|skip|attribute)"(?: data-fragment-extra-id="([^"]*)")?(?: (?:href|src|srcset)="([^"]*)")?\s*\/?>/si';
     31    protected static $frag_html_match_self_close = '/<(img) class="linguise-fragment" data-fragment-name="([^"]*)" data-fragment-param="([^"]*)" data-fragment-key="([^"]*)" data-fragment-format="((?:link|html|html-main|text|media-img|media-imgset)(?:-skip)?)" data-fragment-mode="(auto|override|skip|i18n|attribute)"(?: data-fragment-extra-id="([^"]*)")?(?: (?:href|src|srcset)="([^"]*)")?\s*\/?>/si';
    3232
    3333    /**
     
    165165            if ($json_fragments['mode'] === 'attribute' && isset($json_fragments['attribute'])) {
    166166                $html .= ' data-fragment-extra-id="' . $json_fragments['attribute'] . '"';
     167            }
     168            if ($json_fragments['mode'] === 'i18n' && isset($fragment['index'])) {
     169                $html .= ' data-fragment-extra-id="' . $fragment['index'] . '"';
    167170            }
    168171            if ($fragment['format'] === 'link') {
     
    250253            }
    251254
     255            $fragment_index = null;
     256            if ($fragment_mode === 'i18n' && isset($match[7]) && is_numeric($match[7])) {
     257                $fragment_index = (int)$match[7];
     258            }
     259
    252260            // make it into list for each fragment name
    253261            $fragments[$fragment_name][$fragment_param]['fragments'][] = [
     
    256264                'format' => $fragment_format,
    257265                'match' => $match[0],
     266                'index' => $fragment_index,
    258267                'skip' => $is_skipped, // If `skip` is true, then don't replace this fragment (but remove it)
    259268            ];
     
    346355
    347356    /**
     357     * Parse the translation block from the script tag.
     358     *
     359     * @param \DOMNode|\DOMElement $script The script to be matched
     360     *
     361     * @return array|null
     362     */
     363    public static function tryMatchTranslationBlock($script)
     364    {
     365        $script_content = HTMLHelper::unclobberCdataInternal($script->textContent);
     366        $match_res = preg_match('/\(\s*\"([\w\-_]*)\",\s*(\{.*?\})\s*\);/si', $script_content, $json_match);
     367        if ($match_res === false || $match_res === 0) {
     368            return null;
     369        }
     370
     371        $block_name = $json_match[1];
     372        $json_data = json_decode($json_match[2], true);
     373        if (is_null($json_data)) {
     374            return null;
     375        }
     376
     377        // WP uses Jed format for translation blocks
     378        // https://messageformat.github.io/Jed/
     379        $selected_locale_data = null;
     380        if (isset($json_data['locale_data'][$block_name]) && !empty($json_data['locale_data'][$block_name])) {
     381            $selected_locale_data = $json_data['locale_data'][$block_name];
     382            return null;
     383        } elseif (isset($json_data['locale_data']['messages']) && !empty($json_data['locale_data']['messages'])) {
     384            $block_name = 'messages'; // use messages as block name
     385            $selected_locale_data = $json_data['locale_data']['messages'];
     386        }
     387
     388        if (is_null($selected_locale_data)) {
     389            return null;
     390        }
     391
     392        $collected_temp = [];
     393        foreach ($selected_locale_data as $msg_key => $msg_values) {
     394            if ($msg_key === '') {
     395                // Skip the header
     396                continue;
     397            }
     398
     399            if (is_array($msg_values)) {
     400                // for use index
     401                for ($i = 0; $i < count($msg_values); $i++) { // phpcs:ignore Generic.CodeAnalysis.ForLoopWithTestFunctionCall.NotAllowed
     402                    // hash $msg_key in sha256 to avoid issues with quotes/special chars
     403                    $key_hashed = hash('sha256', $msg_key);
     404                    $collected_temp[] = [
     405                        'key' => $key_hashed,
     406                        'value' => $msg_values[$i],
     407                        'format' => 'text',
     408                        'index' => $i
     409                    ];
     410                }
     411            }
     412        }
     413
     414        return [
     415            'name' => $block_name,
     416            'fragments' => $collected_temp
     417        ];
     418    }
     419
     420    /**
    348421     * Parse the HTML input or data into the fragments.
    349422     * XXX: Maybe normal regex and not DOMDocument if possible.
     
    373446                        'fragments' => $overridden_temp['fragments'],
    374447                    ];
     448
     449                    continue;
     450                }
     451
     452                // Try matching -js-translations
     453                $trans_match_res = preg_match('/^(.*)-js-translations$/', $attr_id, $trans_attr_match);
     454                if ($trans_match_res !== false && $trans_match_res !== 0) {
     455                    $translation_block = self::tryMatchTranslationBlock($script);
     456                    $param_name = $trans_attr_match[1];
     457                    if (is_array($translation_block)) {
     458                        $all_fragments[$param_name][$translation_block['name']] = [
     459                            'mode' => 'i18n',
     460                            'fragments' => $translation_block['fragments'],
     461                        ];
     462                    }
    375463                }
    376464                continue;
     
    576664
    577665    /**
     666     * Apply the translated fragments for the i18n mode.
     667     *
     668     * @param string $html_data  The HTML data to be injected
     669     * @param string $param_name The name of the fragment, e.g. 'woocommerce'
     670     * @param string $param_key  The param of the fragment, e.g. 'messages'
     671     * @param array  $fragments  The array of fragments to be injected, from intoJSON
     672     *
     673     * @return string
     674     */
     675    public static function applyTranslatedFragmentsForI18n($html_data, $param_name, $param_key, $fragments)
     676    {
     677        $full_param_name = $param_name . '-js-translations';
     678        $overall_matchers = preg_match('/id=["\']' . preg_quote($full_param_name) . '.*?>\s*\(\s*function\(\s*domain,\s*translations\s*\)\s*\{.*?\}\s*\)\s*\(\s*["\']([\w_\-]+)["\']\s*,\s*\{(.*?)\}\s*\)\s*;\s*<\/script>/si', $html_data, $html_matches);
     679        if ($overall_matchers === false || $overall_matchers === 0) {
     680            return $html_data;
     681        }
     682
     683        // Get the JSON data for replacement
     684        $code_contents = $html_matches[0];
     685        $match_res = preg_match('/\(\s*\"([\w\-_]+)\",\s*(\{.*?\})\s*\);/si', $code_contents, $json_match);
     686        if ($match_res === false || $match_res === 0) {
     687            return $html_data;
     688        }
     689
     690        $json_data = json_decode($json_match[2], true);
     691        if (is_null($json_data)) {
     692            return $html_data;
     693        }
     694
     695        $message_data = $json_data['locale_data'][$param_key];
     696        if (empty($message_data)) {
     697            return $html_data;
     698        }
     699
     700        $remapped_fragments = [];
     701        foreach ($fragments as $fragment) {
     702            if (isset($fragment['skip']) && $fragment['skip']) {
     703                // If skip is true, then don't replace this fragment (but remove it)
     704                continue;
     705            }
     706
     707            $msg_key = $fragment['key'];
     708            $msg_index = isset($fragment['index']) ? $fragment['index'] : 0;
     709
     710            $remapped_fragments[$msg_key] = [];
     711            $remapped_fragments[$msg_key][$msg_index] = $fragment['value'];
     712        }
     713
     714        foreach ($message_data as $msg_key => &$msg_values) {
     715            if (is_array($msg_values)) {
     716                $hashed_key = hash('sha256', $msg_key);
     717                if (!isset($remapped_fragments[$hashed_key])) {
     718                    continue;
     719                }
     720
     721                // for use index
     722                for ($i = 0; $i < count($msg_values); $i++) { // phpcs:ignore Generic.CodeAnalysis.ForLoopWithTestFunctionCall.NotAllowed
     723                    if (isset($remapped_fragments[$hashed_key][$i])) {
     724                        $msg_values[$i] = $remapped_fragments[$hashed_key][$i];
     725                    }
     726                }
     727            }
     728        }
     729
     730        $json_data['locale_data'][$param_key] = $message_data;
     731
     732        // dump back to JSON
     733        $replaced_json = json_encode($json_data);
     734        $substr_ptrn = '/(id=["\']' . preg_quote($full_param_name) . '["\'].*?>\s*\(\s*function\(\s*domain,\s*translations\s*\)\s*\{.*?\}\s*\)\s*\(\s*["\']([\w_\-]+)["\']\s*,\s*)(.*?)(\s*\)\s*;\s*<\/script>)/si';
     735
     736        $replacement = preg_replace($substr_ptrn, '$1' . $replaced_json . '$4', $html_data, 1, $count);
     737        if ($count) {
     738            $html_data = $replacement;
     739        }
     740
     741        return $html_data;
     742    }
     743
     744    /**
    578745     * Clean up the fragments from the HTML data.
    579746     *
     
    609776                $mode = $fragment_list['mode'];
    610777
    611                 if (!in_array($mode, ['auto', 'override', 'skip'])) {
     778                if (!in_array($mode, ['auto', 'override', 'skip', 'i18n'])) {
    612779                    continue;
    613780                }
     
    624791                }
    625792
     793                if ($mode === 'i18n') {
     794                    // i18n mode for translation blocks
     795                    $html_data = self::applyTranslatedFragmentsForI18n($html_data, $fragment_name, $fragment_param, $fragment_list['fragments']);
     796                    $html_data = self::cleanupFragments($html_data, $fragment_list['fragments']);
     797                    continue;
     798                }
     799
    626800                $id       = preg_quote($fragment_name . '-js-extra', '/');
    627801                $variable = preg_quote($fragment_param . '_params', '/');
  • linguise/tags/2.2.3/src/constants.php

    r3388557 r3393354  
    11<?php
    22if (!defined('LINGUISE_SCRIPT_TRANSLATION_VERSION')) {
    3     define('LINGUISE_SCRIPT_TRANSLATION_VERSION', 'wordpress_plugin/2.2.2');
     3    define('LINGUISE_SCRIPT_TRANSLATION_VERSION', 'wordpress_plugin/2.2.3');
    44}
    55
    66if (!defined('LINGUISE_VERSION')) {
    7     define('LINGUISE_VERSION', '2.2.2');
     7    define('LINGUISE_VERSION', '2.2.3');
    88}
  • linguise/tags/2.2.3/vendor/composer/installed.php

    r3388557 r3393354  
    44        'pretty_version' => 'dev-master',
    55        'version' => 'dev-master',
    6         'reference' => 'd5ea0ccad80735f885e1e50abb162aa6237055ab',
     6        'reference' => 'f9d8386fa79f0e526a39c5c9a943cf62ca2c241a',
    77        'type' => 'library',
    88        'install_path' => __DIR__ . '/../../',
     
    3232            'pretty_version' => 'dev-master',
    3333            'version' => 'dev-master',
    34             'reference' => 'd5ea0ccad80735f885e1e50abb162aa6237055ab',
     34            'reference' => 'f9d8386fa79f0e526a39c5c9a943cf62ca2c241a',
    3535            'type' => 'library',
    3636            'install_path' => __DIR__ . '/../../',
  • linguise/tags/2.2.3/vendor/linguise/script-php/certificates/cacert.pem

    r3358294 r3393354  
    22## Bundle of CA Root Certificates
    33##
    4 ## Certificate data from Mozilla as of: Tue Sep  9 03:12:01 2025 GMT
     4## Certificate data from Mozilla as of: Tue Nov  4 04:12:02 2025 GMT
    55##
    66## Find updated versions here: https://curl.se/docs/caextract.html
     
    1717##
    1818## Conversion done with mk-ca-bundle.pl version 1.29.
    19 ## SHA256: 0078e6bdd280fd89e1b883174387aae84b3eae2ee263416a5f8a14ee7f179ae9
     19## SHA256: 039132bff5179ce57cec5803ba59fe37abe6d0297aeb538c5af27847f0702517
    2020##
    2121
     
    35553555tnu64ZzZ
    35563556-----END CERTIFICATE-----
     3557
     3558OISTE Server Root ECC G1
     3559========================
     3560-----BEGIN CERTIFICATE-----
     3561MIICNTCCAbqgAwIBAgIQI/nD1jWvjyhLH/BU6n6XnTAKBggqhkjOPQQDAzBLMQswCQYDVQQGEwJD
     3562SDEZMBcGA1UECgwQT0lTVEUgRm91bmRhdGlvbjEhMB8GA1UEAwwYT0lTVEUgU2VydmVyIFJvb3Qg
     3563RUNDIEcxMB4XDTIzMDUzMTE0NDIyOFoXDTQ4MDUyNDE0NDIyN1owSzELMAkGA1UEBhMCQ0gxGTAX
     3564BgNVBAoMEE9JU1RFIEZvdW5kYXRpb24xITAfBgNVBAMMGE9JU1RFIFNlcnZlciBSb290IEVDQyBH
     3565MTB2MBAGByqGSM49AgEGBSuBBAAiA2IABBcv+hK8rBjzCvRE1nZCnrPoH7d5qVi2+GXROiFPqOuj
     3566vqQycvO2Ackr/XeFblPdreqqLiWStukhEaivtUwL85Zgmjvn6hp4LrQ95SjeHIC6XG4N2xml4z+c
     3567KrhAS93mT6NjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBQ3TYhlz/w9itWj8UnATgwQ
     3568b0K0nDAdBgNVHQ4EFgQUN02IZc/8PYrVo/FJwE4MEG9CtJwwDgYDVR0PAQH/BAQDAgGGMAoGCCqG
     3569SM49BAMDA2kAMGYCMQCpKjAd0MKfkFFRQD6VVCHNFmb3U2wIFjnQEnx/Yxvf4zgAOdktUyBFCxxg
     3570ZzFDJe0CMQCSia7pXGKDYmH5LVerVrkR3SW+ak5KGoJr3M/TvEqzPNcum9v4KGm8ay3sMaE641c=
     3571-----END CERTIFICATE-----
     3572
     3573 OISTE Server Root RSA G1
     3574=========================
     3575-----BEGIN CERTIFICATE-----
     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
     3601-----END CERTIFICATE-----
  • linguise/tags/2.2.3/vendor/linguise/script-php/certificates/etag.txt

    r3358294 r3393354  
    1 "37a4f-63e55aaf768b0"
     1"3859e-642bd08b1bfbf"
  • linguise/trunk/linguise.php

    r3388557 r3393354  
    55 * Plugin URI: https://www.linguise.com/
    66 * Description: Linguise translation plugin
    7  * Version:2.2.2
     7 * Version:2.2.3
    88 * Text Domain: linguise
    99 * Domain Path: /languages
  • linguise/trunk/readme.txt

    r3391718 r3393354  
    44Requires at least: 4.0
    55Tested up to: 6.8
    6 Stable tag: 2.2.2
     6Stable tag: 2.2.3
    77Requires PHP: 7.0
    88License: GPLv2 or later
     
    107107
    108108== Changelog ==
     109= 2.2.3 =
     110- Fix: i18n not replaced as intended
     111
    109112= 2.2.2 =
    110113- Fix: Unable to change language order
  • linguise/trunk/src/FragmentHandler.php

    r3381590 r3393354  
    2121     * @var string
    2222     */
    23     protected static $frag_html_match = '/<(div|a|linguise-main|img) class="linguise-fragment" data-fragment-name="([^"]*)" data-fragment-param="([^"]*)" data-fragment-key="([^"]*)" data-fragment-format="((?:link|html|html-main|text|media-img|media-imgset)(?:-skip)?)" data-fragment-mode="(auto|override|skip|attribute)"(?: data-fragment-extra-id="([^"]*)")?(?: (?:href|src|srcset)="([^"]*)")?>(.*?)<\/\1>/si';
     23    protected static $frag_html_match = '/<(div|a|linguise-main|img) class="linguise-fragment" data-fragment-name="([^"]*)" data-fragment-param="([^"]*)" data-fragment-key="([^"]*)" data-fragment-format="((?:link|html|html-main|text|media-img|media-imgset)(?:-skip)?)" data-fragment-mode="(auto|override|skip|i18n|attribute)"(?: data-fragment-extra-id="([^"]*)")?(?: (?:href|src|srcset)="([^"]*)")?>(.*?)<\/\1>/si';
    2424    /**
    2525     * Regex/matcher for our custom HTML fragment
     
    2929     * @var string
    3030     */
    31     protected static $frag_html_match_self_close = '/<(img) class="linguise-fragment" data-fragment-name="([^"]*)" data-fragment-param="([^"]*)" data-fragment-key="([^"]*)" data-fragment-format="((?:link|html|html-main|text|media-img|media-imgset)(?:-skip)?)" data-fragment-mode="(auto|override|skip|attribute)"(?: data-fragment-extra-id="([^"]*)")?(?: (?:href|src|srcset)="([^"]*)")?\s*\/?>/si';
     31    protected static $frag_html_match_self_close = '/<(img) class="linguise-fragment" data-fragment-name="([^"]*)" data-fragment-param="([^"]*)" data-fragment-key="([^"]*)" data-fragment-format="((?:link|html|html-main|text|media-img|media-imgset)(?:-skip)?)" data-fragment-mode="(auto|override|skip|i18n|attribute)"(?: data-fragment-extra-id="([^"]*)")?(?: (?:href|src|srcset)="([^"]*)")?\s*\/?>/si';
    3232
    3333    /**
     
    165165            if ($json_fragments['mode'] === 'attribute' && isset($json_fragments['attribute'])) {
    166166                $html .= ' data-fragment-extra-id="' . $json_fragments['attribute'] . '"';
     167            }
     168            if ($json_fragments['mode'] === 'i18n' && isset($fragment['index'])) {
     169                $html .= ' data-fragment-extra-id="' . $fragment['index'] . '"';
    167170            }
    168171            if ($fragment['format'] === 'link') {
     
    250253            }
    251254
     255            $fragment_index = null;
     256            if ($fragment_mode === 'i18n' && isset($match[7]) && is_numeric($match[7])) {
     257                $fragment_index = (int)$match[7];
     258            }
     259
    252260            // make it into list for each fragment name
    253261            $fragments[$fragment_name][$fragment_param]['fragments'][] = [
     
    256264                'format' => $fragment_format,
    257265                'match' => $match[0],
     266                'index' => $fragment_index,
    258267                'skip' => $is_skipped, // If `skip` is true, then don't replace this fragment (but remove it)
    259268            ];
     
    346355
    347356    /**
     357     * Parse the translation block from the script tag.
     358     *
     359     * @param \DOMNode|\DOMElement $script The script to be matched
     360     *
     361     * @return array|null
     362     */
     363    public static function tryMatchTranslationBlock($script)
     364    {
     365        $script_content = HTMLHelper::unclobberCdataInternal($script->textContent);
     366        $match_res = preg_match('/\(\s*\"([\w\-_]*)\",\s*(\{.*?\})\s*\);/si', $script_content, $json_match);
     367        if ($match_res === false || $match_res === 0) {
     368            return null;
     369        }
     370
     371        $block_name = $json_match[1];
     372        $json_data = json_decode($json_match[2], true);
     373        if (is_null($json_data)) {
     374            return null;
     375        }
     376
     377        // WP uses Jed format for translation blocks
     378        // https://messageformat.github.io/Jed/
     379        $selected_locale_data = null;
     380        if (isset($json_data['locale_data'][$block_name]) && !empty($json_data['locale_data'][$block_name])) {
     381            $selected_locale_data = $json_data['locale_data'][$block_name];
     382            return null;
     383        } elseif (isset($json_data['locale_data']['messages']) && !empty($json_data['locale_data']['messages'])) {
     384            $block_name = 'messages'; // use messages as block name
     385            $selected_locale_data = $json_data['locale_data']['messages'];
     386        }
     387
     388        if (is_null($selected_locale_data)) {
     389            return null;
     390        }
     391
     392        $collected_temp = [];
     393        foreach ($selected_locale_data as $msg_key => $msg_values) {
     394            if ($msg_key === '') {
     395                // Skip the header
     396                continue;
     397            }
     398
     399            if (is_array($msg_values)) {
     400                // for use index
     401                for ($i = 0; $i < count($msg_values); $i++) { // phpcs:ignore Generic.CodeAnalysis.ForLoopWithTestFunctionCall.NotAllowed
     402                    // hash $msg_key in sha256 to avoid issues with quotes/special chars
     403                    $key_hashed = hash('sha256', $msg_key);
     404                    $collected_temp[] = [
     405                        'key' => $key_hashed,
     406                        'value' => $msg_values[$i],
     407                        'format' => 'text',
     408                        'index' => $i
     409                    ];
     410                }
     411            }
     412        }
     413
     414        return [
     415            'name' => $block_name,
     416            'fragments' => $collected_temp
     417        ];
     418    }
     419
     420    /**
    348421     * Parse the HTML input or data into the fragments.
    349422     * XXX: Maybe normal regex and not DOMDocument if possible.
     
    373446                        'fragments' => $overridden_temp['fragments'],
    374447                    ];
     448
     449                    continue;
     450                }
     451
     452                // Try matching -js-translations
     453                $trans_match_res = preg_match('/^(.*)-js-translations$/', $attr_id, $trans_attr_match);
     454                if ($trans_match_res !== false && $trans_match_res !== 0) {
     455                    $translation_block = self::tryMatchTranslationBlock($script);
     456                    $param_name = $trans_attr_match[1];
     457                    if (is_array($translation_block)) {
     458                        $all_fragments[$param_name][$translation_block['name']] = [
     459                            'mode' => 'i18n',
     460                            'fragments' => $translation_block['fragments'],
     461                        ];
     462                    }
    375463                }
    376464                continue;
     
    576664
    577665    /**
     666     * Apply the translated fragments for the i18n mode.
     667     *
     668     * @param string $html_data  The HTML data to be injected
     669     * @param string $param_name The name of the fragment, e.g. 'woocommerce'
     670     * @param string $param_key  The param of the fragment, e.g. 'messages'
     671     * @param array  $fragments  The array of fragments to be injected, from intoJSON
     672     *
     673     * @return string
     674     */
     675    public static function applyTranslatedFragmentsForI18n($html_data, $param_name, $param_key, $fragments)
     676    {
     677        $full_param_name = $param_name . '-js-translations';
     678        $overall_matchers = preg_match('/id=["\']' . preg_quote($full_param_name) . '.*?>\s*\(\s*function\(\s*domain,\s*translations\s*\)\s*\{.*?\}\s*\)\s*\(\s*["\']([\w_\-]+)["\']\s*,\s*\{(.*?)\}\s*\)\s*;\s*<\/script>/si', $html_data, $html_matches);
     679        if ($overall_matchers === false || $overall_matchers === 0) {
     680            return $html_data;
     681        }
     682
     683        // Get the JSON data for replacement
     684        $code_contents = $html_matches[0];
     685        $match_res = preg_match('/\(\s*\"([\w\-_]+)\",\s*(\{.*?\})\s*\);/si', $code_contents, $json_match);
     686        if ($match_res === false || $match_res === 0) {
     687            return $html_data;
     688        }
     689
     690        $json_data = json_decode($json_match[2], true);
     691        if (is_null($json_data)) {
     692            return $html_data;
     693        }
     694
     695        $message_data = $json_data['locale_data'][$param_key];
     696        if (empty($message_data)) {
     697            return $html_data;
     698        }
     699
     700        $remapped_fragments = [];
     701        foreach ($fragments as $fragment) {
     702            if (isset($fragment['skip']) && $fragment['skip']) {
     703                // If skip is true, then don't replace this fragment (but remove it)
     704                continue;
     705            }
     706
     707            $msg_key = $fragment['key'];
     708            $msg_index = isset($fragment['index']) ? $fragment['index'] : 0;
     709
     710            $remapped_fragments[$msg_key] = [];
     711            $remapped_fragments[$msg_key][$msg_index] = $fragment['value'];
     712        }
     713
     714        foreach ($message_data as $msg_key => &$msg_values) {
     715            if (is_array($msg_values)) {
     716                $hashed_key = hash('sha256', $msg_key);
     717                if (!isset($remapped_fragments[$hashed_key])) {
     718                    continue;
     719                }
     720
     721                // for use index
     722                for ($i = 0; $i < count($msg_values); $i++) { // phpcs:ignore Generic.CodeAnalysis.ForLoopWithTestFunctionCall.NotAllowed
     723                    if (isset($remapped_fragments[$hashed_key][$i])) {
     724                        $msg_values[$i] = $remapped_fragments[$hashed_key][$i];
     725                    }
     726                }
     727            }
     728        }
     729
     730        $json_data['locale_data'][$param_key] = $message_data;
     731
     732        // dump back to JSON
     733        $replaced_json = json_encode($json_data);
     734        $substr_ptrn = '/(id=["\']' . preg_quote($full_param_name) . '["\'].*?>\s*\(\s*function\(\s*domain,\s*translations\s*\)\s*\{.*?\}\s*\)\s*\(\s*["\']([\w_\-]+)["\']\s*,\s*)(.*?)(\s*\)\s*;\s*<\/script>)/si';
     735
     736        $replacement = preg_replace($substr_ptrn, '$1' . $replaced_json . '$4', $html_data, 1, $count);
     737        if ($count) {
     738            $html_data = $replacement;
     739        }
     740
     741        return $html_data;
     742    }
     743
     744    /**
    578745     * Clean up the fragments from the HTML data.
    579746     *
     
    609776                $mode = $fragment_list['mode'];
    610777
    611                 if (!in_array($mode, ['auto', 'override', 'skip'])) {
     778                if (!in_array($mode, ['auto', 'override', 'skip', 'i18n'])) {
    612779                    continue;
    613780                }
     
    624791                }
    625792
     793                if ($mode === 'i18n') {
     794                    // i18n mode for translation blocks
     795                    $html_data = self::applyTranslatedFragmentsForI18n($html_data, $fragment_name, $fragment_param, $fragment_list['fragments']);
     796                    $html_data = self::cleanupFragments($html_data, $fragment_list['fragments']);
     797                    continue;
     798                }
     799
    626800                $id       = preg_quote($fragment_name . '-js-extra', '/');
    627801                $variable = preg_quote($fragment_param . '_params', '/');
  • linguise/trunk/src/constants.php

    r3388557 r3393354  
    11<?php
    22if (!defined('LINGUISE_SCRIPT_TRANSLATION_VERSION')) {
    3     define('LINGUISE_SCRIPT_TRANSLATION_VERSION', 'wordpress_plugin/2.2.2');
     3    define('LINGUISE_SCRIPT_TRANSLATION_VERSION', 'wordpress_plugin/2.2.3');
    44}
    55
    66if (!defined('LINGUISE_VERSION')) {
    7     define('LINGUISE_VERSION', '2.2.2');
     7    define('LINGUISE_VERSION', '2.2.3');
    88}
  • linguise/trunk/vendor/composer/installed.php

    r3388557 r3393354  
    44        'pretty_version' => 'dev-master',
    55        'version' => 'dev-master',
    6         'reference' => 'd5ea0ccad80735f885e1e50abb162aa6237055ab',
     6        'reference' => 'f9d8386fa79f0e526a39c5c9a943cf62ca2c241a',
    77        'type' => 'library',
    88        'install_path' => __DIR__ . '/../../',
     
    3232            'pretty_version' => 'dev-master',
    3333            'version' => 'dev-master',
    34             'reference' => 'd5ea0ccad80735f885e1e50abb162aa6237055ab',
     34            'reference' => 'f9d8386fa79f0e526a39c5c9a943cf62ca2c241a',
    3535            'type' => 'library',
    3636            'install_path' => __DIR__ . '/../../',
  • linguise/trunk/vendor/linguise/script-php/certificates/cacert.pem

    r3358294 r3393354  
    22## Bundle of CA Root Certificates
    33##
    4 ## Certificate data from Mozilla as of: Tue Sep  9 03:12:01 2025 GMT
     4## Certificate data from Mozilla as of: Tue Nov  4 04:12:02 2025 GMT
    55##
    66## Find updated versions here: https://curl.se/docs/caextract.html
     
    1717##
    1818## Conversion done with mk-ca-bundle.pl version 1.29.
    19 ## SHA256: 0078e6bdd280fd89e1b883174387aae84b3eae2ee263416a5f8a14ee7f179ae9
     19## SHA256: 039132bff5179ce57cec5803ba59fe37abe6d0297aeb538c5af27847f0702517
    2020##
    2121
     
    35553555tnu64ZzZ
    35563556-----END CERTIFICATE-----
     3557
     3558OISTE Server Root ECC G1
     3559========================
     3560-----BEGIN CERTIFICATE-----
     3561MIICNTCCAbqgAwIBAgIQI/nD1jWvjyhLH/BU6n6XnTAKBggqhkjOPQQDAzBLMQswCQYDVQQGEwJD
     3562SDEZMBcGA1UECgwQT0lTVEUgRm91bmRhdGlvbjEhMB8GA1UEAwwYT0lTVEUgU2VydmVyIFJvb3Qg
     3563RUNDIEcxMB4XDTIzMDUzMTE0NDIyOFoXDTQ4MDUyNDE0NDIyN1owSzELMAkGA1UEBhMCQ0gxGTAX
     3564BgNVBAoMEE9JU1RFIEZvdW5kYXRpb24xITAfBgNVBAMMGE9JU1RFIFNlcnZlciBSb290IEVDQyBH
     3565MTB2MBAGByqGSM49AgEGBSuBBAAiA2IABBcv+hK8rBjzCvRE1nZCnrPoH7d5qVi2+GXROiFPqOuj
     3566vqQycvO2Ackr/XeFblPdreqqLiWStukhEaivtUwL85Zgmjvn6hp4LrQ95SjeHIC6XG4N2xml4z+c
     3567KrhAS93mT6NjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBQ3TYhlz/w9itWj8UnATgwQ
     3568b0K0nDAdBgNVHQ4EFgQUN02IZc/8PYrVo/FJwE4MEG9CtJwwDgYDVR0PAQH/BAQDAgGGMAoGCCqG
     3569SM49BAMDA2kAMGYCMQCpKjAd0MKfkFFRQD6VVCHNFmb3U2wIFjnQEnx/Yxvf4zgAOdktUyBFCxxg
     3570ZzFDJe0CMQCSia7pXGKDYmH5LVerVrkR3SW+ak5KGoJr3M/TvEqzPNcum9v4KGm8ay3sMaE641c=
     3571-----END CERTIFICATE-----
     3572
     3573 OISTE Server Root RSA G1
     3574=========================
     3575-----BEGIN CERTIFICATE-----
     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
     3601-----END CERTIFICATE-----
  • linguise/trunk/vendor/linguise/script-php/certificates/etag.txt

    r3358294 r3393354  
    1 "37a4f-63e55aaf768b0"
     1"3859e-642bd08b1bfbf"
Note: See TracChangeset for help on using the changeset viewer.