Bug 244468 - Support reading extension registry in any locale
diff --git a/bundles/org.eclipse.core.runtime.compatibility.registry/META-INF/MANIFEST.MF b/bundles/org.eclipse.core.runtime.compatibility.registry/META-INF/MANIFEST.MF
index 557e5b5..477ece4 100644
--- a/bundles/org.eclipse.core.runtime.compatibility.registry/META-INF/MANIFEST.MF
+++ b/bundles/org.eclipse.core.runtime.compatibility.registry/META-INF/MANIFEST.MF
@@ -2,9 +2,9 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: %fragmentName
 Bundle-SymbolicName: org.eclipse.core.runtime.compatibility.registry
-Bundle-Version: 3.2.300.qualifier
+Bundle-Version: 3.3.0.qualifier
 Bundle-Vendor: %providerName
-Fragment-Host: org.eclipse.equinox.registry;bundle-version="[3.3.0,3.6.0)"
+Fragment-Host: org.eclipse.equinox.registry;bundle-version="[3.5.0,3.6.0)"
 Bundle-Localization: fragment
 Eclipse-PatchFragment: true
 Bundle-ClassPath: runtime_registry_compatibility.jar
diff --git a/bundles/org.eclipse.core.runtime.compatibility.registry/src/org/eclipse/core/runtime/IExtension.java b/bundles/org.eclipse.core.runtime.compatibility.registry/src/org/eclipse/core/runtime/IExtension.java
index 6e37f84..16b634d 100644
--- a/bundles/org.eclipse.core.runtime.compatibility.registry/src/org/eclipse/core/runtime/IExtension.java
+++ b/bundles/org.eclipse.core.runtime.compatibility.registry/src/org/eclipse/core/runtime/IExtension.java
@@ -106,6 +106,27 @@
 	public String getLabel() throws InvalidRegistryObjectException;
 
 	/**
+	 * When multi-language support is enabled, this method returns a displayable label for this 
+	 * extension in the specified locale. Returns the empty string if no label for this extension
+	 * is specified in the plug-in manifest file.
+	 * <p> 
+	 * The locale matching tries to find the best match between available translations and 
+	 * the requested locale, falling back to a more generic locale ("en") when the specific 
+	 * locale ("en_US") is not available. 
+	 * </p><p>
+	 * If multi-language support is not enabled, this method is equivalent to the method 
+	 * {@link #getLabel()}.
+	 * </p>
+	 * @param locale the requested locale
+	 * @return a displayable string label for this extension,
+	 *    possibly the empty string
+	 * @throws InvalidRegistryObjectException if this extension is no longer valid
+	 * @see IExtensionRegistry#isMultiLanguage()
+	 * @since 3.5
+	 */
+	public String getLabel(String locale) throws InvalidRegistryObjectException;
+
+	/**
 	 * Returns the simple identifier of this extension, or <code>null</code>
 	 * if this extension does not have an identifier.
 	 * This identifier is specified in the plug-in manifest (<code>plugin.xml</code>) 
diff --git a/bundles/org.eclipse.core.runtime.compatibility.registry/src/org/eclipse/core/runtime/IExtensionPoint.java b/bundles/org.eclipse.core.runtime.compatibility.registry/src/org/eclipse/core/runtime/IExtensionPoint.java
index 3a8858d..a4e397d 100644
--- a/bundles/org.eclipse.core.runtime.compatibility.registry/src/org/eclipse/core/runtime/IExtensionPoint.java
+++ b/bundles/org.eclipse.core.runtime.compatibility.registry/src/org/eclipse/core/runtime/IExtensionPoint.java
@@ -120,6 +120,28 @@
 	public String getLabel() throws InvalidRegistryObjectException;
 
 	/**
+	 * When multi-language support is enabled, this method returns a displayable label 
+	 * for this extension point in the specified locale.
+	 * Returns the empty string if no label for this extension point
+	 * is specified in the plug-in manifest file.
+	 * <p> 
+	 * The locale matching tries to find the best match between available translations and 
+	 * the requested locale, falling back to a more generic locale ("en") when the specific 
+	 * locale ("en_US") is not available. 
+	 * </p><p>
+	 * If multi-language support is not enabled, this method is equivalent to the method 
+	 * {@link #getLabel()}.
+	 * </p>
+	 * @param locale the requested locale
+	 * @return a displayable string label for this extension point,
+	 *    possibly the empty string
+	 * @throws InvalidRegistryObjectException if this extension point is no longer valid
+	 * @see IExtensionRegistry#isMultiLanguage()
+	 * @since 3.5
+	 */
+	public String getLabel(String locale) throws InvalidRegistryObjectException;
+
+	/**
 	 * Returns reference to the extension point schema. The schema 
 	 * reference is returned as a URL path relative to the plug-in 
 	 * installation URL. 
diff --git a/tests/org.eclipse.core.tests.runtime/Plugin_Testing/registry/multiLang/bundleA/META-INF/MANIFEST.MF b/tests/org.eclipse.core.tests.runtime/Plugin_Testing/registry/multiLang/bundleA/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..baed376
--- /dev/null
+++ b/tests/org.eclipse.core.tests.runtime/Plugin_Testing/registry/multiLang/bundleA/META-INF/MANIFEST.MF
@@ -0,0 +1,7 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: Multi-language registry test
+Bundle-SymbolicName: org.eclipse.equinox.registry.tests.multilang; singleton:=true
+Bundle-Version: 1.0.0.qualifier
+Bundle-Vendor: Eclipse.org
+Bundle-Localization: plugin
diff --git a/tests/org.eclipse.core.tests.runtime/Plugin_Testing/registry/multiLang/bundleA/plugin.properties b/tests/org.eclipse.core.tests.runtime/Plugin_Testing/registry/multiLang/bundleA/plugin.properties
new file mode 100644
index 0000000..221a0d9
--- /dev/null
+++ b/tests/org.eclipse.core.tests.runtime/Plugin_Testing/registry/multiLang/bundleA/plugin.properties
@@ -0,0 +1,3 @@
+attributeTest = Hello World
+valueTest = Cats and dogs
+altTest = eclipse
diff --git a/tests/org.eclipse.core.tests.runtime/Plugin_Testing/registry/multiLang/bundleA/plugin.xml b/tests/org.eclipse.core.tests.runtime/Plugin_Testing/registry/multiLang/bundleA/plugin.xml
new file mode 100644
index 0000000..a403780
--- /dev/null
+++ b/tests/org.eclipse.core.tests.runtime/Plugin_Testing/registry/multiLang/bundleA/plugin.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.2"?>
+<plugin>
+   <extension-point id="org.eclipse.test.registryMulti.PointA" 
+         name="%attributeTest" 
+         schema="schema/PointA.exsd"/>
+   <extension id="org.eclipse.test.registryMulti.ExtA"
+         name="%valueTest"
+         point="org.eclipse.test.registryMulti.PointA">
+      <product
+            application="Application"
+            name="%attributeTest">
+            <section>
+                  <subdivision division="%altTest">
+                  </subdivision>
+            </section>
+      </product>
+   </extension>
+   
+   <extension-point id="org.eclipse.test.registryMulti.PointValue" 
+         name="Multi language registry test PointValue" 
+         schema="schema/PointA.exsd"/>
+   <extension id="org.eclipse.test.registryMulti.ExtValue"
+         name="Multi language registry test Extension Value"
+         point="org.eclipse.test.registryMulti.PointValue">
+      <product>
+            %valueTest
+      </product>
+   </extension>
+   
+</plugin>
diff --git a/tests/org.eclipse.core.tests.runtime/Plugin_Testing/registry/multiLang/bundleA/plugin_de.properties b/tests/org.eclipse.core.tests.runtime/Plugin_Testing/registry/multiLang/bundleA/plugin_de.properties
new file mode 100644
index 0000000..1eb8284
--- /dev/null
+++ b/tests/org.eclipse.core.tests.runtime/Plugin_Testing/registry/multiLang/bundleA/plugin_de.properties
@@ -0,0 +1,3 @@
+attributeTest = Hallo Welt
+valueTest = Hunde und Katzen
+altTest = Eklipse
diff --git a/tests/org.eclipse.core.tests.runtime/Plugin_Testing/registry/multiLang/bundleA/plugin_fi.properties b/tests/org.eclipse.core.tests.runtime/Plugin_Testing/registry/multiLang/bundleA/plugin_fi.properties
new file mode 100644
index 0000000..4c30182
--- /dev/null
+++ b/tests/org.eclipse.core.tests.runtime/Plugin_Testing/registry/multiLang/bundleA/plugin_fi.properties
@@ -0,0 +1,3 @@
+attributeTest = Hei maailma
+valueTest = Kissat ja koirat
+altTest = pimennys
diff --git a/tests/org.eclipse.core.tests.runtime/Plugin_Testing/registry/multiLang/fragmentA/META-INF/MANIFEST.MF b/tests/org.eclipse.core.tests.runtime/Plugin_Testing/registry/multiLang/fragmentA/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..615a01b
--- /dev/null
+++ b/tests/org.eclipse.core.tests.runtime/Plugin_Testing/registry/multiLang/fragmentA/META-INF/MANIFEST.MF
@@ -0,0 +1,8 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: Multi-language fragment registry test
+Bundle-SymbolicName: org.eclipse.equinox.registry.tests.multilang.fragment; singleton:=true
+Bundle-Version: 1.0.0.qualifier
+Fragment-Host: org.eclipse.equinox.registry.tests.multilang;bundle-version="[1.0.0,2.0.0)"
+Bundle-Vendor: Eclipse.org
+Bundle-Localization: fragment
diff --git a/tests/org.eclipse.core.tests.runtime/Plugin_Testing/registry/multiLang/fragmentA/fragment.properties b/tests/org.eclipse.core.tests.runtime/Plugin_Testing/registry/multiLang/fragmentA/fragment.properties
new file mode 100644
index 0000000..606f3e5
--- /dev/null
+++ b/tests/org.eclipse.core.tests.runtime/Plugin_Testing/registry/multiLang/fragmentA/fragment.properties
@@ -0,0 +1 @@
+baseTest = Make haste slowly
diff --git a/tests/org.eclipse.core.tests.runtime/Plugin_Testing/registry/multiLang/fragmentA/fragment.xml b/tests/org.eclipse.core.tests.runtime/Plugin_Testing/registry/multiLang/fragmentA/fragment.xml
new file mode 100644
index 0000000..9c790a9
--- /dev/null
+++ b/tests/org.eclipse.core.tests.runtime/Plugin_Testing/registry/multiLang/fragmentA/fragment.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.2"?>
+<plugin>
+   <extension-point id="org.eclipse.test.registryMulti.FragmentPointA" 
+         name="Multi language registry test FragmentPointA" 
+         schema="schema/FragmentPointA.exsd"/>
+   <extension id="org.eclipse.test.registryMulti.FragmentExtA"
+         name="Multi language registry test Extension A"
+         point="org.eclipse.test.registryMulti.FragmentPointA">
+      <product
+            name="%baseTest"
+            application="Application">
+      </product>
+   </extension>
+</plugin>
diff --git a/tests/org.eclipse.core.tests.runtime/Plugin_Testing/registry/multiLang/fragmentA/fragment_la.properties b/tests/org.eclipse.core.tests.runtime/Plugin_Testing/registry/multiLang/fragmentA/fragment_la.properties
new file mode 100644
index 0000000..ee1a835
--- /dev/null
+++ b/tests/org.eclipse.core.tests.runtime/Plugin_Testing/registry/multiLang/fragmentA/fragment_la.properties
@@ -0,0 +1 @@
+baseTest = Festina lente
diff --git a/tests/org.eclipse.core.tests.runtime/Plugin_Testing/registry/multiLang/fragmentA/plugin_it.properties b/tests/org.eclipse.core.tests.runtime/Plugin_Testing/registry/multiLang/fragmentA/plugin_it.properties
new file mode 100644
index 0000000..373b708
--- /dev/null
+++ b/tests/org.eclipse.core.tests.runtime/Plugin_Testing/registry/multiLang/fragmentA/plugin_it.properties
@@ -0,0 +1,3 @@
+attributeTest = Ciao a tutti
+valueTest = Cani e gatti
+altTest = eclissi
diff --git a/tests/org.eclipse.core.tests.runtime/src/org/eclipse/core/tests/internal/registry/AllTests.java b/tests/org.eclipse.core.tests.runtime/src/org/eclipse/core/tests/internal/registry/AllTests.java
index e4b978a..bfc73db 100644
--- a/tests/org.eclipse.core.tests.runtime/src/org/eclipse/core/tests/internal/registry/AllTests.java
+++ b/tests/org.eclipse.core.tests.runtime/src/org/eclipse/core/tests/internal/registry/AllTests.java
@@ -33,6 +33,7 @@
 		suite.addTest(ExtensionRegistryStaticTest.suite()); // test again
 		suite.addTest(RegistryListenerTest.suite());
 		suite.addTest(InputErrorTest.suite());
+		suite.addTest(MultiLanguageTest.suite());
 		return suite;
 	}
 }
diff --git a/tests/org.eclipse.core.tests.runtime/src/org/eclipse/core/tests/internal/registry/MultiLanguageTest.java b/tests/org.eclipse.core.tests.runtime/src/org/eclipse/core/tests/internal/registry/MultiLanguageTest.java
new file mode 100644
index 0000000..15568eb
--- /dev/null
+++ b/tests/org.eclipse.core.tests.runtime/src/org/eclipse/core/tests/internal/registry/MultiLanguageTest.java
@@ -0,0 +1,319 @@
+/*******************************************************************************
+ * Copyright (c) 2009 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.core.tests.internal.registry;
+
+import java.io.File;
+import java.util.Locale;
+import junit.framework.*;
+import org.eclipse.core.internal.registry.IRegistryConstants;
+import org.eclipse.core.runtime.*;
+import org.eclipse.core.runtime.spi.RegistryStrategy;
+import org.eclipse.core.tests.harness.BundleTestingHelper;
+import org.eclipse.core.tests.harness.FileSystemHelper;
+import org.eclipse.core.tests.runtime.RuntimeTestsPlugin;
+import org.eclipse.osgi.service.localization.LocaleProvider;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.packageadmin.PackageAdmin;
+import org.osgi.util.tracker.ServiceTracker;
+
+/**
+ * Run with no NL argument or with "-nl en".
+ */
+public class MultiLanguageTest extends TestCase {
+
+	class LocaleProviderTest implements LocaleProvider {
+		public Locale currentLocale;
+
+		public Locale getLocale() {
+			return currentLocale;
+		}
+	}
+
+	private ServiceTracker bundleTracker = null;
+
+	private static String helloWorld = "Hello World";
+	private static String helloWorldGerman = "Hallo Welt";
+	private static String helloWorldItalian = "Ciao a tutti";
+	private static String helloWorldFinnish = "Hei maailma";
+
+	private static String catsAndDogs = "Cats and dogs";
+	private static String catsAndDogsGerman = "Hunde und Katzen";
+	private static String catsAndDogsItalian = "Cani e gatti";
+	private static String catsAndDogsFinnish = "Kissat ja koirat";
+
+	private static String eclipse = "eclipse";
+	private static String eclipseGerman = "Eklipse";
+	private static String eclipseItalian = "eclissi";
+	private static String eclipseFinnish = "pimennys";
+
+	private static String proverb = "Make haste slowly";
+	private static String proverbLatin = "Festina lente";
+
+	private Bundle bundle;
+	private Bundle bundleFragment;
+	private String oldMultiLangValue;
+	private IPath tmpPath;
+	private File registryLocation;
+
+	protected void setUp() throws Exception {
+		super.setUp();
+
+		// install test bundles 
+		bundle = BundleTestingHelper.installBundle("0.1", RuntimeTestsPlugin.getContext(), RuntimeTestsPlugin.TEST_FILES_ROOT + "registry/multiLang/bundleA");
+		bundleFragment = BundleTestingHelper.installBundle("0.2", RuntimeTestsPlugin.getContext(), RuntimeTestsPlugin.TEST_FILES_ROOT + "registry/multiLang/fragmentA");
+		getBundleAdmin().resolveBundles(new Bundle[] {bundle});
+
+		// find a place for the extension registry cache
+		tmpPath = FileSystemHelper.getRandomLocation(FileSystemHelper.getTempDir());
+		registryLocation = tmpPath.append("testMulti").toFile();
+		registryLocation.mkdirs();
+
+		// switch environment to multi-language
+		oldMultiLangValue = System.getProperty(IRegistryConstants.PROP_MULTI_LANGUAGE);
+		System.setProperty(IRegistryConstants.PROP_MULTI_LANGUAGE, "true");
+	}
+
+	protected void tearDown() throws Exception {
+		// delete registry cache
+		FileSystemHelper.clear(tmpPath.toFile());
+
+		// remove test bundles
+		bundleFragment.uninstall();
+		bundle.uninstall();
+		getBundleAdmin().refreshPackages(new Bundle[] {bundle});
+
+		// restore system environment
+		if (oldMultiLangValue == null)
+			System.clearProperty(IRegistryConstants.PROP_MULTI_LANGUAGE);
+		else
+			System.setProperty(IRegistryConstants.PROP_MULTI_LANGUAGE, oldMultiLangValue);
+
+		if (bundleTracker != null) {
+			bundleTracker.close();
+			bundleTracker = null;
+		}
+		super.tearDown();
+	}
+
+	/**
+	 * Tests APIs that take Locale as an argument.
+	 */
+	public void testMultiLocale() {
+		Object masterToken = new Object();
+		// Create a multi-language extension registry
+		File[] registryLocations = new File[] {registryLocation};
+		boolean[] readOnly = new boolean[] {false};
+		RegistryStrategy strategy = RegistryFactory.createOSGiStrategy(registryLocations, readOnly, masterToken);
+		IExtensionRegistry localRegistry = RegistryFactory.createRegistry(strategy, masterToken, null);
+		assertTrue(localRegistry.isMultiLanguage());
+
+		// this is a direct test
+		checkTranslations(localRegistry, false);
+
+		// test cache
+		localRegistry.stop(masterToken);
+		IExtensionRegistry registryCached = RegistryFactory.createRegistry(strategy, masterToken, null);
+		assertTrue(registryCached.isMultiLanguage());
+		checkTranslations(registryCached, true);
+
+		registryCached.stop(masterToken);
+	}
+
+	/**
+	 * Tests APIs that use implicit default Locale.
+	 */
+	public void testMultiLocaleService() {
+		ServiceRegistration registration = null;
+		try {
+			Object masterToken = new Object();
+			// Create a multi-language extension registry
+			File[] registryLocations = new File[] {registryLocation};
+			boolean[] readOnly = new boolean[] {false};
+			RegistryStrategy strategy = RegistryFactory.createOSGiStrategy(registryLocations, readOnly, masterToken);
+			IExtensionRegistry localRegistry = RegistryFactory.createRegistry(strategy, masterToken, null);
+			assertTrue(localRegistry.isMultiLanguage());
+
+			// this is a direct test
+			checkTranslationsService(localRegistry, false);
+
+			// test cache
+			localRegistry.stop(masterToken);
+			IExtensionRegistry registryCached = RegistryFactory.createRegistry(strategy, masterToken, null);
+			assertTrue(registryCached.isMultiLanguage());
+			checkTranslationsService(registryCached, true);
+			registryCached.stop(masterToken);
+		} finally {
+			if (registration != null)
+				registration.unregister();
+		}
+	}
+
+	private void checkTranslationsService(IExtensionRegistry registry, boolean extended) {
+		ServiceRegistration registration = null;
+		try {
+			IExtensionPoint extPoint = registry.getExtensionPoint("org.eclipse.test.registryMulti.PointA");
+			assertNotNull(extPoint);
+			IExtension extension = registry.getExtension("org.eclipse.test.registryMulti.ExtA");
+			assertNotNull(extension);
+			IConfigurationElement[] elements = registry.getConfigurationElementsFor("org.eclipse.test.registryMulti", "PointA", "org.eclipse.test.registryMulti.ExtA");
+			assertNotNull(elements);
+			assertEquals(1, elements.length);
+			IConfigurationElement element = elements[0];
+			assertNotNull(element);
+			IConfigurationElement[] sectionElements = element.getChildren("section");
+			assertNotNull(sectionElements);
+			assertEquals(1, sectionElements.length);
+			IConfigurationElement[] subdivisionElements = sectionElements[0].getChildren("subdivision");
+			assertNotNull(subdivisionElements);
+			assertEquals(1, subdivisionElements.length);
+			IConfigurationElement[] elementsValue = registry.getConfigurationElementsFor("org.eclipse.test.registryMulti", "PointValue", "org.eclipse.test.registryMulti.ExtValue");
+			assertNotNull(elementsValue);
+			assertEquals(1, elementsValue.length);
+			IConfigurationElement elementValue = elementsValue[0];
+			assertNotNull(elementValue);
+
+			// default: no service registered
+			assertEquals(helloWorld, extPoint.getLabel());
+			assertEquals(catsAndDogs, extension.getLabel());
+			assertEquals(helloWorld, element.getAttribute("name"));
+			assertEquals(eclipse, subdivisionElements[0].getAttribute("division"));
+			assertEquals(catsAndDogs, elementValue.getValue());
+
+			// locale set to German
+			LocaleProviderTest localeProvider = new LocaleProviderTest();
+			registration = RuntimeTestsPlugin.getContext().registerService(LocaleProvider.class.getName(), localeProvider, null);
+			localeProvider.currentLocale = new Locale("de_DE");
+			assertEquals(helloWorldGerman, extPoint.getLabel());
+			assertEquals(catsAndDogsGerman, extension.getLabel());
+			assertEquals(helloWorldGerman, element.getAttribute("name"));
+			assertEquals(eclipseGerman, subdivisionElements[0].getAttribute("division"));
+			assertEquals(catsAndDogsGerman, elementValue.getValue());
+
+			// locale changed to Italian
+			localeProvider.currentLocale = new Locale("it_IT");
+			assertEquals(catsAndDogsItalian, extension.getLabel());
+			assertEquals(helloWorldItalian, extPoint.getLabel());
+			assertEquals(helloWorldItalian, element.getAttribute("name"));
+			assertEquals(eclipseItalian, subdivisionElements[0].getAttribute("division"));
+			assertEquals(catsAndDogsItalian, elementValue.getValue());
+
+			if (extended) { // check Finnish
+				localeProvider.currentLocale = new Locale("fi_FI");
+				assertEquals(catsAndDogsFinnish, extension.getLabel());
+				assertEquals(helloWorldFinnish, extPoint.getLabel());
+				assertEquals(helloWorldFinnish, element.getAttribute("name"));
+				assertEquals(eclipseFinnish, subdivisionElements[0].getAttribute("division"));
+				assertEquals(catsAndDogsFinnish, elementValue.getValue());
+			}
+
+			// unregister service - locale back to default
+			registration.unregister();
+			registration = null;
+			assertEquals(helloWorld, extPoint.getLabel());
+			assertEquals(catsAndDogs, extension.getLabel());
+			assertEquals(helloWorld, element.getAttribute("name"));
+			assertEquals(eclipse, subdivisionElements[0].getAttribute("division"));
+			assertEquals(catsAndDogs, elementValue.getValue());
+		} finally {
+			if (registration != null)
+				registration.unregister();
+		}
+	}
+
+	private void checkTranslations(IExtensionRegistry registry, boolean extended) {
+		IExtensionPoint extPoint = registry.getExtensionPoint("org.eclipse.test.registryMulti.PointA");
+		assertNotNull(extPoint);
+		IExtension extension = registry.getExtension("org.eclipse.test.registryMulti.ExtA");
+		assertNotNull(extension);
+		IConfigurationElement[] elements = registry.getConfigurationElementsFor("org.eclipse.test.registryMulti", "PointA", "org.eclipse.test.registryMulti.ExtA");
+		assertNotNull(elements);
+		assertEquals(1, elements.length);
+		IConfigurationElement element = elements[0];
+		assertNotNull(element);
+		IConfigurationElement[] sectionElements = element.getChildren("section");
+		assertNotNull(sectionElements);
+		assertEquals(1, sectionElements.length);
+		IConfigurationElement[] subdivisionElements = sectionElements[0].getChildren("subdivision");
+		assertNotNull(subdivisionElements);
+		assertEquals(1, subdivisionElements.length);
+		IConfigurationElement[] elementsValue = registry.getConfigurationElementsFor("org.eclipse.test.registryMulti", "PointValue", "org.eclipse.test.registryMulti.ExtValue");
+		assertNotNull(elementsValue);
+		assertEquals(1, elementsValue.length);
+		IConfigurationElement elementValue = elementsValue[0];
+		assertNotNull(elementValue);
+		IConfigurationElement[] elementsFrag = registry.getConfigurationElementsFor("org.eclipse.test.registryMulti", "FragmentPointA", "org.eclipse.test.registryMulti.FragmentExtA");
+		assertNotNull(elementsFrag);
+		assertEquals(1, elementsFrag.length);
+		IConfigurationElement elementFrag = elementsFrag[0];
+		assertNotNull(elementFrag);
+
+		assertEquals(helloWorldGerman, extPoint.getLabel("de_DE"));
+		assertEquals(helloWorldItalian, extPoint.getLabel("it"));
+		assertEquals(helloWorld, extPoint.getLabel());
+
+		assertEquals(catsAndDogsGerman, extension.getLabel("de_DE"));
+		assertEquals(catsAndDogsItalian, extension.getLabel("it"));
+		assertEquals(catsAndDogs, extension.getLabel());
+
+		assertEquals(helloWorldGerman, element.getAttribute("name", "de_DE"));
+		assertEquals(helloWorldGerman, element.getAttribute("name", "de_DE")); // check internal cache
+
+		assertEquals(helloWorldItalian, element.getAttribute("name", "it"));
+		assertEquals(helloWorldItalian, element.getAttribute("name", "it")); // check internal cache
+
+		assertEquals(helloWorld, element.getAttribute("name", "some_OtherABC"));
+		assertEquals(helloWorld, element.getAttribute("name")); // "default" locale
+
+		assertEquals(eclipseGerman, subdivisionElements[0].getAttribute("division", "de_DE"));
+		assertEquals(eclipseItalian, subdivisionElements[0].getAttribute("division", "it"));
+		assertEquals(eclipse, subdivisionElements[0].getAttribute("division", "some_OtherABC"));
+
+		assertEquals(catsAndDogsGerman, elementValue.getValue("de_DE"));
+		assertEquals(catsAndDogsGerman, elementValue.getValue("de_DE")); // check internal cache
+
+		assertEquals(catsAndDogsItalian, elementValue.getValue("it"));
+		assertEquals(catsAndDogsItalian, elementValue.getValue("it")); // check internal cache
+
+		assertEquals(catsAndDogs, elementValue.getValue("some_OtherABC"));
+		assertEquals(catsAndDogs, elementValue.getValue());
+
+		assertEquals(proverbLatin, elementFrag.getAttribute("name", "la_LA"));
+		assertEquals(proverbLatin, elementFrag.getAttribute("name", "la_LA")); // check internal cache
+		assertEquals(proverb, elementFrag.getAttribute("name", "some_OtherABC"));
+
+		if (!extended)
+			return;
+
+		assertEquals(helloWorldFinnish, extPoint.getLabel("fi_FI"));
+		assertEquals(catsAndDogsFinnish, extension.getLabel("fi_FI"));
+		assertEquals(helloWorldFinnish, element.getAttribute("name", "fi_FI"));
+		assertEquals(helloWorldFinnish, element.getAttribute("name", "fi_FI")); // check internal cache
+		assertEquals(eclipseFinnish, subdivisionElements[0].getAttribute("division", "fi_FI"));
+		assertEquals(catsAndDogsFinnish, elementValue.getValue("fi_FI"));
+		assertEquals(catsAndDogsFinnish, elementValue.getValue("fi_FI")); // check internal cache
+	}
+
+	public static Test suite() {
+		return new TestSuite(MultiLanguageTest.class);
+	}
+
+	/*
+	 * Return the package admin service, if available.
+	 */
+	private PackageAdmin getBundleAdmin() {
+		if (bundleTracker == null) {
+			bundleTracker = new ServiceTracker(RuntimeTestsPlugin.getContext(), PackageAdmin.class.getName(), null);
+			bundleTracker.open();
+		}
+		return (PackageAdmin) bundleTracker.getService();
+	}
+}