Format decimal in <apex:outputText> respecting the user's Locale
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}"/>
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 :(.