Track #122: Optional locale attribute for HTML reports.
diff --git a/org.jacoco.ant/src/org/jacoco/ant/ReportTask.java b/org.jacoco.ant/src/org/jacoco/ant/ReportTask.java
index b38068f..701355d 100644
--- a/org.jacoco.ant/src/org/jacoco/ant/ReportTask.java
+++ b/org.jacoco.ant/src/org/jacoco/ant/ReportTask.java
@@ -25,6 +25,7 @@
 import java.util.HashMap;

 import java.util.Iterator;

 import java.util.List;

+import java.util.Locale;

 import java.util.Map;

 import java.util.zip.ZipOutputStream;

 

@@ -166,6 +167,8 @@
 

 		private String encoding = "UTF-8";

 

+		private Locale locale = Locale.getDefault();

+

 		private ZipOutputStream zipOutput;

 

 		/**

@@ -209,6 +212,17 @@
 			this.encoding = encoding;

 		}

 

+		/**

+		 * Sets the locale for generated text output. By default the platform

+		 * locale is used.

+		 * 

+		 * @param locale

+		 *            text locale

+		 */

+		public void setLocale(final Locale locale) {

+			this.locale = locale;

+		}

+

 		public IReportFormatter createFormatter() throws IOException {

 			final IMultiReportOutput output;

 			if (destfile != null) {

@@ -230,6 +244,7 @@
 			formatter.setReportOutput(output);

 			formatter.setFooterText(footer);

 			formatter.setOutputEncoding(encoding);

+			formatter.setLocale(locale);

 			return formatter;

 		}

 

diff --git a/org.jacoco.doc/buildhook.xml b/org.jacoco.doc/buildhook.xml
index f470271..f7d1c2f 100644
--- a/org.jacoco.doc/buildhook.xml
+++ b/org.jacoco.doc/buildhook.xml
@@ -88,7 +88,8 @@
 				</group>

 			</structure>

 			<html destdir="${result.dist.coverage.dir}"

-				  footer="Code Coverage Report for JaCoCo ${qualified.bundle.version}"/>

+				  footer="Code Coverage Report for JaCoCo ${qualified.bundle.version}"

+			      locale="en"/>

 			<csv destfile="${result.dist.coverage.dir}/coverage.csv"/>

 			<xml destfile="${result.dist.coverage.dir}/coverage.xml"/>

 		</jacoco:report>

diff --git a/org.jacoco.doc/docroot/doc/ant.html b/org.jacoco.doc/docroot/doc/ant.html
index 41ccf9f..9ac7ebc 100644
--- a/org.jacoco.doc/docroot/doc/ant.html
+++ b/org.jacoco.doc/docroot/doc/ant.html
@@ -555,13 +555,18 @@
     <tr>

       <td><code>footer</code></td>

       <td>Footer text for each report page.</td>

-      <td><i>No footer</i></td>

+      <td><i>no footer</i></td>

     </tr>

     <tr>

       <td><code>encoding</code></td>

-      <td>Encoding of the generated HTML pages.</td>

+      <td>Character encoding of generated HTML pages.</td>

       <td><code>UTF-8</code></td>

     </tr>

+    <tr>

+      <td><code>locale</code></td>

+      <td>Locale specified as ISO code (en, fr, jp, ...) used for number formating.</td>

+      <td><i>platform locale</i></td>

+    </tr>

   </tbody>

 </table>

 

diff --git a/org.jacoco.doc/docroot/doc/changes.html b/org.jacoco.doc/docroot/doc/changes.html
index 388fcf2..eeb3d01 100644
--- a/org.jacoco.doc/docroot/doc/changes.html
+++ b/org.jacoco.doc/docroot/doc/changes.html
@@ -22,6 +22,7 @@
 

 <h3>New Features</h3>

 <ul>

+  <li>Optional locale attribute for HTML reports (Track #122).</li>

   <li>Coverage tables in HTML report are now sortable (Track #98).</li>

   <li>The <code>report</code> Ant task issues a warning if source files are

       provided but class files do not contain debug information to collect line

diff --git a/org.jacoco.doc/docroot/doc/flow.html b/org.jacoco.doc/docroot/doc/flow.html
index f4bbb45..b256071 100644
--- a/org.jacoco.doc/docroot/doc/flow.html
+++ b/org.jacoco.doc/docroot/doc/flow.html
@@ -4,10 +4,12 @@
 <head>

   <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />

   <link rel="stylesheet" href=".resources/doc.css" charset="ISO-8859-1" type="text/css" />

+  <link rel="stylesheet" href="../coverage/.resources/prettify.css" charset="ISO-8859-1" type="text/css" />

   <link rel="shortcut icon" href=".resources/report.gif" type="image/gif" />

+  <script type="text/javascript" src="../coverage/.resources/prettify.js"></script>

   <title>JaCoCo - Control Flow Analysis</title>

 </head>

-<body>

+<body onload="prettyPrint()">

 

 <div class="breadcrumb">

   <a href="../index.html" class="el_report">JaCoCo</a> &gt;

@@ -28,16 +30,53 @@
   JaCoCo this analysis needs to happen on compiled class files (bytecode).

   This document defines graph structures for control flow analysis of Java

   bytecode and discusses strategies for probe insertion.

-  Marc R. Hoffmann, April 2010

+  Marc R. Hoffmann, July 2010

 </p>

 

 <h2>Motivation and Requirements</h2>

 

 <ul>

-  <li>Path Coverage</li>

+  <li>Branch Coverage</li>

   <li>Exception Detection</li>

 </ul>

 

+<h2>From Statement Coverage to Branch Coverage</h2>

+

+<p>

+  A 

+  JaCoCo till version 0.4.x provides statement coverage  

+  As as starting point 

+  differnce between statement coverage and branch coverage.

+  probe insertion strategy.  

+

+</p>

+

+<pre class="source lang-java">

+<span class="nr">    1</span>public void example() {

+<span class="nr">    2</span>    a();

+<span class="nr">    3</span>    if (condition()) {

+<span class="nr">    4</span>        b();

+<span class="nr">    5</span>    }

+<span class="nr">    6</span>    c();   

+<span class="nr">    7</span>}

+</pre>

+

+

+<pre class="source">

+<span class="nr">    1</span>public example() : void

+<span class="nr">    2</span>  L0

+<span class="nr">    3</span>    INVOKESTATIC Example.a() : void

+<span class="nr">    4</span>  L1

+<span class="nr">    5</span>    INVOKESTATIC Example.condition() : boolean

+<span class="nr">    6</span>    IFEQ L3

+<span class="nr">    7</span>  L2

+<span class="nr">    8</span>    INVOKESTATIC Example.b() : void

+<span class="nr">    9</span>  L3

+<span class="nr">   10</span>    INVOKESTATIC Example.c() : void

+<span class="nr">   11</span>  L4

+<span class="nr">   11</span>    RETURN

+</pre>

+

 <h2>The Control Flow Graph</h2>

 

 <ul>

@@ -54,9 +93,9 @@
 <p>

   Code coverage analysis is a runtime metric that provides execution details

   of the software under test. This requires detailed recording about the

-  instructions (instruction coverage) that have been executed. For path coverage

-  also the outcome of decisions has to be recorded. In any case execution data

-  is collected by so called probes:

+  instructions (instruction coverage) that have been executed. For branch

+  coverage also the outcome of decisions has to be recorded. In any case

+  execution data is collected by so called probes:

 </p>

 

 <p class="hint">

diff --git a/org.jacoco.report.test/src/org/jacoco/report/html/HTMLFormatterTest.java b/org.jacoco.report.test/src/org/jacoco/report/html/HTMLFormatterTest.java
index bc4c530..8dc4836 100644
--- a/org.jacoco.report.test/src/org/jacoco/report/html/HTMLFormatterTest.java
+++ b/org.jacoco.report.test/src/org/jacoco/report/html/HTMLFormatterTest.java
@@ -11,12 +11,16 @@
  *******************************************************************************/
 package org.jacoco.report.html;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
 
 import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.InputStreamReader;
+import java.util.Locale;
 
+import org.jacoco.report.ILanguageNames;
 import org.jacoco.report.MemoryMultiReportOutput;
 import org.jacoco.report.ReportStructureTestDriver;
 import org.junit.After;
@@ -78,8 +82,8 @@
 		final BufferedReader reader = new BufferedReader(new InputStreamReader(
 				output.getFileAsStream("index.html"), "UTF-8"));
 		final String line = reader.readLine();
-		assertTrue(line, line
-				.startsWith("<?xml version=\"1.0\" encoding=\"UTF-8\""));
+		assertTrue(line,
+				line.startsWith("<?xml version=\"1.0\" encoding=\"UTF-8\""));
 	}
 
 	@Test
@@ -89,8 +93,46 @@
 		final BufferedReader reader = new BufferedReader(new InputStreamReader(
 				output.getFileAsStream("index.html"), "UTF-16"));
 		final String line = reader.readLine();
-		assertTrue(line, line
-				.startsWith("<?xml version=\"1.0\" encoding=\"UTF-16\""));
+		assertTrue(line,
+				line.startsWith("<?xml version=\"1.0\" encoding=\"UTF-16\""));
+	}
+
+	@Test
+	public void testGetLanguageNames() throws Exception {
+		ILanguageNames names = new ILanguageNames() {
+			public String getPackageName(String vmname) {
+				return null;
+			}
+
+			public String getQualifiedClassName(String vmname) {
+				return null;
+			}
+
+			public String getClassName(String vmname, String vmsignature,
+					String vmsuperclass, String[] vminterfaces) {
+				return null;
+			}
+
+			public String getMethodName(String vmclassname,
+					String vmmethodname, String vmdesc, String vmsignature) {
+				return null;
+			}
+
+		};
+		formatter.setLanguageNames(names);
+		assertSame(names, formatter.getLanguageNames());
+	}
+
+	@Test
+	public void testGetFooterText() throws Exception {
+		formatter.setFooterText("Custom Footer");
+		assertEquals("Custom Footer", formatter.getFooterText());
+	}
+
+	@Test
+	public void testGetLocale() throws Exception {
+		formatter.setLocale(Locale.KOREAN);
+		assertEquals(Locale.KOREAN, formatter.getLocale());
 	}
 
 }
diff --git a/org.jacoco.report.test/src/org/jacoco/report/html/NodePageTest.java b/org.jacoco.report.test/src/org/jacoco/report/html/NodePageTest.java
index b13c794..41a314a 100644
--- a/org.jacoco.report.test/src/org/jacoco/report/html/NodePageTest.java
+++ b/org.jacoco.report.test/src/org/jacoco/report/html/NodePageTest.java
@@ -14,6 +14,7 @@
 import static org.junit.Assert.assertEquals;

 

 import java.io.IOException;

+import java.util.Locale;

 

 import org.jacoco.core.analysis.CounterImpl;

 import org.jacoco.core.analysis.CoverageNodeImpl;

@@ -105,6 +106,10 @@
 			public IIndexUpdate getIndexUpdate() {

 				throw new AssertionError("Unexpected method call.");

 			}

+

+			public Locale getLocale() {

+				return Locale.ENGLISH;

+			}

 		};

 		node = new CoverageNodeImpl(ElementType.GROUP, "Test", false);

 		page = new TestNodePage(node);

diff --git a/org.jacoco.report.test/src/org/jacoco/report/html/ReportPageTest.java b/org.jacoco.report.test/src/org/jacoco/report/html/ReportPageTest.java
index e04ef3e..73a0955 100644
--- a/org.jacoco.report.test/src/org/jacoco/report/html/ReportPageTest.java
+++ b/org.jacoco.report.test/src/org/jacoco/report/html/ReportPageTest.java
@@ -14,6 +14,7 @@
 import static org.junit.Assert.assertEquals;

 

 import java.io.IOException;

+import java.util.Locale;

 

 import org.jacoco.report.ILanguageNames;

 import org.jacoco.report.MemoryMultiReportOutput;

@@ -120,6 +121,11 @@
 			public IIndexUpdate getIndexUpdate() {

 				throw new AssertionError("Unexpected method call.");

 			}

+

+			public Locale getLocale() {

+				return Locale.ENGLISH;

+			}

+

 		};

 		ReportPage parent = new TestReportPage("Report", "el_report", null);

 		page = new TestReportPage("Test", "el_group", parent);

diff --git a/org.jacoco.report.test/src/org/jacoco/report/html/SessionsPageTest.java b/org.jacoco.report.test/src/org/jacoco/report/html/SessionsPageTest.java
index 62fb892..6b0b5ab 100644
--- a/org.jacoco.report.test/src/org/jacoco/report/html/SessionsPageTest.java
+++ b/org.jacoco.report.test/src/org/jacoco/report/html/SessionsPageTest.java
@@ -18,6 +18,7 @@
 import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
+import java.util.Locale;
 
 import org.jacoco.core.data.ExecutionData;
 import org.jacoco.core.data.SessionInfo;
@@ -94,6 +95,9 @@
 				return index;
 			}
 
+			public Locale getLocale() {
+				return Locale.ENGLISH;
+			}
 		};
 	}
 
diff --git a/org.jacoco.report.test/src/org/jacoco/report/html/SourceFilePageTest.java b/org.jacoco.report.test/src/org/jacoco/report/html/SourceFilePageTest.java
index b1d528c..fb69c72 100644
--- a/org.jacoco.report.test/src/org/jacoco/report/html/SourceFilePageTest.java
+++ b/org.jacoco.report.test/src/org/jacoco/report/html/SourceFilePageTest.java
@@ -17,6 +17,7 @@
 
 import java.io.File;
 import java.io.IOException;
+import java.util.Locale;
 
 import org.jacoco.core.analysis.CoverageNodeImpl;
 import org.jacoco.core.analysis.ICoverageNode.ElementType;
@@ -86,6 +87,10 @@
 			public IIndexUpdate getIndexUpdate() {
 				throw new AssertionError("Unexpected method call.");
 			}
+
+			public Locale getLocale() {
+				return Locale.ENGLISH;
+			}
 		};
 		locator = new DirectorySourceFileLocator(new File("./src"), "UTF-8");
 	}
diff --git a/org.jacoco.report.test/src/org/jacoco/report/html/table/BarColumnTest.java b/org.jacoco.report.test/src/org/jacoco/report/html/table/BarColumnTest.java
index 1be0ba2..8509b72 100644
--- a/org.jacoco.report.test/src/org/jacoco/report/html/table/BarColumnTest.java
+++ b/org.jacoco.report.test/src/org/jacoco/report/html/table/BarColumnTest.java
@@ -16,6 +16,7 @@
 

 import java.util.Arrays;

 import java.util.Comparator;

+import java.util.Locale;

 

 import org.jacoco.core.analysis.CounterImpl;

 import org.jacoco.core.analysis.CoverageNodeImpl;

@@ -53,6 +54,8 @@
 

 	private HTMLSupport support;

 

+	private IColumnRenderer column;

+

 	@Before

 	public void setup() throws Exception {

 		output = new MemoryMultiReportOutput();

@@ -62,6 +65,7 @@
 		doc.head().title();

 		td = doc.body().table("somestyle").tr().td();

 		support = new HTMLSupport();

+		column = new BarColumn(CounterEntity.LINE, Locale.ENGLISH);

 	}

 

 	@After

@@ -71,7 +75,6 @@
 

 	@Test

 	public void testInit() throws Exception {

-		final BarColumn column = new BarColumn(CounterEntity.LINE);

 		final ITableItem i = createItem(30, 24);

 		assertTrue(column.init(Arrays.asList(i), i.getNode()));

 		doc.close();

@@ -79,8 +82,7 @@
 

 	@Test

 	public void testFooter() throws Exception {

-		new BarColumn(CounterEntity.LINE).footer(td, createNode(20, 5),

-				resources, root);

+		column.footer(td, createNode(20, 5), resources, root);

 		doc.close();

 		final Document doc = support.parse(output.getFile("Test.html"));

 		assertEquals("", support.findStr(doc, "/html/body/table/tr/td/text()"));

@@ -88,11 +90,10 @@
 

 	@Test

 	public void testBarWidths() throws Exception {

-		final BarColumn col = new BarColumn(CounterEntity.LINE);

 		final ITableItem i1 = createItem(20, 5);

 		final ITableItem i2 = createItem(30, 24);

-		col.init(Arrays.asList(i1, i2), createNode(50, 29));

-		col.item(td, i1, resources, root);

+		column.init(Arrays.asList(i1, i2), createNode(50, 29));

+		column.item(td, i1, resources, root);

 		doc.close();

 		final Document doc = support.parse(output.getFile("Test.html"));

 

@@ -118,10 +119,9 @@
 

 	@Test

 	public void testRedBarOnly() throws Exception {

-		final BarColumn col = new BarColumn(CounterEntity.LINE);

 		final ITableItem i1 = createItem(20, 0);

-		col.init(Arrays.asList(i1), createNode(20, 0));

-		col.item(td, i1, resources, root);

+		column.init(Arrays.asList(i1), createNode(20, 0));

+		column.item(td, i1, resources, root);

 		doc.close();

 		final Document doc = support.parse(output.getFile("Test.html"));

 

@@ -139,10 +139,9 @@
 

 	@Test

 	public void testGreenBarOnly() throws Exception {

-		final BarColumn col = new BarColumn(CounterEntity.LINE);

 		final ITableItem i1 = createItem(20, 20);

-		col.init(Arrays.asList(i1), createNode(20, 20));

-		col.item(td, i1, resources, root);

+		column.init(Arrays.asList(i1), createNode(20, 20));

+		column.item(td, i1, resources, root);

 		doc.close();

 		final Document doc = support.parse(output.getFile("Test.html"));

 

@@ -159,9 +158,21 @@
 	}

 

 	@Test

+	public void testLocale() throws Exception {

+		final BarColumn col = new BarColumn(CounterEntity.LINE, Locale.FRENCH);

+		final ITableItem i1 = createItem(123456, 123456);

+		col.init(Arrays.asList(i1), createNode(20, 20));

+		col.item(td, i1, resources, root);

+		doc.close();

+		final Document doc = support.parse(output.getFile("Test.html"));

+

+		assertEquals("123\u00a0456",

+				support.findStr(doc, "/html/body/table/tr[1]/td/img[1]/@alt"));

+	}

+

+	@Test

 	public void testComparator1() throws Exception {

-		final BarColumn col = new BarColumn(CounterEntity.LINE);

-		final Comparator<ITableItem> c = col.getComparator();

+		final Comparator<ITableItem> c = column.getComparator();

 		final ITableItem i1 = createItem(100, 50);

 		final ITableItem i2 = createItem(100, 80);

 		assertTrue(c.compare(i1, i2) < 0);

@@ -172,8 +183,7 @@
 

 	@Test

 	public void testComparator2() throws Exception {

-		final BarColumn col = new BarColumn(CounterEntity.LINE);

-		final Comparator<ITableItem> c = col.getComparator();

+		final Comparator<ITableItem> c = column.getComparator();

 		final ITableItem i1 = createItem(110, 60);

 		final ITableItem i2 = createItem(100, 50);

 		assertTrue(c.compare(i1, i2) < 0);

diff --git a/org.jacoco.report.test/src/org/jacoco/report/html/table/CounterColumnTest.java b/org.jacoco.report.test/src/org/jacoco/report/html/table/CounterColumnTest.java
index dc58455..ae58712 100644
--- a/org.jacoco.report.test/src/org/jacoco/report/html/table/CounterColumnTest.java
+++ b/org.jacoco.report.test/src/org/jacoco/report/html/table/CounterColumnTest.java
@@ -18,6 +18,7 @@
 import java.util.Arrays;

 import java.util.Collections;

 import java.util.Comparator;

+import java.util.Locale;

 

 import org.jacoco.core.analysis.CounterImpl;

 import org.jacoco.core.analysis.CoverageNodeImpl;

@@ -55,6 +56,8 @@
 

 	private HTMLSupport support;

 

+	private Locale locale;

+

 	@Before

 	public void setup() throws Exception {

 		output = new MemoryMultiReportOutput();

@@ -64,6 +67,7 @@
 		doc.head().title();

 		td = doc.body().table("somestyle").tr().td();

 		support = new HTMLSupport();

+		locale = Locale.ENGLISH;

 	}

 

 	@After

@@ -73,7 +77,8 @@
 

 	@Test

 	public void testInitVisible() throws Exception {

-		IColumnRenderer column = CounterColumn.newTotal(CounterEntity.LINE);

+		IColumnRenderer column = CounterColumn.newTotal(CounterEntity.LINE,

+				locale);

 		final ITableItem item = createItem(1, 3);

 		assertTrue(column.init(Arrays.asList(item), item.getNode()));

 		doc.close();

@@ -81,7 +86,8 @@
 

 	@Test

 	public void testInitInvisible() throws Exception {

-		IColumnRenderer column = CounterColumn.newTotal(CounterEntity.LINE);

+		IColumnRenderer column = CounterColumn.newTotal(CounterEntity.LINE,

+				locale);

 		final ITableItem item = createItem(0, 0);

 		assertFalse(column.init(Arrays.asList(item), createNode(1, 0)));

 		doc.close();

@@ -89,7 +95,8 @@
 

 	@Test

 	public void testItemTotal() throws Exception {

-		IColumnRenderer column = CounterColumn.newTotal(CounterEntity.LINE);

+		IColumnRenderer column = CounterColumn.newTotal(CounterEntity.LINE,

+				locale);

 		final ITableItem item = createItem(150, 50);

 		column.init(Collections.singletonList(item), item.getNode());

 		column.item(td, item, resources, root);

@@ -101,7 +108,8 @@
 

 	@Test

 	public void testItemMissed() throws Exception {

-		IColumnRenderer column = CounterColumn.newMissed(CounterEntity.LINE);

+		IColumnRenderer column = CounterColumn.newMissed(CounterEntity.LINE,

+				locale);

 		final ITableItem item = createItem(150, 50);

 		column.init(Collections.singletonList(item), item.getNode());

 		column.item(td, item, resources, root);

@@ -113,7 +121,8 @@
 

 	@Test

 	public void testItemCovered() throws Exception {

-		IColumnRenderer column = CounterColumn.newCovered(CounterEntity.LINE);

+		IColumnRenderer column = CounterColumn.newCovered(CounterEntity.LINE,

+				locale);

 		final ITableItem item = createItem(150, 50);

 		column.init(Collections.singletonList(item), item.getNode());

 		column.item(td, item, resources, root);

@@ -124,8 +133,22 @@
 	}

 

 	@Test

+	public void testLocale() throws Exception {

+		IColumnRenderer column = CounterColumn.newTotal(CounterEntity.LINE,

+				Locale.ITALIAN);

+		final ITableItem item = createItem(1000, 0);

+		column.init(Collections.singletonList(item), item.getNode());

+		column.item(td, item, resources, root);

+		doc.close();

+		final Document doc = support.parse(output.getFile("Test.html"));

+		assertEquals("1.000",

+				support.findStr(doc, "/html/body/table/tr/td[1]/text()"));

+	}

+

+	@Test

 	public void testFooter() throws Exception {

-		IColumnRenderer column = CounterColumn.newTotal(CounterEntity.LINE);

+		IColumnRenderer column = CounterColumn.newTotal(CounterEntity.LINE,

+				locale);

 		final ITableItem item = createItem(80, 60);

 		column.init(Collections.singletonList(item), item.getNode());

 		column.footer(td, item.getNode(), resources, root);

@@ -137,7 +160,8 @@
 

 	@Test

 	public void testComparatorTotal() throws Exception {

-		IColumnRenderer column = CounterColumn.newTotal(CounterEntity.LINE);

+		IColumnRenderer column = CounterColumn.newTotal(CounterEntity.LINE,

+				locale);

 		final Comparator<ITableItem> c = column.getComparator();

 		final ITableItem i1 = createItem(30, 0);

 		final ITableItem i2 = createItem(40, 0);

@@ -149,7 +173,8 @@
 

 	@Test

 	public void testComparatorCovered() throws Exception {

-		IColumnRenderer column = CounterColumn.newCovered(CounterEntity.LINE);

+		IColumnRenderer column = CounterColumn.newCovered(CounterEntity.LINE,

+				locale);

 		final Comparator<ITableItem> c = column.getComparator();

 		final ITableItem i1 = createItem(100, 30);

 		final ITableItem i2 = createItem(100, 50);

@@ -161,7 +186,8 @@
 

 	@Test

 	public void testComparatorMissed() throws Exception {

-		IColumnRenderer column = CounterColumn.newMissed(CounterEntity.LINE);

+		IColumnRenderer column = CounterColumn.newMissed(CounterEntity.LINE,

+				locale);

 		final Comparator<ITableItem> c = column.getComparator();

 		final ITableItem i1 = createItem(100, 80);

 		final ITableItem i2 = createItem(100, 50);

diff --git a/org.jacoco.report.test/src/org/jacoco/report/html/table/PercentageColumnTest.java b/org.jacoco.report.test/src/org/jacoco/report/html/table/PercentageColumnTest.java
index 5dc41d4..2dd14fa 100644
--- a/org.jacoco.report.test/src/org/jacoco/report/html/table/PercentageColumnTest.java
+++ b/org.jacoco.report.test/src/org/jacoco/report/html/table/PercentageColumnTest.java
@@ -15,6 +15,7 @@
 import static org.junit.Assert.assertTrue;

 

 import java.util.Comparator;

+import java.util.Locale;

 

 import org.jacoco.core.analysis.CounterImpl;

 import org.jacoco.core.analysis.CoverageNodeImpl;

@@ -63,7 +64,7 @@
 		doc.head().title();

 		td = doc.body().table("somestyle").tr().td();

 		support = new HTMLSupport();

-		column = new PercentageColumn(CounterEntity.LINE);

+		column = new PercentageColumn(CounterEntity.LINE, Locale.ENGLISH);

 	}

 

 	@After

@@ -98,6 +99,18 @@
 	}

 

 	@Test

+	public void testLocale() throws Exception {

+		IColumnRenderer column = new PercentageColumn(CounterEntity.LINE,

+				Locale.FRENCH);

+		final ITableItem item = createItem(123, 1230);

+		column.item(td, item, resources, root);

+		doc.close();

+		final Document doc = support.parse(output.getFile("Test.html"));

+		assertEquals("1\u00a0000 %",

+				support.findStr(doc, "/html/body/table/tr/td[1]/text()"));

+	}

+

+	@Test

 	public void testFooter1() throws Exception {

 		final ITableItem item = createItem(80, 60);

 		column.footer(td, item.getNode(), resources, root);

diff --git a/org.jacoco.report/src/org/jacoco/report/html/HTMLFormatter.java b/org.jacoco.report/src/org/jacoco/report/html/HTMLFormatter.java
index 195a69d..de3ab6e 100644
--- a/org.jacoco.report/src/org/jacoco/report/html/HTMLFormatter.java
+++ b/org.jacoco.report/src/org/jacoco/report/html/HTMLFormatter.java
@@ -20,6 +20,7 @@
 import java.io.IOException;

 import java.util.Collection;

 import java.util.List;

+import java.util.Locale;

 

 import org.jacoco.core.analysis.ICoverageNode;

 import org.jacoco.core.analysis.ICoverageNode.CounterEntity;

@@ -54,6 +55,8 @@
 

 	private ILanguageNames languageNames = new JavaNames();

 

+	private Locale locale = Locale.getDefault();

+

 	private String footerText = "";

 

 	private String outputEncoding = "UTF-8";

@@ -64,31 +67,12 @@
 

 	private SessionsPage sessionsPage;

 

-	private final Table defaultTable;

+	private Table table;

 

 	/**

 	 * New instance with default settings.

 	 */

 	public HTMLFormatter() {

-		defaultTable = createDefaultTable();

-	}

-

-	private Table createDefaultTable() {

-		final Table table = new Table();

-		table.add("Element", null, new LabelColumn(), false);

-		table.add("Missed Instructions", null, new BarColumn(INSTRUCTION), true);

-		table.add("Cov.", Styles.CTR2, new PercentageColumn(INSTRUCTION), false);

-		addMissedTotalColumns(table, "Classes", CLASS);

-		addMissedTotalColumns(table, "Methods", METHOD);

-		addMissedTotalColumns(table, "Blocks", BLOCK);

-		addMissedTotalColumns(table, "Lines", LINE);

-		return table;

-	}

-

-	private static void addMissedTotalColumns(final Table table,

-			final String label, final CounterEntity entity) {

-		table.add("Missed", Styles.CTR1, CounterColumn.newMissed(entity), false);

-		table.add(label, Styles.CTR2, CounterColumn.newTotal(entity), false);

 	}

 

 	/**

@@ -114,6 +98,17 @@
 	}

 

 	/**

+	 * Sets the locale used for report rendering. The current default locale is

+	 * used by default.

+	 * 

+	 * @param locale

+	 *            locale used for report rendering

+	 */

+	public void setLocale(final Locale locale) {

+		this.locale = locale;

+	}

+

+	/**

 	 * Sets the optional text that should be included in every footer page.

 	 * 

 	 * @param footerText

@@ -144,7 +139,32 @@
 	}

 

 	public Table getTable() {

-		return defaultTable;

+		if (table == null) {

+			table = createTable();

+		}

+		return table;

+	}

+

+	private Table createTable() {

+		final Table table = new Table();

+		table.add("Element", null, new LabelColumn(), false);

+		table.add("Missed Instructions", null, new BarColumn(INSTRUCTION,

+				locale), true);

+		table.add("Cov.", Styles.CTR2,

+				new PercentageColumn(INSTRUCTION, locale), false);

+		addMissedTotalColumns(table, "Classes", CLASS);

+		addMissedTotalColumns(table, "Methods", METHOD);

+		addMissedTotalColumns(table, "Blocks", BLOCK);

+		addMissedTotalColumns(table, "Lines", LINE);

+		return table;

+	}

+

+	private void addMissedTotalColumns(final Table table, final String label,

+			final CounterEntity entity) {

+		table.add("Missed", Styles.CTR1,

+				CounterColumn.newMissed(entity, locale), false);

+		table.add(label, Styles.CTR2, CounterColumn.newTotal(entity, locale),

+				false);

 	}

 

 	public String getFooterText() {

@@ -163,6 +183,10 @@
 		return index;

 	}

 

+	public Locale getLocale() {

+		return locale;

+	}

+

 	// === IReportFormatter ===

 

 	public IReportVisitor createReportVisitor(final ICoverageNode rootNode,

diff --git a/org.jacoco.report/src/org/jacoco/report/html/IHTMLReportContext.java b/org.jacoco.report/src/org/jacoco/report/html/IHTMLReportContext.java
index 9a5853f..0c5cf1b 100644
--- a/org.jacoco.report/src/org/jacoco/report/html/IHTMLReportContext.java
+++ b/org.jacoco.report/src/org/jacoco/report/html/IHTMLReportContext.java
@@ -11,6 +11,8 @@
  *******************************************************************************/

 package org.jacoco.report.html;

 

+import java.util.Locale;

+

 import org.jacoco.report.ILanguageNames;

 import org.jacoco.report.html.index.IIndexUpdate;

 import org.jacoco.report.html.resources.Resources;

@@ -73,4 +75,11 @@
 	 */

 	public IIndexUpdate getIndexUpdate();

 

+	/**

+	 * Returns the locale used to format numbers and dates.

+	 * 

+	 * @return locale for numbers and dates

+	 */

+	public Locale getLocale();

+

 }
\ No newline at end of file
diff --git a/org.jacoco.report/src/org/jacoco/report/html/SessionsPage.java b/org.jacoco.report/src/org/jacoco/report/html/SessionsPage.java
index 58d30c7..09652d5 100644
--- a/org.jacoco.report/src/org/jacoco/report/html/SessionsPage.java
+++ b/org.jacoco.report/src/org/jacoco/report/html/SessionsPage.java
@@ -47,7 +47,7 @@
 

 	private final List<SessionInfo> sessionInfos;

 

-	private final DateFormat dateFormat = DateFormat.getDateTimeInstance();

+	private final DateFormat dateFormat;

 

 	private final List<ExecutionData> executionData;

 

@@ -71,6 +71,8 @@
 		this.sessionInfos = sessionInfos;

 		this.executionData = new ArrayList<ExecutionData>(executionData);

 		this.index = index;

+		dateFormat = DateFormat.getDateTimeInstance(DateFormat.DEFAULT,

+				DateFormat.DEFAULT, context.getLocale());

 		final ILanguageNames names = context.getLanguageNames();

 		Collections.sort(this.executionData, new Comparator<ExecutionData>() {

 			public int compare(final ExecutionData e1, final ExecutionData e2) {

@@ -141,7 +143,7 @@
 	protected String getFileName() {

 		return ".sessions.html";

 	}

-	

+

 	public String getLinkStyle() {

 		return Styles.EL_SESSION;

 	}

diff --git a/org.jacoco.report/src/org/jacoco/report/html/table/BarColumn.java b/org.jacoco.report/src/org/jacoco/report/html/table/BarColumn.java
index b11059a..e73a6b9 100644
--- a/org.jacoco.report/src/org/jacoco/report/html/table/BarColumn.java
+++ b/org.jacoco.report/src/org/jacoco/report/html/table/BarColumn.java
@@ -16,6 +16,7 @@
 import java.text.NumberFormat;

 import java.util.Comparator;

 import java.util.List;

+import java.util.Locale;

 

 import org.jacoco.core.analysis.CounterComparator;

 import org.jacoco.core.analysis.ICounter;

@@ -37,11 +38,10 @@
 

 	private static final int WIDTH = 120;

 

-	private final NumberFormat integerFormat = DecimalFormat

-			.getIntegerInstance();

-

 	private final CounterEntity entity;

 

+	private final NumberFormat integerFormat;

+

 	private int max;

 

 	private final Comparator<ITableItem> comparator;

@@ -52,9 +52,12 @@
 	 * 

 	 * @param entity

 	 *            counter entity for visualization

+	 * @param locale

+	 *            locale for rendering numbers

 	 */

-	public BarColumn(final CounterEntity entity) {

+	public BarColumn(final CounterEntity entity, final Locale locale) {

 		this.entity = entity;

+		this.integerFormat = DecimalFormat.getIntegerInstance(locale);

 		this.comparator = new TableItemComparator(CounterComparator.MISSEDITEMS

 				.reverse().on(entity)

 				.second(CounterComparator.TOTALITEMS.reverse().on(entity)));

diff --git a/org.jacoco.report/src/org/jacoco/report/html/table/CounterColumn.java b/org.jacoco.report/src/org/jacoco/report/html/table/CounterColumn.java
index f7d4f24..67c6310 100644
--- a/org.jacoco.report/src/org/jacoco/report/html/table/CounterColumn.java
+++ b/org.jacoco.report/src/org/jacoco/report/html/table/CounterColumn.java
@@ -16,6 +16,7 @@
 import java.text.NumberFormat;

 import java.util.Comparator;

 import java.util.List;

+import java.util.Locale;

 

 import org.jacoco.core.analysis.CounterComparator;

 import org.jacoco.core.analysis.ICounter;

@@ -40,11 +41,14 @@
 	 * 

 	 * @param entity

 	 *            counter entity for this column

+	 * @param locale

+	 *            locale for rendering numbers

 	 * @return column instance

 	 */

-	public static CounterColumn newTotal(final CounterEntity entity) {

-		return new CounterColumn(entity, CounterComparator.TOTALITEMS.reverse()

-				.on(entity)) {

+	public static CounterColumn newTotal(final CounterEntity entity,

+			final Locale locale) {

+		return new CounterColumn(entity, locale, CounterComparator.TOTALITEMS

+				.reverse().on(entity)) {

 			@Override

 			protected int getValue(final ICounter counter) {

 				return counter.getTotalCount();

@@ -57,10 +61,13 @@
 	 * 

 	 * @param entity

 	 *            counter entity for this column

+	 * @param locale

+	 *            locale for rendering numbers

 	 * @return column instance

 	 */

-	public static CounterColumn newMissed(final CounterEntity entity) {

-		return new CounterColumn(entity, CounterComparator.MISSEDITEMS

+	public static CounterColumn newMissed(final CounterEntity entity,

+			final Locale locale) {

+		return new CounterColumn(entity, locale, CounterComparator.MISSEDITEMS

 				.reverse().on(entity)) {

 			@Override

 			protected int getValue(final ICounter counter) {

@@ -74,10 +81,13 @@
 	 * 

 	 * @param entity

 	 *            counter entity for this column

+	 * @param locale

+	 *            locale for rendering numbers

 	 * @return column instance

 	 */

-	public static CounterColumn newCovered(final CounterEntity entity) {

-		return new CounterColumn(entity, CounterComparator.COVEREDITEMS

+	public static CounterColumn newCovered(final CounterEntity entity,

+			final Locale locale) {

+		return new CounterColumn(entity, locale, CounterComparator.COVEREDITEMS

 				.reverse().on(entity)) {

 			@Override

 			protected int getValue(final ICounter counter) {

@@ -86,11 +96,10 @@
 		};

 	}

 

-	private final NumberFormat integerFormat = DecimalFormat

-			.getIntegerInstance();

-

 	private final CounterEntity entity;

 

+	private final NumberFormat integerFormat;

+

 	private final Comparator<ITableItem> comparator;

 

 	/**

@@ -99,12 +108,15 @@
 	 * 

 	 * @param entity

 	 *            counter entity for this column

+	 * @param locale

+	 *            locale for rendering numbers

 	 * @param comparator

 	 *            comparator for the nodes of this column

 	 */

-	protected CounterColumn(final CounterEntity entity,

+	protected CounterColumn(final CounterEntity entity, final Locale locale,

 			final Comparator<ICoverageNode> comparator) {

 		this.entity = entity;

+		this.integerFormat = DecimalFormat.getIntegerInstance(locale);

 		this.comparator = new TableItemComparator(comparator);

 	}

 

diff --git a/org.jacoco.report/src/org/jacoco/report/html/table/PercentageColumn.java b/org.jacoco.report/src/org/jacoco/report/html/table/PercentageColumn.java
index 5b2267b..bfcb3b4 100644
--- a/org.jacoco.report/src/org/jacoco/report/html/table/PercentageColumn.java
+++ b/org.jacoco.report/src/org/jacoco/report/html/table/PercentageColumn.java
@@ -16,6 +16,7 @@
 import java.text.NumberFormat;

 import java.util.Comparator;

 import java.util.List;

+import java.util.Locale;

 

 import org.jacoco.core.analysis.CounterComparator;

 import org.jacoco.core.analysis.ICounter;

@@ -35,11 +36,10 @@
  */

 public class PercentageColumn implements IColumnRenderer {

 

-	private final NumberFormat percentageFormat = DecimalFormat

-			.getPercentInstance();

-

 	private final CounterEntity entity;

 

+	private final NumberFormat percentageFormat;

+

 	private final Comparator<ITableItem> comparator;

 

 	/**

@@ -48,9 +48,12 @@
 	 * 

 	 * @param entity

 	 *            counter entity for this column

+	 * @param locale

+	 *            locale for rendering numbers

 	 */

-	public PercentageColumn(final CounterEntity entity) {

+	public PercentageColumn(final CounterEntity entity, final Locale locale) {

 		this.entity = entity;

+		this.percentageFormat = DecimalFormat.getPercentInstance(locale);

 		comparator = new TableItemComparator(

 				CounterComparator.MISSEDRATIO.on(entity));

 	}