Como dice la documentación de PHP:
"La función gettext implementa el API del NLS (Native Language Support). Puede ser usuado para internacionalizar sus aplicaciones en PHP."
Drupal no utiliza esta extensión de PHP para el sistema de traducciones, sino que implementa su propio sistema de almacenar y presentar las cadenas en distintos idiomas.
Como resumen rápido, nuestras pruebas muestran de forma consistente mejoras de rendimiento que dependiendo de las circunstancias pueden variar entre un 10 y un 60 por ciento.
Como se almacenan las traducciones en Drupal
Drupal almacena todas las traducciones en tablas de la base de datos. Para no tener que hacer una consulta por cada traducción, el sistema de traducciones saca con una consulta de la base de datos todas las traducciones de longitud menor a 75 caracteres.
Este bloque inmenso de traducciones se almacena posteriormente en caché y es regenerado cada vez que se encuentra una traducción nueva.
Esto tiene las siguientes desventajas:
- La extracción de las traducciones de la base de datos para generar la caché se hace mediante una consulta muy costosa.
- El registro de traducciones en la caché es bastante grande y esto afecta al rendimiento y la escalabilidad de la web.
- Si un proceso encuentra que no tiene las traducciones en la caché y que no puede regenerarla (porque ya lo está haciendo otro proceso), hará una consulta por cada traducción que haya que imprimir en el sistema.
Como se puede ver, el sistema de traducciones de Drupal tiene algunas inconsistencias que pueden perjudicar el rendimiento. La solución que presentamos aquí evita estos problemas en los casos en que pueda aplicarse.
El enfoque Gettext
El parche es muy simple: cuando Drupal inicia el sistema de traducciones se comprueba si está disponible el fichero de traducciones compilado. Si es así, se carga en memoria y se hace que cualquier intento de traducción utilice llamadas a la extensión gettext de PHP. Podéis encontrar el parche adjunto al artículo.
Una vez aplicado el mismo, habrá que compilar un fichero de traducciones. Para ello, primero se necesita un fichero .po con todas las cadenas traducidas de vuestra web. Esto se consigue en admin/build/translate/export. Tras esto, obtendréis un fichero con nombre es.po (suponiendo que hemos exportado el idioma castellano).
La compilación del fichero se hace de la siguiente manera:
msgfmt -o messages.mo es.po
Con lo que obtendréis un fichero messages.mo. Este proceso puede dar algunos errores y es normal que haya que intentarlo más de una vez, sobre todo porque algunas cadenas aparecerán duplicadas en el fichero .po y necesitarás eliminar las duplicidades del fichero manualmente.
Una vez tenemos el fichero compilado, debemos ubicarlo en la ruta /sites/{domain}/locale/es/LC_MESSAGES/messages.mo dentro del directorio raiz de la instalación Drupal. Nótese que la ruta incluye un directorio con el nombre del idioma exportado, en este caso "es".
Con estos pasos, Drupal ya empezará a tomar las traducciones del fichero binario que hemos compilado.
Benchmarks
Hemos realizado algunas pruebas de estrés usando apache benchmark y el módulo devel. Hay que tener en cuenta que las mejoras en cuanto a consultas MySQL y memoria se toman como reducciones respecto al valor normal en Drupal, mientras que las de peticiones por segundo se toman como aumentos respecto al valor normal. Las pruebas han sido realizadas sobre un equipo MacBook Pro Core 2 Duo 2.66 Ghz y 4 GB RAM, en una instalación Drupal 6. Estos son los resultados con una instalación limpia de Drupal:
Clean Drupal 6 Install, Front page, Anonymous, No Cache.
| Normal | Con parche gettext | Mejora | |
| Peticiones / segundo | 33.4 | 36.47 | 9.19% |
| Consultas MySQL | 31 | 24 | 22.58% |
| Memoria | 1.03 | 0.95 | 7.77% |
Hemos probado también a desactivar la caché de locales.
| Peticiones / segundo | |
| Sin cache locale | 29.71 |
| Drupal Normal | 33.98 |
| Con parche gettext | 39.63 |

Y estos son los resultados para una instalación Drupal más compleja, con algunos campos cck creados de varios tipos, incluyendo imágenes y nodereferences. También se crearon (usando devel generate) 50 categorías, 100 usuarios, y 100 nodos.
Drupal, CCK fields, filefield, imagecache, 100 users, 100 nodes, Front page, Anonymous, No cache.
| Normal | Con parche gettext | Mejora | |
| Consultas MySQL | 146 | 122 | 16.44% |
| Memoria | 4.49 | 4.26 | 5.12% |
| Peticiones / segundo (anónimo) | |||
| Concurrencia: 1 petición | 5.86 | 6.03 | 2.90% |
| Concurrencia: 5 peticiones | 10.39 | 10.53 | 1.35% |
| Concurrencia: 25 peticiones | 8.83 | 10.09 | 14.27% |
| Peticiones / segundo (autenticado) | |||
| Concurrencia: 1 petición | 4.13 | 4.31 | 4.36% |
| Concurrencia: 5 peticiones | 6.28 | 7.05 | 12.26% |
| Concurrencia: 25 peticiones | 6.77 | 7.04 | 3.99% |
También hemos probado a deshabilitar la caché del módulo locale. Esto se puede hacer poniendo el valor de la variable locale_cache_strings a 0. Por supuesto, en este caso, ya que Drupal tiene que obtener todas las traducciones desde la base de datos, la mejora en rendimiento es mucho más grande.
| Normal | Con parche gettext | Mejora | |
| Consultas MySQL | 370 | 122 | 67.03% |
| Memoria | 4.48 | 4.26 | 4.91% |
| Peticiones / segundo (anónimo) | |||
| Concurrencia: 1 petición | 2.98 | 4.34 | 45.64% |
| Concurrencia: 5 peticiones | 4.76 | 7.34 | 54.20% |
| Concurrencia: 25 peticiones | 4.34 | 7.13 | 64.29% |
Unicef.es Portada
Seguimos con el benchmark, esta vez de una web real, compleja y con gran cantidad de contenido. Para la portada obtenemos los siguientes números:
| Peticiones / segundo | Mejora | |
| Sin Cache de locale | 0.69 | 0% |
| Drupal Normal | 0.75 | 8.70% |
| Con parche gettext | 0.82 | 18.84% |

Unicef.es Sección Actualidad
Para la sección actualidad, los resultados son los siguientes:
| Peticiones / segundo | Mejora | |
| Sin Cache de locale | 0.42 | 0% |
| Drupal Normal | 0.47 | 11.90% |
| Con parche gettext | 0.51 | 21.43% |

Unicef.es Nodo Noticia
Por último, si visitamos un nodo de tipo noticia, obtenemos la siguiente gráfica:
| Peticiones / segundo | Mejora | |
| Sin Cache de locale | 0.54 | 0% |
| Drupal Normal | 0.61 | 12.96% |
| Con parche gettext | 0.67 | 24.07% |

Conclusión
Como se puede apreciar en los benchmarks la mejora se presenta en todos los casos y para todos los parámetros medidos. Dependiendo de la instalación los resultados pueden ser más interesantes, pero en todos los casos se produce una mejora de nuestro sistema.

