Oracle APEX - apex_lang.message vs apex_lang.lang
Similarities. Differences. Pros. Cons. You know..."vs."
Table of contents
This is a complicated subject because apex_lang.message (message
) and apex_lang.lang (lang
) are very similar and yet the differences are meaningful. Both message
and lang
allow you to do substitutions into the string and translate the string to another language. The devil, as they say, is in the details. Deciding when to use one or the other is complicated.
TLDR
If you are translating your application to another language, use message
.
If you want to store all of your translations (or substitutions) in a single application and use them in other applications, use message
.
If you want to create translations dynamically (using an API) use message
.
NOTE: message
requires you to register a message in order to do substitutions or translations.
If none of the above apply, you just want to do substitutions, and you don't plan to translate to another language, use lang
. (Yes, despite the name, lang
should only be used for substitutions, not translations. And yes...lang
can do translations, but message
is just the better choice.)
Note: lang
does not require you to register a dynamic translation to do substitutions, but it does require a dynamic translation to do translations. lang
is case sensitive.
The Details
The easiest way to show how each behaves is to show a few examples. These examples assume I have 2 APEX applications (app 111 and app 222). Both applications have two languages, English and Spanish. App 111 has translations defined for both message
and lang
. App 222 does not have any translations defined.
apex_lang.message
App 111 has the following "Text Messages" defined in Shared Components > Translate > Text Messages:
Name | English (en) | Spanish (es) |
GREETING | Hello | Hola |
APPROVED | %0 approved expense report number %1. | %0 aprobó el informe de gastos número %1. |
Let's look at the results you get for certain input bind variables. Assume we have a classic report with the following query:
select apex_lang.message(p_name => :P1_NAME,
p0 => :P1_PARAM0,
p1 => :P1_PARAM1,
p_lang => :P1_LANG,
p_application_id => :P1_APP_ID) the_result
from dual
If :P1_LANG is null, apex_lang.message assumes the current application language.
If :P1_APP_ID is null, apex_lang.message assumes the current application id (:APP_ID).
Sorry, you have to scroll left and right on the table below. I haven't figured out how to improve the format of this blog yet.
The application you are running | Application Language | P1_NAME | P1_PARAM0 | P1_PARAM1 | P1_LANG | P1_APP_ID | the_result | Notes about this result |
111 | en | GREETING | any value | any value | Hello | |||
111 | es | GREETING | any value | any value | Hola | |||
111 | en | greeting | any value | any value | Hello | p_name always converts to upper case in order to find the message. | ||
111 | en | grEeTing | any value | any value | Hola | p_name always converts to upper case in order to find the message. | ||
111 | en | GREETING | any value | any value | es | Hola | because we specified the language, it did the translation | |
222 | en | grEEting | any value | any value | APEX Version Dependent: Greeting (v22.1), grEEting (v19.2), GREETING (other versions) | because app 222 does not have messages defined, message converts to upper case, and can't find a value, so it returns "Greeting" in some manner, case depending on version. | ||
222 | en | greETing | any value | any value | es | 111 | Hola | Because we provided both p_lang and p_application_id, message was able to find the translation in app 11 and convert to Spanish. |
111 | en | approved | Velimir | 17 | Velimir approved expense report number 17. | |||
111 | es | APPROVED | Velimir | 17 | Velimir aprobó el informe de gastos número 17. | |||
222 | en | Approved | Velimir | 17 | Approved | Case depends on APEX Version | ||
111 or 222 | en | %0 Approved expense report number %1 | Velimir | 17 | %0 APPROVED EXPENSE REPORT NUMBER %1 | message will not do substitutions if the string has not been registered. |
apex_lang.lang
App 111 has the following "Dynamic Translations" defined in Shared Components > Translate > Dynamic Translations:
Translation From | Language | Translate To |
Hello | es | Hola |
%0 approved expense report number %1. | es | %0 aprobó el informe de gastos número %1. |
Let's look at the results you get for certain input bind variables. Assume we have a classic report with the following query:
select apex_lang.lang(p_primary_text_string => :P1_NAME,
p0 => :P1_PARAM0,
p1 => :P1_PARAM1,
p_primary_language => :P1_LANG) the_result
from dual
If :P1_LANG is null, apex_lang.lang assumes the current application language.
apex_lang.lang does not have the ability to look for a Dynamic Translation in another application. It must be in the current application.
Sorry, you have to scroll left and right on the table below. I haven't figured out how to improve the format of this blog yet.
The application you are running | Application Session Language | P1_NAME | P1_PARAM0 | P1_PARAM1 | P1_LANG | the_result | Notes about this result |
111 | en | Hello | any value | any value | Hello | ||
111 | es | Hello | any value | any value | Hola | ||
111 | en | hello | any value | any value | hello | hello, lower case, is not registered. | |
222 | es | Hello | any value | any value | Hello | Hello, is not registered in app 222 and will not translate. | |
111 | en | %0 approved expense report number %1. | Velimir | 17 | Velimir approved expense report number 17. | ||
111 | es | %0 approved expense report number %1. | Velimir | 17 | Velimir aprobó el informe de gastos número 17. | ||
111 | en | %0 approved expense report number %1. | Velimir | 17 | es | Velimir aprobó el informe de gastos número 17. | because we specified the language it translated. |
111 | es | %0 Approved expense report number %1. | Velimir | 17 | Velimir Approved expense report number 17. | apex_lang.lang is case sensitive. Because "Approved" has a capital A it did not translate. | |
222 | en | %0 approved expense report number %1. | Velimer | 17 | Velimir approved expense report number 17. | apex_lang.lang does not require a registration to do subsitutions. | |
222 | es | %0 approved expense report number %1. | Velimer | 17 | Velimir approved expense report number 17. | apex_lang.lang does not require a registration to do subsitutions, but it will not translate without a registered translation. | |
111 or 222 | en | Hi %0, have a great %1. | Michael | day | Hi Michael, have a great day. | apex_lang.lang does not require a registration to do substitutions. |