[Oracle ADF] Локализация для Модели
Локализация для Model
Если не нужно переопределять данные из базы данных, то лучше делать не тем способом, который описывается ниже, а просто использовать способ как и для перевода на страницах jsf.
Т.е. для данных из базы использовать следующего вида конструкции.
#{myBundle[node.myAttribute]}
Или еще пример
#{myBundle[bindings.myAttribute.inputValue]}
Поехали. Далее описывается способ, где нужно менять в бине данные из базы данных
Из базы данных приходят ключи. И я их меняю на значения из файлов ModelBundle_ru.properties или ModelBundle_en.properties
Итак, создал файлы:
1) ModelBundle.properties, ModelBundle_ru.properties, ModelBundle_en.properties
2) В ModelBundle_ru.properties и ModelBundle_en.properties добавил
tasks.stores.newStore = New store tasks.stores.newStore = Новый магазин
3) Model Project –> Properties –> Resource Bundle
- Use Project Settings
One Bundle Per Project:
Default Project Bundle Name: ModelBundle.properties
Далее
BundleSearch
добавляю ModelBundle.properties
4) В базе делаю для поля ключ, который потом будет заменен значением из Bundle. Т.е. название на английском / русском меняю на tasks.stores.newStore
==================
В файле ModelBundle.properties создаем пару ключ - значение. Например model.myKey = myValue
Повторяем тоже самое для для ModelBundle_ru.properties и ModelBundle_ru.properties. В ModelBundle_ru.properties вставляем текст с переводом.
5) Во ViewObject иду в Attributes –> UiHints –> В поле label указываю какое-то описание.
Это делается, чтобы в исходниках VO прописался Bundle. Кто хочет, впринципе, могут и руками прописать следующее:
<ResourceBundle>
<PropertiesBundle
PropertiesFile="***.model.ModelBundle"/>
</ResourceBundle>
Далее напротив lable выбираю “Select text resource”
Выбираю в списке созданный ранее ключ. (Можно скопировать его из bundle и вставить в поле key, чтобы не искать).
<ViewAttribute
****
<Properties>
<SchemaBasedProperties>
<LABEL
ResId="Сюда вроде прописывается ключ"/>
</SchemaBasedProperties>
</Properties>
</ViewAttribute>
Далее привожу способ переопределения в java классе IMPL
6) VO вкладка JAVA –> Generate View Row Class + Include accessors
Вот такой код у меня получился:
getName - сгенерированное поле.
Было:
public String getName() {
return (String) getAttributeInternal(NAME);
}
Стало:
public String getName() {
// return (String) getAttributeInternal(NAME);
return getLocalizedText(NAME);
}
private String getLocalizedText(int index){
String key = (String) getAttributeInternal(index);
if (((AppModuleImpl)this.getApplicationModule()).getLocalizedText(key) != null){
return ((AppModuleImpl)this.getApplicationModule()).getLocalizedText(key);
}
return key;
}
А сам метод получения локали я вынес в AppModuelImpl
Даже не так.
Создал класс.
public class MyApplicationModuleImpl extends ApplicationModuleImpl { ... }
И AppModule отнаследовал от него
public class AppModuleImpl extends MyApplicationModuleImpl implements AppModule { ... }
Вот такой коду у меня получился:
private String loggedInUser;
private String userLocale;
@Override
protected void prepareSession(Session session) {
super.prepareSession(session);
setLoggedInUser();
}
private void setLoggedInUser(){
SessionImpl sessionImpl = (SessionImpl) getDBTransaction().getSession();
this.loggedInUser = sessionImpl.getUserPrincipalName();
}
public String getLocalizedText(String key){
ResourceBundleDef resourceDef = this.getResourceBundleDef();
String userLocale = getUserLocaleFromAppModule();
Locale locale = new Locale(userLocale);
String retVal =
StringManager.getLocalizedStringFromResourceDef(
resourceDef,
key,
null,
locale,
null,
false);
if (retVal != null){
return retVal;
} else {
return null;
}
}
public String getUserLocaleFromAppModule() {
if (userLocale == null){
this.userLocale = setUserLocale();
}
return userLocale;
}
private String setUserLocale(){
return getUserLocaleByUserName(this.loggedInUser);
}
private String getUserLocaleByUserName(String loggedInUser){
String userLocaleAttribute = "Language";
String voName = "UsersVO";
String res;
try {
ViewObjectImpl vo = (ViewObjectImpl) findViewObject(voName);
vo.ensureVariableManager().setVariableValue("p_login", loggedInUser);
vo.executeQuery();
vo.first();
Row row = vo.getCurrentRow();
res = (String) row.getAttribute(userLocaleAttribute);
} catch (Exception ex) {
logger.severe("AppModuleImpl Exception getUserLocale()");
res = "en";
}
return res;
}
Try / Catch обернут, т.к. иногда в считывании статического VO он ингда даже ошибку умудряется поймать. Ну да ладно.
Разобраться во всем этом мне помог следующий пример:
Ссылка в статье на проект идет на ресурс которого уже нет. Можно взять пример этого приложения здесь:
https://bitbucket.org/oracle-adf/adf-samples2/src
Нужно отметить.
В этом примере из статьи “Accessing Resource Bundles from a ViewObject” локаль берется из браузера (или откуда там из операционной системы).
В моем примере, пользователь может сам выбирать язык интерфейса. Поэтому приходится брать из базы значение и как следствие выполнить немного больше шагов.
af:query - Убрать текст “По умолчанию”
Находим VO на снове которого создан af:query
ViewCriteria –> Находим наш VC.
Criteria UI Hints
Повторить тоже самое, что и при задании lable для атрибута.