Skip to Main Content
Feature Request FR-4993
Product Area Developer Experience
Status OPEN

7 Voters

Translation with text messages per workspace instead of per application

tim van dooremalen Public
· Aug 20 2026

Idea Summary
In APEX 26.1 a new translation approach for applications based on Text Messages was introduced. This is a much more interesting way to translate an application than the shadow-application approach as far as I'm concerned. But it is still based on translating ONE application at a time. It would be a good idea to make one overall text-message “repository” that can be used in all your applications.

Use Case
We have dozens of applications that, to the user, act as one. Currently we have a homemade translation mechanism (that works ok-ish) but using the text-message approach would be much more solid. These applications share a set of approx. 6 to 7 thousand what we call “terms” that all have translations for 4 languages. So if we change a translation it will be immediately used in all applications, no need to copy it to application-specific messages. 

Preferred Solution (Optional)
Make it possible to use a workspace (or even instance) based text-message repository for translations. Of course it would be great if the PL/SQL API would work on this as well so we could leverage our current translation system.

Comments

Comments

  • tibor2 OP 3 weeks ago

    The Text Message–based translation approach is indeed much more flexible and modern than the previous shadow‑application model. As I understand it, your suggestion — a workspace‑ or instance‑level central translation repository — is technically already achievable with the current APEX architecture.

    The apex_application_translations table stores all translations. Each record has a unique identifier (translation_entry_id) along with application‑ and component‑level metadata: application_id, static_id, and language_code. Based on these attributes, translations can be synchronized into a custom table of any structure you prefer, and then written back into the APEX translation system when needed.

    A custom translation table can be designed flexibly, for example:

    application_id

    static_id

    from_language

    from_string

    to_language

    to_string

    note

    optional

    optional

    optional

    optional

    not null

    not null

    optional

    The core behavior is as follows:

    • If both application_id and static_id are provided, the same term can be translated differently per application or per component. Example: application_id = X, static_id = SAVE1, to_string = "Save changes" → applies only to that specific application/component.
    • If application_id and static_id are not provided, the translation is used uniformly across all applications. Example: from_string = "save", to_string = "Save" → identical translation everywhere.

    Writing translations back via PL/SQL is fully supported. For workspace‑level operation, you must first set the workspace security group ID:

    v_workspace_id := apex_util.find_security_group_id(p_workspace => _YOUR_WORKSPACE_NAME_);
    apex_util.set_security_group_id(p_security_group_id => v_workspace_id);
    

    Then the translation can be updated using the APEX API (in my program, “r” is a cursor alias):

    apex_lang.update_message (
        p_id                 => r.translation_entry_id,
        p_name               => r.message_name,
        p_language           => r.language_code,
        p_message_text       => r.value_to_publish,
        p_used_in_javascript => r.is_js_message,
        p_comment            => r.developer_comment,
        p_metadata           => r.metadata
    );
    

    As I understand it, this mechanism allows you to maintain a single central translation table and have changes immediately reflected across all applications — exactly as your proposal aims to achieve.

    The only difficulty is that APEX does not automatically generate a STATIC_ID for every translatable element. If STATIC_IDs were consistently available, central‑repository synchronization would be even simpler and more uniform.

    Ha szeretnéd, készíthetek egy még formálisabb, „Oracle APEX Ideas” stílusú változatot is.

  • tim van dooremalen OP 3 weeks ago

    Thank you for your analysis. I understand your solution, but if I understand correctly you would have to store every translation-message multiple times (once in every application it is used). My solution would be to store them only ONCE and make them available in all applications making maintenance a lot easier (within APEX as well). 

    Also, in your solution you might change e.g. the translation for SAVE (which is probably used in all applications) and then have to export all those applications to deploy them on another enviroment. In my solution it would only require deploying the translations. As we have over 60 applications that would require quite a lot less effort.

  • tibor2 OP 2 weeks ago

    Íme a teljes, egységes, finomított angol változat — szakmailag pontos, gördülékeny, dokumentáció‑stílusú, és minden korábbi tartalmat koherensen foglal össze.

    Using a custom translation table, each translation only needs to be stored once, and it can be updated through the API for all applications. In my example, the SAVE translation can be made available to every application through the API: the loop updates every entry where translate_from = 'save', so there is no need to export the applications. With some fine‑tuning, you can also distinguish between multiple translate_from = 'save' values by using STATIC_ID. In the custom translation table, using STATIC_ID is optional, but the API must always be called with the corresponding TRANSLATION_ENTRY_ID.

    If the applications are accessible within the same database, you may need a loop that iterates through the values of v_workspace, calls apex_util.set_security_group_id for each workspace, and then invokes the translation API for the relevant TRANSLATION_ENTRY_ID — in this example, for entries where translate_from is “save”. If an application resides in a different database, there are two options through a database link: either update the custom translation table and call the API from a program written in that database (which appears to be the cleaner solution), or call the API directly in the remote database (which tends to be more problematic).

    Creating translation entries — when they do not yet exist — is done using APEX_LANG.IMPORT_TEXT_MESSAGES.

    The following program is a working example that creates a single translation row; the code also makes it clear how multiple rows could be generated. The program constructs a CSV inside a CLOB variable (using chr(10) for line breaks, a mandatory header row, and a strict column order). The header is required, but its actual text does not matter; the column order cannot be changed, and the last column cannot be omitted.

    Kód

    procedure apex_new_trans_element(
        p_name         in varchar2, 
        p_language     in varchar2, 
        p_message_text in varchar2
    ) as
        v_app_id         NUMBER        := #YOUR_APP_ID#;
        v_workspace_name VARCHAR2(255) := '#YOUR_WORKSPACE_NAME#';
        v_workspace_id   NUMBER;
        v_csv_data       CLOB;
        v_escaped_text   VARCHAR2(32767);
    begin
        -- initialize APEX environment
        v_workspace_id := apex_util.find_security_group_id(p_workspace => v_workspace_name);
        apex_util.set_security_group_id(p_security_group_id => v_workspace_id);
    
        v_escaped_text := replace(p_message_text, '"', '""');
        
    v_csv_data := 'name,source,target,source language,target language,comment' || CHR(10) ||
                  p_name || ',"' || v_escaped_text || '","' || v_escaped_text || '",en,' || p_language || ',';
    
        -- call APEX 26.1 API
        apex_lang.import_text_messages(
            p_application_id => v_app_id,
            p_file           => v_csv_data,
            p_format         => apex_lang.c_export_format_csv
        );
    end apex_new_trans_element;
    

    Its usage is straightforward: the value of p_name becomes the STATIC_ID, which you can reference later. If its value is, for example, ELEM, then the &{ELEM}. reference will work.

    Ha szeretnéd, megírhatom ugyanezt még formálisabb Oracle‑dokumentációs hangnemben, vagy StackOverflow‑ra optimalizált tömör válaszként is.

  • tibor2 OP 2 weeks ago

    The following four ideas seek a solution to the same problem; please take a look at the other three ideas as well, and if you agree, vote for them.

    FR-5034 Globalization attributes use on objects
    FR-5029 Direct Translation Management from Page Designer
    FR-4993 Translation with text messages per workspace instead of per application
    FR-4994 One-Click "Seed & Publish All Languages" in APEX Page Designer or toolbar