10.11.2012

Vaadin Internationlization localization.

Впервые познакомившись с Vaadin я был в восторге от него, но со временем интерес к нему прошел, из-за ряда вещей но кое-какие наработки остались.Вот одна из наработок - это как наиболле просто локализовать программу, точнее где правильно хранить локаль пользователя. Правильно хранить локаль и другие данные нужно в глобальной сессии пользователя, для этого нужно создать ThreadLocal сингильтон который будет содержать объекты ResourceBundle bundle, Locale locale, Application app и сингильтон при этом должен наследовать interface ApplicationContext.TransactionListener - у этого интерфейса есть 2 метода:
public void transactionStart(Application application,
                                 Object transactionData) {     
        if (this.app == application)
            instance.set(this);
    }
который связывает данные пользователя с текушим потоком во ThreadLocal и
public void transactionEnd(Application application,
                               Object transactionData) {
        // Clear the reference to avoid potential problems
        if (this.app == application)
            instance.set(null);
    }
который разрывает эту связь. Коротко что мы здесь сделали - ThreadLocal позволяет нам хранить разные данные для каждого пользователя, т.е. для каждого потока(сессии пользователя) будут разные значения объектов ResourceBundle bundle, Locale locale.
package com.vit;

import com.vaadin.Application;
import com.vaadin.service.ApplicationContext;

import java.io.Serializable;
import java.util.Locale;
import java.util.ResourceBundle;

/** Holds data for one user session. */
public class AppData implements ApplicationContext.TransactionListener, Serializable {
    private ResourceBundle bundle;
    private Locale locale;   // Current locale
    private Application app; // For distinguishing between apps

    private static ThreadLocal instance =
        new ThreadLocal();

    public AppData(Application app) {
        this.app = app;
        // It's usable from now on in the current request
        instance.set(this);
    }

    @Override
    public void transactionStart(Application application,
                                 Object transactionData) {
        // Set this data instance of this application
        // as the one active in the current thread.
        if (this.app == application)
            instance.set(this);
    }

    @Override
    public void transactionEnd(Application application,
                               Object transactionData) {
        // Clear the reference to avoid potential problems
        if (this.app == application)
            instance.set(null);
    }

    public static void initLocale(Locale locale,
                                  String bundleName) {
        instance.get().locale = locale;
        instance.get().bundle =
            ResourceBundle.getBundle(bundleName, locale);
    }

    public static Locale getLocale() {
        return instance.get().locale;
    }

    public static String getMessage(String msgId) {
        return instance.get().bundle.getString(msgId);
    }
}
Дальше создаем ComboBox который позволяет нам менять текушую локаль и соответственно настроить под неё ResourceBundle.
package com.vit;

import com.vaadin.ui.ComboBox;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;

public class ComboBoxLocale extends ComboBox{
    private final List locales = Arrays.asList(
            new Locale("ru", "RU"), Locale.US, Locale.ENGLISH, AppData.getLocale());

    public ComboBoxLocale(String caption) {
        super(caption);
        for (Locale l:locales) {
            addItem(l);
            setItemCaption(l,l.getDisplayName());
        }
        setNullSelectionAllowed(false);
        setImmediate(true);
        setVisible(true);
    }

    @Override
    public void attach() {
        super.attach();
        setValue(AppData.getLocale());
    }
}
Далее создаем файл ресурсов для английского языка MyVaadinApplication_en.properties:
Button.text=Click me English
Label.text=Thank you for clicking Еnglish
и для русского MyVaadinApplication_ru_RU.properties:
Button.text=Click me Russian
Label.text=Thank you for clicking Russian
И наконец все встраиваем в наше веб приложение.
package com.vit;

import com.vaadin.Application;
import com.vaadin.data.Property;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.*;
import com.vaadin.ui.themes.Runo;

import java.util.Locale;

public class MyVaadinApplication extends Application {
    private Window window;
    public ComboBoxLocale comboBoxLocale;
    public Button button;

    @Override
    public void init() {
        setTheme("runo");
        window = new Window("Hello Vaadin!");
        setMainWindow(window);
        window.setImmediate(true);
        // Create the application data instance
        AppData sessionData = new AppData(this);
        // Register it as a listener in the application context
        getContext().addTransactionListener(sessionData);
        // Initialize the session-global data
        AppData.initLocale(getLocale(),
                MyVaadinApplication.class.getSimpleName());

        comboBoxLocale = new ComboBoxLocale("Change Locale:");
        comboBoxLocale.setWidth("150px");
        comboBoxLocale.setValue(getLocale());
        Property.ValueChangeListener listener = new Property.ValueChangeListener() {
            public void valueChange(Property.ValueChangeEvent event) {
                AppData.initLocale((Locale) comboBoxLocale.getValue(),
                        MyVaadinApplication.class.getSimpleName());
                setLocale((Locale) comboBoxLocale.getValue());
                window.showNotification(
                        ((Locale) comboBoxLocale.getValue()).getDisplayName() + " : " +
                                AppData.getLocale().getLanguage() );
                button.setLocale((Locale) comboBoxLocale.getValue());
                button.setCaption(AppData.getMessage("Button.text"));
            }
        };
        comboBoxLocale.addListener(listener);
        window.addComponent(comboBoxLocale);

        button = new Button(AppData.getMessage("Button.text"));
        button.addListener(new Button.ClickListener() {
            public void buttonClick(ClickEvent event) {
                window.addComponent(new Label(AppData.getMessage("Label.text")));
            }
        });
        button.addStyleName(Runo.BUTTON_SMALL);
        window.addComponent(button);
    }
}
Опишу пару строк важных строк создаем наш сингильтон - AppData sessionData = new AppData(this); регистрируем наш обработчик - getContext().addTransactionListener(sessionData); устанвливаем текушую локаль и связываем с ним ResourceBundle - AppData.initLocale(getLocale(),MyVaadinApplication.class.getSimpleName()); создаем кнопку и выдергиваем строчку Button.text из ResourceBundle - button = new Button(AppData.getMessage("Button.text")); Вот и все на последок привожу файл pom.xml с зависимостями:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.vit</groupId>
  <artifactId>VaadinTest11</artifactId>
  <packaging>war</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>Vaadin Web Application</name>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <vaadin.version>6.6.6</vaadin.version>
    <gwt.version>2.3.0</gwt.version>
    <gwt.plugin.version>2.2.0</gwt.plugin.version>
  </properties>

  <build>
    <finalName>test</finalName>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
          <source>1.5</source>
          <target>1.5</target>
          <encoding>UTF-8</encoding>
        </configuration>
      </plugin>

      <!-- A simple Jetty test server at http://localhost:8080/VaadinTest11 can be launched with the Maven goal jetty:run 
        and stopped with jetty:stop -->
      <plugin>
        <groupId>org.mortbay.jetty</groupId>
        <artifactId>maven-jetty-plugin</artifactId>
        <version>6.1.24</version>
        <configuration>
          <stopPort>9966</stopPort>
          <stopKey>VaadinTest11</stopKey>
          <!-- Redeploy every x seconds if changes are detected, 0 for no automatic redeployment -->
          <scanIntervalSeconds>0</scanIntervalSeconds>
          <!-- make sure Jetty also finds the widgetset -->
          <webAppConfig>
            <contextPath>/VaadinTest11</contextPath>
            <baseResource implementation="org.mortbay.resource.ResourceCollection">
              <!-- Workaround for Maven/Jetty issue http://jira.codehaus.org/browse/JETTY-680 -->
              <!-- <resources>src/main/webapp,${project.build.directory}/${project.build.finalName}</resources> -->
              <resourcesAsCSV>src/main/webapp,${project.build.directory}/${project.build.finalName}</resourcesAsCSV>
            </baseResource>
          </webAppConfig>
        </configuration>
      </plugin>
    </plugins>
  </build>

  <repositories>
    <repository>
      <id>vaadin-snapshots</id>
      <url>http://oss.sonatype.org/content/repositories/vaadin-snapshots/</url>
      <releases>
        <enabled>false</enabled>
      </releases>
      <snapshots>
        <enabled>true</enabled>
      </snapshots>
    </repository>
    <repository>
      <id>vaadin-addons</id>
      <url>http://maven.vaadin.com/vaadin-addons</url>
    </repository>
  </repositories>

  <dependencies>
    <dependency>
      <groupId>com.vaadin</groupId>
      <artifactId>vaadin</artifactId>
      <version>${vaadin.version}</version>
    </dependency>
  </dependencies>

</project>

Комментариев нет:

Отправить комментарий