Снова пятница (не тяпница, по тяпницам у меня хорошее настроение), на улице дождь, настроение в ноль. Целую неделю прихожу на работу на час раньше, ну не дурень разве?)
В добавок ко всему больной... Ну да ладно о плохом, раскажу ка я лучше о своей очередной бредовой идее.
Проснулся как то ночью и решил, хочу чтобы мои справочники в БД были локализованы... Начал рыться по нету, что да как... Суть в том, что есть какие то сущности замапленые с помощью hibernate на реляционную БД, у этих сущностей есть нейкий description, который и нужно локализировать.
Так вот, подумал немного и кое как с горем попалам придумал кое чего, хотя мне кажется, что уж слишком грязно все получилось. Ну да ладно, как бы не было стыдно, покажу то, что у меня получилось.
Для начала сделал вот такой интерфейсик, для интернационализации чего-то, и 2 его реализации
package itdep.common.i18n;
import java.util.Locale;
/**
* @author Ivan Khalopik
* @version $Revision: 267 $ $Date: 2009-04-09 09:38:38 +0300 (Чт, 09 апр 2009) $
*/
public interface I18n<T> {
T getValue(final Locale locale);
void setValue(final Locale locale, final T value);
}
package itdep.common.i18n.impl;
import itdep.common.i18n.I18n;
import java.util.Locale;
/**
* @author Ivan Khalopik
* @version $Revision: 267 $ $Date: 2009-04-09 09:38:38 +0300 (Чт, 09 апр 2009) $
*/
public class SimpleI18n<T> implements I18n<T> {
private T value;
public SimpleI18n() {
}
public SimpleI18n(final T value) {
this.value = value;
}
public T getValue(final Locale locale) {
return value;
}
public void setValue(final Locale locale, final T value) {
this.value = value;
}
@Override
public String toString() {
return String.valueOf(value);
}
}
package itdep.common.i18n.impl;
import itdep.common.i18n.I18n;
import itdep.common.util.I18nUtils;
import java.util.List;
import java.util.Locale;
import java.util.Map;
/**
* @author Ivan Khalopik
* @version $Revision: 268 $ $Date: 2009-04-09 11:55:04 +0300 (Чт, 09 апр 2009) $
*/
public class I18nMapWrapper<T> implements I18n<T> {
private final Map<Locale, T> values;
public I18nMapWrapper(final Map<Locale, T> values) {
this.values = values;
}
public T getValue(final Locale locale) {
final List<Locale> candidates = I18nUtils.getCandidateLocales(locale);
for (Locale candidate : candidates) {
if (values.containsKey(candidate)) {
return values.get(candidate);
}
}
return null;
}
public void setValue(final Locale locale, final T value) {
values.put(locale, value);
}
@Override
public String toString() {
return String.valueOf(getValue(Locale.getDefault()));
}
}
Первая реализация - это что вроде заглушки, когда объект во всех локалях имеет одно и то же значение, во вторую подсовываем мапу с ключем в виде локали, из которой в соответсвии с нужной локалью и будет браться локализированое значение.
Далее все это нужно совместить с hibernate сущностью. Для этого объявил интерфейс:<>package itdep.common.i18n;
import itdep.common.dao.Entity;
import java.io.Serializable;
/**
* @author Ivan Khalopik
* @version $Revision: 265 $ $Date: 2009-04-08 11:37:12 +0300 (Ср, 08 апр 2009) $
*/
public interface I15dEntity<PK extends Serializable> extends Entity<PK> {
I18n<String> getDescription();
}
Ну и реализацияpackage itdep.model;
import itdep.common.i18n.I18n;
import itdep.common.i18n.impl.I18nMapWrapper;
import org.hibernate.annotations.CollectionOfElements;
import org.hibernate.annotations.MapKey;
import javax.persistence.*;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
/**
* @author Ivan Khalopik
* @version $Revision: 265 $ $Date: 2009-04-08 11:37:12 +0300 (Ср, 08 апр 2009) $
*/
@MappedSuperclass
public abstract class CodedEntity extends SomeEntity implements I15dEntity<Long> {
@Column(name = "CODE", nullable = true, insertable = true, updatable = true)
private String code;
@CollectionOfElements(fetch = FetchType.EAGER)
@JoinTable(name = "I18N",
joinColumns = @JoinColumn(name = "CODE", referencedColumnName = "CODE", nullable = false))
@MapKey(columns = @Column(name = "LOCALE", nullable = true, insertable = true, updatable = true))
@Column(name = "VALUE", nullable = false, insertable = true, updatable = true)
private Map<Locale, String> i15dName = new HashMap<Locale, String>();
public String getCode() {
return code;
}
public void setCode(final String code) {
this.code = code;
}
@Override
public I18n<String> getDescription() {
return new I18nMapWrapper<String>(i15dName);
}
}
Здесь для локализации используется таблица I18N с полями CODE(код), LOCALE(локаль), VALUE(значение), в самой таблице сущности храним поле CODE, которое и соотетсвует тому, что в I18N. В итоге получаем, что #getDescription() возвращает нам локализированую строку. Ну а в случае, если надо, чтоб возвращалось одно и то же значение во всех локалях можно сделать так:
package itdep.model;
import itdep.common.i18n.I18n;
import itdep.common.i18n.impl.SimpleI18n;
import javax.persistence.Column;
import javax.persistence.MappedSuperclass;
/**
* @author Ivan Khalopik
* @version $Revision: 265 $ $Date: 2009-04-08 11:37:12 +0300 (Ср, 08 апр 2009) $
*/
@MappedSuperclass
public abstract class NamedEntity extends SomeEntity implements I15dEntity<Long> {
@SuppressWarnings({"UnusedDeclaration"})
@Column(name = "NAME", nullable = false, insertable = true, updatable = true)
private String name;
@Override
public I18n<String> getDescription() {
return new SimpleI18n<String>(name);
}
}
Ну вот что-то и получилось, но мне не нравиться, буду видимо переделывать, хочу реализовать отображение через спринговый MessageSource, а редактирование можно и так, немного переделать, или, возможно, что-то совсем по другому сделать. Вобщем продолжение следует.
Все, пойду лечиться...
Комментариев нет:
Отправить комментарий