14

I'd like to format a decimal number in an <apex:outputText> respecting the user's locale:

Using

{0,number,####.###}

should show a German user

10,234

and an American user

10.234

The Java MessageFormat which is used in Salesforce seems to do this but it does not work in Salesforce.

  • It will not work with outputText fields, so for the following format {0,number,####.###} you will always get 10.234 The use of outputField will solve this problem. The only inconvenience here is that the outputFields can be used only with sObjects. – Sergej Utko Nov 28 '13 at 10:48
  • 1
    @mastOr: How would you use the format string thing with an <apex:outputField>? Is that possible? – Robert Sösemann Nov 28 '13 at 10:53
  • 1
    @RobertSösemann It is not possible! For that i would create an extra helper sObject with fields of many possible data types (number, text, percent, ...) an use it ony for the output purposes. So if you have an Decimal variable and want to display it on the page with format that respects the user's locale - just assign the variables value to the the helper objects field of the same type and display this on the page. – Sergej Utko Nov 28 '13 at 11:21
12

Yes it is odd that the format strings are not interpreted in a locale sensitive way, i can only assume its due to the Java thread not being set to the users locale internally. There are two ways to approach this problem. Both approaches could be used directly in a controller with custom bindings or wrapped for reuse in a Visualforce Component, as per this idea, How to call parametrized function from Visualforce?.

Dynamically Generating your Format String

Ideally UserInfo would give us the decimal and thousand separators but it does not currently. However we can determine them indirectly. The Apex Decimal.format method is locale sensitive, the following code can be used to derive the separators needed.

public String getDynamicFormatString()
{
    Decimal value = 1000.10;
    String formattedValue = value.format();
    String thousandSep = formattedValue.substring(1,2);
    String decimalSep = formattedValue.substring(5,6);
    return '{0,number,#'+thousandSep+'###'+thousandSep+'###'+thousandSep+'###'+thousandSep+'###'+thousandSep+'##0'+decimalSep+'00}';
}

You can then expose this as binding in your page or component to use with the

<apex:outputText value="{!DynamicFormatString}">
    <apex:param value="{!ValueToFormat}" />
</apex:outputText>

Using outputField component with a dummy SObject Field

With this approach you have to use the outputField component instead of the outputText component. This requires a custom field binding though. So in this case you will have to create a custom object in your org / package who's sole purpose is to be used for formatting values, no data or user interaction.

For example if you are setting up your view state, construct the object and set its field/s with the values you wish to format, then bind to those fields, the following code fragments show the general idea.

public OutputHelper__c outputHelper {get;set;}

outputHelper = new OutputHelper__c(Number__c = valueToFormat);    

<apex:outputField value="{!outputHelper.Number__c}"/>

The above sample can be scaled to support multiple fields to format by either wrapping it a Visualforce Component or adding more fields e.g. Number1__c. For a lighter version you can hijack a standard field, for example the AnnualRevenue field on the Account.

public Account outputHelper {get;set;}

outputHelper = new Account(AnnualRevenue = valueToFormat);    

<apex:outputField value="{!outputHelper.AnnualRevenue}"/>
  • Your very welcome, please don't forget to mark the answer as valid if you feel it resolves the original question posed. Good luck! :) – Andrew Fawcett Nov 28 '13 at 12:37
  • I will do so as soon as I am finished with it! – Mathias Maciossek Nov 28 '13 at 12:59
  • A note to add to @AndrewFawcett's great answer, you can just as easily use a native field on a native object (User, Contact etc) in memory, to avoid dirtying your schema. – bigassforce Nov 28 '13 at 13:41
  • 1
    @user320 great point, basically hijack a standard field that does the trick, i'll update the answer, thanks! – Andrew Fawcett Nov 28 '13 at 21:57
8

I don't have enough reputation to writes comment. Therefore I have to put them into this answer:

Comment to Andrew Fawcett's answer

The first part of his post "Dynamically Generating your Format String" works only in locales where comma and point are the thousands separator and decimal separator, because DynamicFormatString in

apex:outputText value="{!DynamicFormatString}">

demands this format! You cannot just use other characters here. How would outputText know which characters you chose? It is not locale-aware. Source: http://docs.oracle.com/javase/7/docs/api/java/text/DecimalFormat.html and my tests.

Comment to the question

Interesting that Salesforce's documentation says the opposite: "This component does take localization into account." (source: http://www.salesforce.com/us/developer/docs/pages/Content/pages_compref_outputText.htm) But my tests (on API 29) also confirm what you say and that the documentation is wrong :(.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.