Changeset 118322 in spip-zone


Ignore:
Timestamp:
Oct 28, 2019, 5:18:22 PM (5 months ago)
Author:
cedric@…
Message:

On separe les traducteurs des fonctions d'utilisation traduire() et traduire_texte()

Location:
_plugins_/traduire_texte/trunk
Files:
2 edited
1 copied

Legend:

Unmodified
Added
Removed
  • _plugins_/traduire_texte/trunk/inc/traducteurs.php

    r118321 r118322  
    206206
    207207}
    208 
    209 /**
    210  * Retourne un traducteur disponible
    211  * @return \TT_Traducteur|false
    212  */
    213 function TT_traducteur(){
    214         static $traducteur = null;
    215         if (is_null($traducteur)){
    216                 include_spip('inc/config');
    217 
    218                 $traducteur = false;
    219 
    220                 $traducteurs_dispo = [
    221                         'bing' => '_BING_APIKEY',
    222                         'google' => '_GOOGLETRANSLATE_APIKEY',
    223                         'yandex' => '_YANDEX_APIKEY',
    224                 ];
    225                 $classes = [
    226                         'bing' => 'TT_Traducteur_Bing',
    227                         'google' => 'TT_Traducteur_GGTranslate',
    228                         'yandex' => 'TT_Traducteur_Yandex',
    229                 ];
    230 
    231                 foreach ($traducteurs_dispo as $traducteur_dispo => $nom_constante){
    232                         if ((defined($nom_constante) and $key = constant($nom_constante))
    233                                 or $key = lire_config('traduiretexte/cle_' . $traducteur_dispo)){
    234                                 $class = $classes[$traducteur_dispo];
    235                                 $traducteur = new $class($key);
    236                         }
    237                 }
    238 
    239                 if (!$traducteur and defined('_TRANSLATESHELL_CMD')){
    240                         $traducteur = new TT_Traducteur_Shell();
    241                 }
    242         }
    243         return $traducteur;
    244 }
    245 
    246 
    247 /**
    248  * Découpe un code HTML en paragraphes.
    249  *
    250  * Découpe un texte en autant de morceaux que de balises `<p>`.
    251  * Cependant, si la longueur du paragraphe dépasse `$maxlen` caractères,
    252  * il est aussi découpé.
    253  * @param string $texte
    254  *     Texte à découper
    255  * @param int $maxlen
    256  *     Nombre maximum de caractères.
    257  * @param bool $html
    258  *     True pour conserver les balises HTML ; false pour les enlever.
    259  * @return array
    260  *     Couples [hash => paragraphe]
    261  */
    262 function TT_decouper_texte($texte, $maxlen = 0, $html = true){
    263         $liste = array();
    264         $texte = trim($texte);
    265 
    266         if (strlen($texte)==0){
    267                 return $liste;
    268         }
    269 
    270         $prep = html2unicode($texte);
    271         $options = $html ? (PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE) : PREG_SPLIT_NO_EMPTY;
    272         $prep = preg_split(",(<p\b[^>]*>),i", $prep, -1, $options);
    273 
    274         $last = ''; // remettre les <p> en début de ligne.
    275         foreach ($prep as $line){
    276                 if ($html){
    277                         if (preg_match(",^<p\b[^>]*>$,i", $line)){
    278                                 $last .= $line;
    279                                 continue;
    280                         } else {
    281                                 $line = $last . $line;
    282                                 $last = '';
    283                         }
    284                 } else {
    285                         $line = preg_replace(",<[^>]*>,i", " ", $line);
    286                 }
    287 
    288                 if ($maxlen){
    289                         // max line = XXX chars
    290                         $a = array();
    291                         while (mb_strlen($line)>$maxlen){
    292                                 $len = intval($maxlen*0.6); // 60% de la longueur
    293                                 $debut = mb_substr($line, 0, $len);
    294                                 $suite = mb_substr($line, $len);
    295                                 $point = mb_strpos($suite, '.');
    296 
    297                                 // chercher une fin de phrase pas trop loin
    298                                 // ou a defaut, une virgule ; au pire un espace
    299                                 if ($point===false){
    300                                         $point = mb_strpos(preg_replace('/[,;?:!]/', ' ', $suite), ' ');
    301                                 }
    302                                 if ($point===false){
    303                                         $point = mb_strpos($suite, ' ');
    304                                 }
    305                                 if ($point===false){
    306                                         $point = 0;
    307                                 }
    308                                 $a[] = trim($debut . mb_substr($suite, 0, 1+$point));
    309                                 $line = mb_substr($line, $len+1+$point);
    310                         }
    311                 }
    312                 $a[] = trim($line);
    313 
    314                 foreach ($a as $l){
    315                         $liste[md5($l)] = $l;
    316                 }
    317         }
    318 
    319         return $liste;
    320 }
    321 
    322 
    323 /**
    324  * Traduire sans utiliser le cache ni mettre en cache le resultat
    325  *
    326  * Retourne le texte traduit encadré d’une div indiquant la langue et sa direction.
    327  *
    328  * @param string $texte
    329  * @param string $destLang
    330  * @param string $srcLang
    331  * @param bool $raw
    332  * @return string|false
    333  */
    334 function traduire_texte($texte, $destLang = 'fr', $srcLang = 'en'){
    335         if (strlen(trim($texte))==0){
    336                 return '';
    337         }
    338 
    339         //$text = rawurlencode( $text );
    340         $destLang = urlencode($destLang);
    341         $srcLang = urlencode($srcLang);
    342 
    343         $traducteur = TT_traducteur();
    344         if (!$traducteur){
    345                 return false;
    346         }
    347 
    348         $trans = $traducteur->traduire($texte, $destLang, $srcLang);
    349 
    350         if (strlen($trans)){
    351                 $ltr = lang_dir($destLang, 'ltr', 'rtl');
    352                 return "<div dir='$ltr' lang='$destLang'>$trans</div>";
    353         } else {
    354                 return false;
    355         }
    356 }
    357 
    358 
    359 /**
    360  * Traduire avec un cache
    361  *
    362  * Le texte est découpé en paragraphe ; chaque paragraphe est traduit et mis en cache.
    363  * Si un paragraphe dépasse la taille maximale acceptée par le traducteur, il sera découpé
    364  * lui aussi en morceaux.
    365  *
    366  * @param string $texte
    367  * @param string $destLang
    368  * @param string $srcLang
    369  * @param array $options {
    370  *   @var bool $raw
    371  *         Retourne un tableau des couples [ hash => [source, trad, new(bool)] ]
    372  *   @var bool $throw
    373  *         Lancer une exception en cas d'erreur
    374  * }
    375  * @return string|false|array
    376  * @throws Exception
    377  */
    378 function traduire($texte, $destLang = 'fr', $srcLang = 'en', $options = array()){
    379         if (strlen(trim($texte))==0){
    380                 return '';
    381         }
    382 
    383         $traducteur = TT_traducteur();
    384         if (!$traducteur){
    385                 return false;
    386         }
    387 
    388         $hashes = TT_decouper_texte($texte, $traducteur->maxlen, true);
    389         $traductions = array_fill_keys(array_keys($hashes), null);
    390         $deja_traduits = sql_allfetsel(
    391                 array('hash', 'texte'),
    392                 "spip_traductions",
    393                 array(
    394                         sql_in('hash', array_keys($hashes)),
    395                         'langue = ' . sql_quote($destLang),
    396                 )
    397         );
    398 
    399         if ($deja_traduits){
    400                 $deja_traduits = array_column($deja_traduits, 'texte', 'hash');
    401                 foreach ($deja_traduits as $hash => $trad){
    402                         $traductions[$hash] = $trad;
    403                 }
    404         }
    405 
    406         $throw = ((isset($options['throw']) and $options['throw']) ? true : false);
    407 
    408         $todo = array_filter($traductions, 'is_null');
    409         $inserts = array();
    410         $fail = false;
    411         foreach ($todo as $hash => $dummy){
    412                 $paragraphe = $hashes[$hash];
    413                 $trad = $traducteur->traduire($paragraphe, $destLang, $srcLang, $throw);
    414                 if ($trad !== false){
    415                         $traductions[$hash] = $trad;
    416                         $inserts[] = array(
    417                                 "hash" => $hash,
    418                                 "texte" => $trad,
    419                                 "langue" => $destLang
    420                         );
    421                 } else {
    422                         spip_log('[' . $destLang . "] ECHEC $paragraphe", 'translate');
    423                         $fail = true;
    424                         break;
    425                 }
    426         }
    427         if ($inserts){
    428                 sql_insertq_multi("spip_traductions", $inserts);
    429         }
    430 
    431         if ($fail) {
    432                 return "";
    433         }
    434 
    435         // retour brut
    436         if (!empty($options['raw'])){
    437                 $res = array();
    438                 foreach ($hashes as $hash => $paragraphe){
    439                         $res[$hash] = array(
    440                                 'source' => $paragraphe,
    441                                 'trad' => $traductions[$hash],
    442                                 'new' => array_key_exists($hash, $todo)
    443                         );
    444                 }
    445                 return $res;
    446         }
    447 
    448         $traductions = implode(" ", $traductions);
    449         $ltr = lang_dir($destLang, 'ltr', 'rtl');
    450         return "<div dir='$ltr' lang='$destLang'>$traductions</div>";
    451 }
    452 
  • _plugins_/traduire_texte/trunk/inc/traduire_texte.php

    r118317 r118322  
    11<?php
    2 
    3 
    4 /** Description de l’outil de traduction */
    5 abstract class TT_Traducteur {
    6         /** @var string Nom de l’outil */
    7         public $type;
    8         /** @var string Clé d’api */
    9         public $apikey;
    10         /** @var int Maximum de caractères traitables en un coup */
    11         public $maxlen;
    12 
    13         /**
    14          * TT_Traducteur constructor.
    15          * @param string $apikey
    16          */
    17         public function __construct($apikey = null){
    18                 $this->apikey = $apikey;
    19         }
    20 
    21         /**
    22          * @param $texte
    23          * @param string $destLang
    24          * @param string $srcLang
    25          * @param bool $throw
    26          * @return string
    27          * @throws Exception
    28          */
    29         public function traduire($texte, $destLang = 'fr', $srcLang = 'en', $throw = false){
    30                 if (strlen(trim($texte))==0){
    31                         return '';
    32                 }
    33                 $len = mb_strlen($texte);
    34                 $extrait = mb_substr($texte, 0, 40);
    35                 spip_log('Trad:' . $this->type . ' ' . $len . 'c. : ' . $extrait . ($len>40 ? '...' : ''), 'translate' . _LOG_DEBUG);
    36                 $erreur = false;
    37                 $res = $this->_traduire($texte, $destLang, $srcLang, $erreur);
    38                 if ($erreur) {
    39                         spip_log($erreur, 'translate' . _LOG_ERREUR);
    40                         if ($throw) {
    41                                 throw new \Exception($erreur);
    42                         }
    43                 }
    44 
    45                 return $res;
    46         }
    47 
    48         abstract protected function _traduire($texte, $destLang, $srcLang, &$erreur);
    49 }
    50 
    51 /**
    52  * Traduire avec Bing
    53  */
    54 class TT_Traducteur_Bing extends TT_Traducteur {
    55         public $type = 'bing';
    56         public $maxlen = 10000;
    57 
    58         protected function _traduire($texte, $destLang, $srcLang, &$erreur){
    59                 // Bon sang, si tu n'utilises pas .NET, ce truc est documenté par les corbeaux
    60                 // attaquer le machin en SOAP (la méthode HTTP ne convient que pour des textes très courts (GET, pas POST)
    61                 try {
    62                         $client = new \SoapClient("http://api.microsofttranslator.com/V2/Soap.svc");
    63                         $params = array(
    64                                 'appId' => $this->apikey,
    65                                 'text' => $texte,
    66                                 'from' => $srcLang,
    67                                 'to' => $destLang
    68                         );
    69                         $translation = $client->translate($params);
    70                 } catch (Exception $e) {
    71                         $erreur = $e->getMessage();
    72                         return false;
    73                 }
    74 
    75                 return $translation->TranslateResult;
    76         }
    77 }
    78 
    79 /**
    80  * Traduire avec Google Translate
    81  */
    82 class TT_Traducteur_GGTranslate extends TT_Traducteur {
    83         public $type = 'google';
    84         public $maxlen = 4500;
    85 
    86         protected function _traduire($texte, $destLang = 'fr', $srcLang = 'en', &$erreur){
    87                 $destLang = urlencode($destLang);
    88                 $srcLang = urlencode($srcLang);
    89 
    90                 $url_page = "https://www.googleapis.com/language/translate/v2?";
    91                 $parameters = "key=" . $this->apikey . "&source=$srcLang&target=$destLang&q=" . rawurlencode($texte);
    92 
    93                 # $parameters_explode = explode("&", $parameters);
    94                 # $nombre_param = count($parameters_explode);
    95 
    96                 $ch = curl_init();
    97                 curl_setopt($ch, CURLOPT_URL, $url_page);
    98                 curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    99                 curl_setopt($ch, CURLOPT_REFERER, !empty($_SERVER["HTTP_REFERER"]) ? $_SERVER["HTTP_REFERER"] : "");
    100                 #curl_setopt($ch, CURLOPT_POST, nombre_param);
    101                 curl_setopt($ch, CURLOPT_POSTFIELDS, $parameters);
    102                 curl_setopt($ch, CURLOPT_HTTPHEADER, array('X-HTTP-Method-Override: GET'));
    103                 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    104                 $body = curl_exec($ch);
    105                 curl_close($ch);
    106 
    107                 $json = json_decode($body, true);
    108 
    109                 if (isset($json["error"])){
    110                         spip_log($json, 'translate' . _LOG_DEBUG);
    111                         $erreur = _T('traduiretexte:erreur') . " " . $json["error"]['code'] . ": " . $json["error"]['message'];
    112                         return false;
    113                 }
    114 
    115                 return urldecode($json["data"]["translations"][0]["translatedText"]);
    116         }
    117 }
    118 
    119 /**
    120  * Traduire avec Yandex
    121  */
    122 class TT_Traducteur_Yandex extends TT_Traducteur {
    123         public $type = 'yandex';
    124         public $maxlen = 10000;
    125 
    126         protected function _traduire($texte, $destLang = 'fr', $srcLang, &$erreur){
    127                 $destLang = urlencode($destLang);
    128                 //yandex peut deviner la langue source
    129                 if (isset($srcLang)){
    130                         $srcLang = urlencode($srcLang);
    131                         $lang = "$srcLang-$destLang";
    132                 } else {
    133                         $lang = $destLang;
    134                 }
    135 
    136                 $url_page = "https://translate.yandex.net/api/v1.5/tr.json/translate?";
    137                 //  & [format=<text format>] & [options=<translation options>] & [callback=<name of the callback function>]
    138                 $parameters = "key=" . $this->apikey . "&text=" . rawurlencode($texte) . "&lang=$lang";
    139 
    140                 $ch = curl_init();
    141                 curl_setopt($ch, CURLOPT_URL, $url_page);
    142                 curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    143                 curl_setopt($ch, CURLOPT_REFERER, !empty($_SERVER["HTTP_REFERER"]) ? $_SERVER["HTTP_REFERER"] : "");
    144                 curl_setopt($ch, CURLOPT_POSTFIELDS, $parameters);
    145                 curl_setopt($ch, CURLOPT_HTTPHEADER, array('X-HTTP-Method-Override: GET'));
    146                 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    147                 $body = curl_exec($ch);
    148                 curl_close($ch);
    149 
    150                 //{"code":200,"lang":"fr-en","text":["hello"]}
    151                 $json = json_decode($body, true);
    152 
    153                 if (isset($json['code']) && $json['code']>200){
    154                         spip_log($json, 'translate' . _LOG_DEBUG);
    155                         $erreur = _T('traduiretexte:erreur') . " " . $json['code'] . ": " . $json['message'];
    156                         return false;
    157                 }
    158 
    159                 return urldecode($json["text"][0]);
    160         }
    161 }
    162 
    163 
    164 class TT_Traducteur_Shell extends TT_Traducteur {
    165         public $type = 'shell';
    166         public $maxlen = 1000;
    167 
    168         public function _traduire($texte, $destLang = 'fr', $srcLang = 'en', &$erreur){
    169                 if (!defined('_TRANSLATESHELL_CMD')){
    170                         $erreur = "chemin de Translate shell non défini";
    171                         return false;
    172                 }
    173 
    174                 return $this->translate_line($texte, $destLang);
    175 
    176                 /*
    177                 // Équivalent ~ de l’ancien fonctionnement. (qui supprimait les tags html)
    178                 $liste = TT_decouper_texte($texte, $this->maxlen);
    179                 foreach ($liste as $l) {
    180                         spip_log("IN: " . $l, 'translate');
    181                         $trad = $this->translate_line($l, $destLang);
    182                         spip_log("OUT: " . $trad, 'translate');
    183                         $trans[] = $trad;
    184                 }
    185                 return join(" ", $trans);
    186                 */
    187         }
    188 
    189         public function translate_line($texte, $destLang){
    190                 if (strlen(trim($texte))==0){
    191                         return '';
    192                 }
    193                 $descriptorspec = array(
    194                         0 => array("pipe", "r"),
    195                         1 => array("pipe", "w")
    196                 );
    197                 $cmd = _TRANSLATESHELL_CMD . ' -b ' . ':' . escapeshellarg($destLang);
    198                 $cmdr = proc_open($cmd, $descriptorspec, $pipes);
    199                 if (is_resource($cmdr)){
    200                         fwrite($pipes[0], $texte) && fclose($pipes[0]);
    201                         $trad = stream_get_contents($pipes[1]);
    202                         fclose($pipes[1]);
    203                 }
    204                 return $trad;
    205         }
    206 
    207 }
    2082
    2093/**
     
    23327                                or $key = lire_config('traduiretexte/cle_' . $traducteur_dispo)){
    23428                                $class = $classes[$traducteur_dispo];
     29                                if (!class_exists($class)) {
     30                                        include_spip('inc/traducteurs');
     31                                }
    23532                                $traducteur = new $class($key);
     33                                break;
    23634                        }
    23735                }
  • _plugins_/traduire_texte/trunk/paquet.xml

    r118317 r118322  
    22        prefix="traduiretexte"
    33        categorie="outil"
    4         version="0.5.2"
     4        version="0.5.3"
    55        etat="dev"
    66        compatibilite="[3.0.0;3.2.*]"
Note: See TracChangeset for help on using the changeset viewer.