Schimbă limba prin apăsarea unui buton

5 dec. 2011, 20:53:52
Vizualizări: 14.2K
Voturi: 22

Scopul este să ofer un buton/select drop-down sau similar pentru a schimba limba interfeței publice1) în timp real.

Ceea ce caut:

  • Plugin sau Cod din Temă...
  • ... sau Idei
  • Folosirea unei soluții alternative cu load_textdomain() ar fi apreciată pentru a lăsa traducerea în fișierele .po/.mo
  • Idei despre cum să analizezi șirurile în interfață (ex. ajax/php simplu/ini, json, fișiere xml) când nu te bazezi pe o funcție de textdomain

Notă:

1) Nu este vorba despre publicare în limbi diferite.

2) Nu am nevoie de cod pentru a crea drop-down-ul/butonul/orice altceva. Este doar despre codul/sistemul care furnizează șirurile pentru UI.

Mulțumesc!

5
Comentarii

Dacă te poți mulțumi cu o reîmprospătare a paginii, redefinirea constantei WPLANG ar putea fi o opțiune. Eu fac asta pe două site-uri cu conținut multilingv unde pluginul de multilingvism nu reușește să declanșeze traducerea interfeței. Dacă trebuie să fie o soluție AJAX/JSON, nu aș ști cum să ajut.

Johannes Pille Johannes Pille
5 dec. 2011 21:01:45

@JohannesPille În ce moment sau pe ce hook faci schimbarea? Apropo: Ai putea muta asta într-un răspuns. Deja merită un vot pozitiv. Mulțumesc.

kaiser kaiser
5 dec. 2011 21:04:22

Eu fac asta într-un plugin, fără a folosi hooks. Este o soluție destul de murdară și nu sunt foarte mândru de ea, dar și-a făcut treaba la momentul respectiv. Poți vedea codul pluginului în acest pastebin. Ce face este auto-explicativ. Site-ul de pe care am copiat asta utilizează ultima versiune gratuită a WPML. Bine, am mutat-o într-un răspuns.

Johannes Pille Johannes Pille
5 dec. 2011 21:33:59

URL-ul pastebin pare să nu mai funcționeze.

PapaFreud PapaFreud
20 mar. 2012 16:04:48

@JohannesPille Ai putea, te rog, să postezi codul tău ca o actualizare la întrebarea ta sau să adaugi un link pastebin care nu expiră?

kaiser kaiser
20 mar. 2012 16:59:56
Toate răspunsurile la întrebare 3
5
15

De departe cel mai bun (și mai ușor) mod este să folosești filtrul locale (în interiorul funcției get_locale()).

Mai întâi configurează o funcție rapidă pentru a prelua o limbă diferită de utilizat pe filtrul locale.

/**
 * O funcție care returnează locale-ul selectat de utilizator, dacă este stocat.
 */
function wpse35622_get_new_locale($locale=false){
$new_locale = get_user_meta(get_current_user_id(), 'wpse_locale', true);
    if($new_locale)
        return $new_locale;

    return $locale;
}

Am lăsat aceasta ca o funcție globală, ar putea fi utilă...? Restul plugin-ului l-am încapsulat într-o clasă.

Acesta creează un meniu derulant cu limbi posibile din care poți selecta.

Dezavantaje

  • Caută în wp-content/languages fișiere de forma xx_xx.mo. Dacă nu sunt de acea formă (nu toate fișierele .mo sunt), plugin-ul nu le va detecta!
  • Meniul derulant oferă o listă cu locale-urile găsite pentru a alege, dar acestea sunt afișate în formatul 'xx_xx' al locale-urilor, nu într-un mod prietenos pentru om - idei??
  • Oare $locale face altceva în afară de limbă? Dacă da, este încă posibil să obții același locale, dar să furnizezi traduceri alternative. Totuși, este mult mai complicat...

Codul

class SH_Pick_Lang{
    /**
     * Un nume unic pentru acest plugin
     */
    static $name ='sh_pick_lang';

    /**
     * Conectează funcțiile
     */
    public function __construct(){

        if( isset($_POST[self::$name]) ){
            add_action('locale',array($this,'update_user'));
        }
        add_filter( 'locale', 'wpse35622_get_new_locale',20 );
        add_action( 'wp_before_admin_bar_render', array( $this, 'admin_bar') );
    }

    /**
     * Actualizează opțiunea utilizatorului chiar la timp! Doar o dată, atenție...
     */
    function update_user($locale){
        $save_locale = $_POST[self::$name];
        update_user_meta(get_current_user_id(), 'wpse_locale', $save_locale);
        remove_filter(current_filter(),__FUNCTION__);
        return $locale;
    }

    /**
     * Adaugă un meniu derulant cu aspect oribil, sunt sigur că Kaiser îl va face să arate fantastic.
     */
    function admin_bar(){
        global $wp_admin_bar;

        $wp_admin_bar->add_menu( array(
            'id'        => 'shlangpick',
            'title'     => $this->wpse_language_dropown(),
        ) );
    }

    /**
     * Generează o listă cu locale-uri disponibile.
     * Caută în folderul wp-content/languages fișiere de forma xx_xx.mo
     * 
     * TODO Nu toate locale-urile sunt de forma xx_xx.mo - s-ar putea să rateze unele.
     * TODO O modalitate mai bună de a obține folderul wp-content/languages fără o constantă?
     */
    function wpse_language_dropown(){
         $name = self::$name;
         $locale = get_locale();
         $langs = get_available_languages();
         $langs[] = 'en_US';

         //Pentru etichete (format_code_lang)
         require_once( ABSPATH . 'wp-admin/includes/ms.php');

         $html = "<form method='post'> ";
         $html .= "<select name='{$name}'>";
         foreach($langs as $lang){
              $label = format_code_lang( $lang );
              $html .= "<option ".selected( $lang, $locale, false)." value='{$lang}'>{$label}</option>";
        }
         $html .= "</select>";
         $html .= get_submit_button('Schimbă Limba','secondary', 'submit', true);
         $html .= "</form >";

         return $html;
    }

} // Sfârșit Clasă

//Inițializează...
$sh_pick_lang = new SH_Pick_Lang();
5 iul. 2012 16:21:51
Comentarii

Vot efectuat (râzând și de toate comentariile inline). Recompensa este stabilită și ți va fi acordată imediat ce voi fi autorizat (mai am 23 de ore - atenționează-mă dacă uit).

kaiser kaiser
6 iul. 2012 14:36:16

Actualizat pentru a reflecta răspunsul la această întrebare.

Stephen Harris Stephen Harris
6 iul. 2012 14:57:16

Foarte tare. Am salvat. +1

Johannes Pille Johannes Pille
6 iul. 2012 19:50:13

Am observat că doar includerea fișierului 'wp-admin/includes/ms.php' declanșează o notificare de administrare pentru actualizarea site-urilor din rețea (când ai un singur site!). S-ar putea ca funcția format_code_lang() să necesite duplicare în interiorul unei funcții personalizate.

Stephen Harris Stephen Harris
6 iul. 2012 19:54:46

Am adăugat un Gist cu curățenia mea - nu am avut timp să o testez, deoarece în prezent mă joc cu folderele de plugin-uri și asta înseamnă că niciun alt plugin nu funcționează. Sper că poți lucra cu gist-ul oferit și poate să-l modifici/actualizezi. Pot acorda recompensa în jumătate de oră, dar trebuie să plec acum, așa că o voi trimite mâine. Mulțumesc pentru toată munca depusă - ar trebui să fie inclusă în orice instalare implicită :)

kaiser kaiser
7 iul. 2012 14:15:46
5

Dacă poți accepta o reîmprospătare a paginii, redefinirea constantei WPLANG ar putea fi o opțiune. Eu folosesc această metodă pe două site-uri cu conținut multilingv unde plugin-ul de multilingvism nu reușește să declanșeze traducerea interfeței.

5 dec. 2011 21:23:47
Comentarii

Hmm.. ai putea folosi ajax pentru a înlocui body-ul sau chiar întregul tag html al paginii, după executarea codului de mai sus (în aceeași cerere ajax), la onclick pe butonul tău sau ceva similar.

Joshua Abenazer Joshua Abenazer
5 dec. 2011 21:44:46

+1. Tocmai am verificat pastebin-ul tău. Asta înseamnă că configurația ta este http://example.com/language/whatever/, corect?

kaiser kaiser
5 dec. 2011 23:18:07

@kaiser Da, asta este configurația pe site-ul de unde provine codul. Dacă te interesează doar limba UI-ului, transmiterea unui query string în URL sau setarea unei variabile $_SESSION pentru a declanșa redefinirea WPLANG la următoarea încărcare de pagină ar trebui să fie suficientă. Dacă vrei să replici acest lucru pe un site multilingv, reține că, așa cum menționează comentariul din pastebin, codul funcționează cu WPML, ultima versiune gratuită. Nu poate fi replicat 1 la 1 cu qTranslate, deoarece acele URI-uri nu sunt fizice, ci rescrise prin modulul mod_rewrite din Apache. Sunt sigur că poate fi adaptat, dar nu va funcționa "ca atare".

Johannes Pille Johannes Pille
6 dec. 2011 00:40:40

Nu voi folosi qTranslate sau WPML. Este vorba doar despre limba interfeței. Adăugând $_SESSION) Problema mea este că, din câte știu, sunt destul de greu de gestionat și lucrurile dintre globale și array se pot amesteca ușor. Deci, dacă aș încerca să găsesc o metodă de a schimba WPLANG, atunci trebuie să găsesc o modalitate solidă de a o transmite de la o solicitare la alta. Poate add_query_arg/get_query_var va face treaba...

kaiser kaiser
6 dec. 2011 03:19:00

Mă gândeam din nou la asta (soluția încă nu este implementată în proiect): Ai putea înfășura asta într-un ajax? Cred că aceasta ar fi cea mai bună metodă pentru a ocoli problema. Vreau să închid întrebarea și să o marchez ca soluție :) Mulțumesc.

kaiser kaiser
4 feb. 2012 05:21:44
5

http://www.qianqin.de/qtranslate/

este ceea ce ai nevoie...

Editare I - după comentariu. În primul rând - mulțumesc tuturor care au contribuit la ploaia de voturi negative. (asta se întâmplă când nu vizitezi suficient de des :- ) )

acum - Funcția care gestionează comutarea se află în qtranslate-core. (începe aproximativ la linia 80 - depinde de versiunea pe care o dorești.)

Deoarece nu poți analiza un cod NON OOP, iar eu acum nu am altceva de făcut - am luat 10 minute pentru a sintetiza, parafraza și compila acel cod non-OOP cu încă un cod non-OOP pentru tine.

(scuze, - sunt un vechi mod de a face lucrurile aici)

Presupunând că am înțeles întrebarea && Presupunând că vrei ca codul să fie pentru administrator && presupunând că vei ști cum să-l adaptezi pentru front-end dacă dorești && presupunând că înțelegi că codul nu este optim:

<?php
/*
Plugin Name: k99 language switcher
Plugin URI: http://www.krembo99.com
Description: Admin Language switcher proof of concept only - do not use in production.
Version: 0.0.0.0.0.0.0.1
Author: Krembo99
Author URI: http://www.krembo99.com
*/ 
?>
<?php function k99_add_language_menu() {
    //  k99_load_ajax_display_functions();
?>  
    <div class="mgmb_help_setting">
    <?php _e('Limbă:','your_text_domain'); ?>
    <select name="mgmb_language_setting_help" id="mgmb_language_setting_help" onChange="mgmb_set_language_cookies(this.value);" >
        <option value="en_US" <?php if($_COOKIE['k99_userLang']=="en_US"){echo "selected";} ?>><?php _e('Engleză','your_text_domain');?></option>
        <option value="de_DE" <?php if($_COOKIE['k99_userLang']=="de_DE"){echo "selected";} ?>><?php _e('Germană','your_text_domain');?></option>
        <option value="zh_CN" <?php if($_COOKIE['k99_userLang']=="zh_CN"){echo "selected";} ?>><?php _e('Chineză','your_text_domain');?></option>
    </select>
    </div>
<?php   
}
// Acum setăm acea funcție să se execute când acțiunea de ajutor este apelată
add_filter('contextual_help', 'k99_add_language_menu');

// Cred că acesta este "lucrul cu browserul" tău misterios
function k99_language_change($lang){ 
 global $locale;
 // wp_cache_set( "language", $lang, 'options' );
    if ( isset($_COOKIE['k99_userLang'])) {
      $lang = $_COOKIE['k99_userLang'];
    }
    define( 'WPLANG', $lang );
 if($locale!= $lang) {
    $locale = $lang;
    load_plugin_textdomain('your_text_domain', false, dirname( plugin_basename(__FILE__) ) . '/lang'); // exemplu de utilizare pentru textdomain plugin
    load_plugin_textdomain('your_text_domain2', false, dirname( plugin_basename(__FILE__) ) . '/lang');
    load_plugin_textdomain('your_text_domain3', false, dirname( plugin_basename(__FILE__) ) . '/lang');
 }
  return $locale;
}
add_filter('locale', 'k99_language_change',99);

////////// +++++++++++++++  ÎNCEPUT CREARE COOKIES +++++++++++++++//////////////////
// Funcția Javascript setează cookie-urile pentru limbă
// acces extern
// @param lang - codul limbii
// @return NULL
// sau poate acesta este "lucrul cu browserul" misterios al OP??
    function mgmb_print_script() {
    ?>
    <script type="text/javascript" >
    function mgmb_set_language_cookies(lang){   
        var Then = new Date(); 
        Then.setTime(Then.getTime() + 10000*60*60*1000 ); //setează expirarea cookie-ului la 10000 ore (oră*minut*secunde*1000)
        document.cookie = "k99_userLang="+lang+";expires="+ Then.toGMTString();
        window.location.reload();
        } 
        </script>
<?php
} 
add_action('admin_print_scripts', 'mgmb_print_script');  // nu este modul corect de a face.. dar nu am timp acum.
?>

OBSERVAȚII:

1 - Acest cod a fost construit în 10 minute pe un calculator local în timp ce eram în aeroport. Motivul pentru care spun asta este că singura instalare WordPress pe care o am aici este destul de veche. (cred că 2.9).

Aceasta înseamnă că probabil meniul de limbă va apărea SUB div-ul de ajutor contextual, din cauza faptului că o nouă structură de div-uri a fost introdusă recent (cu file) - dar totuși ar trebui să funcționeze. (Promit să revin la asta mai târziu dacă am timp)

Dacă aș fi avut mai mult timp (și un cod WordPress nou aici) probabil aș fi integrat asta în noua bara de administrare cu add_action( 'admin_bar_menu', 'k99_add_language_menu_2', 1000 ); (am promis deja să revin la asta)

2 - ar trebui să ai fișierele de limbă enumerate în interiorul folderului "languages" în wp-content (mai bine??) sau wp-include. referitor la acest punct - codul este doar o dovadă a conceptului - și desigur dacă ai mai mult timp meniul ar trebui construit într-un mod dinamic și nu așa cum este făcut aici.

3 - WPLANG din config ar trebui să fie gol. Nu sunt sigur că va funcționa pe versiuni mai noi de wp dacă o limbă este deja setată.

4 - este o simplă dovadă a conceptului sintetizată și parafrazată construită pe ceea ce s-a văzut în codul qtranslate (tot o versiune veche) - deci majoritatea lucrurilor sunt făcute în modul "rapid", nu neapărat modul "corect" (cum ar fi adăugarea JS, fără textdomain dedicat etc..).

EDITARE II

cineva are noroc astăzi! (Întârziere la zbor)

Deoarece căutai "idei" pentru abordări, iată încă una faimoasă.

Nu se va potrivi într-un plugin, sau de fapt în orice alt mediu non-exclusiv, dar ar putea să-ți ofere o altă direcție despre cum să gestionezi "lucrul cu browserul".

Acest lucru va permite obținerea limbii cu un GET precum: <a href="index.php?lang=de">Germană</a> sau <a href="whatever.php?lang=ml">Limba mea</a>

Pentru a utiliza, poți crea un cod (să-l numim wp-langswitch.php)

 session_start();
 if ( isset( $_GET['lang'] ) ) {
    $_SESSION['WPLANG'] = $_GET['lang'];
    define ('WPLANG', $_SESSION[WPLANG]);
 } else {
    if(isset($_SESSION['WPLANG'])) {
        define ('WPLANG', $_SESSION['WPLANG']);
        $_GET['lang'] = $_SESSION['WPLANG'];
    } else {
        if ( isset( $_SERVER["HTTP_ACCEPT_LANGUAGE"] ) ) {
            $languages = strtolower( $_SERVER["HTTP_ACCEPT_LANGUAGE"] );
             $languages = explode( ",", $languages );
            $_SESSION['WPLANG'] = $languages[0];
            $_SESSION['WPLANG'] = str_replace("-", "_", $_SESSION['WPLANG']);
            $_GET['lang'] = substr($_SESSION['WPLANG'],0,2);
            define ('WPLANG', $_SESSION[WPLANG]);
        } else {
            define ('WPLANG', '');
        }
    }
 }

acum, în wp-config, chiar înainte de constanta WPLANG, trebuie să includem codul nostru.

 require_once(dirname(__FILE__).'/wp-langswitch.php');
 define ('WPLANG', ''); 

Acum - evident ar fi mai bine să adăugăm niște cookie-uri în amestec pentru a stoca limbile.

EDITARE III

Am promis să revin la asta mai târziu - iată cum (într-un mod foarte necorect și primitiv) ar putea fi integrat în bara de administrare (în loc de meniul de ajutor contextual)

 function k99_add_language_menu_bar() {
    global $wp_admin_bar, $wpdb;
    if ( !is_super_admin() || !is_admin_bar_showing() )
        return;
// Sunt sigur că poți găsi o modalitate de a construi array-ul citind folderul. Dacă nu, comentează și voi actualiza din nou.

if($_COOKIE['k99_userLang']=="en_US"){$sel==$_COOKIE['k99_userLang'];} 
if($_COOKIE['k99_userLang']=="de_DE"){$sel==$_COOKIE['k99_userLang'];}
if($_COOKIE['k99_userLang']=="zh_CN"){$sel==$_COOKIE['k99_userLang'];}

    $k99_lang = '';
    $k99_lang .= '<select name="mgmb_language_setting_help" id="mgmb_language_setting_help" onChange="mgmb_set_language_cookies(this.value);" >';
    $k99_lang .= '<option value="en_US" >Engleză</option>';
    $k99_lang .= '<option value="de_DE" >Germană</option>';
    $k99_lang .= '<option value="zh_CN" >Chineză</option></select>';

    /* Adaugă elementul principal de meniu siteadmin */
    $wp_admin_bar->add_menu( array( 'id' => 'Language', 'title' => __( 'limbă', 'your_text_domain3' ), 'href' => FALSE ) );
    $wp_admin_bar->add_menu( array( 'parent' => 'Language', 'title' => $k99_lang, 'href' => FALSE ) );
}
add_action( 'admin_bar_menu', 'k99_add_language_menu_bar', 999 );

Doar înlocuiește această funcție (sau adaugă) la vechiul cod (originalul NON-OOP non-plugin).

Cum am spus, nu am o instalare WordPress nouă aici pe local care să aibă bara de administrare - dar ar trebui să funcționeze.

(și apoi din nou, s-ar putea să nu funcționeze...dar sunt sigur că ai putea repara asta dacă chiar vrei - chiar dacă nu este OOP) :-)

trebuie să plec acum. sper că ajută cumva.

EDITARE IV - schimbat editarea III la versiunea funcțională pentru bara de meniu admin (cel puțin pe wp 3.4)

Deoarece nu aveam o instalare funcțională de 3.4 - și acum m-am întors și am - am editat soluția din Editarea III - și funcționează pentru mine.

În legătură cu voturile pozitive, nu-mi pasă deloc. Și nu am nevoie de nicio "răsplată" (orice ar fi acelea..) A fost doar de dragul exercițiului. Poate ar trebui să o dai autorului qTranslate. :-) în ciuda faptului că nu este OOP - este un plugin genial cu multe de învățat în multe domenii. considerând "când" a fost lansat acest plugin, este chiar uimitor. merită efortul indescriptibil de a citi un cod NON OOP - chiar dacă nu este - OOP. Și chiar dacă nu este indentat corect (doamne!).

5 dec. 2011 22:30:30
Comentarii

Poate există o soluție ascunsă în adâncul acestui cod, dar este aproape imposibil să descoperi toate căile, deoarece nu este scris în OOP. Dacă știi unde exact se află detectarea limbii (partea cu browserul) și cum filtrează șirurile gettext, te rog să-mi spui.

kaiser kaiser
5 dec. 2011 23:24:40

@kaiser - vezi editarea I pentru "partea cu browserul".

krembo99 krembo99
8 iul. 2012 12:19:43

@kaiser ..și vezi editarea II pentru mai multe detalii despre "partea cu browserul" - și editarea III pentru cum să încorporezi "partea cu browserul" în interiorul "browserului (partea)".

krembo99 krembo99
8 iul. 2012 12:49:32

Ok, am votat pozitiv (nu negativ pentru a anula aici), pentru efortul tău. Ideea de a folosi un cookie, este interesantă. Oricum, iată câteva observații: Editarea II va arunca o eroare după require(). Nu poți folosi define() pentru același șir de două ori. Editarea III are unele probleme cu limbile. Selectarea en_US nu ar face nimic(?), dar de_DE ar seta-o la English ;). Pe scurt: acord recompense și le ofer (de exemplu lui StephenHarris) pentru un răspuns complet și funcțional. Dacă ai ceva de genul acesta, te rog actualizează răspunsul tău (abordarea cu cookie interesantă) și poate voi adăuga și recompensa un bounty.

kaiser kaiser
8 iul. 2012 14:45:17

Te rog să nu lași comentarii pentru mine. Fă modificări în răspunsul tău, astfel încât toată lumea să poată citi ideile tale. Notă laterală: în opinia mea codul extern ar trebui întotdeauna adăugat ca Plugin/MU-Plugin/Theme/DropIn pentru a fi portabil.

kaiser kaiser
8 iul. 2012 18:40:23