Can we access the Locale inside an Entity to use in calculated field?

I’m experimenting with supporting multiple languages in Lookup type tables (e.g. LookupCustomerStatus, LookupOrderStatus, etc) where I have created a separate string field for each of the supported languages. For example: getTitleEn(), getTitleFr(), getTitleDe(), etc.

I now want to create a transient property called getTitle() on these Lookup Xxx entities that is used in all dropdowns in the UI, and it should take into account the locale of the current user and return the relevant language property on that Lookup entity. For example, when the user is logged in as English the getTitle() property should return getTitleEn(), when the user logs in under the French language, the the getTitle() method should return the getTitleFr() value and so on.

I’ve tried to inject the UserSessionSource into the entity class to have access to getLocale() inside the getTitle() method, but that causes an excaption at runtime and the application will not start.

Is there any way to achieve this or is there a better way to do this?

Thanks in advance

Try to use Service.

Thanks @Earl02 I tried by creating a separate service that uses the UserSessionSource, but as soon as one injects this new service into the entity you get the same error. It appears therefore that you cannot inject a service into an entity.

I’ve also tried using an entity listener service but those appear to only be aimed at creating, updating and deleting entities and not just loading entities.

There must be a way though… I just don’t know enough about CUBA yet.

Seems like you want to use BeforeDetachEntityListener with non-persistent attribute like ‘locale’. Try it out.

Success at last! The secret was to not use injection in the entity class but rather use AppBeans.get() inside of the transient field method:

@MetaProperty
public String getTitle() {
    UserSessionSource us = AppBeans.get(UserSessionSource.NAME);
    String currentLanguage = us.getLocale().getLanguage();
    ...use a switch statement to return the appropriate field based on the current language...
}
1 Like

Thanks Ivan, I will try BeforeDetachEntityListener as well and report back.

Based on the hint above from @Ivan I can confirm that using an entity listener also works. So one can follow either of the two solutions in this thread.

Solution 1
Using an entity listener on the onBeforeDetach() event (needs the transient “title” property to be read/write):

@Component("juno_TranslationListener")
public class TranslationListener implements BeforeDetachEntityListener<LookupBase> {

    @Inject
    protected UserSessionSource userSessionSource;

    @Override
    public void onBeforeDetach(LookupBase entity, EntityManager entityManager) {
        String lang = userSessionSource.getLocale().getLanguage();
        switch (lang) {
            case "en":
                entity.setTitle(entity.getTitleEn());
                break;
            case "de":
                entity.setTitle(entity.getTitleDe());
                break;
            case "fr":
                entity.setTitle(entity.getTitleFr());
                break;
            case "it":
                entity.setTitle(entity.getTitleIt());
                break;
            default:
                entity.setTitle(entity.getTitleEn());
                break;
        }
    }
}

Solution 2
Using AppBeans.get() inside of a read-only transient field method:

@MetaProperty
public String getTitle() {
    UserSessionSource us = AppBeans.get(UserSessionSource.NAME);
    String currentLanguage = us.getLocale().getLanguage();
        switch (lang) {
            case "en":
                return getTitleEn();
            case "de":
                return getTitleDe();
            case "fr":
                return getTitleFr();
            case "it":
                return getTitleIt();
            default:
                return getTitleEn();
        }
}
1 Like