Plugin Directory

Changeset 3749545


Ignore:
Timestamp:
10/16/2026 01:58:54 AM (10 days ago)
Author:
domclic
Message:

3.3.27: glossary import reads columns by name, refuses one-column pastes

Location:
effortless-multisite-auto-translate/trunk
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • effortless-multisite-auto-translate/trunk/effortless-multisite-auto-translate.php

    r3749538 r3749545  
    33 * Plugin Name: EffortLess Multisite Auto Translate
    44 * Description: Translate Gutenberg posts and titles across a WordPress multisite using GPT. Includes retries, error logging, live log highlighting, and automatic sync of trash/delete operations.
    5  * Version: 3.3.26
     5 * Version: 3.3.27
    66 * Requires at least: 5.4
    77 * Requires PHP: 7.4
  • effortless-multisite-auto-translate/trunk/includes/class-elmat-admin.php

    r3749486 r3749545  
    13161316         * Import a glossary from an uploaded CSV/TSV file or text pasted from a spreadsheet.
    13171317         *
    1318          * The first row names the columns: source, default, then one column per
    1319          * destination site, named by its language (e.g. ko_KR, or ko), its address
    1320          * (e.g. /ko/) or "site_ID", as the export writes them. Comma, semicolon and
     1318         * The first row names the columns: the source term first, then "default" (the
     1319         * value for every language, optional) and one column per destination site, named
     1320         * by its language (e.g. ko_KR, or ko), its address (e.g. /ko/) or "site_ID", as the
     1321         * export writes them, in any order. Comma, semicolon and
    13211322         * tab separators are recognised. "Add and update" replaces the entries whose
    13221323         * source term is in the file and keeps the others; "Replace" keeps only the
    … …  
    13451346                if ( count( $rows ) < 2 ) {
    13461347                        $this->redirect_after_glossary_import( array( 'glossary-import-error' => 'empty' ) );
     1348                }
     1349                // A header with one column means the separators were lost (tabs copied as spaces
     1350                // from a chat or a web page): importing would turn whole lines into source terms.
     1351                if ( count( $rows[0] ) < 2 ) {
     1352                        $this->redirect_after_glossary_import( array( 'glossary-import-error' => 'columns' ) );
    13471353                }
    13481354
    … …  
    13701376                        }
    13711377                }
    1372                 $site_map = array();
    1373                 $ignored  = array();
     1378                // Columns are read by name: the first is the source term, "default" (or "all") the
     1379                // value for every language, any other a destination site.
     1380                $site_map    = array();
     1381                $ignored     = array();
     1382                $default_col = -1;
    13741383                foreach ( $header as $index => $name ) {
    1375                         if ( $index < 2 ) {
     1384                        if ( 0 === $index ) {
    13761385                                continue;
    13771386                        }
    13781387                        $key = strtolower( trim( str_replace( '-', '_', $name ), " /\t" ) );
     1388                        if ( in_array( $key, array( 'default', 'all', 'all_languages' ), true ) ) {
     1389                                $default_col = $index;
     1390                                continue;
     1391                        }
    13791392                        if ( isset( $lookup[ $key ] ) ) {
    13801393                                $site_map[ $index ] = $lookup[ $key ];
    … …  
    14031416                        $imported[ $source ] = array(
    14041417                                'source'   => $source,
    1405                                 'global'   => $clean( $row[1] ?? '' ),
     1418                                'global'   => $default_col > 0 ? $clean( $row[ $default_col ] ?? '' ) : '',
    14061419                                'per_site' => $per_site,
    14071420                        );
    … …  
    15081521                // phpcs:disable WordPress.Security.NonceVerification.Recommended -- Read-only result flags of the redirect after a nonce-checked import.
    15091522                if ( isset( $_GET['glossary-import-error'] ) ) {
    1510                         $error = sanitize_key( wp_unslash( $_GET['glossary-import-error'] ) );
    1511                         $text  = 'file' === $error
    1512                                 ? 'The file could not be read. Use a .csv, .tsv or .txt file of at most 1 MB.'
    1513                                 : 'Nothing to import: the table needs a header row (source, default, then one column per language) and at least one term.';
     1523                        $error    = sanitize_key( wp_unslash( $_GET['glossary-import-error'] ) );
     1524                        $messages = array(
     1525                                'file'    => 'The file could not be read. Use a .csv, .tsv or .txt file of at most 1 MB.',
     1526                                'columns' => 'Only one column was found: separate the columns with commas, semicolons or tabs (tabs copied from a chat or a web page often become spaces — use commas then). Nothing was imported.',
     1527                                'empty'   => 'Nothing to import: the table needs a header row (source, default, then one column per language) and at least one term.',
     1528                        );
     1529                        $text     = $messages[ $error ] ?? $messages['empty'];
    15141530                        echo '<div class="notice notice-error is-dismissible"><p><strong>📖 Glossary not imported.</strong> ' . esc_html( $text ) . '</p></div>';
    15151531                } elseif ( isset( $_GET['glossary-imported'] ) ) {
    … …  
    23502366                                                <summary style="cursor:pointer; font-weight:600;">⇅ Import / export</summary>
    23512367                                                <p style="color:#6b7280;">
    2352                                                         The file has one row per term: <code>source</code>, <code>default</code>, then one column per destination site, named by its language
    2353                                                         (<?php echo esc_html( implode( ', ', $this->glossary_site_columns() ) ); ?>). An empty cell means no value for that site.
    2354                                                         Export first to get the right columns, edit the file in a spreadsheet, then import it, or copy the cells from the spreadsheet and paste them below.
     2368                                                        One row per term. The first row names the columns: <code>source</code> first, then, in any order, <code>default</code> (the value for every language, optional) and one column per language
     2369                                                        (<?php echo esc_html( implode( ', ', $this->glossary_site_columns() ) ); ?>, or just the language code: en, fr, ko…). An empty cell means no value for that language.
     2370                                                        Separate the columns with commas, semicolons or tabs. Export first to get the right columns, edit the file in a spreadsheet, then import it, or copy the cells from the spreadsheet and paste them below.
    23552371                                                </p>
    23562372                                                <p>
    … …  
    23652381                                                        <p>
    23662382                                                                <label for="elmat_gloss_paste"><strong>…or paste the cells</strong> (header row included)</label><br>
    2367                                                                 <textarea id="elmat_gloss_paste" name="elmat_gloss_paste" rows="6" class="elmat-input" style="width:100%; font-family:monospace;" placeholder="source&#9;default&#9;ko_KR&#10;平溪&#9;&#9;핑시"></textarea>
     2383                                                                <textarea id="elmat_gloss_paste" name="elmat_gloss_paste" rows="6" class="elmat-input" style="width:100%; font-family:monospace;" placeholder="source,default,ko&#10;平溪,Pingxi,핑시"></textarea>
    23682384                                                        </p>
    23692385                                                        <p>
  • effortless-multisite-auto-translate/trunk/includes/class-elmat-translator.php

    r3749538 r3749545  
    5050        // -------------------------------------------------------------------------
    5151
    52         const PLUGIN_VERSION = '3.3.26';
     52        const PLUGIN_VERSION = '3.3.27';
    5353
    5454        const MAX_RETRIES        = 2;
  • effortless-multisite-auto-translate/trunk/readme.txt

    r3749538 r3749545  
    55Tested up to: 7.1
    66Requires PHP: 7.4
    7 Stable tag: 3.3.26
     7Stable tag: 3.3.27
    88License: GPLv2 or later
    99License URI: https://www.gnu.org/licenses/gpl-2.0.html
    … …  
    186186Only the most recent versions are listed here to stay within WordPress.org's changelog length limit; see the plugin's own repository for the full history.
    187187
     188= 3.3.27 =
     189* Fix: glossary import read the second column as the default value whatever its name, so a table like "source,fr,ko" put the French values into the default for every language. Columns are now read by name, in any order: "default" (or "all") is the default, any other name a language (ko_KR, ko, /ko/ or site_ID).
     190* Fix: a pasted table with a single column (tabs turned into spaces when copied from a chat or a web page) was imported as whole lines of source terms; it is now refused with an explanation, and nothing is imported.
     191
    188192= 3.3.26 =
    189193* Fix: translated SEO descriptions and other multi-sentence texts could start with or contain "__ELMAT_SEG_1__": the rule about these internal markers (used only for Custom HTML blocks) was sent with every text, and the model sometimes added markers of its own. The rule is now sent only with texts that contain markers, and markers in a translation whose source has none are removed.
    … …  
    353357* Fix: a background image or other `url(...)` reference inside the source site's Additional CSS was copied to destination sites unchanged, so it kept loading from the source site's own address. It now goes through the same media-URL rewrite already used for images inside pages and templates.
    354358
    355 = 3.2.55 =
    356 * Fix: a reusable/synced pattern embedded in a header, footer, template, or another pattern could render blank or show the wrong content on destination sites. That kind of pattern is referenced by a raw post ID with no slug involved, and the ID was being copied unchanged across sites, pointing at an unrelated (or missing) post on the destination. Every pattern reference is now remapped to the correct destination post, the same way navigation menu references already were.
    357 
    358359== Upgrade Notice ==
    359360
Note: See TracChangeset for help on using the changeset viewer.