Código Java – Modificar Ficheros de Propiedades en Tiempo de Ejecución


Este es el Ejemplo #23 del Topic: Programación Gráfica en Java.

Nuevamente jugando con el ResourceBundle y los ficheros de propiedades, pero a diferencia del post realizado anteriormente respecto a este tema ahora no solo veremos como acceder a los datos del fichero de propiedades, si no también poder editarlos.

Esto es muy importante porque su uso no radicará solo en desarrollar aplicaciones multi-lenguaje, sino para poder generar ficheros de configuración donde podamos almacenar datos que cambian esporádica o frecuentemente, por ejemplo, los de acceso a base de datos, establecer un idioma, una apariencia, los items seleccionados en las preferencias de la aplicación, directorios donde se almacenarán registros, etc, es decir, información externa que no requiera almacenarse en una base de datos al estilo de un cache, por ello usaremos simples ficheros de propiedades.

En el ejemplo siguiente usaremos los ficheros de propiedades creados en el post  Código Java – Internacionalización de Aplicaciones con ResourceBundle, la mayor parte del código es el mismo excepto que esta vez no nos enfocamos a la internacionalización.

Este es el procedimiento necesario para poder realizar nuestro objetivo, donde:

fichero: Ubicación del fichero .properties.
key: Palabra Clave dentro del fichero .properties.
values: Nuevo valor que reemplazará al anterior.

...
    private void escribirProperties(String fichero, String key, String value)
    {
                // Crear el objeto archivo
		File archivo = new File(this.getClass().getResource(fichero).getFile().replace("%20", " "));
		//Crear el objeto properties

                System.out.println(archivo);

		Properties properties = new Properties();
		try {
			// Cargar las propiedades del archivo
			properties.load(new FileInputStream(archivo));
			properties.setProperty(key,value);
			// Escribier en el archivo los cambios
                        FileOutputStream fos=new FileOutputStream(archivo.toString().replace("\\", "/"));

                        properties.store(fos,null);

                } catch (FileNotFoundException e) {
			System.out.println(e.getMessage());
		} catch (IOException e) {
			System.out.println(e.getMessage());
		}
    }
...

Código de Ejemplo:

/**
*Modificamos el valor del Keyword: beastieux.gui.Ejm19_Internacionalizacion.lbl3
*Del fichero /beastieux/language/LANG_es_PE.properties", creado en el Post 19.
 */

package beastieux.gui;

import java.awt.GridLayout;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Properties;
import java.util.ResourceBundle;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextField;

/**
 *
 * @author beastieux
 */
public class Ejm23_EscribirFicheroProperties extends JFrame {

    JLabel lbl1;
    JLabel lbl2;
    JLabel lbl3;
    JTextField txt1;
    JTextField txt2;
    JTextField txt3;
    JComboBox cmb1;
    JButton btn1;

    public Ejm23_EscribirFicheroProperties()
    {

        lbl1=new JLabel();
        txt1=new JTextField();

        lbl2=new JLabel();
        txt2=new JTextField();

        lbl3=new JLabel();
        cmb1=new JComboBox();
        cmb1.addItemListener(new java.awt.event.ItemListener() {
            public void itemStateChanged(java.awt.event.ItemEvent evt) {
                cmb1ItemStateChanged(evt);
            }
        });

        cmb1.addItem("Español");

        txt3=new JTextField();

        btn1=new JButton("Cambiar Etiqueta 3");
        btn1.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btn1ActionPerformed(evt);
            }
        });

        this.add(lbl1);
        this.add(txt1);
        this.add(lbl2);
        this.add(txt2);
        this.add(lbl3);
        this.add(cmb1);
        this.add(btn1);
        this.add(txt3);
        this.setLayout(new GridLayout(4,2));
        this.setSize(500, 150);

        this.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
    }

    private void btn1ActionPerformed(java.awt.event.ActionEvent evt) {
        ResourceBundle.clearCache();
        escribirProperties("/beastieux/language/LANG_es_PE.properties",
                           "beastieux.gui.Ejm19_Internacionalizacion.lbl3",
                           this.txt3.getText());

        setBundles("beastieux.language.LANG_es_PE");
    }

    private void cmb1ItemStateChanged(java.awt.event.ItemEvent evt) {

        switch(cmb1.getSelectedIndex())
        {
            case 1:setBundles("beastieux.language.LANG_es_PE"); break;
            default:setBundles("beastieux.language.LANG");
        }
    }

    private void setBundles(String propertyFile)
    {
            ResourceBundle rb = ResourceBundle.getBundle(propertyFile);

            String keyBundle="beastieux.gui.Ejm19_Internacionalizacion";

            this.setTitle(rb.getString(keyBundle + ".this"));
            this.lbl1.setText(rb.getString(keyBundle + ".lbl1"));
            this.lbl2.setText(rb.getString(keyBundle + ".lbl2"));
            this.lbl3.setText(rb.getString(keyBundle + ".lbl3"));

    }

    private void escribirProperties(String fichero, String key, String value)
    {
                // Crear el objeto archivo
		File archivo = new File(this.getClass().getResource(fichero).getFile().replace("%20", " "));
		//Crear el objeto properties

                System.out.println(archivo);

		Properties properties = new Properties();
		try {
			// Cargar las propiedades del archivo
			properties.load(new FileInputStream(archivo));
			properties.setProperty(key,value);
			// Escribier en el archivo los cambios
                        FileOutputStream fos=new FileOutputStream(archivo.toString().replace("\\", "/"));

                        properties.store(fos,null);

                } catch (FileNotFoundException e) {
			System.out.println(e.getMessage());
		} catch (IOException e) {
			System.out.println(e.getMessage());
		}
    }

        public static void main(String args[]) {
        Ejm23_EscribirFicheroProperties obj = new Ejm23_EscribirFicheroProperties();
        obj.setVisible(true);
    }
}
Anuncios

Código Java – Internacionalización de Aplicaciones con ResourceBundle


Este es el Ejemplo #19 del Topic: Programación Gráfica en Java.

Con este post aprenderemos a hacer nuestras aplicaciones en java internacionales y poder generar software en varios idiomas como queramos. Esto yo es algo que la mayoría de las aplicaciones lo vienen realizando sean de escritorio o aplicaciones web que hacen uso de la internacionalización, que no es otra cosa más que adaptar nuestro software a diferentes idiomas y regiones, todo ello sin necesidad de hacer cambios considerables en el código fuente, sino haciendo uso de ficheros de propiedades que nos serán de gran ayuda.

En Java debemos acceder a la clase ResourceBundle que deberá enlazarse con el fichero de propiedades(.properties) y de esa manera obtener el recurso a usar. Deberán existir tantos ficheros de propiedades como idiomas que soportará la aplicación, cuyo nombre del fichero deberá guardar relación con los siguientes estándares:

Para el idioma – ISO 639.
Para el país – ISO3166

La composición del nombre de identificación deberá contar con el NombreFichero_pais_IDIOMA; respetando mayúsculas y minúsculas:
LANG_en_US – Inglés/EE.UU
LANG_es_PE – Español/Perú

El fichero de propiedades deberá contener la palabra clave y el texto con el cual está relacionado. La palabra clave deberá ser la misma en todos los ficheros de cada idioma, por ejemplo:

LANG_en_US.properties
IDIOMA=Spanish

LANG_es_PE.properties
IDIOMA=Español

Al momento de construir los ficheros properties de la aplicación,algunos programadores suelen usar el nombre del componente como palabra clave, yo prefiero poner como palabra clave la ruta completa de los componentes, y cuando sea necesaria alguna propiedad, por ejemplo hago uso de this cuando me refiero el contenedor principal.
En este ejemplo, el directorio donde estarán ubicados los ficheros de propiedades guardará la siguiente organización:

Para efectos didácticos solo usaré 2 idiomas, Ingles (en_US), y español (es_PE), además del fichero que se usará por defecto identificado solo como LANG.properties. Cada uno de estos ficheros deberá contener los siguientes datos:

LANG_en_US.properties
beastieux.gui.Ejm19_Internacionalizacion.this=Configuration
beastieux.gui.Ejm19_Internacionalizacion.lbl1=Country
beastieux.gui.Ejm19_Internacionalizacion.lbl2=City
beastieux.gui.Ejm19_Internacionalizacion.lbl3=Language

LANG_es_PE.properties
beastieux.gui.Ejm19_Internacionalizacion.this=Configuración
beastieux.gui.Ejm19_Internacionalizacion.lbl1=País
beastieux.gui.Ejm19_Internacionalizacion.lbl2=Ciudad
beastieux.gui.Ejm19_Internacionalizacion.lbl3=Idioma

El siguiente procedimiento recibirá como único parámetro la ruta del fichero de propiedades ejm: beastieux.language.LANG_en_US, y seteará el ResourceBundle con los datos de dicho fichero, con el cual cambiará automáticamente al idioma definido.

...
    private void setBundles(String propertyFile)
    {
            ResourceBundle rb = ResourceBundle.getBundle(propertyFile);

            String keyBundle=this.getClass().getName();

            this.setTitle(rb.getString(keyBundle + ".this"));
            this.lbl1.setText(rb.getString(keyBundle + ".lbl1"));
            this.lbl2.setText(rb.getString(keyBundle + ".lbl2"));
            this.lbl3.setText(rb.getString(keyBundle + ".lbl3"));
    }
...

Código de Ejemplo:

package beastieux.gui;

import java.awt.GridLayout;
import java.util.ResourceBundle;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextField;

/**
 *
 * @author beastieux
 */
public class Ejm19_Internacionalizacion extends JFrame{

    JLabel lbl1;
    JLabel lbl2;
    JLabel lbl3;
    JTextField txt1;
    JTextField txt2;
    JComboBox cmb1;

    public Ejm19_Internacionalizacion()
    {

        lbl1=new JLabel();
        txt1=new JTextField();

        lbl2=new JLabel();
        txt2=new JTextField();

        lbl3=new JLabel();

        cmb1=new JComboBox();
        cmb1.addItemListener(new java.awt.event.ItemListener() {
            public void itemStateChanged(java.awt.event.ItemEvent evt) {
                cmb1ItemStateChanged(evt);
            }
        });

        cmb1.addItem("Inglés");
        cmb1.addItem("Español");

        this.add(lbl1);
        this.add(txt1);
        this.add(lbl2);
        this.add(txt2);
        this.add(lbl3);
        this.add(cmb1);

        this.setLayout(new GridLayout(3,2));
        this.setSize(400, 100);

        this.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
    }

    private void cmb1ItemStateChanged(java.awt.event.ItemEvent evt) {

        switch(this.cmb1.getSelectedIndex())
        {
            case 0:setBundles("beastieux.language.LANG_en_US"); break;
            case 1:setBundles("beastieux.language.LANG_es_PE"); break;
            default:setBundles("beastieux.language.LANG");
        }
    }

    private void setBundles(String propertyFile)
    {
            ResourceBundle rb = ResourceBundle.getBundle(propertyFile);

            String keyBundle=this.getClass().getName();

            this.setTitle(rb.getString(keyBundle + ".this"));
            this.lbl1.setText(rb.getString(keyBundle + ".lbl1"));
            this.lbl2.setText(rb.getString(keyBundle + ".lbl2"));
            this.lbl3.setText(rb.getString(keyBundle + ".lbl3"));

    }

    public static void main(String args[]) {
        Ejm19_Internacionalizacion obj = new Ejm19_Internacionalizacion();
        obj.setVisible(true);
    }

}

Finalmente, cabe mencionar que los IDE’s de desarrollo modernos nos permiten realizar esta tarea fácilmente como es el caso de NetBeans o Eclipse. El procedimiento en Netbeans seria ir al menu Tools –> Internationalization, y elegir la modalidad, el más sencillo es con Internationalization Wizard.