GNU/Linux, Open Source, Cloud Computing, DevOps y más...

Solucionando problemas de Qtranslate con la traducción del slug

3 comentarios

A la hora de crear un sitio web multi-idioma basado en WordPress son básicamente dos las opciones que tenemos. Una implica crear páginas y artículos distintos, cada uno en su idioma, usando plugins del tipo de WPML, Polylang o xili-language. Otra introduce el contenido traducido en todos los idiomas que manejemos en el mismo post, separado por unas meta-etiquetas dentro del propio contenido, y es el propio plugin el que los separa en pestañas distintas dentro del editor de un único post existente.

Nota:

Los problemas y las soluciones descritas en este artículo son aplicables a estas versiones de los plugins:

  • Qtranslate 2.5.39
  • Qtranslate Slug 1.1.7

Este es el caso de Qtranslate, que resulta ser la solución más sencilla desde mi punto de vista, pues no es necesario modificar la base de datos de WordPress para crear relaciones entre un artículo y sus traducciones, al igual que para el resto de objetos de WordPress: etiquetas, categorías, widgets, menús, etc. Por eso Qtranslate es mi opción preferida a la hora de crear un sitio web multi-idioma en WordPress.

Sin embargo, Qtranslate no está exento de complicaciones, pues tiene algunos fallos que es necesario solventar para que nuestro sitio sea realmente multi-idioma:

1. Qtranslate no ofrece soporte para traducción de URL’s y slugs

El principal impedimento que encontramos es que Qtranslate no ofrece soporte para la traducción de las URL’s de nuestro sitio, lo cual supone una gran limitación que puede invalidar completamente su uso y forzarnos a optar por otra alternativa. Afortunadamente existe un plugin complementario que nos permitirá traducir nuestras URL’s: Qtranslate Slug. Soporta la traducción no sólo de los slugs de nuestros artículos y páginas, sino también de etiquetas y categorías.

Qtranslate Slug

2. Qtranslate Slug provoca que se genere contenido duplicado en nuestro sitio

Sin embargo, Qtranslate no resuelve otro incómodo problema: aunque nuestras URL’s sean traducidas correctamente con Qtranslate Slug, cuando solicitemos cualquier artículo, página o categoría empleando el slug en el idioma por defecto de nuestro sitio, da igual qué variable o subdirectorio de idioma indiquemos en nuestra URL, pues se mostrará el mismo contenido siempre. Así, siendo el idioma por defecto de nuestro sitio el inglés, si solicitamos la URL /en/article-name obtendremos exactamente el mismo resultado que si solicitamos /es/article-name, lo cual es erróneo, pues la dirección del artículo en español es /es/nombre-articulo. La dirección /es/article-name no tiene sentido y debería devolver un error 404: no encontrado. Sin embargo se nos muestra el artículo en inglés, con exactamente el mismo contenido que en el caso de /en/article-name, lo cual es contenido duplicado que Google y otros buscadores pueden llegar a indexar o al menos marcar como contenido duplicado y crearnos problemas.

Esto mismo ocurre con páginas, categorías y etiquetas. Por ejemplo, la dirección /es/category/programming mostrará el mismo contenido que /en/category/programming.

Para solventar esto y mostrar errores 404 de página no encontrada cuando solicitamos URL’s incorrectas debemos hacer algunas modificaciones en el fichero wp-content/plugins/qtranslate-slug/qtranslate-slug.php del plugin Qtranslate Slug.

882                         // <DLA>
883                         if (!$post)
884                         {
885                                 $query['name'] = 'dladladladla';
886                                 return $query;
887                         }
888                         // </DLA>

...

900                         // <DLA>
901                         if (!$term)
902                         {
903                                 $query['category_name'] = 'dladladladla';
904                                 return $query;
905                         }
906                         // </DLA>

...

1068                     /*} else {
1069                         $last_part = array_pop($parts);
1070                         $page_id = $wpdb->get_var( "SELECT ID FROM $wpdb->posts WHERE post_name = '$last_part' AND (post_type = '$post_type_sql' OR post_type = 'attachment')" );
1071 
1072                         if ( $page_id )
1073                                 return $page_id;
1074                     }*/

...

1560                 /*if ( !$term && 'slug' == $original_field ) {
1561                         $field = 't.slug';
1562                         $term = $wpdb->get_row( $wpdb->prepare( "SELECT t.*, tt.* FROM $wpdb->terms AS t INNER JOIN $wpdb->term_taxonomy AS tt ON t.term_id = tt.term_id WHERE tt.taxonomy = %s AND $field = %     s LIMIT 1", $taxonomy, $value) );
1563                 }*/

3. La paginación no funciona correctamente

Cuando nos encontramos en una página interna del blog, de una categoría o de posts archivados y seleccionamos otro idioma desde el widget de cambio de idioma la información de paginación se pierde y siempre nos lleva a la página principal, con lo cual nunca podemos ver la versión de dicha página en los otros idiomas disponibles de nuestro sitio web. Es decir, si accedemos a /es/blog/page/2 y cambiamos el idioma a inglés, en lugar de mostrarse la página /en/blog/page/2 se muestra /en/blog.


Error: Your Requested widget " ai_widget-6" is not in the widget list.
  • [do_widget_area above-nav-left]
    • [do_widget_area above-nav-right]
      • [do_widget_area footer-1]
        • [do_widget id="wpp-4"]
      • [do_widget_area footer-2]
        • [do_widget id="recent-posts-4"]
      • [do_widget_area footer-3]
        • [do_widget id="recent-comments-3"]
      • [do_widget_area footer-4]
        • [do_widget id="archives-4"]
      • [do_widget_area logo-bar]
        • [do_widget id="oxywidgetwpml-3"]
      • [do_widget_area menu-bar]
        • [do_widget id="search-3"]
      • [do_widget_area sidebar]
        • [do_widget id="search-4"]
        • [do_widget id="ai_widget-2"]
        • [do_widget id="categories-5"]
        • [do_widget id="ai_widget-3"]
        • [do_widget id="ai_widget-4"]
        • [do_widget id="ai_widget-5"]
      • [do_widget_area sub-footer-1]
        • [do_widget id="text-4"]
      • [do_widget_area sub-footer-2]
        • [do_widget_area sub-footer-3]
          • [do_widget_area sub-footer-4]
            • [do_widget_area upper-footer-1]
              • [do_widget id="search-2"]
              • [do_widget id="recent-posts-2"]
              • [do_widget id="recent-comments-2"]
              • [do_widget id="archives-2"]
              • [do_widget id="categories-2"]
              • [do_widget id="meta-2"]
            • [do_widget_area upper-footer-2]
              • [do_widget_area upper-footer-3]
                • [do_widget_area upper-footer-4]
                  • [do_widget_area widgets_for_shortcodes]
                    • [do_widget id="search-5"]
                    • [do_widget id="ai_widget-6"]
                  • [do_widget_area wp_inactive_widgets]
                    • [do_widget id="wpp-2"]
                    • [do_widget id="text-1"]
                    • [do_widget id="recent-posts-3"]
                    • [do_widget id="categories-3"]
                    • [do_widget id="archives-3"]
                    • [do_widget id="icl_lang_sel_widget-3"]

                  Yo lo he solucionado añadiendo las siguientes líneas al final de la función filter_request() del fichero qtranslate-slug.php, aunque probablemente haya una forma mejor si buceamos más en el código de Qtranslate Slug:

                   972                 // <DLA>
                   973                 // Add support for pagination to qtranslate slug widget
                   974                 if (isset($query['paged']))
                   975                 {
                   976                         if ($this->current_url == null)
                   977                         {
                   978                                 global $q_config;
                   979                                 foreach ($q_config['enabled_languages'] as $lang)
                   980                                 {
                   981                                         $this->current_url[$lang] = '/'.$lang . str_replace('/'.qtrans_getLanguage().'/', '/'.$lang.'/', $_SERVER['REQUEST_URI']);
                   982                                 }
                   983                         }
                   984                         else
                   985                         {
                   986                                 foreach ($this->current_url as $lang => $language_url)
                   987                                 {
                   988                                         $this->current_url[$lang] .= 'page/'.$query['paged'];
                   989                                 }
                   990                         }
                   991                 }
                   992                 // </DLA>
                  

                  4. Qtranslate genera enlaces hreflang erróneos

                  Otro efecto colateral indeseable que sufriremos por no ofrecer Qtranslate soporte para traducir el slug de las URL’s es el de que se creen enlaces hreflang erróneos en la sección HEAD de todas nuestras páginas. Así, la URL de este mismo post aparecería como /en/solucionando-problemas-qtranslate-slug/ en lugar de /es/solucionando-problemas-qtranslate-slug/ en la versión en español, mientras que en la versión en inglés aparecería como /es/fixing-qtranslate-slug-problems/ en lugar de /en/fixing-qtranslate-slug-problems/, lo que resulta en un montón de errores 404 de página no encontrada en las Webmaster Tools de Google.

                  Podemos solucionar esto realizando una pequeña modificación en el fichero wp-content/plugins/qtranslate/qtranslate_hooks.php:

                  Antes:
                   41         foreach($q_config['enabled_languages'] as $language) {
                   42                 if($language != qtrans_getLanguage())
                   43                         echo '<link hreflang="'.$language.'" href="'.qtrans_convertURL('',$language).'" rel="alternate" />'."\n";
                   44         }        
                  
                  Después:
                   41         foreach($q_config['enabled_languages'] as $language) {
                   42                 if($language != qtrans_getLanguage())
                   43                 // <DLA>
                   44                 {       
                   45                         global $qtranslate_slug;
                   46                         $language_url = $qtranslate_slug->get_current_url($language);
                   47                         //echo '<link hreflang="'.$language.'" href="'.qtrans_convertURL('',$language).'" rel="alternate" />'."\n";
                   48                         echo '<link hreflang="'.$language.'" href="'.$language_url.'" rel="alternate" />'."\n";
                   49                 }
                   50                 // </DLA>
                   51         }
                  

                  5. Comments reply links doesn’t include language

                  Todos los comentarios de un post incluyen normalmente un enlace «Responder» que no es filtrado por Qtranslate para añadir la variable o subdirectorio de idioma a la URL que aparece en el atributo href de dicho enlace. Esto provoca que enlaces que deberían ser como /es/solucionando-problemas-de-qtranslate-con-la-traduccion-del-slug/?replytocom=1868#respond aparezcan como /solucionando-problemas-de-qtranslate-con-la-traduccion-del-slug/?replytocom=1868#respond, lo que provoca también más errores 404 en las Herramientas para Webmasters de Google.

                  Podemos solucionarlo añadiendo estas líneas al fichero qtranslate-slug.php:

                   533                 // <DLA>
                   534                 add_filter( 'comment_reply_link', array(&$this, 'fix_comment_reply_link'));
                   535                 add_filter( 'cancel_comment_reply_link', array(&$this, 'fix_cancel_comment_reply_link'));
                   536                 // </DLA>
                   537 
                   538         }
                   539 
                   540         // <DLA>
                   541         /*
                   542          * fixes comments reply link adding language subdirectory to href URL
                   543          */
                   544         function fix_comment_reply_link($link)
                   545         {
                   546                 preg_match('/href=\'([^\']*)\'/', $link, $href);
                   547 
                   548                 return str_replace($href[1], qtrans_convertURL($href[1]), $link);
                   549         }
                   550         /*
                   551          * Fixes cancel comment reply link by adding language subdirectory to href URL
                   552          */
                   553         function fix_cancel_comment_reply_link($link)
                   554         {
                   555                 preg_match('/href=\"([^\']*)\"/', $link, $href);
                   556 
                   557                 return str_replace($href[1], qtrans_convertURL($href[1]), $link);
                   558         }
                   559         // </DLA>
                  

                  6. Google XML Sitemaps v3 for Qtranslate no funciona con Qtranslate Slug

                  Este problema hace que se generen URL’s incorrectas en nuestro mapa del sitio, las cuales provocarán que se genere un sitemap plagado de URL’s que devuelven un error 404 de página no encontrada. En este otro artículo describo mejor la problemática y su resolución: Google XML Sitemaps v3 for Qtranslate no funciona con Qtranslate Slug.

                   

                  Sobre el autor

                  Daniel López Azaña
                  Arquitecto de soluciones Cloud AWS & Linux Sysadmin Freelance

                  Emprendedor, generador de ideas y mente inquieta. Apasionado de las nuevas tecnologías, especialmente de los sistemas Linux y del software libre. Me gusta escribir además sobre actualidad tecnológica, Cloud Computing, AWSi, DevOps, DevSecOps, seguridad, desarrollo web y programación, SEO, ciencia, innovación, emprendimiento, etc.

                  DanielSolucionando problemas de Qtranslate con la traducción del slug

                  Artículos relacionados

                  3 comentarios

                  Unirte a la conversación
                  • sara - 27/12/2016 responder

                    Buenas,
                    Esto ya no funciona así, verdad?
                    Tengo el problema nº4 y estoy usando las versiones:
                    QTranslate Slug 1.1.18
                    QTranslate X 3.4.6.8
                    He colocado el código que indicas en q-translate-hooks.php pero me devuelve error 500.
                    ¿Alguien sabe cómo solucionarlo?

                    Muchas gracias

                  • José - 30/04/2017 responder

                    Hola Daniel,

                    En mi opinión generar un error 404 para resolver el problema de contenido duplicado no es una opción aceptable, ya que puede generar una cantidad importante de rebotes de usuarios que se encuentran que una página que puede que exista en su idioma local devuelve un error 404.

                    Lo ideal sería que si el idioma actual no coincide con el del slug, se produzca una redirección al contenido correcto. Por poner un ejemplo, si un usuario accede a /es/en-slug redireccionara a /es/es-slug.

                    ¿Sería posible modificando el plugin añadir esta funcionalidad?

                    Un saludo.

                    Daniel - 23/05/2017 responder

                    Gracias José. Yo creo que nuestra web nunca debería generar una URL tipo /es/en-slug, ya que si no está traducida no existirá tampoco /en/en-slug, y si lo está debería tener también traducido el slug, por lo que poner un idioma y el slug en otro idioma yo lo considero un error. En cualquier caso, antes esta situación puede perfectamente redirigirse al usuario al slug correcto en el idioma seleccionado en lugar de mostrarse un error 404, pero creo que esto que tú planteas es más costoso de implementar. No obstante, el código puede modificarse todo lo que se quiera, por lo que sí creo que es posible modificar el plugin para obtener esa funcionalidad.

                  Deja una respuesta

                  Tu dirección de correo electrónico no será publicada.