[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 для атрибута.