Skip to main content

Multilingual APEX app using page items


You probably know the official way how to translate APEX apps. You most likely also know ho to translate APEX itself or how to add unsupported languages. For me, translating my apps the official way is too slow and complicated.

I often have requirements to translate just the most important things in the app, so people without english knowledge can get around. There is no need to translate every bit. Which is ideal for utilizing APEX items.


Lets explore this alternative. The main idea is to use APEX items instead of texts and translate these items based on user preference (or browser language when preference is missing). The main issue with this approach is the time needed to create and maintain these items. And also the item clutter madness and minimal item reusability. Who likes to have tens to hundreds items on page?

Check the source for this translated page, you should notice that I don't use item prefixes (for translation items to make code readable and reusable) and I don't have these translation items on same page... In my oppinion this is a clean page which can be easily changed by less skilled team members.


My workflow:

  • I create page (well, the whole app) in the primary language (english)
  • then I check Translations page, specifically New Items tab/region which contains list of texts which needs translations; I focus on just one page, translate it and then move to another page
  • I can adjust translated texts and make translations specific to a page or shared through the app (by using page_id 0)
  • I don't use prefixes to keep the page clean and items reusable on different pages (as you can see on screen above)

So all I need to do is to go to a Translation page, New items tab, check and confirm translations I would like to make and then switch text on the page with these (automatically created) page items. I can check supporting pages to take care of untranslated (slipped) and unused items.

I don't translate/extract everything. My focus is on page names, region names, buttons, hero regions and static texts there, grid column names and groups, chart series and field labels. You can see the extractions in translations_extracts view. You can add whatever you need.

All items are created automatically on a dedicated page (magic provided by app_actions.rebuild_page_947 procedure), I just have to switch text on page for the generated item name.

All translations are stored in a Translated_items table, can be easily adjusted and copyied between environments and changed by app administrators on the fly.

I have a function app.get_translated_item to take care of translations on server. And I have a init_translations process in APEX called before header on every page which will load translations into page items used on requested page.


CREATE TABLE translated_items (
    app_id              NUMBER(4)       CONSTRAINT nn_translated_items_app_id       NOT NULL,
    page_id             NUMBER(6)       CONSTRAINT nn_translated_items_page_id      NOT NULL,
    item_name           VARCHAR2(64)    CONSTRAINT nn_translated_items_name         NOT NULL,
    value_en            VARCHAR2(2000),
    value_cz            VARCHAR2(2000),
    value_sk            VARCHAR2(2000),
    value_pl            VARCHAR2(2000),
    value_hu            VARCHAR2(2000),
    CONSTRAINT pk_translated_items
        PRIMARY KEY (app_id, page_id, item_name),
    CONSTRAINT ch_translated_items_name
        CHECK (REGEXP_LIKE(item_name, '^([A-Z][A-Z0-9-_]*)$'))

Note to item reusability. If I have a column USER_NAME, I can have shared value stored under page_id 0 and page specific value under that page_id number. So if I am on page 945 and I have a translation under USER_NAME, page_id 945, I will get that. Otherwise I will get translation for page_id 0.


Lets translate a page 970 - Settings:

First step - open Translation page, New Items tab, select page 970.

You can adjust delete rows you dont want to translate, you can change texts, item names, add new rows... You save changes, save all rows or just selected rows.

I am ok with how it is so I will click on Save all rows.

Second step - go to first tab Translated Items, refresh the page or the grid and fill in values for other languages. Hit Save. Note that I removed two buttons because I already have BUTTON_REFRESH on page 0 and I will use that for all refresh buttons.

Third step - open 970 Settings page in APEX Builder and switch texts for items. Items were created automatically on page 947 (which holds all translated items) when you hit Save button on grid. I start with regions (headers) and buttons, then move to columns, groups and fields.

Last step - switch to the translated language to verify that all texts were translated.

For me, it is a game changer. I can easily and quickly translate texts in app or even delegate this to others in the team or even to people from business department. When something changes, I can response much quicker than with traditional approach.

What do you think?