sábado, 10 de diciembre de 2011

Plantillas javascript

Las aplicaciones web que usan AJAX suelen seguir un patrón similar:
1) Se lanza un evento javascript
2) Se genera una petición al servidor
3) El servidor produce código javascript de vuelta con el objetivo de añadir/eliminar HTML de la página.

Cuando hay que insertar gran cantidad de HTML el código javascript producido suele ser poco mantenible, el primer planteamiento es crear una gran cadena de marcado HTML para insertarla en algún lugar de la página.

Por suerte, existe un plugin para la librería jQuery llamado jQuery Templates que elimina este problema.

Para usar este plugin, podemos definir una plantilla javascript de la siguiente forma:
<script id="templateId" type="text/x-jquery-tmpl">
${templateText}
</script>
Siguiendo este ejemplo, con el id 'templateId' recuperaremos posteriormente la plantilla y podremos hacer la sustitución de 'templateText' con la siguiente llamada.
$("#templateId").tmpl({templateText:"Hello world"})
Como se puede ver, es similar a cualquier sistema de plantillas, se puede interpolar marcado HTML, crear condicionales:
<script id="templateId" type="text/x-jquery-tmpl">
{{if error}}
<h2>Error!</h2>
{{else}}
<h1>OK</h1>
{{/if}}
</script>
$("#templateId").tmpl({error:false})
O incluso bucles:
<script id="templateId" type="text/x-jquery-tmpl">
<h1>${title}</h1>
{{each items}}
<li>${$value}</li>
{{/each}}
</script>
$("#templateId").tmpl({title:"Titulo", items:["uno", "dos", "tres"]})



domingo, 18 de septiembre de 2011

Batch processing en rails

En aplicaciones web con cierta complejidad, es común que aparte de responder a las peticiones de los clientes, se necesite realizar trabajos batch o simplemente migrar la base de datos a una nueva estructura.

Cuando la base de datos crece, aparecen nuevos problemas, uno de ellos es que las tablas de la base de datos pueden no caber en memoria. En hostings baratos este problema se acentúa ya que no se suele contar con demasiada RAM. Con ruby on rails es muy fácil solventar esta dificultad.

Tomando como ejemplo una tabla muy grande de usuarios en la que hay que recalcular un campo para cada usuario.
User.find_each{|u| u.karma = calculate_karma(:user => u)}
find_each toma bloques de 1000 usuarios y va devolviendo de uno en uno de forma transparente, se utilizan 1000 entradas por defecto pero se puede cambiar mediante el parámetro batch_size.
User.find_each(:batch_size => 200){|u| u.karma = calculate_karma(:user => u)}
find_each se implementa usando find_in_batches, se puede llegar a mayor nivel de control usando esta función que devuelve directamente los grupos de entradas.
User.find_in_batches(:batch_size => 2000){|group| group.each{|u| u.karma = calculate_karma(:user => u)}}
Puede que este último ejemplo parezca más complejo sin ningún tipo de beneficio, pero sería muy útil en caso de querer paralelizar el proceso.
User.find_in_batches(:batch_size => 2000){|group| Process.fork{calculate_karma(:group => group)}}

domingo, 4 de septiembre de 2011

Temporizadores en javascript: PollJS

Realizar tareas regulares en el tiempo en una web con javascript es una tarea algo pesada. PollJS es una librería muy pequeña y sencilla que facilita algo esta tarea.

Un ejemplo de una tarea regular con PollJS.
Poll.start({
    name: "refresh_list",
    interval: 1000,
    action: function(){}
});
Esa es la sintaxis básica para crear una tarea con PollJS, evidentemente nos deja establecer un intervalo de espera entre repeticiones y definir la acción que queremos ejecutar. Además se puede dar nombre a cada tarea para referenciarla posteriormente, por ejemplo, para detenerla.
Poll.stop("refresh_list");
Existe otra forma de detener una tarea, devolviendo false en la función que se pasa como acción se detiene el temporizador.

Con esta librería podemos además definir un número de reintentos máximo y una función de fallback si en ninguno de los intentos se ha detenido el temporizador.
Poll.start({
    name: "refresh_list",
    action: function(){},
    interval: 1000, 
    attempts: 5,
    fallback: function(){}
});

miércoles, 24 de agosto de 2011

Visor de PDF en HTML5

Andreas Gal (investigador de Mozilla Corporation) ha publicado la librería javascript PDF.js

Con esta librería se pueden visualizar ficheros PDF en el navegador sin plugins externos, las ventajas son claras, no hay necesidad de un programa externo, es multiplataforma, más seguro y provee de mayor interacción con el navegador.

PDF.js está todavía en proceso de desarrollo y pero el autor pretende lanzar una extensión de firefox para abrir los ficheros PDF directamente en el navegador.
Por ahora para visualizar un fichero PDF se crea dinámicamente un elemento canvas en el que se muestra la información, sin embargo, se planea migrar a SVG para permitir selección de texto, búsquedas y mayor interacción con el fichero.

Es un paso importante hacer que este tipo de ficheros se integren completamente en la web, ya algunos buscadores indexan su texto y lo incluyen en las búsquedas.

Por contra, tanto canvas como SVG están disponibles solo en los navegadores que soportan HTML5 y aún no hay un porcentaje aceptable de usuarios que usen este tipo de navegadores para aceptar esta solución como medida única.

viernes, 3 de junio de 2011

Extensión de clases en Scala

En algunos lenguajes de programación dinámicos como ruby se permite añadir funcionalidad a clases ya existentes. Cuando esto ocurre, se dice que las clases en ese lenguaje son 'abiertas'.

Un lenguaje de programación con clases abiertas añade mucha flexibilidad para el programador, sin embargo, esta flexibilidad hace que sea más difícil auditar el código.

La principal ventaja de esta técnica es poder aumentar la funcionalidad de las clases que proporciona en lenguaje. Al tener unos tipos básicos con una interfaz más rica, el código comienza a ser más sencillo y se reduce el número de líneas de código para desarrollar una funcionalidad.

En Scala, las clases no son abiertas, sin embargo, tiene un mecanismo similar con el que se pueden llegar a resultados no muy distintos.

Ejemplo:

class RomanNumber(val number:Int){
def toRoman:String = {
if(number == 1) return "I";
else if(number == 2) return "II";
else if(number == 3) return "III";
else if(number == 4) return "IV";
else if(number == 5) return "V";
else return "Unknown";
}
}

object Main extends Application{
implicit def intRomanNumber(x:Int) = new RomanNumber(x);

override def main(args: Array[String]){
println(1.toRoman);
println(3.toRoman);
println(5.toRoman);
println(6.toRoman);
}
}

En este ejemplo se crea una clase 'RomanNumber' que contiene la funcionalidad que necesitamos añadir a los enteros 'toRoman'.

El código resultaría muy redundante si cada vez que queremos usar el método 'toRoman' necesitamos crear una instancia de la clase y pasarle como argumento el entero. Algo como: new RomanNumber(4).toRoman.

Para este tipo de casos, Scala provee del mecanismo de conversión implícita, en el ejemplo el método 'intRomanNumber'.
Al definir un método como 'implicit' se llamará para hacer el correspondiente cambio de tipos como se le indique, en este caso creando una instancia de 'RomanNumber'.

El resultado final es el que aparece en el ejemplo, parece que los métodos añadidos mediante conversión implícita pertenezcan a la clase original, muy similar al caso de los lenguajes dinámicos y las clases abiertas.

sábado, 16 de abril de 2011

attr_accessor_with_default

Un pequeño tip sobre los atributos en ruby on rails, normalmente en cualquier clase se pueden declarar atributos con attr_accessor, pero, si lo que se necesita es un atributo que tenga un valor por defecto, existe una función menos conocida attr_accessor_with_default.

Un ejemplo

class Example
attr_accessor_with_default :attr, 'default message'
end

e = Example.new
e.attr
=> 'default message'

domingo, 20 de marzo de 2011

Propagación de eventos en jQuery

La primera aproximación de asignación de eventos a los elementos del DOM es la más sencilla, simplemente se establece el callback a ejecutar en el elemento que posee el evento.

$('#element').click(function(){alert('hello');})

Usando este método se disparará el evento del elemento con id 'element', después su padre, y así sucesivamente.

La segunda posibilidad es usar 'live', de esta forma todos los elementos futuros que cumplan con el selector dispararán el evento.

$('#element').live('click', function(){alert('hello');})

Esta aproximación asigna el callback a la raíz del DOM (document) de tal forma que cada vez que se dispara un evento si coincide tanto en tipo como en su selector, se dispara el callback.
Esta implementación, aún siendo muy útil puede dar lugar a comportamientos inesperados, el callback establecido con 'live' se ejecutará el último en la jerarquía de propagación del evento.

'live' no es más que una particularización de 'delegate'. 'delegate' se puede usar para hilar más fino en el establecimiento de la respuesta a eventos.

$('#parent').delegate('#element', 'click', function() { alert("hello") });

En este caso, establecemos el callback en 'parent' en lugar de en document, por lo demás el funcionamiento es similar a 'live'.
Cada vez que el evento llegue a 'parent' se comprobará si coincide tanto en tipo como en el selector, de ser cierto se dispara el callback.

'delegate' es mucho más eficiente que 'live' puesto que solo comprueba los eventos tomando como raíz el elemento que le indicamos en lugar de todo el documento como es el caso de 'live'. Aún así el problema en el orden de propagación aparece al igual que en 'live'.

jueves, 3 de febrero de 2011

Generar proyectos ruby on rails con versiones anteriores

Después del cambio de versión de ruby on rails de la rama 2 a la 3, surge un caso muy típico, tener instalado rails 3 y querer generar un proyecto con la versión 2.

Para generar un proyecto de ruby on rails con una versión anterior que tengamos instalada tan solo hay que ejecutar lo siguiente:

rails _VERSION_ proyecto

Donde VERSION es la numeración específica de la versión de rails, por ejemplo, para crear un proyecto con la versión 2.3.8 (actualmente la última de la rama 2).

rails _2.3.8_ proyecto

jueves, 20 de enero de 2011

Depuración android por red

Hay dispositivos android que no permiten la depuración a través del conector USB, aún así, es posible usarlos para desarrollo usando la conectividad por Wi-Fi.

Simplemente hay que conectar el dispositivo a la misma red Wi-Fi que el PC desde el que estamos desarrollando y ejecutar el comando:

adb connect ip:5555

Donde ip es la dirección IP del dispositivo en la interfaz Wi-Fi.
A partir de ahí se puede usar adb igual que cuando está conectada la depuración USB, se puede usar la shell, la transferencia de ficheros, etc, incluso el android SDK sin necesidad de cables.

viernes, 7 de enero de 2011

Conocer el método desde el que una función es llamada en Java

El lenguaje de programación Java en sus últimas versiones tiene algunas construcciones que permiten introspección.

Como ejemplo en el siguiente trozo de código la función 'print' tiene un comportamiento u otro dependiendo de que método le llama. En general esto no es una buena práctica de programación pero sirve como ejemplo ilustrativo.

public class Ejemplo{
public static void print(){
StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
StackTraceElement e;
String str = stackTraceElements[2].getMethodName();

if(str.equals("other")){
System.out.println("Other message!");
}
else{
System.out.println("Hello world!");
}
}

public static void other(){
print();
}

public static void main(String[] args){
print();
other();
}
}

La llamada 'Thread.currentThread().getStackTrace()' devuelve un array de elementos 'StackTraceElement', cada uno de estos elementos representa una llamada de la pila de llamadas a funciones.

En el ejemplo anterior se consulta el nombre del método, pero se pueden extraer más datos, más información en el javadoc de StackTraceElement.

sábado, 25 de diciembre de 2010

Javascript orientado a objetos

Debido al gran auge de la web, últimamente han surgido numerosas librerías y tutoriales acerca de como programar javascript orientado a objetos.

No es difícil encapsular código javascript simulando que se está trabajando con clases.

function Article(title, body){
this.title = title;
this.body = body;
}

var a = new Article('titulo', 'noticia')

Incluso se puede conseguir visibilidad privada para los atributos de la 'clase' que elijamos.

function Article(title, body){
this.body = body;
var _title = title;
this.getTitle = function(){
return _title;
}
this.setTitle = function(title){
_title = title;
}
}

Sin embargo, en mi opinión todas estas aproximaciones conducen a escribir código javascript poco natural. Javascript fue pensado como un lenguaje de programación basado en prototipos y su flujo principal de ejecución es orientado a eventos.

Está basado en prototipos, la encapsulación, las 'clases' se obtienen a partir de la clonación de objetos y no de una estructura tan rígida como la orientación a objetos. Esto hace al lenguaje mucho más propicio para las tareas que fue pensado.

De la orientación a eventos del lenguaje han surgido proyectos muy interesantes como node.js, hay que tratar de aprovechar las bondades del lenguaje, no cambiarlas a través de capas de abstracción.

miércoles, 15 de diciembre de 2010

Logger en ruby

Similar al proyecto log4j existe para ruby una librería de logging para el depurado de aplicaciones, gestión de mensajes de error, etc.

El nombre de la librería es log4r, se distribuye como gema y es fácilmente personalizable.

Para usarla tan solo hay que instancia un objeto de la clase Logger. Para dicho objeto se pueden seleccionar distintos outputters (medio de salida), en el ejemplo se muestran los mensajes tanto por salida estándar como por UDP.

Posteriormente, para cada outputter se puede elegir un formatter (formato de la salida). En el ejemplo la salida por UDP será en el formato por defecto mientras que la salida estándar será en XML.

El ejemplo de uso de la librería.

require 'rubygems'
require 'log4r'
require 'log4r/formatter/log4jxmlformatter'
require 'log4r/outputter/udpoutputter'

include Log4r

logger = Logger.new 'mylog'

#Formatters
xmlformat = Log4jXmlFormatter.new

#Ouputters
stdout = Outputter.stdout
udpout = UDPOutputter.new 'udp', :hostname => "localhost", :port => 8888

stdout.formatter = xmlformat

logger.outputters = [stdout, udpout]


def debug(logger, txt)
logger.debug txt
end

def error(logger, txt)
logger.error txt
end


debug(logger, 'Mensaje de DEBUG')
error(logger, 'Mensaje de error')

Para más información se puede consultar la web oficial de log4r.

sábado, 20 de noviembre de 2010

Lectura de memoria entre procesos Windows

En todos los sistemas operativos modernos la memoria está protegida entre procesos.
Si un proceso accede o escribe en una posición de memoria no esperada no debe afectar a los demás procesos.

A pesar de este planteamiento, en Windows es posible leer o escribir zonas de memoria entre procesos, para ello están las funciones del API ReadProcessMemory y WriteProcessMemory.

El primer paso es encontrar el PID del proceso en el que estamos interesados y después debe obtenerse un handle con la función OpenProcess.

Para buscar el proceso destino hay varias formas, en este ejemplo se usa el nombre de la ventana visible del proceso.

#include <QtCore/QCoreApplication>
#include <windows.h>

DWORD getPIDByWindowName(WCHAR* name);

int main(int argc, char *argv[]){
QCoreApplication a(argc, argv);
BYTE buffer[300];
DWORD readed;
DWORD processID = getPIDByWindowName(TEXT("Calculadora"));
HANDLE procHandle = OpenProcess(0x0010, 0, processID);
ReadProcessMemory(procHandle, (void*)0x00951558, buffer, 50, &readed);
return a.exec();
}

DWORD getPIDByWindowName(WCHAR* name){
DWORD processID;
HWND windowHandle = FindWindowW(NULL, name);
GetWindowThreadProcessId(windowHandle, &processID);
return processID;
}

Gracias al uso de estas funciones del API se abre una nueva posibilidad de comunicación entre procesos, sin embargo, abre también un grave riesgo de seguridad. Entre otros usos, modificando la memoria de los procesos de antivirus o cortafuegos se pueden inutilizar dando una falsa sensación se seguridad.

martes, 16 de noviembre de 2010

Ejecución de tareas asíncronas en C++ con QT

En los programas con interfaz gráfica no deben ejecutarse tareas que puedan demorarse en el mismo hilo de la interfaz.
Esto ocurre muy a menudo si en el evento 'click' de un botón se hace una lectura/escritura de un fichero o una base de datos.

Con las librerías QT se puede solucionar de varias formas, una es creando un hilo (una clase que herede de QThread). Una forma aún más sencilla es crear un objeto QRunnable y hacer que el pool de QT lo ejecute en segundo plano.

Un ejemplo de lo segundo.

class AsynchrounousTask : public QRunnable{
protected:
QLabel *label;
public:
AsynchrounousTask(QLabel *label){
this->label = label;
}

void run(){
sleep(5); //long task;
label->setText("Done!");
}
};

Y para usarlo tan solo hay que hacer.

AsynchrounousTask *aTask = new AsynchrounousTask(ui->label);
QThreadPool::globalInstance()->start(aTask);

Aunque creamos un objeto con new no hay que preocuparse por su destrucción, al terminar su ejecución a través del pool se liberará de forma automática. Si preferimos que no se libere de forma automática tan solo hay que llamar al método 'setAutoDelete(false)'.

Ejecutando las tareas más pesadas de la aplicación de esta forma no se bloqueará la aplicación en ningún momento y siempre responderá a las nuevas peticiones que el usuario haga.

miércoles, 10 de noviembre de 2010

Compilación de ejecutable con Qt Creator

Cuando creamos una aplicación con Qt Creator en Windows es necesario incluir los ficheros dll de Qt para que la aplicación funcione correctamente.

En ocasiones este no es el comportamiento deseado, se puede generar un fichero ejecutable autónomo (sin necesidad de ninguna librería dll externa) ejecutando el siguiente comando:

qmake -nodepend -o Makefile project.pro

Si no se encuentra el programa qmake hay que añadirlo al PATH, la instalación por defecto de QT Creator no lo hace.
Una vez ejecutado el comando anterior, al compilar obtendremos un ejecutable con toda la funcionalidad incluida, sin necesidad de incluir ningún fichero dll.

domingo, 17 de octubre de 2010

Anidamiento de módulos en ruby

Tal y como ocurre en python con los decoradores, cuando se programa un módulo en ruby debería dejarse la puerta abierta a que no fuera el único.

En el siguiente ejemplo tenemos dos módulos (Printable y Serializable), ambos métodos se deben poder combinar en cualquier orden y pudiendo aparecer uno, ninguno o ambos.

La clave para que un mismo método se ejecute en la clase y en cada uno de sus módulos, es la llamada a super.

En otros lenguajes esto no sería correcto, puesto que los módulos Printable y Serializable no son superclase de la clase Test, pero en ruby, super no llama exactamente a la superclase, sino que repite el mismo método que se está ejecutando obviando la definición actual.

module Printable
def print_method
super
puts "I'm printable"
end
end

module Serializable
def print_method
super
puts "I'm serializable"
end
end


class Test
include Printable
include Serializable

def method_missing(method, *args, &block)
super if method.to_s != 'print_method'
end

def print_method
super
puts "I'm object of Test class"
end

end

t = Test.new
t.print_method

Con este planteamiento hay un problema añadido, al final de la cadena de llamadas a print_method estará la clase de la que hereda Test, y esta clase no tiene porqué tener implementado print_method.

Para solucionarlo en este caso se redefine el method_missing, cuando llegue el momento de ejecutar el método en alguna clase/módulo que no lo entienda, se corta la cadena de ejecuciones.

I'm printable
I'm serializable
I'm object of Test class

viernes, 17 de septiembre de 2010

Conversión implícita de tipos

Es común escribir nuevas clases que expandan a las básicas del lenguaje.

Uno de los problemas que nos podemos encontrar cuando hacemos esto es la conversión de tipos.

Si por ejemplo creamos una nueva clase para manejar cadenas, el código se llenará rápidamente de castings para convertir las cadenas nativas del lenguaje a nuestra implementación. Esto ocurre sobre todo en lenguajes fuertemente tipados.

C# provee una solución bastante elegante, la conversión implícita de tipos.

Para mostrar el uso de esta característica se muestra una clase con dos tipos, una cadena y un entero y sus declaraciones de conversiones implícitas.

public class MyClass
{
private string str { get; set; }
private int number { get; set; }

public static implicit operator MyClass(string s)
{
MyClass ms = new MyClass();
ms.str = s;
return ms;
}

public static implicit operator MyClass(int i)
{
MyClass ms = new MyClass();
ms.number = i;
return ms;
}

public string getStr()
{
return str;
}

public int getNumber()
{
return number;
}
}

Declarando un operador estático, implícito y público se consigue la sintaxis siguiente para la conversión de tipos.

MyClass ms1 = "hello";
MyClass ms2 = 2;

Console.WriteLine(ms1.getStr());
Console.WriteLine(ms2.getNumber());

En el ejemplo se puede ver que no es necesaria ninguna conversión, y se pasan tanto la cadena "hello" como el entero 2 a tipo MyClass.

domingo, 12 de septiembre de 2010

Extension methods en c#

En algunos lenguajes dinámicos como ruby las clases se denominan "abiertas".
Esto significa que a cualquier clase se le puede añadir nuevos métodos o funcionalidades en tiempo de ejecución.

Los lenguajes fuertemente tipados no suelen ofrecer tanta libertad, pero se disponen de otras herramientas.

En C#, se pueden definir clases parciales, lo que significa que se puede definir el comportamiento de la clase en varias etapas.

public partial class PartialClass
{
public static void method1()
{
Console.WriteLine("method1");
}
}
...
public partial class PartialClass
{
public static void method2()
{
Console.WriteLine("method2");
}
}

Manteniendo las clases como parciales en cualquier momento se puede añadir funcionalidad a una clase existente fuera de su definición original.

Este método es útil tan solo para las clases que programamos, pero si queremos extender una librería externa o las clases del propio lenguaje las clases parciales no son de gran ayuda.

C# tiene en cambio una posibilidad más interesante, los "extension methods".

public static class ExtensionMethods
{
public static string withDot(this string str)
{
return str + ".";
}
}
...
string str = "text ";
str.withDot();

Con el código anterior se le añade a la clase string el nuevo método (withDot).
Para hacer lo mismo sin "extension methods" habría sido necesario crear una nueva clase que heredara de string y añadirle el método withDot.

Gracias a los "extension methods" se puede evitar crear clases intermedias para extender funcionalidades de las ya existentes.

sábado, 28 de agosto de 2010

Implementación explícita de interfaces en C#

Por diversas razones como la colisión de nombres o simplemente por diseño, puede que necesitemos mayor granularidad para distinguir que método de que interfaz estamos definiendo.

Supongamos que tenemos el caso de una clase que implementa dos interfaces tal y como sigue:

public interface IInterface1
{
int method();
int method1();
}

public interface IInterface2
{
int method();
int method2();
}

public class ExampleClass : IInterface1, IInterface2
{
public int method() { return 1; }
public int method1() { return 1; }
public int method2() { return 2; }

}

En este caso, el método method está presente en las dos interfaces y lo definimos en la clase.

Si necesitáramos distinguir alguno de los casos se podría usar la implementación explícita de interfaces.

public class ExampleClass : IInterface1, IInterface2
{
public int method() { return 1; }
public int method1() { return 1; }
public int method2() { return 2; }

int IInterface1.method() { return 1; }
int IInterface2.method() { return 2; }

}


public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();

ExampleClass example = new ExampleClass();
IInterface1 i1 = (IInterface1)example;
IInterface2 i2 = (IInterface2)example;

MessageBox.Show("Interface 1: " + i1.method());
MessageBox.Show("Interface 2: " + i2.method());
}
}

Esto devolvería como resultados 1 y 2 respectivamente. Como vemos, a pesar de realizar la implementación explícita de ambas interfaces se sigue pudiendo implementar de la forma tradicional como caso base.

miércoles, 21 de julio de 2010

Internacionalización con QT

La librería QT está desarrollada de tal forma que las aplicaciones
que estén hechas usando su API pueden internacionalizarse de forma bastante
fácil.

En primer lugar todas las cadenas de la aplicación deben sustituirse por llamadas
a la función tr.

QObject::tr("cadena");

La cadena que pasemos a la función tr servirá de índice para las cadenas
definitivas en los distintos idiomas.

Después se debe añadir una entrada en el fichero de proyecto (.pro) con los ficheros
que se deben generar para cada idioma de las traducciones, con extensión .ts.

TRANSLATIONS = en.ts es.ts

Los ficheros se generarán al ejecutar el comando:

lupdate proyecto.pro

Estos ficheros .ts se pueden editar con QT Linguist, una vez introducidas todas las
traducciones, se pueden exportar mediante la opción Release, esto generaráa
unos ficheros .qm.

Posteriormente hay que crear un fichero de recursos que contenga los ficheros .qm
de traducciones.

Para obtener el idioma del equipo en el que se está ejecutándo la aplicación se puede
hacer lo siguiente

QString locale = QLocale::system().name();

Para que las traducciones se carguen hay que instanciar la clase QTranslator y pasársela
a la aplicación.

QTranslator translator;
translator.load(locale, ":/");
a.installTranslator(&translator);

La ruta ":/" se refiere al prefijo introducido en el fichero de recursos.

Tras estos pasos las cadenas de la aplicación aparecerán traducidas dependiendo del idioma
del equipo en el que se esté ejecutándo.