[gatein-commits] gatein SVN: r6784 - in portal/trunk: component/portal/src/main/java and 33 other directories.

do-not-reply at jboss.org do-not-reply at jboss.org
Fri Jul 1 03:05:26 EDT 2011


Author: trong.tran
Date: 2011-07-01 03:05:25 -0400 (Fri, 01 Jul 2011)
New Revision: 6784

Added:
   portal/trunk/component/portal/src/main/java/org/exoplatform/portal/config/model/LocalizedValue.java
   portal/trunk/component/portal/src/main/java/org/exoplatform/portal/config/model/ModelUnmarshaller.java
   portal/trunk/component/portal/src/main/java/org/exoplatform/portal/config/model/UnmarshalledObject.java
   portal/trunk/component/portal/src/main/java/org/exoplatform/portal/config/model/Version.java
   portal/trunk/component/portal/src/main/java/org/exoplatform/portal/config/serialize/LocalizedValueMapper.java
   portal/trunk/component/portal/src/main/java/org/exoplatform/portal/mop/description/
   portal/trunk/component/portal/src/main/java/org/exoplatform/portal/mop/description/CacheKey.java
   portal/trunk/component/portal/src/main/java/org/exoplatform/portal/mop/description/CacheValue.java
   portal/trunk/component/portal/src/main/java/org/exoplatform/portal/mop/description/DataCache.java
   portal/trunk/component/portal/src/main/java/org/exoplatform/portal/mop/description/DescriptionService.java
   portal/trunk/component/portal/src/main/java/org/exoplatform/portal/mop/description/DescriptionServiceImpl.java
   portal/trunk/component/portal/src/main/java/org/exoplatform/portal/mop/description/ExoDataCache.java
   portal/trunk/component/portal/src/main/java/org/exoplatform/portal/mop/description/SimpleDataCache.java
   portal/trunk/component/portal/src/main/java/org/exoplatform/portal/mop/i18n/
   portal/trunk/component/portal/src/main/java/org/exoplatform/portal/mop/i18n/I18NAdapter.java
   portal/trunk/component/portal/src/main/java/org/exoplatform/portal/mop/i18n/I18Nized.java
   portal/trunk/component/portal/src/main/java/org/exoplatform/portal/mop/i18n/Injector.java
   portal/trunk/component/portal/src/main/java/org/exoplatform/portal/mop/i18n/Language.java
   portal/trunk/component/portal/src/main/java/org/exoplatform/portal/mop/i18n/LanguageSpace.java
   portal/trunk/component/portal/src/main/java/org/exoplatform/portal/mop/i18n/Resolution.java
   portal/trunk/component/portal/src/main/resources/META-INF/
   portal/trunk/component/portal/src/main/resources/META-INF/services/
   portal/trunk/component/portal/src/main/resources/META-INF/services/org.gatein.mop.spi.AdapterLifeCycle
   portal/trunk/component/portal/src/test/java/org/exoplatform/portal/i18n/
   portal/trunk/component/portal/src/test/java/org/exoplatform/portal/i18n/A.java
   portal/trunk/component/portal/src/test/java/org/exoplatform/portal/i18n/B.java
   portal/trunk/component/portal/src/test/java/org/exoplatform/portal/i18n/Described.java
   portal/trunk/component/portal/src/test/java/org/exoplatform/portal/i18n/NavigationNode.java
   portal/trunk/component/portal/src/test/java/org/exoplatform/portal/i18n/TestI18NFramework.java
   portal/trunk/component/portal/src/test/java/org/exoplatform/portal/i18n/package-info.java
   portal/trunk/component/portal/src/test/java/org/exoplatform/portal/mop/description/
   portal/trunk/component/portal/src/test/java/org/exoplatform/portal/mop/description/TestDescriptionService.java
   portal/trunk/component/portal/src/test/java/org/exoplatform/portal/mop/user/SimpleUserPortalContext.java
   portal/trunk/component/portal/src/test/resources/conf/test-i18nframework-configuration.xml
   portal/trunk/component/portal/src/test/resources/jibx/extended-navigation.xml
   portal/trunk/component/portal/src/test/resources/jibx/simple-navigation.xml
   portal/trunk/component/portal/src/test/resources/portal/portal/extended/
   portal/trunk/component/portal/src/test/resources/portal/portal/extended/navigation.xml
   portal/trunk/component/portal/src/test/resources/portal/portal/extended/portal.xml
Modified:
   portal/trunk/component/portal/src/main/java/conf/gatein-nodetypes.xml
   portal/trunk/component/portal/src/main/java/gatein_objects_1_2.xsd
   portal/trunk/component/portal/src/main/java/org/exoplatform/portal/config/NewPortalConfigListener.java
   portal/trunk/component/portal/src/main/java/org/exoplatform/portal/config/UserPortalConfig.java
   portal/trunk/component/portal/src/main/java/org/exoplatform/portal/config/UserPortalConfigService.java
   portal/trunk/component/portal/src/main/java/org/exoplatform/portal/config/importer/NavigationImporter.java
   portal/trunk/component/portal/src/main/java/org/exoplatform/portal/config/model/PageNode.java
   portal/trunk/component/portal/src/main/java/org/exoplatform/portal/mop/Described.java
   portal/trunk/component/portal/src/main/java/org/exoplatform/portal/mop/user/UserNode.java
   portal/trunk/component/portal/src/main/java/org/exoplatform/portal/mop/user/UserNodeFilter.java
   portal/trunk/component/portal/src/main/java/org/exoplatform/portal/mop/user/UserPortal.java
   portal/trunk/component/portal/src/main/java/org/exoplatform/portal/mop/user/UserPortalContext.java
   portal/trunk/component/portal/src/main/java/org/exoplatform/portal/mop/user/UserPortalImpl.java
   portal/trunk/component/portal/src/main/java/org/exoplatform/portal/pom/config/MOPChromatticLifeCycle.java
   portal/trunk/component/portal/src/main/resources/binding.xml
   portal/trunk/component/portal/src/test/java/org/exoplatform/portal/TestXSDCorruption.java
   portal/trunk/component/portal/src/test/java/org/exoplatform/portal/config/AbstractPortalTest.java
   portal/trunk/component/portal/src/test/java/org/exoplatform/portal/config/TestJIBXXmlMapping.java
   portal/trunk/component/portal/src/test/java/org/exoplatform/portal/config/importer/TestNavigationImporter.java
   portal/trunk/component/portal/src/test/java/org/exoplatform/portal/mop/navigation/AbstractTestNavigationService.java
   portal/trunk/component/portal/src/test/java/org/exoplatform/portal/mop/user/TestUserPortal.java
   portal/trunk/component/portal/src/test/resources/conf/exo.portal.component.portal-configuration1.xml
   portal/trunk/component/portal/src/test/resources/conf/exo.portal.component.portal-configuration2.xml
   portal/trunk/pom.xml
   portal/trunk/portlet/exoadmin/src/main/java/org/exoplatform/navigation/webui/TreeNode.java
   portal/trunk/portlet/exoadmin/src/main/java/org/exoplatform/navigation/webui/component/UIGroupNavigationManagement.java
   portal/trunk/portlet/exoadmin/src/main/java/org/exoplatform/navigation/webui/component/UINavigationNodeSelector.java
   portal/trunk/portlet/exoadmin/src/main/java/org/exoplatform/navigation/webui/component/UIPageNodeForm.java
   portal/trunk/portlet/exoadmin/src/main/java/org/exoplatform/navigation/webui/component/UISiteManagement.java
   portal/trunk/web/eXoResources/src/main/webapp/skin/DefaultSkin/webui/component/UIWizard/Stylesheet.css
   portal/trunk/web/portal/src/main/webapp/WEB-INF/classes/locale/portal/webui_en.properties
   portal/trunk/web/portal/src/main/webapp/WEB-INF/classes/locale/portal/webui_vi.properties
   portal/trunk/web/portal/src/main/webapp/WEB-INF/conf/portal/portal-configuration.xml
   portal/trunk/web/portal/src/main/webapp/WEB-INF/conf/portal/portal/classic/navigation.xml
   portal/trunk/webui/portal/src/main/java/org/exoplatform/portal/application/PortalRequestContext.java
   portal/trunk/webui/portal/src/main/java/org/exoplatform/portal/webui/page/UIPageCreationWizard.java
   portal/trunk/webui/portal/src/main/java/org/exoplatform/portal/webui/page/UIWizardPageSetInfo.java
Log:
DescriptionService and Navigation i18n implementation

Modified: portal/trunk/component/portal/src/main/java/conf/gatein-nodetypes.xml
===================================================================
--- portal/trunk/component/portal/src/main/java/conf/gatein-nodetypes.xml	2011-07-01 06:44:15 UTC (rev 6783)
+++ portal/trunk/component/portal/src/main/java/conf/gatein-nodetypes.xml	2011-07-01 07:05:25 UTC (rev 6784)
@@ -18,28 +18,67 @@
   -->
 <nodeTypes xmlns:nt="http://www.jcp.org/jcr/nt/1.0" xmlns:mix="http://www.jcp.org/jcr/mix/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0">
 
-    <nodeType name="gtn:protectedresource" isMixin="true" hasOrderableChildNodes="false" primaryItemName="">
-      <propertyDefinitions>
-        <propertyDefinition name="gtn:access-permissions" requiredType="String" autoCreated="false" mandatory="false" onParentVersion="COPY" protected="false" multiple="true">
-          <valueConstraints/>
-        </propertyDefinition>
-        <propertyDefinition name="gtn:edit-permissions" requiredType="String" autoCreated="false" mandatory="false" onParentVersion="COPY" protected="false" multiple="true">
-          <valueConstraints/>
-        </propertyDefinition>
-      </propertyDefinitions>
-    </nodeType>
+  <nodeType name="gtn:language" isMixin="false" hasOrderableChildNodes="false">
+    <supertypes>
+      <supertype>nt:base</supertype>
+      <supertype>mix:referenceable</supertype>
+    </supertypes>
+    <propertyDefinitions/>
+    <childNodeDefinitions/>
+  </nodeType>
 
-    <nodeType name="gtn:described" isMixin="true" hasOrderableChildNodes="false" primaryItemName="">
-      <propertyDefinitions>
-        <propertyDefinition name="gtn:name" requiredType="String" autoCreated="false" mandatory="false" onParentVersion="COPY" protected="false" multiple="false">
-          <valueConstraints/>
-        </propertyDefinition>
-        <propertyDefinition name="gtn:description" requiredType="String" autoCreated="false" mandatory="false" onParentVersion="COPY" protected="false" multiple="false">
-          <valueConstraints/>
-        </propertyDefinition>
-      </propertyDefinitions>
-    </nodeType>
+  <nodeType name="gtn:languages" isMixin="false" hasOrderableChildNodes="false">
+    <supertypes>
+      <supertype>nt:base</supertype>
+      <supertype>mix:referenceable</supertype>
+    </supertypes>
+    <propertyDefinitions/>
+    <childNodeDefinitions>
+      <childNodeDefinition name="*" defaultPrimaryType="gtn:language" autoCreated="false" mandatory="false" onParentVersion="COPY" protected="false" sameNameSiblings="false">
+        <requiredPrimaryTypes>
+          <requiredPrimaryType>gtn:language</requiredPrimaryType>
+        </requiredPrimaryTypes>
+      </childNodeDefinition>
+    </childNodeDefinitions>
+  </nodeType>
 
+  <nodeType name="gtn:i18nized" isMixin="true" hasOrderableChildNodes="false">
+    <supertypes>
+      <supertype>nt:base</supertype>
+      <supertype>mix:referenceable</supertype>
+    </supertypes>
+    <propertyDefinitions/>
+    <childNodeDefinitions>
+      <childNodeDefinition name="gtn:languages" defaultPrimaryType="gtn:languages" autoCreated="false" mandatory="false" onParentVersion="COPY" protected="false" sameNameSiblings="false">
+        <requiredPrimaryTypes>
+          <requiredPrimaryType>gtn:languages</requiredPrimaryType>
+        </requiredPrimaryTypes>
+      </childNodeDefinition>
+    </childNodeDefinitions>
+  </nodeType>
+
+  <nodeType name="gtn:protectedresource" isMixin="true" hasOrderableChildNodes="false" primaryItemName="">
+    <propertyDefinitions>
+      <propertyDefinition name="gtn:access-permissions" requiredType="String" autoCreated="false" mandatory="false" onParentVersion="COPY" protected="false" multiple="true">
+        <valueConstraints/>
+      </propertyDefinition>
+      <propertyDefinition name="gtn:edit-permissions" requiredType="String" autoCreated="false" mandatory="false" onParentVersion="COPY" protected="false" multiple="true">
+        <valueConstraints/>
+      </propertyDefinition>
+    </propertyDefinitions>
+  </nodeType>
+
+  <nodeType name="gtn:described" isMixin="true" hasOrderableChildNodes="false" primaryItemName="">
+    <propertyDefinitions>
+      <propertyDefinition name="gtn:name" requiredType="String" autoCreated="false" mandatory="false" onParentVersion="COPY" protected="false" multiple="false">
+        <valueConstraints/>
+      </propertyDefinition>
+      <propertyDefinition name="gtn:description" requiredType="String" autoCreated="false" mandatory="false" onParentVersion="COPY" protected="false" multiple="false">
+        <valueConstraints/>
+      </propertyDefinition>
+    </propertyDefinitions>
+  </nodeType>
+
   <nodeType name="gtn:visible" isMixin="true" hasOrderableChildNodes="false" primaryItemName="">
     <propertyDefinitions>
       <propertyDefinition name="gtn:startpublicationdate" requiredType="Date" autoCreated="false" mandatory="false" onParentVersion="COPY" protected="false" multiple="false">

Modified: portal/trunk/component/portal/src/main/java/gatein_objects_1_2.xsd
===================================================================
--- portal/trunk/component/portal/src/main/java/gatein_objects_1_2.xsd	2011-07-01 06:44:15 UTC (rev 6783)
+++ portal/trunk/component/portal/src/main/java/gatein_objects_1_2.xsd	2011-07-01 07:05:25 UTC (rev 6784)
@@ -32,176 +32,206 @@
    attributeFormDefault="unqualified"
    version="1.0">
 
-  <!-- A top page element -->
-  <xs:element name="page" type="pageType"/>
+   <!-- A top page element -->
+   <xs:element name="page" type="pageType"/>
 
-  <!-- A top page-set element -->
-  <xs:element name="page-set" type="pageSetType"/>
+   <!-- A top page-set element -->
+   <xs:element name="page-set" type="pageSetType"/>
 
-  <!-- A top portal-config element -->
-  <xs:element name="portal-config" type="portalConfigType"/>
+   <!-- A top portal-config element -->
+   <xs:element name="portal-config" type="portalConfigType"/>
 
-  <!-- A top container element -->
-  <xs:element name="container" type="containerType"/>
+   <!-- A top container element -->
+   <xs:element name="container" type="containerType"/>
 
-  <!-- A top node-navigation element -->
-  <xs:element name="node-navigation" type="nodeNavigationType"/>
+   <!-- A top node-navigation element -->
+   <xs:element name="node-navigation" type="nodeNavigationType"/>
 
-  <!-- A localized string -->
-  <xs:complexType name="localizedString">
-    <xs:simpleContent>
-      <xs:extension base="xs:string">
-        <xs:attribute ref="xml:lang"/>
-      </xs:extension>
-    </xs:simpleContent>
-  </xs:complexType>
+   <!-- A localized string -->
+   <xs:complexType name="localizedString">
+      <xs:simpleContent>
+         <xs:extension base="xs:string">
+            <xs:attribute ref="xml:lang" />
+         </xs:extension>
+      </xs:simpleContent>
+   </xs:complexType>
 
-  <!-- The type of a top navigation node -->
-  <xs:complexType name="nodeNavigationType">
-    <xs:sequence>
-      <xs:element name="priority" type="xs:positiveInteger"/>
-      <xs:element name="page-nodes" minOccurs="0" maxOccurs="1">
-        <xs:complexType>
-          <xs:sequence>
-            <xs:element name="node" type="nodeType" minOccurs="0" maxOccurs="unbounded"/>
-          </xs:sequence>
-        </xs:complexType>
-      </xs:element>
-    </xs:sequence>
-  </xs:complexType>
+   <!-- The type of a top navigation node -->
+   <xs:complexType name="nodeNavigationType">
+      <xs:sequence>
+         <xs:element name="priority" type="xs:positiveInteger"/>
+         <xs:element name="page-nodes" minOccurs="0" maxOccurs="1">
+            <xs:complexType>
+               <xs:sequence>
+                  <xs:element name="node" type="nodeType" minOccurs="0" maxOccurs="unbounded"/>
+               </xs:sequence>
+            </xs:complexType>
+         </xs:element>
+      </xs:sequence>
+   </xs:complexType>
 
-  <!-- The type of a navigation node -->
-  <xs:complexType name="nodeType">
-    <xs:sequence>
-      <xs:element name="uri" type="xs:string" minOccurs="0" maxOccurs="1"/>
-      <xs:element name="name" type="xs:string"/>
-      <xs:element name="label" type="localizedString" minOccurs="0" maxOccurs="unbounded"/>
-      <xs:element name="icon" type="xs:string" minOccurs="0" maxOccurs="1"/>
-      <xs:element name="start-publication-date" type="xs:string" minOccurs="0" maxOccurs="1"/>
-      <xs:element name="end-publication-date" type="xs:string" minOccurs="0" maxOccurs="1"/>
-      <xs:element name="visibility" type="visibility" default="VISIBLE" minOccurs="0" maxOccurs="1"/>
-      <xs:element name="page-reference" type="xs:string" minOccurs="0" maxOccurs="1"/>
-      <xs:element name="node" type="nodeType" minOccurs="0" maxOccurs="unbounded"/>
-    </xs:sequence>
-  </xs:complexType>
+   <!-- The type of a navigation node -->
+   <xs:complexType name="nodeType">
+      <xs:sequence>
+         <xs:element name="uri" type="xs:string" minOccurs="0" maxOccurs="1"/>
+         <xs:element name="name" type="xs:string"/>
+         <xs:element name="label" type="localizedString" minOccurs="0" maxOccurs="unbounded"/>
+         <xs:element name="icon" type="xs:string" minOccurs="0" maxOccurs="1"/>
+         <xs:element name="start-publication-date" type="xs:string" minOccurs="0" maxOccurs="1"/>
+         <xs:element name="end-publication-date" type="xs:string" minOccurs="0" maxOccurs="1"/>
+         <xs:element name="visibility" type="visibility" default="DISPLAYED" minOccurs="0" maxOccurs="1"/>
+         <xs:element name="page-reference" type="xs:string" minOccurs="0" maxOccurs="1"/>
+         <xs:element name="node" type="nodeType" minOccurs="0" maxOccurs="unbounded"/>
+      </xs:sequence>
+   </xs:complexType>
 
-  <xs:simpleType name="visibility">
-    <xs:restriction base='xs:string'>
-      <xs:enumeration value="DISPLAYED"/>
-      <xs:enumeration value="HIDDEN"/>
-      <xs:enumeration value="TEMPORAL"/>
-      <xs:enumeration value="SYSTEM"/>
-    </xs:restriction>
-  </xs:simpleType>
+   <xs:simpleType name="visibility">
+      <xs:restriction base='xs:string'>
+         <xs:enumeration value="DISPLAYED"/>
+         <xs:enumeration value="HIDDEN"/>
+         <xs:enumeration value="TEMPORAL"/>
+         <xs:enumeration value="SYSTEM"/>
+      </xs:restriction>
+   </xs:simpleType>
 
-  <xs:complexType name="pageSetType">
-    <xs:sequence>
-      <xs:element name="page" type="pageType" minOccurs="0" maxOccurs="unbounded"/>
-    </xs:sequence>
-  </xs:complexType>
+   <xs:complexType name="pageSetType">
+      <xs:sequence>
+         <xs:element name="page" type="pageType" minOccurs="0" maxOccurs="unbounded"/>
+      </xs:sequence>
+   </xs:complexType>
 
-  <xs:complexType name="portalConfigType">
-    <xs:sequence>
-      <xs:element name="portal-name" type="xs:string" minOccurs="1" maxOccurs="1"/>
-      <xs:element name="locale" type="xs:string" minOccurs="1" maxOccurs="1"/>
-      <xs:element name="access-permissions" type="xs:string" minOccurs="0" maxOccurs="1"/>
-      <xs:element name="edit-permission" type="xs:string" minOccurs="0" maxOccurs="1"/>
-      <xs:element name="skin" type="xs:string" minOccurs="0" maxOccurs="1"/>
-      <xs:element name="properties" type="propertiesType" minOccurs="0" maxOccurs="1"/>
-      <xs:element name="portal-layout" minOccurs="1" maxOccurs="1">
-        <xs:complexType>
-          <xs:group ref="containerChildrenGroup"/>
-        </xs:complexType>
-      </xs:element>
-    </xs:sequence>
-  </xs:complexType>
+   <xs:complexType name="portalConfigType">
+      <xs:sequence>
+         <xs:element name="portal-name" type="xs:string" minOccurs="1" maxOccurs="1"/>
+         <xs:element name="label" type="xs:string" minOccurs="0" maxOccurs="1"/>
+         <xs:element name="description" type="xs:string" minOccurs="0" maxOccurs="1"/>
+         <xs:element name="locale" type="xs:string" minOccurs="1" maxOccurs="1"/>
+         <xs:element name="access-permissions" type="xs:string" minOccurs="0" maxOccurs="1"/>
+         <xs:element name="edit-permission" type="xs:string" minOccurs="0" maxOccurs="1"/>
+         <xs:element name="skin" type="xs:string" minOccurs="0" maxOccurs="1"/>
+         <xs:element name="properties" type="propertiesType" minOccurs="0" maxOccurs="1"/>
+         <xs:element name="portal-layout" minOccurs="1" maxOccurs="1">
+            <xs:complexType>
+               <xs:group ref="containerChildrenGroup"/>
+            </xs:complexType>
+         </xs:element>
+      </xs:sequence>
+   </xs:complexType>
 
-  <xs:complexType name="propertiesType">
-    <xs:sequence minOccurs="0" maxOccurs="unbounded">
-      <xs:element name="entry" type="propertiesEntryType" minOccurs="1" maxOccurs="1"/>
-    </xs:sequence>
-  </xs:complexType>
+   <xs:complexType name="propertiesType">
+      <xs:sequence minOccurs="0" maxOccurs="unbounded">
+         <xs:element name="entry" type="propertiesEntryType" minOccurs="1" maxOccurs="1"/>
+      </xs:sequence>
+   </xs:complexType>
 
-  <xs:complexType name="propertiesEntryType">
-    <xs:simpleContent>
-      <xs:extension base="xs:string">
-        <xs:attribute name="key" type="xs:string"/>
-      </xs:extension>
-    </xs:simpleContent>
-  </xs:complexType>
+   <xs:complexType name="propertiesEntryType">
+      <xs:simpleContent>
+         <xs:extension base="xs:string">
+            <xs:attribute name="key" type="xs:string"/>
+         </xs:extension>
+      </xs:simpleContent>
+   </xs:complexType>
 
-  <xs:group name="containerChildrenGroup">
-    <xs:sequence>
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element name="portlet-application" type="portletApplicationType" minOccurs="1" maxOccurs="1"/>
-        <xs:element name="container" type="containerType" minOccurs="1" maxOccurs="1"/>
-        <xs:element name="page-body" type="xs:string" minOccurs="1" maxOccurs="1"/>
-        <xs:element name="site-body" type="xs:string" minOccurs="1" maxOccurs="1"/>
-      </xs:choice>
-    </xs:sequence>
-  </xs:group>
+   <xs:group name="containerChildrenGroup">
+      <xs:sequence>
+         <xs:choice minOccurs="0" maxOccurs="unbounded">
+            <xs:element name="portlet-application" type="portletApplicationType" minOccurs="1" maxOccurs="1"/>
+            <xs:element name="gadget-application" type="gadgetApplicationType" minOccurs="1" maxOccurs="1"/>
+            <xs:element name="container" type="containerType" minOccurs="1" maxOccurs="1"/>
+            <xs:element name="page-body" type="xs:string" minOccurs="1" maxOccurs="1"/>
+            <xs:element name="site-body" type="xs:string" minOccurs="1" maxOccurs="1"/>
+         </xs:choice>
+      </xs:sequence>
+   </xs:group>
 
-  <xs:complexType name="pageType">
-    <xs:sequence>
-      <xs:element name="name" type="xs:string" minOccurs="1" maxOccurs="1"/>
-      <xs:element name="title" type="xs:string" minOccurs="0" maxOccurs="1"/>
-      <xs:element name="factory-id" type="xs:string" minOccurs="0" maxOccurs="1"/>
-      <xs:element name="access-permissions" type="xs:string" minOccurs="0" maxOccurs="1"/>
-      <xs:element name="edit-permission" type="xs:string" minOccurs="0" maxOccurs="1"/>
-      <xs:element name="show-max-window" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
-      <xs:group ref="containerChildrenGroup"/>
-    </xs:sequence>
-  </xs:complexType>
+   <xs:complexType name="pageType">
+      <xs:sequence>
+         <xs:element name="name" type="xs:string" minOccurs="1" maxOccurs="1"/>
+         <xs:element name="title" type="xs:string" minOccurs="0" maxOccurs="1"/>
+         <xs:element name="factory-id" type="xs:string" minOccurs="0" maxOccurs="1"/>
+         <xs:element name="access-permissions" type="xs:string" minOccurs="0" maxOccurs="1"/>
+         <xs:element name="edit-permission" type="xs:string" minOccurs="0" maxOccurs="1"/>
+         <xs:element name="show-max-window" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
+         <xs:group ref="containerChildrenGroup"/>
+      </xs:sequence>
+   </xs:complexType>
 
-  <xs:complexType name="containerType">
-    <xs:sequence>
-      <xs:element name="name" type="xs:string" minOccurs="0" maxOccurs="1"/>
-      <xs:element name="title" type="xs:string" minOccurs="0" maxOccurs="1"/>
-      <xs:element name="icon" type="xs:string" minOccurs="0" maxOccurs="1"/>
-      <xs:element name="access-permissions" type="xs:string" minOccurs="0" maxOccurs="1"/>
-      <xs:element name="factory-id" type="xs:string" minOccurs="0" maxOccurs="1"/>
-      <xs:element name="description" type="xs:string" minOccurs="0" maxOccurs="1"/>
-      <xs:element name="width" type="xs:string" minOccurs="0" maxOccurs="1"/>
-      <xs:element name="height" type="xs:string" minOccurs="0" maxOccurs="1"/>
-      <xs:group ref="containerChildrenGroup"/>
-    </xs:sequence>
-    <xs:attribute name="id" type="xs:string"/>
-    <xs:attribute name="template" type="xs:string"/>
-    <xs:attribute name="attribute" type="xs:string"/>
-  </xs:complexType>
+   <xs:complexType name="containerType">
+      <xs:sequence>
+         <xs:element name="name" type="xs:string" minOccurs="0" maxOccurs="1"/>
+         <xs:element name="title" type="xs:string" minOccurs="0" maxOccurs="1"/>
+         <xs:element name="icon" type="xs:string" minOccurs="0" maxOccurs="1"/>
+         <xs:element name="access-permissions" type="xs:string" minOccurs="0" maxOccurs="1"/>
+         <xs:element name="factory-id" type="xs:string" minOccurs="0" maxOccurs="1"/>
+         <xs:element name="description" type="xs:string" minOccurs="0" maxOccurs="1"/>
+         <xs:group ref="containerChildrenGroup"/>
+      </xs:sequence>
+      <xs:attribute name="id" type="xs:string"/>
+      <xs:attribute name="template" type="xs:string"/>
+      <xs:attribute name="attribute" type="xs:string"/>
+      <xs:attribute name="width" type="xs:string"/>
+      <xs:attribute name="height" type="xs:string"/>
+   </xs:complexType>
 
-  <xs:complexType name="portletApplicationType">
-    <xs:sequence>
-      <xs:element name="portlet" type="portletType" minOccurs="1" maxOccurs="1"/>
-      <xs:element name="title" type="xs:string" minOccurs="0" maxOccurs="1"/>
-      <xs:element name="access-permissions" type="xs:string" minOccurs="1" maxOccurs="1"/>
-      <xs:element name="show-info-bar" type="xs:boolean" minOccurs="1" maxOccurs="1"/>
-      <xs:element name="show-application-state" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
-      <xs:element name="show-application-mode" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
-      <xs:element name="width" type="xs:string" minOccurs="0" maxOccurs="1"/>
- 	 	 	<xs:element name="height" type="xs:string" minOccurs="0" maxOccurs="1"/>
-    </xs:sequence>
-  </xs:complexType>
+   <xs:complexType name="portletApplicationType">
+      <xs:sequence>
+       <xs:choice>
+          <xs:element name="portlet" type="portletType"/>
+          <xs:element name="wsrp" type="xs:string"/>
+       </xs:choice>
+         <xs:element name="title" type="xs:string" minOccurs="0" maxOccurs="1"/>
+         <xs:element name="access-permissions" type="xs:string" minOccurs="1" maxOccurs="1"/>
+         <xs:element name="show-info-bar" type="xs:boolean" minOccurs="1" maxOccurs="1"/>
+         <xs:element name="show-application-state" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
+         <xs:element name="show-application-mode" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
+         <xs:element name="description" type="xs:string" minOccurs="0" maxOccurs="1"/>
+         <xs:element name="icon" type="xs:string" minOccurs="0" maxOccurs="1"/>
+         <xs:element name="width" type="xs:string" minOccurs="0" maxOccurs="1"/>
+         <xs:element name="height" type="xs:string" minOccurs="0" maxOccurs="1"/>
+      </xs:sequence>
+   </xs:complexType>
 
-  <xs:complexType name="portletType">
-    <xs:sequence>
-      <xs:element name="application-ref" type="xs:string" minOccurs="1" maxOccurs="1"/>
-      <xs:element name="portlet-ref" type="xs:string" minOccurs="1" maxOccurs="1"/>
-      <xs:element name="preferences" type="portletPreferencesType" minOccurs="0" maxOccurs="1"/>
-    </xs:sequence>
-  </xs:complexType>
+   <xs:complexType name="gadgetApplicationType">
+      <xs:sequence>
+         <xs:element name="gadget" type="gadgetType" minOccurs="1" maxOccurs="1"/>
+         <xs:element name="theme" type="xs:string" minOccurs="0" maxOccurs="1"/>
+         <xs:element name="title" type="xs:string" minOccurs="0" maxOccurs="1"/>
+         <xs:element name="access-permissions" type="xs:string" minOccurs="1" maxOccurs="1"/>
+         <xs:element name="show-info-bar" type="xs:boolean" minOccurs="1" maxOccurs="1"/>
+         <xs:element name="show-application-state" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
+         <xs:element name="show-application-mode" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
+         <xs:element name="description" type="xs:string" minOccurs="0" maxOccurs="1"/>
+         <xs:element name="icon" type="xs:string" minOccurs="0" maxOccurs="1"/>
+         <xs:element name="width" type="xs:string" minOccurs="0" maxOccurs="1"/>
+         <xs:element name="height" type="xs:string" minOccurs="0" maxOccurs="1"/>
+      </xs:sequence>
+   </xs:complexType>
 
-  <xs:complexType name="portletPreferencesType">
-    <xs:sequence>
-      <xs:element name="preference" type="portletPreferenceType" minOccurs="0" maxOccurs="unbounded"/>
-    </xs:sequence>
-  </xs:complexType>
+   <xs:complexType name="portletType">
+      <xs:sequence>
+         <xs:element name="application-ref" type="xs:string" minOccurs="1" maxOccurs="1"/>
+         <xs:element name="portlet-ref" type="xs:string" minOccurs="1" maxOccurs="1"/>
+         <xs:element name="preferences" type="portletPreferencesType" minOccurs="0" maxOccurs="1"/>
+      </xs:sequence>
+   </xs:complexType>
 
-  <xs:complexType name="portletPreferenceType">
-    <xs:sequence>
-      <xs:element name="name" type="xs:string" minOccurs="1" maxOccurs="1"/>
-      <xs:element name="value" type="xs:string" minOccurs="0" maxOccurs="1"/>
-      <xs:element name="read-only" type="xs:string" minOccurs="0" maxOccurs="1"/>
-    </xs:sequence>
-  </xs:complexType>
+   <xs:complexType name="gadgetType">
+      <xs:sequence>
+         <xs:element name="gadget-ref" type="xs:string" minOccurs="1" maxOccurs="1"/>
+      </xs:sequence>
+   </xs:complexType>
+
+   <xs:complexType name="portletPreferencesType">
+      <xs:sequence>
+         <xs:element name="preference" type="portletPreferenceType" minOccurs="0" maxOccurs="unbounded"/>
+      </xs:sequence>
+   </xs:complexType>
+
+   <xs:complexType name="portletPreferenceType">
+      <xs:sequence>
+         <xs:element name="name" type="xs:string" minOccurs="1" maxOccurs="1"/>
+         <xs:element name="value" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
+         <xs:element name="read-only" type="xs:string" minOccurs="0" maxOccurs="1"/>
+      </xs:sequence>
+   </xs:complexType>
 </xs:schema>
\ No newline at end of file

Modified: portal/trunk/component/portal/src/main/java/org/exoplatform/portal/config/NewPortalConfigListener.java
===================================================================
--- portal/trunk/component/portal/src/main/java/org/exoplatform/portal/config/NewPortalConfigListener.java	2011-07-01 06:44:15 UTC (rev 6783)
+++ portal/trunk/component/portal/src/main/java/org/exoplatform/portal/config/NewPortalConfigListener.java	2011-07-01 07:05:25 UTC (rev 6784)
@@ -31,24 +31,28 @@
 import org.exoplatform.portal.config.importer.ImportMode;
 import org.exoplatform.portal.config.importer.NavigationImporter;
 import org.exoplatform.portal.config.model.Container;
+import org.exoplatform.portal.config.model.ModelUnmarshaller;
 import org.exoplatform.portal.config.model.Page;
+import org.exoplatform.portal.config.model.Page.PageSet;
 import org.exoplatform.portal.config.model.PageNavigation;
 import org.exoplatform.portal.config.model.PageNode;
 import org.exoplatform.portal.config.model.PortalConfig;
-import org.exoplatform.portal.config.model.Page.PageSet;
+import org.exoplatform.portal.config.model.UnmarshalledObject;
+import org.exoplatform.portal.config.model.Version;
+import org.exoplatform.portal.mop.description.DescriptionService;
 import org.exoplatform.portal.mop.navigation.NavigationService;
 import org.exoplatform.portal.pom.config.POMSessionManager;
 import org.gatein.common.logging.Logger;
 import org.gatein.common.logging.LoggerFactory;
-import org.jibx.runtime.*;
-import org.jibx.runtime.impl.UnmarshallingContext;
+import org.jibx.runtime.JiBXException;
 
-import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Locale;
 import java.util.Set;
 import java.util.regex.Pattern;
 
@@ -102,12 +106,22 @@
    /** . */
    private NavigationService navigationService_;
 
-   public NewPortalConfigListener(POMSessionManager pomMgr, DataStorage dataStorage, ConfigurationManager cmanager, InitParams params, NavigationService navigationService)
+   /** . */
+   private DescriptionService descriptionService_;
+
+   public NewPortalConfigListener(
+      POMSessionManager pomMgr,
+      DataStorage dataStorage,
+      ConfigurationManager cmanager,
+      InitParams params,
+      NavigationService navigationService,
+      DescriptionService descriptionService)
       throws Exception
    {
       cmanager_ = cmanager;
       dataStorage_ = dataStorage;
       navigationService_ = navigationService;
+      descriptionService_ = descriptionService;
 
       ValueParam valueParam = params.getValueParam("page.templates.location");
       if (valueParam != null)
@@ -396,9 +410,9 @@
       try
       {
          String type = config.getOwnerType();
-         PortalConfig pconfig = getConfig(config, owner, type, PortalConfig.class);
+         UnmarshalledObject<PortalConfig> obj = getConfig(config, owner, type, PortalConfig.class);
 
-         if (pconfig == null)
+         if (obj == null)
          {
             // Ensure that the PortalConfig has been defined
             // The PortalConfig could be empty if the related PortalConfigListener
@@ -414,6 +428,9 @@
             return;
          }
 
+         //
+         PortalConfig pconfig = obj.getObject();
+
          // We use that owner value because it may have been fixed for group names
          owner = pconfig.getName();
 
@@ -436,12 +453,12 @@
 
    public void createPage(NewPortalConfig config, String owner) throws Exception
    {
-      PageSet pageSet = getConfig(config, owner, "pages", PageSet.class);
+      UnmarshalledObject<PageSet> pageSet = getConfig(config, owner, "pages", PageSet.class);
       if (pageSet == null)
       {
          return;
       }
-      ArrayList<Page> list = pageSet.getPages();
+      ArrayList<Page> list = pageSet.getObject().getPages();
       for (Page page : list)
       {
          RequestLifeCycle.begin(PortalContainer.getInstance());
@@ -458,29 +475,44 @@
 
    public void createPageNavigation(NewPortalConfig config, String owner) throws Exception
    {
-      PageNavigation navigation = getConfig(config, owner, "navigation", PageNavigation.class);
-      if (navigation == null)
+      UnmarshalledObject<PageNavigation> obj = getConfig(config, owner, "navigation", PageNavigation.class);
+      if (obj == null)
       {
          return;
       }
 
       //
+      PageNavigation navigation = obj.getObject();
       ImportMode importMode = overrideExistingData ? ImportMode.REIMPORT : ImportMode.MERGE;
+      boolean extendedNavigation = obj.getVersion() == Version.V_1_2;
 
       //
-      NavigationImporter merge =new NavigationImporter(importMode, navigation, navigationService_);
+      Locale locale;
+      PortalConfig portalConfig = dataStorage_.getPortalConfig(config.getOwnerType(), owner);
+      if (portalConfig != null && portalConfig.getLocale() != null)
+      {
+         locale = new Locale(portalConfig.getLocale());
+      }
+      else
+      {
+         locale = Locale.ENGLISH;
+      }
 
       //
+      NavigationImporter merge = new NavigationImporter(locale, importMode, extendedNavigation, navigation, navigationService_, descriptionService_);
+
+      //
       merge.perform();
    }
 
    public void createPortletPreferences(NewPortalConfig config, String owner) throws Exception
    {
-      PortletPreferencesSet portletSet = getConfig(config, owner, "portlet-preferences", PortletPreferencesSet.class);
-      if (portletSet == null)
+      UnmarshalledObject<PortletPreferencesSet> obj = getConfig(config, owner, "portlet-preferences", PortletPreferencesSet.class);
+      if (obj == null)
       {
          return;
       }
+      PortletPreferencesSet portletSet = obj.getObject();
       ArrayList<PortletPreferences> list = portletSet.getPortlets();
       for (PortletPreferences portlet : list)
       {
@@ -501,7 +533,7 @@
     * @throws Exception any exception
     * @param <T> the generic type to unmarshall to
     */
-   private <T> T getConfig(NewPortalConfig config, String owner, String fileName, Class<T> type) throws Exception
+   private <T> UnmarshalledObject<T> getConfig(NewPortalConfig config, String owner, String fileName, Class<T> type) throws Exception
    {
       log.debug("About to load config=" + config + " owner=" + owner + " fileName=" + fileName);
 
@@ -533,9 +565,9 @@
          boolean ok = false;
          try
          {
-            final T t = fromXML(config.getOwnerType(), owner, xml, type);
+            final UnmarshalledObject<T> o = fromXML(config.getOwnerType(), owner, xml, type);
             ok = true;
-            return t;
+            return o;
          }
          catch (JiBXException e)
          {
@@ -577,7 +609,7 @@
       String path = pageTemplatesLocation_ + "/" + temp + "/page.xml";
       InputStream is = cmanager_.getInputStream(path);
       String xml = IOUtil.getStreamContentAsString(is);
-      return fromXML(ownerType, owner, xml, Page.class);
+      return fromXML(ownerType, owner, xml, Page.class).getObject();
    }
 
    public String getTemplateConfig(String type, String name)
@@ -590,16 +622,60 @@
       }
       return null;
    }
+   
+   /**
+    * Get all template configurations
+    * @param siteType (portal, group, user)
+    * @return set of template name
+    */
+   public Set<String> getTemplateConfigs(String siteType)
+   {
+      Set<String> result = new HashSet<String>();      
+      for(SiteConfigTemplates tempConfig : templateConfigs)
+      {
+         Set<String> templates = tempConfig.getTemplates(siteType);
+         if(templates != null && templates.size() > 0)
+         {
+            result.addAll(templates);
+         }
+      }      
+      return result;
+   }
+   
+   /**
+    * Get detail configuration from a template file 
+    * @param siteType (portal, group, user)
+    * @param templateName name of template
+    * @return PortalConfig object
+    */
+   public PortalConfig getPortalConfigFromTemplate(String siteType, String templateName)
+   {
+      String templatePath = getTemplateConfig(siteType, templateName);
+      NewPortalConfig config = new NewPortalConfig(templatePath);
+      config.setTemplateName(templateName);
+      config.setOwnerType(siteType);
+      UnmarshalledObject<PortalConfig> result = null;
+      try
+      {
+         result = getConfig(config, templateName, siteType, PortalConfig.class);
+         if (result != null)
+         {
+            return result.getObject();
+         }
+      }
+      catch (Exception e)
+      {
+         log.warn("Cannot find configuration of template: " + templateName);
+      }
+      return null;
+   }
 
    // Deserializing code
 
-   private <T> T fromXML(String ownerType, String owner, String xml, Class<T> clazz) throws Exception
+   private <T> UnmarshalledObject<T> fromXML(String ownerType, String owner, String xml, Class<T> clazz) throws Exception
    {
-      ByteArrayInputStream is = new ByteArrayInputStream(xml.getBytes("UTF-8"));
-      IBindingFactory bfact = BindingDirectory.getFactory(clazz);
-      UnmarshallingContext uctx = (UnmarshallingContext)bfact.createUnmarshallingContext();
-      uctx.setDocument(is, null, "UTF-8", false);
-      T o = clazz.cast(uctx.unmarshalElement());
+      UnmarshalledObject<T> obj = ModelUnmarshaller.unmarshall(clazz, xml.getBytes("UTF-8"));
+      T o = obj.getObject();
       if (o instanceof PageNavigation)
       {
          PageNavigation nav = (PageNavigation)o;
@@ -632,7 +708,7 @@
             //        pdcService_.create(page);
          }
       }
-      return o;
+      return obj;
    }
 
    private static String fixOwnerName(String type, String owner)

Modified: portal/trunk/component/portal/src/main/java/org/exoplatform/portal/config/UserPortalConfig.java
===================================================================
--- portal/trunk/component/portal/src/main/java/org/exoplatform/portal/config/UserPortalConfig.java	2011-07-01 06:44:15 UTC (rev 6783)
+++ portal/trunk/component/portal/src/main/java/org/exoplatform/portal/config/UserPortalConfig.java	2011-07-01 07:05:25 UTC (rev 6784)
@@ -39,7 +39,7 @@
    private UserPortalImpl userPortal;
 
    /** . */
-   private UserPortalContext bundleResolver;
+   private UserPortalContext userPortalContext;
 
    public UserPortalConfig()
    {
@@ -47,29 +47,26 @@
       this.service = null;
       this.portalName = null;
       this.accessUser = null;
-      this.bundleResolver = null;
+      this.userPortalContext = null;
    }
 
-   public UserPortalConfig(PortalConfig portal, UserPortalConfigService service, String portalName, String accessUser, UserPortalContext bundleResolver)
+   public UserPortalConfig(PortalConfig portal, UserPortalConfigService service, String portalName, String accessUser, UserPortalContext userPortalContext)
    {
       this.portal = portal;
       this.service = service;
       this.portalName = portalName;
       this.accessUser = accessUser;
-      this.bundleResolver = bundleResolver;
+      this.userPortalContext = userPortalContext;
    }
 
    public UserPortal getUserPortal()
    {
          userPortal = new UserPortalImpl(
             service,
-            service.navService,
-            service.orgService_,
-            service.userACL_,
             portalName,
             portal,
             accessUser,
-            bundleResolver
+            userPortalContext
          );
       return userPortal;
    }

Modified: portal/trunk/component/portal/src/main/java/org/exoplatform/portal/config/UserPortalConfigService.java
===================================================================
--- portal/trunk/component/portal/src/main/java/org/exoplatform/portal/config/UserPortalConfigService.java	2011-07-01 06:44:15 UTC (rev 6783)
+++ portal/trunk/component/portal/src/main/java/org/exoplatform/portal/config/UserPortalConfigService.java	2011-07-01 07:05:25 UTC (rev 6784)
@@ -28,9 +28,11 @@
 import org.exoplatform.portal.config.model.PortalConfig;
 import org.exoplatform.portal.config.model.TransientApplicationState;
 import org.exoplatform.portal.mop.SiteKey;
+import org.exoplatform.portal.mop.description.DescriptionService;
 import org.exoplatform.portal.mop.navigation.NavigationContext;
 import org.exoplatform.portal.mop.navigation.NavigationService;
 import org.exoplatform.portal.mop.navigation.NavigationState;
+import org.exoplatform.portal.mop.user.UserNavigation;
 import org.exoplatform.portal.mop.user.UserPortalContext;
 import org.exoplatform.portal.pom.data.ModelChange;
 import org.exoplatform.services.log.ExoLogger;
@@ -58,17 +60,22 @@
    /** . */
    final NavigationService navService;
    
+   /** . */
+   final DescriptionService descriptionService;
+
    private Log log = ExoLogger.getLogger("Portal:UserPortalConfigService");
 
    public UserPortalConfigService(
       UserACL userACL, DataStorage storage,
       OrganizationService orgService,
-      NavigationService navService) throws Exception
+      NavigationService navService,
+      DescriptionService descriptionService) throws Exception
    {
       this.storage_ = storage;
       this.orgService_ = orgService;
       this.userACL_ = userACL;
       this.navService = navService;
+      this.descriptionService = descriptionService;
    }
 
    /**
@@ -81,6 +88,34 @@
       return navService;
    }
 
+   public DescriptionService getDescriptionService()
+   {
+      return descriptionService;
+   }
+
+   public UserACL getUserACL()
+   {
+      return userACL_;
+   }
+
+   public OrganizationService getOrganizationService()
+   {
+      return orgService_;
+   }
+
+   /** Temporary until the {@link #getUserPortalConfig(String, String)} is removed. */
+   private static final UserPortalContext NULL_CONTEXT = new UserPortalContext()
+   {
+      public ResourceBundle getBundle(UserNavigation navigation)
+      {
+         return null;
+      }
+      public Locale getUserLocale()
+      {
+         return Locale.ENGLISH;
+      }
+   };
+
    /**
     * <p> Build and returns an instance of <tt>UserPortalConfig</tt>. </p>
     * <p/>
@@ -105,13 +140,15 @@
     * @param accessUser the user name
     * @return the config
     * @throws Exception any exception
+    * @deprecated the method {@link #getUserPortalConfig(String, String, org.exoplatform.portal.mop.user.UserPortalContext)} should be used instead
     */
+   @Deprecated
    public UserPortalConfig getUserPortalConfig(String portalName, String accessUser) throws Exception
    {
-      return getUserPortalConfig(portalName, accessUser, null);
+      return getUserPortalConfig(portalName, accessUser, NULL_CONTEXT);
    }
 
-   public UserPortalConfig getUserPortalConfig(String portalName, String accessUser, UserPortalContext bundleResolver) throws Exception
+   public UserPortalConfig getUserPortalConfig(String portalName, String accessUser, UserPortalContext userPortalContext) throws Exception
    {
       PortalConfig portal = storage_.getPortalConfig(portalName);
       if (portal == null || !userACL_.hasPermission(portal))
@@ -120,7 +157,7 @@
       }
 
 
-      return new UserPortalConfig(portal, this, portalName, accessUser, bundleResolver);
+      return new UserPortalConfig(portal, this, portalName, accessUser, userPortalContext);
    }
 
    /**

Modified: portal/trunk/component/portal/src/main/java/org/exoplatform/portal/config/importer/NavigationImporter.java
===================================================================
--- portal/trunk/component/portal/src/main/java/org/exoplatform/portal/config/importer/NavigationImporter.java	2011-07-01 06:44:15 UTC (rev 6783)
+++ portal/trunk/component/portal/src/main/java/org/exoplatform/portal/config/importer/NavigationImporter.java	2011-07-01 07:05:25 UTC (rev 6784)
@@ -19,10 +19,13 @@
 
 package org.exoplatform.portal.config.importer;
 
+import org.exoplatform.portal.config.model.LocalizedValue;
 import org.exoplatform.portal.config.model.PageNavigation;
 import org.exoplatform.portal.config.model.PageNode;
 import org.exoplatform.portal.config.model.PageNodeContainer;
+import org.exoplatform.portal.mop.Described;
 import org.exoplatform.portal.mop.SiteKey;
+import org.exoplatform.portal.mop.description.DescriptionService;
 import org.exoplatform.portal.mop.navigation.NavigationContext;
 import org.exoplatform.portal.mop.navigation.NavigationService;
 import org.exoplatform.portal.mop.navigation.NavigationState;
@@ -37,11 +40,15 @@
 import org.exoplatform.portal.tree.diff.ListChangeIterator;
 import org.exoplatform.portal.tree.diff.ListChangeType;
 import org.exoplatform.portal.tree.diff.ListDiff;
+import org.gatein.common.i18n.LocaleFormat;
 
 import java.util.Collections;
 import java.util.Date;
+import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Locale;
+import java.util.Map;
 
 /**
  * @author <a href="mailto:julien.viet at exoplatform.com">Julien Viet</a>
@@ -104,6 +111,12 @@
    };
 
    /** . */
+   private final Locale portalLocale;
+
+   /** . */
+   private final boolean extendedNavigation;
+
+   /** . */
    private final PageNavigation src;
 
    /** . */
@@ -112,11 +125,23 @@
    /** . */
    private final ImportMode mode;
 
-   public NavigationImporter(ImportMode mode, PageNavigation src, NavigationService service)
+   /** . */
+   private final DescriptionService descriptionService;
+
+   public NavigationImporter(
+      Locale portalLocale,
+      ImportMode mode,
+      boolean extendedNavigation,
+      PageNavigation src,
+      NavigationService service,
+      DescriptionService descriptionService)
    {
+      this.portalLocale = portalLocale;
+      this.extendedNavigation = extendedNavigation;
       this.mode = mode;
       this.src = src;
       this.service = service;
+      this.descriptionService = descriptionService;
    }
 
    public void perform()
@@ -166,12 +191,26 @@
       if (dst != null)
       {
          NodeContext<?> node = service.loadNode(NodeModel.SELF_MODEL, dst, Scope.SINGLE, null).getNode();
-         perform(src, node);
+
+         // Collect labels
+         Map<NodeContext<?>, Map<Locale, Described.State>> labelMap = new HashMap<NodeContext<?>, Map<Locale, Described.State>>();
+
+         // Perform save
+         perform(src, node, labelMap);
+
+         // Save the node
          service.saveNode(node, null);
+
+         //
+         for (Map.Entry<NodeContext<?>, Map<Locale, Described.State>> entry : labelMap.entrySet())
+         {
+            String id = entry.getKey().getId();
+            descriptionService.setDescriptions(id, entry.getValue());
+         }
       }
    }
 
-   private void perform(PageNodeContainer src, final NodeContext<?> dst)
+   private void perform(PageNodeContainer src, final NodeContext<?> dst, final Map<NodeContext<?>, Map<Locale, Described.State>> labelMap)
    {
       service.rebaseNode(dst, Scope.CHILDREN, null);
 
@@ -197,7 +236,7 @@
          switch (changeType)
          {
             case SAME:
-               perform(srcChild, dstChild);
+               perform(srcChild, dstChild, labelMap);
                break;
             case REMOVE:
                if (dst.getNode(name) != null)
@@ -239,6 +278,70 @@
 
          private void add(PageNode target, PageNode previous, NodeContext<?> dst)
          {
+
+            //
+            LocalizedValue unqualifiedLabel = null;
+            List<LocalizedValue> labels = target.getLabels();
+            Map<Locale, Described.State> description = null;
+            if (labels.size() > 0)
+            {
+               for (LocalizedValue label : labels)
+               {
+                  Locale lang = label.getLang();
+                  if (lang != null)
+                  {
+                     if (description == null)
+                     {
+                        description = new HashMap<Locale, Described.State>(labels.size());
+                     }
+                     description.put(lang, new Described.State(label.getValue(), null));
+                  }
+                  else
+                  {
+                     unqualifiedLabel = label;
+                  }
+               }
+            }
+
+            //
+            String label;
+            if (extendedNavigation)
+            {
+               if (description == null)
+               {
+                  description = new HashMap<Locale, Described.State>();
+               }
+               if (!description.containsKey(portalLocale))
+               {
+                  if (unqualifiedLabel != null)
+                  {
+                     description.put(portalLocale, new Described.State(unqualifiedLabel.getValue(), null));
+                  }
+               }
+
+               //
+               label = null;
+            }
+            else
+            {
+               if (unqualifiedLabel != null)
+               {
+                  label = unqualifiedLabel.getValue();
+               }
+               else if (description != null && description.containsKey(portalLocale))
+               {
+                  label = description.get(portalLocale).getName();
+               }
+               else
+               {
+                  label = null;
+               }
+
+               //
+               description = null;
+            }
+
+            //
             String name = target.getName();
             int index = 0;
             if (previous != null)
@@ -249,7 +352,7 @@
             Date start = target.getStartPublicationDate();
             Date end = target.getEndPublicationDate();
             NodeState state = new NodeState(
-               target.getLabel(),
+               label,
                target.getIcon(),
                start == null ? -1 : start.getTime(),
                end == null ? -1 : end.getTime(),
@@ -259,6 +362,12 @@
             child.setState(state);
 
             //
+            if (description != null)
+            {
+               labelMap.put(child, description);
+            }
+
+            //
             List<PageNode> targetChildren = target.getNodes();
             if (targetChildren != null)
             {

Added: portal/trunk/component/portal/src/main/java/org/exoplatform/portal/config/model/LocalizedValue.java
===================================================================
--- portal/trunk/component/portal/src/main/java/org/exoplatform/portal/config/model/LocalizedValue.java	                        (rev 0)
+++ portal/trunk/component/portal/src/main/java/org/exoplatform/portal/config/model/LocalizedValue.java	2011-07-01 07:05:25 UTC (rev 6784)
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2011 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+
+package org.exoplatform.portal.config.model;
+
+import java.util.Locale;
+
+/**
+ * @author <a href="mailto:julien.viet at exoplatform.com">Julien Viet</a>
+ */
+public class LocalizedValue
+{
+
+   /** . */
+   private String value;
+
+   /** . */
+   private Locale lang;
+
+   public LocalizedValue()
+   {
+   }
+
+   public LocalizedValue(String value)
+   {
+      this.value = value;
+   }
+
+   public LocalizedValue(String value, Locale lang)
+   {
+      this.value = value;
+      this.lang = lang;
+   }
+
+   public String getValue()
+   {
+      return value;
+   }
+
+   public void setValue(String value)
+   {
+      this.value = value;
+   }
+
+   public Locale getLang()
+   {
+      return lang;
+   }
+
+   public void setLang(Locale lang)
+   {
+      this.lang = lang;
+   }
+}

Added: portal/trunk/component/portal/src/main/java/org/exoplatform/portal/config/model/ModelUnmarshaller.java
===================================================================
--- portal/trunk/component/portal/src/main/java/org/exoplatform/portal/config/model/ModelUnmarshaller.java	                        (rev 0)
+++ portal/trunk/component/portal/src/main/java/org/exoplatform/portal/config/model/ModelUnmarshaller.java	2011-07-01 07:05:25 UTC (rev 6784)
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2011 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+
+package org.exoplatform.portal.config.model;
+
+import org.gatein.common.io.IOTools;
+import org.jibx.runtime.BindingDirectory;
+import org.jibx.runtime.IBindingFactory;
+import org.jibx.runtime.impl.UnmarshallingContext;
+
+import javax.xml.namespace.QName;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLStreamReader;
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+
+/**
+ * @author <a href="mailto:julien.viet at exoplatform.com">Julien Viet</a>
+ */
+public class ModelUnmarshaller
+{
+
+   public static <T> UnmarshalledObject<T> unmarshall(Class<T> type, InputStream in) throws Exception
+   {
+      return unmarshall(type, IOTools.getBytes(in));
+   }
+
+   public static <T> UnmarshalledObject<T> unmarshall(Class<T> type, byte[] bytes) throws Exception
+   {
+      ByteArrayInputStream baos = new ByteArrayInputStream(bytes);
+
+      //
+      IBindingFactory bfact = BindingDirectory.getFactory(type);
+      UnmarshallingContext uctx = (UnmarshallingContext)bfact.createUnmarshallingContext();
+      uctx.setDocument(baos, null, "UTF-8", false);
+      T obj = type.cast(uctx.unmarshalElement());
+
+      // Find out version
+      XMLInputFactory factory = XMLInputFactory.newInstance();
+      baos.reset();
+      XMLStreamReader reader = factory.createXMLStreamReader(baos);
+      Version version = Version.UNKNOWN;
+      while (reader.hasNext())
+      {
+         int next = reader.next();
+         if (next == XMLStreamReader.START_ELEMENT)
+         {
+            QName name = reader.getName();
+            String uri = name.getNamespaceURI();
+            if (uri != null)
+            {
+               version = Version.forURI(uri);
+            }
+            break;
+         }
+      }
+
+      //
+      return new UnmarshalledObject<T>(version, obj);
+   }
+
+}

Modified: portal/trunk/component/portal/src/main/java/org/exoplatform/portal/config/model/PageNode.java
===================================================================
--- portal/trunk/component/portal/src/main/java/org/exoplatform/portal/config/model/PageNode.java	2011-07-01 06:44:15 UTC (rev 6783)
+++ portal/trunk/component/portal/src/main/java/org/exoplatform/portal/config/model/PageNode.java	2011-07-01 07:05:25 UTC (rev 6784)
@@ -22,8 +22,12 @@
 import org.exoplatform.portal.mop.Visibility;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.Date;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Locale;
+import java.util.Map;
 
 public class PageNode extends PageNodeContainer
 {
@@ -35,7 +39,7 @@
    private String uri;
 
    /** . */
-   private String label;
+   private ArrayList<LocalizedValue> labels;
 
    /** . */
    private String icon;
@@ -70,14 +74,75 @@
       uri = s;
    }
 
+   public ArrayList<LocalizedValue> getLabels()
+   {
+      return labels;
+   }
+
+   public Map<Locale, String> getLocalizedLabel(Locale defaultLocale)
+   {
+      Map<Locale, String> map = Collections.emptyMap();
+      LocalizedValue portalLocaleLabel = null;
+      for (LocalizedValue label : labels)
+      {
+         if (label.getLang() != null)
+         {
+            if (map.isEmpty())
+            {
+               map = new HashMap<Locale, String>();
+            }
+            map.put(label.getLang(), label.getValue());
+         }
+         else
+         {
+            portalLocaleLabel = label;
+         }
+      }
+      if (map.isEmpty())
+      {
+         return null;
+      }
+      else
+      {
+         if (portalLocaleLabel != null && !map.containsKey(defaultLocale))
+         {
+            map.put(defaultLocale, portalLocaleLabel.getValue());
+         }
+         return map;
+      }
+   }
+
+   public void setLabels(ArrayList<LocalizedValue> labels)
+   {
+      this.labels = labels;
+   }
+
    public String getLabel()
    {
-      return label;
+      if (labels != null)
+      {
+         for (LocalizedValue label : labels)
+         {
+            if (label.getLang() == null)
+            {
+               return label.getValue();
+            }
+         }
+      }
+      return null;
    }
 
    public void setLabel(String s)
    {
-      label = s;
+      if (labels == null)
+      {
+         labels = new ArrayList<LocalizedValue>();
+      }
+      else
+      {
+         labels.clear();
+      }
+      labels.add(new LocalizedValue(s));
    }
 
    public String getIcon()

Added: portal/trunk/component/portal/src/main/java/org/exoplatform/portal/config/model/UnmarshalledObject.java
===================================================================
--- portal/trunk/component/portal/src/main/java/org/exoplatform/portal/config/model/UnmarshalledObject.java	                        (rev 0)
+++ portal/trunk/component/portal/src/main/java/org/exoplatform/portal/config/model/UnmarshalledObject.java	2011-07-01 07:05:25 UTC (rev 6784)
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2011 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+
+package org.exoplatform.portal.config.model;
+
+/**
+ * @author <a href="mailto:julien.viet at exoplatform.com">Julien Viet</a>
+ */
+public class UnmarshalledObject<T>
+{
+
+   /** . */
+   private final Version version;
+
+   /** . */
+   private final T object;
+
+   public UnmarshalledObject(Version version, T object)
+   {
+      this.version = version;
+      this.object = object;
+   }
+
+   public Version getVersion()
+   {
+      return version;
+   }
+
+   public T getObject()
+   {
+      return object;
+   }
+}

Added: portal/trunk/component/portal/src/main/java/org/exoplatform/portal/config/model/Version.java
===================================================================
--- portal/trunk/component/portal/src/main/java/org/exoplatform/portal/config/model/Version.java	                        (rev 0)
+++ portal/trunk/component/portal/src/main/java/org/exoplatform/portal/config/model/Version.java	2011-07-01 07:05:25 UTC (rev 6784)
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2011 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+
+package org.exoplatform.portal.config.model;
+
+/**
+ * @author <a href="mailto:julien.viet at exoplatform.com">Julien Viet</a>
+ */
+public enum Version
+{
+
+   UNKNOWN(null),
+
+   V_1_0("http://www.gatein.org/xml/ns/gatein_objects_1_0"),
+
+   V_1_1("http://www.gatein.org/xml/ns/gatein_objects_1_1"),
+
+   V_1_2("http://www.gatein.org/xml/ns/gatein_objects_1_2");
+
+   /** . */
+   private final String uri;
+
+   Version(String uri)
+   {
+      this.uri = uri;
+   }
+
+   public String getURI()
+   {
+      return uri;
+   }
+
+   public static Version forURI(String uri)
+   {
+      if (uri == null)
+      {
+         throw new NullPointerException();
+      }
+      for (Version version : values())
+      {
+         if (uri.equals(version.uri))
+         {
+            return version;
+         }
+      }
+      return null;
+   }
+}

Added: portal/trunk/component/portal/src/main/java/org/exoplatform/portal/config/serialize/LocalizedValueMapper.java
===================================================================
--- portal/trunk/component/portal/src/main/java/org/exoplatform/portal/config/serialize/LocalizedValueMapper.java	                        (rev 0)
+++ portal/trunk/component/portal/src/main/java/org/exoplatform/portal/config/serialize/LocalizedValueMapper.java	2011-07-01 07:05:25 UTC (rev 6784)
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2011 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+
+package org.exoplatform.portal.config.serialize;
+
+import org.exoplatform.portal.config.model.LocalizedValue;
+import org.gatein.common.i18n.LocaleFormat;
+import org.gatein.common.util.ConversionException;
+import org.jibx.runtime.IAliasable;
+import org.jibx.runtime.IMarshaller;
+import org.jibx.runtime.IMarshallingContext;
+import org.jibx.runtime.IUnmarshaller;
+import org.jibx.runtime.IUnmarshallingContext;
+import org.jibx.runtime.JiBXException;
+import org.jibx.runtime.JiBXParseException;
+import org.jibx.runtime.impl.UnmarshallingContext;
+
+import java.util.Locale;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * @author <a href="mailto:julien.viet at exoplatform.com">Julien Viet</a>
+ */
+public class LocalizedValueMapper implements IUnmarshaller, IAliasable, IMarshaller
+{
+
+   /** . */
+   private String marshalURI;
+
+   /** . */
+   private String marshallName;
+
+   /** . */
+   private int marshallIndex;
+
+   public LocalizedValueMapper(String uri, int index, String name)
+   {
+      this.marshalURI = uri;
+      this.marshallName = name;
+      this.marshallIndex = index;
+   }
+
+   public LocalizedValueMapper()
+   {
+      this.marshalURI = null;
+      this.marshallName = "label";
+      this.marshallIndex = 0;
+   }
+
+   public boolean isPresent(IUnmarshallingContext ctx) throws JiBXException
+   {
+      return ctx.isAt(marshalURI, marshallName);
+   }
+
+   private static final Pattern RFC1766_PATTERN = Pattern.compile("^([a-zA-Z]{2})(?:-([a-zA-Z]{2}))?$");
+
+   public Object unmarshal(Object o, IUnmarshallingContext ictx) throws JiBXException
+   {
+      UnmarshallingContext ctx = (UnmarshallingContext)ictx;
+      if (!ctx.isAt(marshalURI, marshallName))
+      {
+         ctx.throwStartTagNameError(marshalURI, marshallName);
+      }
+      int count = ctx.getAttributeCount();
+      Locale lang = null;
+      for (int i = 0;i < count;i++)
+      {
+         String attrName = ctx.getAttributeName(i);
+         if (attrName.equals("xml:lang"))
+         {
+            String attrValue= ctx.getAttributeValue(i).trim();
+            Matcher matcher = RFC1766_PATTERN.matcher(attrValue);
+            if (matcher.matches())
+            {
+               String langISO = matcher.group(1);
+               String countryISO = matcher.group(2);
+               if (countryISO == null)
+               {
+                  lang = new Locale(langISO.toLowerCase());
+               }
+               else
+               {
+                  lang = new Locale(langISO.toLowerCase(), countryISO.toLowerCase());
+               }
+            }
+            else
+            {
+               throw new JiBXParseException("The attribute xml:lang " + attrValue + " does not represent a valid language as defined by RFC 1766", attrValue);
+            }
+            break;
+         }
+      }
+      ctx.parsePastStartTag(marshalURI, marshallName);
+      String value = ctx.getText();
+      ctx.parsePastEndTag(marshalURI, marshallName);
+      return new LocalizedValue(value, lang);
+   }
+
+   //
+
+
+   public boolean isExtension(String s)
+   {
+      throw new UnsupportedOperationException();
+   }
+
+   public void marshal(Object o, IMarshallingContext iMarshallingContext) throws JiBXException
+   {
+      throw new UnsupportedOperationException();
+   }
+}

Modified: portal/trunk/component/portal/src/main/java/org/exoplatform/portal/mop/Described.java
===================================================================
--- portal/trunk/component/portal/src/main/java/org/exoplatform/portal/mop/Described.java	2011-07-01 06:44:15 UTC (rev 6783)
+++ portal/trunk/component/portal/src/main/java/org/exoplatform/portal/mop/Described.java	2011-07-01 07:05:25 UTC (rev 6784)
@@ -21,7 +21,10 @@
 
 import org.chromattic.api.annotations.MixinType;
 import org.chromattic.api.annotations.Property;
+import org.exoplatform.commons.utils.Safe;
 
+import java.io.Serializable;
+
 /**
  * Something having a human readable name and a description. The semantic of the name is to be human readable, it
  * can be expressed under various ways : name, display name, label, title, etc...
@@ -33,15 +36,113 @@
 public abstract class Described
 {
 
+   /**
+    * Returns the namet.
+    *
+    * @return the name
+    */
    @Property(name = "gtn:name")
    public abstract String getName();
 
+   /**
+    * Update the name.
+    *
+    * @param name the new name
+    */
    public abstract void setName(String name);
 
+   /**
+    * Returns the description.
+    *
+    * @return the description
+    */
    @Property(name = "gtn:description")
    public abstract String getDescription();
 
+   /**
+    * Update the description.
+    *
+    * @param description the new description
+    */
    public abstract void setDescription(String description);
 
+   /**
+    * Return the state.
+    *
+    * @return the state
+    */
+   public State getState()
+   {
+      String name = getName();
+      String description = getDescription();
+      return new State(name, description);
+   }
 
+   /**
+    * Update the state.
+    *
+    * @param state the new state
+    * @throws NullPointerException if the new state is null
+    */
+   public void setState(State state) throws NullPointerException
+   {
+      if (state == null)
+      {
+         throw new NullPointerException("No null state accepted");
+      }
+
+      //
+      setName(state.getName());
+      setDescription(state.getDescription());
+   }
+
+   /**
+    * The composite state of the {@code Described} mixin.
+    */
+   public static class State implements Serializable
+   {
+
+      /** . */
+      private final String name;
+
+      /** . */
+      private final String description;
+
+      public State(String name, String description)
+      {
+         this.name = name;
+         this.description = description;
+      }
+
+      public String getName()
+      {
+         return name;
+      }
+
+      public String getDescription()
+      {
+         return description;
+      }
+
+      @Override
+      public boolean equals(Object obj)
+      {
+         if (obj == this)
+         {
+            return true;
+         }
+         if (obj instanceof State)
+         {
+            State that = (State)obj;
+            return Safe.equals(name, that.name) && Safe.equals(description, that.description);
+         }
+         return false;
+      }
+
+      @Override
+      public String toString()
+      {
+         return "Description[name=" + name + ",description=" + description + "]";
+      }
+   }
 }

Added: portal/trunk/component/portal/src/main/java/org/exoplatform/portal/mop/description/CacheKey.java
===================================================================
--- portal/trunk/component/portal/src/main/java/org/exoplatform/portal/mop/description/CacheKey.java	                        (rev 0)
+++ portal/trunk/component/portal/src/main/java/org/exoplatform/portal/mop/description/CacheKey.java	2011-07-01 07:05:25 UTC (rev 6784)
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2011 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+
+package org.exoplatform.portal.mop.description;
+
+import java.io.Serializable;
+import java.util.Locale;
+
+/**
+ * @author <a href="mailto:julien.viet at exoplatform.com">Julien Viet</a>
+ */
+public final class CacheKey implements Serializable
+{
+
+   /** . */
+   final Locale locale;
+
+   /** . */
+   final String id;
+
+   public CacheKey(Locale locale, String id)
+   {
+      if (locale == null)
+      {
+         throw new NullPointerException();
+      }
+      if (id == null)
+      {
+         throw new NullPointerException();
+      }
+
+      //
+      this.locale = locale;
+      this.id = id;
+   }
+
+   @Override
+   public boolean equals(Object obj)
+   {
+      if (obj == this)
+      {
+         return true;
+      }
+      if (obj instanceof CacheKey)
+      {
+         CacheKey that = (CacheKey)obj;
+         return locale.equals(that.locale) && id.equals(that.id);
+      }
+      return false;
+   }
+
+   @Override
+   public int hashCode()
+   {
+      return locale.hashCode() ^ id.hashCode();
+   }
+}

Added: portal/trunk/component/portal/src/main/java/org/exoplatform/portal/mop/description/CacheValue.java
===================================================================
--- portal/trunk/component/portal/src/main/java/org/exoplatform/portal/mop/description/CacheValue.java	                        (rev 0)
+++ portal/trunk/component/portal/src/main/java/org/exoplatform/portal/mop/description/CacheValue.java	2011-07-01 07:05:25 UTC (rev 6784)
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2011 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+
+package org.exoplatform.portal.mop.description;
+
+import org.exoplatform.portal.mop.Described;
+
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * @author <a href="mailto:julien.viet at exoplatform.com">Julien Viet</a>
+ */
+public class CacheValue
+{
+
+   /** . */
+   private static final AtomicLong SEQUENCE = new AtomicLong();
+
+   /** . */
+   final CacheKey origin;
+
+   /** . */
+   final long serial;
+
+   /** . */
+   final Described.State state;
+
+   public CacheValue(CacheKey origin, long serial, Described.State state)
+   {
+      this.origin = origin;
+      this.serial = serial;
+      this.state = state;
+   }
+
+   public CacheValue(Described.State state)
+   {
+      this.origin = null;
+      this.serial = SEQUENCE.incrementAndGet();
+      this.state = state;
+   }
+}

Added: portal/trunk/component/portal/src/main/java/org/exoplatform/portal/mop/description/DataCache.java
===================================================================
--- portal/trunk/component/portal/src/main/java/org/exoplatform/portal/mop/description/DataCache.java	                        (rev 0)
+++ portal/trunk/component/portal/src/main/java/org/exoplatform/portal/mop/description/DataCache.java	2011-07-01 07:05:25 UTC (rev 6784)
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2011 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+
+package org.exoplatform.portal.mop.description;
+
+import org.exoplatform.portal.mop.Described;
+import org.exoplatform.portal.mop.i18n.I18NAdapter;
+import org.exoplatform.portal.mop.i18n.Resolution;
+import org.exoplatform.portal.pom.config.POMSession;
+import org.gatein.mop.api.workspace.WorkspaceObject;
+
+/**
+ * @author <a href="mailto:julien.viet at exoplatform.com">Julien Viet</a>
+ */
+abstract class DataCache
+{
+
+   protected abstract void removeState(CacheKey key);
+
+   protected abstract Described.State getState(POMSession session, CacheKey key);
+
+   protected final CacheValue getValue(POMSession session, CacheKey key)
+   {
+      WorkspaceObject obj = session.findObjectById(key.id);
+      I18NAdapter able = obj.adapt(I18NAdapter.class);
+      Resolution<Described> res = able.resolveI18NMixin(Described.class, key.locale);
+      if (res != null)
+      {
+         Described.State state = res.getMixin().getState();
+         if (key.locale.equals(res.getLocale()))
+         {
+            CacheValue foo = new CacheValue(state);
+            putValue(key, foo);
+            return foo;
+         }
+         else
+         {
+            CacheValue origin = new CacheValue(state);
+            CacheKey originKey = new CacheKey(res.getLocale(), key.id);
+            putValue(originKey, origin);
+            CacheValue foo = new CacheValue(originKey, origin.serial, state);
+            putValue(key, foo);
+            return foo;
+         }
+      }
+      return null;
+   }
+
+   protected abstract void putValue(CacheKey key, CacheValue value);
+
+}

Added: portal/trunk/component/portal/src/main/java/org/exoplatform/portal/mop/description/DescriptionService.java
===================================================================
--- portal/trunk/component/portal/src/main/java/org/exoplatform/portal/mop/description/DescriptionService.java	                        (rev 0)
+++ portal/trunk/component/portal/src/main/java/org/exoplatform/portal/mop/description/DescriptionService.java	2011-07-01 07:05:25 UTC (rev 6784)
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2011 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+
+package org.exoplatform.portal.mop.description;
+
+import org.exoplatform.portal.mop.Described;
+
+import java.util.Locale;
+import java.util.Map;
+
+/**
+ * The description service provides configuration and runtime interaction of described objects.
+ *
+ * @author <a href="mailto:julien.viet at exoplatform.com">Julien Viet</a>
+ */
+public interface DescriptionService
+{
+
+   /**
+    * <p>Resolve a description with the <code>locale</code> argument.</p>
+    *
+    * @param id the object id
+    * @param locale the locale to resolve
+    * @return the description
+    * @throws NullPointerException if the <code>id</code> or the <code>locale</code> argument is null
+    */
+   Described.State resolveDescription(String id, Locale locale) throws NullPointerException;
+
+   /**
+    * <p>Resolve a description, the <code>locale1</code> argument specifies which locale is relevant for retrieval,
+    * the <code>locale2</code> specifies which locale should be defaulted to when the <code>locale1</code>
+    * cannot provide any relevant match. The <code>locale2</code> argument is optional.</p>
+    *
+    * <p>The resolution follows those rules:
+    * <ul>
+    *    <li>The resolution is performed against the locale1.</li>
+    *    <li>When the locale1 does not resolve and a locale2 is provided, a resolution is performed with locale2.</li>
+    *    <li>Otherwise null is returned.<li>
+    * </ul>
+    * </p>
+    *
+    * @param id the object id
+    * @param locale2 the first locale
+    * @param locale1 the second locale
+    * @return the description
+    * @throws NullPointerException if the <code>id</code> or the <code>locale1</code> argument is null
+    */
+   Described.State resolveDescription(String id, Locale locale2, Locale locale1) throws NullPointerException;
+
+   /**
+    * Returns the default description or null if it does not exist.
+    *
+    * @param id the object id
+    * @return the description
+    * @throws NullPointerException if the id argument is null
+    */
+   Described.State getDescription(String id) throws NullPointerException;
+
+   /**
+    * Update the default description to the new description or remove it if the description argument is null.
+    *
+    * @param id the object id
+    * @param description the new description
+    * @throws NullPointerException if the id argument is null
+    */
+   void setDescription(String id, Described.State description) throws NullPointerException;
+
+   /**
+    * Returns a description for the specified locale argument or null if it does not exist.
+    *
+    * @param id the object id
+    * @param locale the locale
+    * @return the description
+    * @throws NullPointerException if the id or locale argument is null
+    */
+   Described.State getDescription(String id, Locale locale) throws NullPointerException;
+
+   /**
+    * Update the description for the specified locale to the new description or remove it if the description
+    * argument is null.
+    *
+    * @param id the object id
+    * @param locale the locale
+    * @param description the new description
+    * @throws NullPointerException if the id or locale argument is null
+    */
+   void setDescription(String id, Locale locale, Described.State description) throws NullPointerException;
+
+   /**
+    * Returns a map containing all the descriptions of an object or null if the object is not internationalized.
+    *
+    * @param id the object id
+    * @return the map the description map
+    * @throws NullPointerException if the id is null
+    */
+   Map<Locale, Described.State> getDescriptions(String id) throws NullPointerException;
+
+   /**
+    * Updates the description of the specified object or remove the internationalized characteristic of
+    * the object if the description map is null.
+    *
+    * @param id the object id
+    * @param descriptions the new descriptions
+    * @throws NullPointerException if the id is null
+    */
+   void setDescriptions(String id, Map<Locale, Described.State> descriptions) throws NullPointerException;
+
+}

Added: portal/trunk/component/portal/src/main/java/org/exoplatform/portal/mop/description/DescriptionServiceImpl.java
===================================================================
--- portal/trunk/component/portal/src/main/java/org/exoplatform/portal/mop/description/DescriptionServiceImpl.java	                        (rev 0)
+++ portal/trunk/component/portal/src/main/java/org/exoplatform/portal/mop/description/DescriptionServiceImpl.java	2011-07-01 07:05:25 UTC (rev 6784)
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2011 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+
+package org.exoplatform.portal.mop.description;
+
+import org.exoplatform.portal.mop.Described;
+import org.exoplatform.portal.mop.i18n.I18NAdapter;
+import org.exoplatform.portal.pom.config.POMSession;
+import org.exoplatform.portal.pom.config.POMSessionManager;
+import org.gatein.mop.api.workspace.WorkspaceObject;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+/**
+ * @author <a href="mailto:julien.viet at exoplatform.com">Julien Viet</a>
+ */
+public class DescriptionServiceImpl implements DescriptionService
+{
+
+   /** . */
+   private final POMSessionManager manager;
+
+   /** . */
+   private DataCache cache;
+
+   public DescriptionServiceImpl(POMSessionManager manager)
+   {
+      this(manager, new SimpleDataCache());
+   }
+
+   public DescriptionServiceImpl(POMSessionManager manager, DataCache cache)
+   {
+      this.manager = manager;
+      this.cache = cache;
+   }
+
+   public Described.State resolveDescription(String id, Locale locale) throws NullPointerException
+   {
+      return resolveDescription(id, null, locale);
+   }
+
+   public Described.State resolveDescription(String id, Locale locale2, Locale locale1) throws NullPointerException
+   {
+      if (id == null)
+      {
+         throw new NullPointerException("No null id accepted");
+      }
+      if (locale1 == null)
+      {
+         throw new NullPointerException("No null locale accepted");
+      }
+
+      //
+      POMSession session = manager.getSession();
+      Described.State state = resolveDescription(session, id, locale1);
+      if (state == null && locale2 != null)
+      {
+         state = resolveDescription(session, id, locale2);
+      }
+      return state;
+   }
+
+   private Described.State resolveDescription(POMSession session, String id, Locale locale) throws NullPointerException
+   {
+      return cache.getState(session, new CacheKey(locale, id));
+   }
+
+   public Described.State getDescription(String id, Locale locale)
+   {
+      if (id == null)
+      {
+         throw new NullPointerException("No null id accepted");
+      }
+      if (locale == null)
+      {
+         throw new NullPointerException("No null locale accepted");
+      }
+      POMSession session = manager.getSession();
+      WorkspaceObject obj = session.findObjectById(id);
+      I18NAdapter able = obj.adapt(I18NAdapter.class);
+      Described desc = able.getI18NMixin(Described.class, locale, false);
+      return desc != null ? desc.getState() : null;
+   }
+
+   public void setDescription(String id, Locale locale, Described.State description)
+   {
+      if (id == null)
+      {
+         throw new NullPointerException("No null id accepted");
+      }
+      if (locale == null)
+      {
+         throw new NullPointerException("No null locale accepted");
+      }
+      POMSession session = manager.getSession();
+      WorkspaceObject obj = session.findObjectById(id);
+      I18NAdapter able = obj.adapt(I18NAdapter.class);
+      Described desc = able.getI18NMixin(Described.class, locale, true);
+      desc.setState(description);
+   }
+
+   public Described.State getDescription(String id)
+   {
+      if (id == null)
+      {
+         throw new NullPointerException("No null id accepted");
+      }
+      POMSession session = manager.getSession();
+      WorkspaceObject obj = session.findObjectById(id);
+      I18NAdapter able = obj.adapt(I18NAdapter.class);
+      Described desc = able.getMixin(Described.class, false);
+      return desc != null ? desc.getState() : null;
+   }
+
+   public void setDescription(String id, Described.State description)
+   {
+      if (id == null)
+      {
+         throw new NullPointerException("No null id accepted");
+      }
+      POMSession session = manager.getSession();
+      WorkspaceObject obj = session.findObjectById(id);
+      I18NAdapter able = obj.adapt(I18NAdapter.class);
+      if (description != null)
+      {
+         Described desc = able.getMixin(Described.class, true);
+         desc.setState(description);
+      }
+      else
+      {
+         able.removeMixin(Described.class);
+      }
+   }
+
+   public Map<Locale, Described.State> getDescriptions(String id)
+   {
+      if (id == null)
+      {
+         throw new NullPointerException("No null id accepted");
+      }
+      POMSession session = manager.getSession();
+      WorkspaceObject obj = session.findObjectById(id);
+      I18NAdapter able = obj.adapt(I18NAdapter.class);
+      Map<Locale, Described> mixins = able.getI18NMixin(Described.class);
+      Map<Locale, Described.State> names = null;
+      if (mixins != null)
+      {
+         names = new HashMap<Locale, Described.State>(mixins.size());
+         for (Map.Entry<Locale, Described> entry : mixins.entrySet())
+         {
+            names.put(entry.getKey(), entry.getValue().getState());
+         }
+      }
+      return names;
+   }
+
+   public void setDescriptions(String id, Map<Locale, Described.State> descriptions)
+   {
+      if (id == null)
+      {
+         throw new NullPointerException("No null id accepted");
+      }
+      POMSession session = manager.getSession();
+      WorkspaceObject obj = session.findObjectById(id);
+      I18NAdapter able = obj.adapt(I18NAdapter.class);
+      Collection<Locale> locales = able.removeI18NMixin(Described.class);
+      for (Locale locale : locales)
+      {
+         cache.removeState(new CacheKey(locale, id));
+      }
+      for (Map.Entry<Locale, Described.State> entry : descriptions.entrySet())
+      {
+         Described described = able.addI18NMixin(Described.class, entry.getKey());
+         described.setState(entry.getValue());
+      }
+   }
+}

Added: portal/trunk/component/portal/src/main/java/org/exoplatform/portal/mop/description/ExoDataCache.java
===================================================================
--- portal/trunk/component/portal/src/main/java/org/exoplatform/portal/mop/description/ExoDataCache.java	                        (rev 0)
+++ portal/trunk/component/portal/src/main/java/org/exoplatform/portal/mop/description/ExoDataCache.java	2011-07-01 07:05:25 UTC (rev 6784)
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2011 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+
+package org.exoplatform.portal.mop.description;
+
+import org.exoplatform.commons.cache.future.FutureExoCache;
+import org.exoplatform.commons.cache.future.Loader;
+import org.exoplatform.portal.mop.Described;
+import org.exoplatform.portal.pom.config.POMSession;
+import org.exoplatform.services.cache.CacheService;
+import org.exoplatform.services.cache.ExoCache;
+
+/**
+ * @author <a href="mailto:julien.viet at exoplatform.com">Julien Viet</a>
+ */
+public class ExoDataCache extends DataCache
+{
+
+   /** . */
+   protected ExoCache<CacheKey, CacheValue> cache;
+
+   /** . */
+   protected FutureExoCache<CacheKey, CacheValue, POMSession> values;
+
+   /** . */
+   private Loader<CacheKey, CacheValue, POMSession> valueLoader = new Loader<CacheKey, CacheValue, POMSession>()
+   {
+      public CacheValue retrieve(POMSession session, CacheKey key) throws Exception
+      {
+         return getValue(session, key);
+      }
+   };
+
+   public ExoDataCache(CacheService cacheService)
+   {
+      this.cache = cacheService.getCacheInstance("NavigationService");
+      this.values = new FutureExoCache<CacheKey, CacheValue, POMSession>(valueLoader, cache)
+      {
+         @Override
+         protected void put(CacheKey key, CacheValue entry)
+         {
+            // Do nothing on purpose
+            // as data in inserted with the putValue method
+            // during the getValue method
+         }
+      };
+   }
+
+   @Override
+   protected void removeState(CacheKey key)
+   {
+      cache.remove(key);
+   }
+
+   @Override
+   protected Described.State getState(POMSession session, CacheKey key)
+   {
+      CacheValue value = values.get(session, key);
+      return value != null ? value.state : null;
+   }
+
+   @Override
+   protected void putValue(CacheKey key, CacheValue value)
+   {
+      cache.put(key, value);
+   }
+}

Added: portal/trunk/component/portal/src/main/java/org/exoplatform/portal/mop/description/SimpleDataCache.java
===================================================================
--- portal/trunk/component/portal/src/main/java/org/exoplatform/portal/mop/description/SimpleDataCache.java	                        (rev 0)
+++ portal/trunk/component/portal/src/main/java/org/exoplatform/portal/mop/description/SimpleDataCache.java	2011-07-01 07:05:25 UTC (rev 6784)
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2011 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+
+package org.exoplatform.portal.mop.description;
+
+import org.exoplatform.portal.mop.Described;
+import org.exoplatform.portal.pom.config.POMSession;
+
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * @author <a href="mailto:julien.viet at exoplatform.com">Julien Viet</a>
+ */
+public class SimpleDataCache extends DataCache
+{
+
+   /** . */
+   private final ConcurrentHashMap<CacheKey, CacheValue> map;
+
+   public SimpleDataCache()
+   {
+      this.map = new ConcurrentHashMap<CacheKey, CacheValue>();
+   }
+
+   @Override
+   protected Described.State getState(POMSession session, CacheKey key)
+   {
+      CacheValue value = map.get(key);
+      if (value == null)
+      {
+         value = getValue(session, key);
+      }
+      return value != null ? value.state : null;
+   }
+
+   @Override
+   protected void removeState(CacheKey key)
+   {
+      map.remove(key);
+   }
+
+   @Override
+   protected void putValue(CacheKey key, CacheValue value)
+   {
+      map.put(key, value);
+   }
+}

Added: portal/trunk/component/portal/src/main/java/org/exoplatform/portal/mop/i18n/I18NAdapter.java
===================================================================
--- portal/trunk/component/portal/src/main/java/org/exoplatform/portal/mop/i18n/I18NAdapter.java	                        (rev 0)
+++ portal/trunk/component/portal/src/main/java/org/exoplatform/portal/mop/i18n/I18NAdapter.java	2011-07-01 07:05:25 UTC (rev 6784)
@@ -0,0 +1,207 @@
+/*
+ * Copyright (C) 2011 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+
+package org.exoplatform.portal.mop.i18n;
+
+import org.gatein.common.i18n.LocaleFormat;
+import org.gatein.common.util.ConversionException;
+import org.gatein.mop.api.workspace.WorkspaceObject;
+import org.gatein.mop.spi.AdapterLifeCycle;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Locale;
+import java.util.Map;
+
+/**
+ * An adapter that provides the i18n support for mop mixins, giving read/write access to default mixins and/or
+ * i18n mixins.
+ *
+ * @author <a href="mailto:khoi.nguyen at exoplatform.com">Nguyen Duc Khoi</a>
+ * @author <a href="mailto:julien.viet at exoplatform.com">Julien Viet</a>
+ */
+public class I18NAdapter
+{
+
+   /** The locale serialization format. */
+   private static final LocaleFormat format = LocaleFormat.DEFAULT;
+
+   /** . */
+   private final WorkspaceObject obj;
+
+   private I18NAdapter(WorkspaceObject obj)
+   {
+      this.obj = obj;
+   }
+
+   static String toString(Locale locale)
+   {
+      return locale.toString();
+   }
+
+   static Locale parseLocale(String s) throws ConversionException
+   {
+      return format.getLocale(s);
+   }
+
+   public <M> M getMixin(Class<M> mixinType, boolean create) throws NullPointerException
+   {
+      if (mixinType == null)
+      {
+         throw new NullPointerException("No null mixin type accepted");
+      }
+      if (obj.isAdapted(mixinType) || create)
+      {
+         return obj.adapt(mixinType);
+      }
+      else
+      {
+         return null;
+      }
+   }
+
+   public <M> void removeMixin(Class<M> mixinType) throws NullPointerException
+   {
+      if (mixinType == null)
+      {
+         throw new NullPointerException("No null mixin type accepted");
+      }
+      if (obj.isAdapted(mixinType))
+      {
+         obj.removeAdapter(mixinType);
+      }
+   }
+
+   public <M> Resolution<M> resolveI18NMixin(Class<M> mixinType, Locale locale) throws NullPointerException
+   {
+      if (mixinType == null)
+      {
+         throw new NullPointerException("No null mixin type accepted");
+      }
+      if (locale == null)
+      {
+         throw new NullPointerException("No null locale accepted");
+      }
+      if (obj.isAdapted(I18Nized.class))
+      {
+         I18Nized ized = obj.adapt(I18Nized.class);
+         return ized.resolveMixin(mixinType, locale);
+      }
+      else
+      {
+         return null;
+      }
+   }
+
+   public <M> M getI18NMixin(Class<M> mixinType, Locale locale, boolean create) throws NullPointerException
+   {
+      if (mixinType == null)
+      {
+         throw new NullPointerException("No null mixin type accepted");
+      }
+      if (locale == null)
+      {
+         throw new NullPointerException("No null locale accepted");
+      }
+      if (obj.isAdapted(I18Nized.class))
+      {
+         I18Nized ized = obj.adapt(I18Nized.class);
+         return ized.getMixin(mixinType, locale, create);
+      }
+      else if (create)
+      {
+         I18Nized ized = obj.adapt(I18Nized.class);
+         return ized.getMixin(mixinType, locale, true);
+      }
+      else
+      {
+         return null;
+      }
+   }
+
+   public <M> Map<Locale, M> getI18NMixin(Class<M> mixinType) throws NullPointerException
+   {
+      if (mixinType == null)
+      {
+         throw new NullPointerException("No null mixin type accepted");
+      }
+      if (obj.isAdapted(I18Nized.class))
+      {
+         I18Nized ized = obj.adapt(I18Nized.class);
+         return ized.getMixins(mixinType);
+      }
+      else
+      {
+         return null;
+      }
+   }
+
+   public <M> M addI18NMixin(Class<M> mixinType, Locale locale)
+   {
+      if (mixinType == null)
+      {
+         throw new NullPointerException("No null mixin type accepted");
+      }
+      if (locale == null)
+      {
+         throw new NullPointerException("No null locale accepted");
+      }
+      I18Nized ized;
+      if (obj.isAdapted(I18Nized.class))
+      {
+         ized = obj.adapt(I18Nized.class);
+      }
+      else
+      {
+         ized = obj.adapt(I18Nized.class);
+      }
+      return ized.getMixin(mixinType, locale, true);
+   }
+
+   public <M> Collection<Locale> removeI18NMixin(Class<M> mixinType)
+   {
+      if (mixinType == null)
+      {
+         throw new NullPointerException("No null mixin type accepted");
+      }
+      if (obj.isAdapted(I18Nized.class))
+      {
+         I18Nized ized = obj.adapt(I18Nized.class);
+         return ized.removeMixin(mixinType);
+      }
+      else
+      {
+         return Collections.emptyList();
+      }
+   }
+
+   public static class LifeCycle extends AdapterLifeCycle<WorkspaceObject, I18NAdapter>
+   {
+      @Override
+      public I18NAdapter create(WorkspaceObject adaptee, Class<I18NAdapter> adapterType)
+      {
+         return new I18NAdapter(adaptee);
+      }
+
+      @Override
+      public void destroy(I18NAdapter adapter, WorkspaceObject adaptee, Class<I18NAdapter> adapterType)
+      {
+      }
+   }
+}

Added: portal/trunk/component/portal/src/main/java/org/exoplatform/portal/mop/i18n/I18Nized.java
===================================================================
--- portal/trunk/component/portal/src/main/java/org/exoplatform/portal/mop/i18n/I18Nized.java	                        (rev 0)
+++ portal/trunk/component/portal/src/main/java/org/exoplatform/portal/mop/i18n/I18Nized.java	2011-07-01 07:05:25 UTC (rev 6784)
@@ -0,0 +1,186 @@
+/**
+ * Copyright (C) 2009 eXo Platform SAS.
+ * 
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ * 
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.portal.mop.i18n;
+
+import org.chromattic.api.annotations.Create;
+import org.chromattic.api.annotations.MappedBy;
+import org.chromattic.api.annotations.MixinType;
+import org.chromattic.api.annotations.OneToOne;
+import org.chromattic.api.annotations.Owner;
+import org.gatein.common.util.ConversionException;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+/**
+ * @author <a href="mailto:khoi.nguyen at exoplatform.com">Nguyen Duc Khoi</a>
+ * Apr 15, 2011
+ */
+
+/**
+ * The entry point for carrying the information
+ * and can be attached to mop entities
+ */
+ at MixinType(name = "gtn:i18nized")
+public abstract class I18Nized
+{
+
+   private static Locale parent(Locale locale)
+   {
+      if (locale.getVariant() != null && !locale.getVariant().isEmpty())
+      {
+         return new Locale(locale.getLanguage(), locale.getCountry());
+      }
+      else if (locale.getCountry() != null && !locale.getCountry().isEmpty())
+      {
+         return new Locale(locale.getLanguage());
+      }
+      else
+      {
+         return null;
+      }
+   }
+
+   @Create
+   public abstract LanguageSpace createLanguageSpace();
+   
+   @OneToOne
+   @Owner
+   @MappedBy("gtn:languages")
+   public abstract LanguageSpace getLanguageSpace();
+   
+   public abstract void setLanguageSpace(LanguageSpace languageSpace);
+
+   public <M> Resolution<M> resolveMixin(Class<M> mixinType, Locale wantedLocale)
+   {
+      if (mixinType == null)
+      {
+         throw new NullPointerException("No null mixin type accepted");
+      }
+      if (wantedLocale == null)
+      {
+         throw new NullPointerException("No null wanted locale accepted");
+      }
+      for (Locale current = wantedLocale;current != null;current = parent(current))
+      {
+         M mixin = getMixin(mixinType, current, false);
+         if (mixin != null)
+         {
+            return new Resolution<M>(current, mixin);
+         }
+      }
+      return null;
+   }
+
+   public <M> Map<Locale, M> getMixins(Class<M> mixinType)
+   {
+      if (mixinType == null)
+      {
+         throw new NullPointerException("No null mixin type accepted");
+      }
+      Map<Locale, M> mixins = new HashMap<Locale, M>();
+      LanguageSpace languageSpace = getLanguageSpace();
+      if (languageSpace != null)
+      {
+         for (Map.Entry<String, Language> entry : languageSpace.getChildren().entrySet())
+         {
+            M mixin = entry.getValue().getMixin(mixinType, false);
+            if (mixin != null)
+            {
+               try
+               {
+                  Locale locale = I18NAdapter.parseLocale(entry.getKey());
+                  mixins.put(locale, mixin);
+               }
+               catch (ConversionException e)
+               {
+                  // Handle me gracefully
+                  e.printStackTrace();
+               }
+            }
+         }
+      }
+      return mixins;
+   }
+   
+   public <M> M getMixin(Class<M> mixinType, Locale locale, boolean createMixin) throws NullPointerException
+   {
+      if (mixinType == null)
+      {
+         throw new NullPointerException("No null mixin type accepted");
+      }
+      if (locale == null)
+      {
+         throw new NullPointerException("No null locale accepted");
+      }
+      LanguageSpace languageSpace = getLanguageSpace();
+      if (languageSpace == null && createMixin)
+      {
+         languageSpace = createLanguageSpace();
+         setLanguageSpace(languageSpace);
+      }
+      if (languageSpace != null)
+      {
+         return languageSpace.getLanguage(mixinType, I18NAdapter.toString(locale), createMixin);
+      }
+      else
+      {
+         return null;
+      }
+   }
+
+   public <M> Collection<Locale> removeMixin(Class<M> mixinType)
+   {
+      if (mixinType == null)
+      {
+         throw new NullPointerException("No null mixin type accepted");
+      }
+      Collection<Locale> locales = Collections.emptyList();
+      LanguageSpace languageSpace = getLanguageSpace();
+      if (languageSpace != null)
+      {
+         for (Language language : languageSpace.getChildren().values())
+         {
+            if (language.removeMixin(mixinType))
+            {
+               try
+               {
+                  String lang = language.getName();
+                  Locale locale = I18NAdapter.parseLocale(lang);
+                  if (locales.isEmpty())
+                  {
+                     locales = new ArrayList<Locale>();
+                  }
+                  locales.add(locale);
+               }
+               catch (ConversionException e)
+               {
+                  // Handle me gracefully
+                  e.printStackTrace();
+               }
+            }
+         }
+      }
+      return locales;
+   }
+}

Added: portal/trunk/component/portal/src/main/java/org/exoplatform/portal/mop/i18n/Injector.java
===================================================================
--- portal/trunk/component/portal/src/main/java/org/exoplatform/portal/mop/i18n/Injector.java	                        (rev 0)
+++ portal/trunk/component/portal/src/main/java/org/exoplatform/portal/mop/i18n/Injector.java	2011-07-01 07:05:25 UTC (rev 6784)
@@ -0,0 +1,72 @@
+/**
+ * Copyright (C) 2009 eXo Platform SAS.
+ * 
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ * 
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.portal.mop.i18n;
+
+import org.chromattic.api.ChromatticSession;
+import org.chromattic.api.event.LifeCycleListener;
+
+/**
+ * @author <a href="mailto:khoi.nguyen at exoplatform.com">Nguyen Duc Khoi</a>
+ * Apr 22, 2011
+ */
+
+/**
+ * 
+ */
+public class Injector implements LifeCycleListener
+{
+   private ChromatticSession session;
+   
+   public Injector(ChromatticSession session)
+   {
+      this.session = session;
+   }
+   
+   @Override
+   public void created(Object o)
+   {
+   }
+
+   @Override
+   public void loaded(String id, String path, String name, Object o)
+   {
+      if (o instanceof Language)
+      {
+         ((Language)o).session = this.session;
+      }
+   }
+
+   @Override
+   public void added(String id, String path, String name, Object o)
+   {
+      if (o instanceof Language)
+      {
+         ((Language)o).session = this.session;
+      }
+   }
+
+   @Override
+   public void removed(String id, String path, String name, Object o)
+   {
+      if (o instanceof Language)
+      {
+         ((Language)o).session = null;
+      }
+   }
+}

Added: portal/trunk/component/portal/src/main/java/org/exoplatform/portal/mop/i18n/Language.java
===================================================================
--- portal/trunk/component/portal/src/main/java/org/exoplatform/portal/mop/i18n/Language.java	                        (rev 0)
+++ portal/trunk/component/portal/src/main/java/org/exoplatform/portal/mop/i18n/Language.java	2011-07-01 07:05:25 UTC (rev 6784)
@@ -0,0 +1,68 @@
+/**
+ * Copyright (C) 2009 eXo Platform SAS.
+ * 
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ * 
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.portal.mop.i18n;
+
+import org.chromattic.api.ChromatticSession;
+import org.chromattic.api.annotations.Name;
+import org.chromattic.api.annotations.PrimaryType;
+
+/**
+ * @author <a href="mailto:khoi.nguyen at exoplatform.com">Nguyen Duc Khoi</a>
+ * Apr 15, 2011
+ */
+
+/**
+ * A nake node type that describe a language entry
+ * This node is able to support data through addition of mixins
+ */
+ at PrimaryType(name = "gtn:language")
+public abstract class Language
+{
+
+   /** . */
+   public ChromatticSession session;
+
+   @Name
+   abstract String getName();
+
+   <M> M getMixin(Class<M> mixinType, boolean create)
+   {
+      M mixin = session.getEmbedded(this, mixinType);
+      if (mixin == null && create)
+      {
+         mixin = session.create(mixinType);
+         session.setEmbedded(this, mixinType, mixin);
+      }
+      return mixin;
+   }
+
+   <M> boolean removeMixin(Class<M> mixinType)
+   {
+      M mixin = session.getEmbedded(this, mixinType);
+      if (mixin != null)
+      {
+         session.setEmbedded(this, mixinType, null);
+         return true;
+      }
+      else
+      {
+         return false;
+      }
+   }
+}

Added: portal/trunk/component/portal/src/main/java/org/exoplatform/portal/mop/i18n/LanguageSpace.java
===================================================================
--- portal/trunk/component/portal/src/main/java/org/exoplatform/portal/mop/i18n/LanguageSpace.java	                        (rev 0)
+++ portal/trunk/component/portal/src/main/java/org/exoplatform/portal/mop/i18n/LanguageSpace.java	2011-07-01 07:05:25 UTC (rev 6784)
@@ -0,0 +1,67 @@
+/**
+ * Copyright (C) 2009 eXo Platform SAS.
+ * 
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ * 
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.portal.mop.i18n;
+
+import java.util.Map;
+
+import org.chromattic.api.ChromatticSession;
+import org.chromattic.api.annotations.Create;
+import org.chromattic.api.annotations.OneToMany;
+import org.chromattic.api.annotations.PrimaryType;
+
+/**
+ * @author <a href="mailto:khoi.nguyen at exoplatform.com">Nguyen Duc Khoi</a>
+ * Apr 15, 2011
+ */
+
+/**
+ * A bare node container for language entries
+ */
+ at PrimaryType(name = "gtn:languages")
+public abstract class LanguageSpace
+{
+
+   @Create
+   public abstract Language createLanguage();
+
+   @OneToMany
+   public abstract Map<String, Language> getChildren();
+
+   protected <E> E getLanguage(Class<E> mixinType, String locale, boolean create)
+   {
+      Language language;
+      Map<String, Language> children = getChildren();
+      if (children.containsKey(locale))
+      {
+         language = children.get(locale);
+      }
+      else if (create)
+      {
+         language = createLanguage();
+         children.put(locale, language);
+      }
+      else
+      {
+         return null;
+      }
+
+      //
+      return language.getMixin(mixinType, create);
+   }
+}

Added: portal/trunk/component/portal/src/main/java/org/exoplatform/portal/mop/i18n/Resolution.java
===================================================================
--- portal/trunk/component/portal/src/main/java/org/exoplatform/portal/mop/i18n/Resolution.java	                        (rev 0)
+++ portal/trunk/component/portal/src/main/java/org/exoplatform/portal/mop/i18n/Resolution.java	2011-07-01 07:05:25 UTC (rev 6784)
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2011 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+
+package org.exoplatform.portal.mop.i18n;
+
+import java.util.Locale;
+
+/**
+ * @author <a href="mailto:julien.viet at exoplatform.com">Julien Viet</a>
+ */
+public class Resolution<M>
+{
+
+   /** . */
+   private final Locale locale;
+
+   /** . */
+   private final M mixin;
+
+   public Resolution(Locale locale, M mixin)
+   {
+      if (locale == null)
+      {
+         throw new NullPointerException("No null locale accepted");
+      }
+      if (mixin == null)
+      {
+         throw new NullPointerException("No null mixin accepted");
+      }
+
+      //
+      this.locale = locale;
+      this.mixin = mixin;
+   }
+
+   public Locale getLocale()
+   {
+      return locale;
+   }
+
+   public M getMixin()
+   {
+      return mixin;
+   }
+}

Modified: portal/trunk/component/portal/src/main/java/org/exoplatform/portal/mop/user/UserNode.java
===================================================================
--- portal/trunk/component/portal/src/main/java/org/exoplatform/portal/mop/user/UserNode.java	2011-07-01 06:44:15 UTC (rev 6783)
+++ portal/trunk/component/portal/src/main/java/org/exoplatform/portal/mop/user/UserNode.java	2011-07-01 07:05:25 UTC (rev 6784)
@@ -20,15 +20,16 @@
 package org.exoplatform.portal.mop.user;
 
 import org.exoplatform.commons.utils.ExpressionUtil;
+import org.exoplatform.portal.mop.Described;
 import org.exoplatform.portal.mop.Visibility;
-import org.exoplatform.portal.mop.navigation.NavigationServiceException;
+import org.exoplatform.portal.mop.description.DescriptionService;
 import org.exoplatform.portal.mop.navigation.NodeContext;
-import org.exoplatform.portal.mop.navigation.NodeFilter;
 import org.exoplatform.portal.mop.navigation.NodeState;
 import org.gatein.common.text.EntityEncoder;
 
 import java.util.Collection;
 import java.util.Collections;
+import java.util.Locale;
 import java.util.ResourceBundle;
 
 /**
@@ -185,15 +186,27 @@
    {
       if (resolvedLabel == null)
       {
-         String resolvedLabel;
+         String resolvedLabel = null;
+
+         //
+         String id = context.getId();
+
+         //
          if (context.getState().getLabel() != null)
          {
             ResourceBundle bundle = owner.navigation.getBundle();
             resolvedLabel = ExpressionUtil.getExpressionValue(bundle, context.getState().getLabel());
          }
-         else
+         else if (id != null)
          {
-            resolvedLabel = null;
+            Locale userLocale = owner.navigation.portal.context.getUserLocale();
+            Locale portalLocale = owner.navigation.portal.getLocale();
+            DescriptionService descriptionService = owner.navigation.portal.service.getDescriptionService();
+            Described.State description = descriptionService.resolveDescription(id, portalLocale, userLocale);
+            if (description != null)
+            {
+               resolvedLabel = description.getName();
+            }
          }
 
          //

Modified: portal/trunk/component/portal/src/main/java/org/exoplatform/portal/mop/user/UserNodeFilter.java
===================================================================
--- portal/trunk/component/portal/src/main/java/org/exoplatform/portal/mop/user/UserNodeFilter.java	2011-07-01 06:44:15 UTC (rev 6783)
+++ portal/trunk/component/portal/src/main/java/org/exoplatform/portal/mop/user/UserNodeFilter.java	2011-07-01 07:05:25 UTC (rev 6784)
@@ -75,7 +75,7 @@
       {
          if (visibility == Visibility.SYSTEM)
          {
-            UserACL acl = userPortal.acl;
+            UserACL acl = userPortal.service.getUserACL();
             String userName = userPortal.userName;
             if (!acl.getSuperUser().equals(userName))
             {

Modified: portal/trunk/component/portal/src/main/java/org/exoplatform/portal/mop/user/UserPortal.java
===================================================================
--- portal/trunk/component/portal/src/main/java/org/exoplatform/portal/mop/user/UserPortal.java	2011-07-01 06:44:15 UTC (rev 6783)
+++ portal/trunk/component/portal/src/main/java/org/exoplatform/portal/mop/user/UserPortal.java	2011-07-01 07:05:25 UTC (rev 6784)
@@ -20,6 +20,7 @@
 package org.exoplatform.portal.mop.user;
 
 import java.util.List;
+import java.util.Locale;
 
 import org.exoplatform.portal.mop.SiteKey;
 import org.exoplatform.portal.mop.navigation.NavigationServiceException;
@@ -36,6 +37,13 @@
 {
 
    /**
+    * Returns the portal locale.
+    *
+    * @return the portal locale
+    */
+   Locale getLocale();
+
+   /**
     * Returns the sorted list of current user navigations.
     *
     * @return the current user navigations

Modified: portal/trunk/component/portal/src/main/java/org/exoplatform/portal/mop/user/UserPortalContext.java
===================================================================
--- portal/trunk/component/portal/src/main/java/org/exoplatform/portal/mop/user/UserPortalContext.java	2011-07-01 06:44:15 UTC (rev 6783)
+++ portal/trunk/component/portal/src/main/java/org/exoplatform/portal/mop/user/UserPortalContext.java	2011-07-01 07:05:25 UTC (rev 6784)
@@ -19,6 +19,7 @@
 
 package org.exoplatform.portal.mop.user;
 
+import java.util.Locale;
 import java.util.ResourceBundle;
 
 /**
@@ -39,4 +40,10 @@
     */
    ResourceBundle getBundle(UserNavigation navigation);
 
+   /**
+    * Returns the user locale.
+    *
+    * @return the user locale
+    */
+   Locale getUserLocale();
 }

Modified: portal/trunk/component/portal/src/main/java/org/exoplatform/portal/mop/user/UserPortalImpl.java
===================================================================
--- portal/trunk/component/portal/src/main/java/org/exoplatform/portal/mop/user/UserPortalImpl.java	2011-07-01 06:44:15 UTC (rev 6783)
+++ portal/trunk/component/portal/src/main/java/org/exoplatform/portal/mop/user/UserPortalImpl.java	2011-07-01 07:05:25 UTC (rev 6784)
@@ -24,15 +24,13 @@
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
-import java.util.ResourceBundle;
+import java.util.Locale;
 
-import org.exoplatform.portal.config.UserACL;
 import org.exoplatform.portal.config.UserPortalConfigService;
 import org.exoplatform.portal.config.model.PortalConfig;
 import org.exoplatform.portal.mop.SiteKey;
 import org.exoplatform.portal.mop.SiteType;
 import org.exoplatform.portal.mop.navigation.NavigationContext;
-import org.exoplatform.portal.mop.navigation.NavigationService;
 import org.exoplatform.portal.mop.navigation.NavigationServiceException;
 import org.exoplatform.portal.mop.navigation.NodeChangeListener;
 import org.exoplatform.portal.mop.navigation.NodeContext;
@@ -41,7 +39,6 @@
 import org.exoplatform.portal.mop.navigation.Scope;
 import org.exoplatform.portal.mop.navigation.VisitMode;
 import org.exoplatform.services.organization.Group;
-import org.exoplatform.services.organization.OrganizationService;
 
 /**
  * @author <a href="mailto:julien.viet at exoplatform.com">Julien Viet</a>
@@ -50,30 +47,10 @@
 public class UserPortalImpl implements UserPortal
 {
 
-   /**
-    * A context that always return null.
-    */
-   private static final UserPortalContext NULL_CONTEXT = new UserPortalContext()
-   {
-      public ResourceBundle getBundle(UserNavigation navigation)
-      {
-         return null;
-      }
-   };
-
    /** . */
    final UserPortalConfigService service;
 
    /** . */
-   final NavigationService navigationService;
-   
-   /** . */
-   private final OrganizationService organizationService;
-
-   /** . */
-   final UserACL acl;
-   
-   /** . */
    private final PortalConfig portal;
 
    /** . */
@@ -88,33 +65,39 @@
    /** . */
    private final String portalName;
 
+   /** . */
+   private final Locale portalLocale;
+
    public UserPortalImpl(
       UserPortalConfigService service,
-      NavigationService navigationService,
-      OrganizationService organizationService,
-      UserACL acl,
       String portalName,
       PortalConfig portal,
       String userName,
       UserPortalContext context)
    {
-      // So we don't care about testing nullity
       if (context == null)
       {
-         context = NULL_CONTEXT;
+         throw new NullPointerException("No null context argument allowed");
       }
 
       //
+      String locale = portal.getLocale();
+
+      //
+      this.portalLocale = locale != null ? new Locale(locale) : null;
       this.service = service;
-      this.navigationService = navigationService;
-      this.organizationService = organizationService;
-      this.acl = acl;
       this.portalName = portalName;
       this.portal = portal;
       this.userName = userName;
       this.context = context;
       this.navigations = null;
    }
+
+   public Locale getLocale()
+   {
+      return portalLocale;
+   }
+
    /**
     * Returns an immutable sorted list of the valid navigations related to the user.
     *
@@ -126,16 +109,16 @@
       if (navigations == null)
       {
          List<UserNavigation> navigations = new ArrayList<UserNavigation>(userName == null ? 1 : 10);
-         NavigationContext portalNav = navigationService.loadNavigation(new SiteKey(SiteType.PORTAL, portalName));
+         NavigationContext portalNav = service.getNavigationService().loadNavigation(new SiteKey(SiteType.PORTAL, portalName));
          if (portalNav != null && portalNav.getState() != null)
          {
-            navigations.add(new UserNavigation(this, portalNav, acl.hasEditPermission(portal)));
+            navigations.add(new UserNavigation(this, portalNav, service.getUserACL().hasEditPermission(portal)));
          }
          //
          if (userName != null)
          {
             // Add user nav if any
-            NavigationContext userNavigation = navigationService.loadNavigation(SiteKey.user(userName));
+            NavigationContext userNavigation = service.getNavigationService().loadNavigation(SiteKey.user(userName));
             if (userNavigation != null && userNavigation.getState() != null)
             {
                navigations.add(new UserNavigation(this, userNavigation, true));
@@ -145,13 +128,13 @@
             Collection<?> groups;
             try
             {
-               if (acl.getSuperUser().equals(userName))
+               if (service.getUserACL().getSuperUser().equals(userName))
                {
-                  groups = organizationService.getGroupHandler().getAllGroups();
+                  groups = service.getOrganizationService().getGroupHandler().getAllGroups();
                }
                else
                {
-                  groups = organizationService.getGroupHandler().findGroupsOfUser(userName);
+                  groups = service.getOrganizationService().getGroupHandler().findGroupsOfUser(userName);
                }
             }
             catch (Exception e)
@@ -164,15 +147,15 @@
             {
                Group m = (Group)group;
                String groupId = m.getId().trim();
-               if (!groupId.equals(acl.getGuestsGroup()))
+               if (!groupId.equals(service.getUserACL().getGuestsGroup()))
                {
-                  NavigationContext groupNavigation = navigationService.loadNavigation(SiteKey.group(groupId));
+                  NavigationContext groupNavigation = service.getNavigationService().loadNavigation(SiteKey.group(groupId));
                   if (groupNavigation != null && groupNavigation.getState() != null)
                   {
                      navigations.add(new UserNavigation(
                         this,
                         groupNavigation,
-                        acl.hasEditPermissionOnNavigation(groupNavigation.getKey())));
+                        service.getUserACL().hasEditPermissionOnNavigation(groupNavigation.getKey())));
                   }
                }
             }
@@ -218,7 +201,7 @@
       NodeChangeListener<UserNode> listener) throws NullPointerException, UserPortalException, NavigationServiceException
    {
       UserNodeContext context = new UserNodeContext(userNavigation, filterConfig);
-      NodeContext<UserNode> nodeContext = navigationService.loadNode(context, userNavigation.navigation, scope, NodeContextChangeAdapter.safeWrap(listener));
+      NodeContext<UserNode> nodeContext = service.getNavigationService().loadNode(context, userNavigation.navigation, scope, NodeContextChangeAdapter.safeWrap(listener));
       if (nodeContext != null)
       {
          return nodeContext.getNode().filter();
@@ -236,7 +219,7 @@
       {
          throw new NullPointerException("No null node accepted");
       }
-      navigationService.updateNode(node.context, scope, NodeContextChangeAdapter.safeWrap(listener));
+      service.getNavigationService().updateNode(node.context, scope, NodeContextChangeAdapter.safeWrap(listener));
       node.filter();
    }
    
@@ -247,7 +230,7 @@
       {
          throw new NullPointerException("No null node accepted");
       }
-      navigationService.rebaseNode(node.context, scope, NodeContextChangeAdapter.safeWrap(listener));
+      service.getNavigationService().rebaseNode(node.context, scope, NodeContextChangeAdapter.safeWrap(listener));
       node.filter();
    }
 
@@ -257,7 +240,7 @@
       {
          throw new NullPointerException("No null node accepted");
       }
-      navigationService.saveNode(node.context, NodeContextChangeAdapter.safeWrap(listener));
+      service.getNavigationService().saveNode(node.context, NodeContextChangeAdapter.safeWrap(listener));
       node.filter();
    }
 
@@ -280,7 +263,7 @@
       void resolve() throws NavigationServiceException
       {
          UserNodeContext context = new UserNodeContext(userNavigation, filterConfig);
-         NodeContext<UserNode> nodeContext = navigationService.loadNode(context, userNavigation.navigation, this, null);
+         NodeContext<UserNode> nodeContext = service.getNavigationService().loadNode(context, userNavigation.navigation, this, null);
          if (context != null)
          {
             if (score > 0)
@@ -329,7 +312,7 @@
          if (navigation.getState() != null)
          {
             UserNodeContext context = new UserNodeContext(userNavigation, filterConfig);
-            NodeContext<UserNode> nodeContext = navigationService.loadNode(context, navigation, Scope.CHILDREN, null);
+            NodeContext<UserNode> nodeContext = service.getNavigationService().loadNode(context, navigation, Scope.CHILDREN, null);
             if (nodeContext != null)
             {
                UserNode root = nodeContext.getNode().filter();

Modified: portal/trunk/component/portal/src/main/java/org/exoplatform/portal/pom/config/MOPChromatticLifeCycle.java
===================================================================
--- portal/trunk/component/portal/src/main/java/org/exoplatform/portal/pom/config/MOPChromatticLifeCycle.java	2011-07-01 06:44:15 UTC (rev 6783)
+++ portal/trunk/component/portal/src/main/java/org/exoplatform/portal/pom/config/MOPChromatticLifeCycle.java	2011-07-01 07:05:25 UTC (rev 6784)
@@ -21,6 +21,7 @@
 import org.exoplatform.commons.chromattic.ChromatticLifeCycle;
 import org.exoplatform.commons.chromattic.SessionContext;
 import org.exoplatform.container.xml.InitParams;
+import org.exoplatform.portal.mop.i18n.Injector;
 
 /**
  * Extends the chromattic life cycle to associate the mop session as an attachment of the chromattic session.
@@ -43,6 +44,7 @@
    protected void onOpenSession(SessionContext context)
    {
       POMSession session = new POMSession(manager, this, context);
+      context.getSession().addEventListener(new Injector(context.getSession()));
       context.setAttachment("mopsession", session);
    }
 

Added: portal/trunk/component/portal/src/main/resources/META-INF/services/org.gatein.mop.spi.AdapterLifeCycle
===================================================================
--- portal/trunk/component/portal/src/main/resources/META-INF/services/org.gatein.mop.spi.AdapterLifeCycle	                        (rev 0)
+++ portal/trunk/component/portal/src/main/resources/META-INF/services/org.gatein.mop.spi.AdapterLifeCycle	2011-07-01 07:05:25 UTC (rev 6784)
@@ -0,0 +1 @@
+org.exoplatform.portal.mop.i18n.I18NAdapter$LifeCycle

Modified: portal/trunk/component/portal/src/main/resources/binding.xml
===================================================================
--- portal/trunk/component/portal/src/main/resources/binding.xml	2011-07-01 06:44:15 UTC (rev 6783)
+++ portal/trunk/component/portal/src/main/resources/binding.xml	2011-07-01 07:05:25 UTC (rev 6784)
@@ -19,15 +19,21 @@
 
 -->
 
-<binding>  
+<binding>
 
-  <format type="java.lang.String[]" 
+  <format type="java.lang.String[]"
           serializer="org.exoplatform.portal.config.serialize.JibxArraySerialize.serializeStringArray"
           deserializer="org.exoplatform.portal.config.serialize.JibxArraySerialize.deserializeStringArray"/>
           
   <mapping class="org.exoplatform.portal.config.model.Properties" name="properties" 
            marshaller="org.exoplatform.portal.config.serialize.JibxPropertiesMapper" 
-           unmarshaller="org.exoplatform.portal.config.serialize.JibxPropertiesMapper"/>           
+           unmarshaller="org.exoplatform.portal.config.serialize.JibxPropertiesMapper"/>
+
+  <mapping class="org.exoplatform.portal.config.model.LocalizedValue"
+           name="label"
+           unmarshaller="org.exoplatform.portal.config.serialize.LocalizedValueMapper"
+           marshaller="org.exoplatform.portal.config.serialize.LocalizedValueMapper">
+  </mapping>
   
   <mapping
       name="application"
@@ -101,7 +107,9 @@
    <mapping name="node" label="node" class="org.exoplatform.portal.config.model.PageNode">
     <value name="uri" field="uri" usage="optional"/>
     <value name="name" field="name"/>
-    <value name="label" field="label" usage="optional" set-method="setLabel"/>
+    <collection field="labels" ordered="false">
+      <structure map-as="org.exoplatform.portal.config.model.LocalizedValue" usage="optional"/>
+    </collection>
     <value name="icon" field="icon" usage="optional"/>
     <value name="start-publication-date" field="startPublicationDate" usage="optional"/>
     <value name="end-publication-date" field="endPublicationDate" usage="optional"/>

Modified: portal/trunk/component/portal/src/test/java/org/exoplatform/portal/TestXSDCorruption.java
===================================================================
--- portal/trunk/component/portal/src/test/java/org/exoplatform/portal/TestXSDCorruption.java	2011-07-01 06:44:15 UTC (rev 6783)
+++ portal/trunk/component/portal/src/test/java/org/exoplatform/portal/TestXSDCorruption.java	2011-07-01 07:05:25 UTC (rev 6784)
@@ -20,6 +20,7 @@
 package org.exoplatform.portal;
 
 import junit.framework.TestCase;
+
 import org.gatein.common.io.IOTools;
 
 import java.io.InputStream;
@@ -55,10 +56,10 @@
       assertEquals(expected, sb.toString());
    }
 
-   public void testGateInResources1_x() throws Exception
+   public void testGateInObjects1_x() throws Exception
    {
       assertHash("d0591b0a022a0c2929e1aed8979857cd", "gatein_objects_1_0.xsd");
       assertHash("99ae24c9bbfe1b59e066756a29ab6c79", "gatein_objects_1_1.xsd");
-      assertHash("9a031c15ce0e2b4dd1e283458f590581", "gatein_objects_1_2.xsd");
+      assertHash("8bb0cd234fc32e11149e38f689dd7cef", "gatein_objects_1_2.xsd");
    }
 }

Modified: portal/trunk/component/portal/src/test/java/org/exoplatform/portal/config/AbstractPortalTest.java
===================================================================
--- portal/trunk/component/portal/src/test/java/org/exoplatform/portal/config/AbstractPortalTest.java	2011-07-01 06:44:15 UTC (rev 6783)
+++ portal/trunk/component/portal/src/test/java/org/exoplatform/portal/config/AbstractPortalTest.java	2011-07-01 07:05:25 UTC (rev 6784)
@@ -58,6 +58,18 @@
       super.end();
    }
 
+   protected final void sync()
+   {
+      end();
+      begin();
+   }
+
+   protected final void sync(boolean save)
+   {
+      end(save);
+      begin();
+   }
+
    @Override
    protected void setUp() throws Exception
    {

Modified: portal/trunk/component/portal/src/test/java/org/exoplatform/portal/config/TestJIBXXmlMapping.java
===================================================================
--- portal/trunk/component/portal/src/test/java/org/exoplatform/portal/config/TestJIBXXmlMapping.java	2011-07-01 06:44:15 UTC (rev 6783)
+++ portal/trunk/component/portal/src/test/java/org/exoplatform/portal/config/TestJIBXXmlMapping.java	2011-07-01 07:05:25 UTC (rev 6784)
@@ -22,15 +22,19 @@
 import org.exoplatform.component.test.AbstractGateInTest;
 import org.exoplatform.portal.application.PortletPreferences.PortletPreferencesSet;
 import org.exoplatform.portal.config.model.Application;
-import org.exoplatform.portal.config.model.ApplicationType;
+import org.exoplatform.portal.config.model.LocalizedValue;
+import org.exoplatform.portal.config.model.ModelUnmarshaller;
 import org.exoplatform.portal.config.model.Page;
+import org.exoplatform.portal.config.model.Page.PageSet;
 import org.exoplatform.portal.config.model.PageNavigation;
+import org.exoplatform.portal.config.model.PageNode;
 import org.exoplatform.portal.config.model.PortalConfig;
 import org.exoplatform.portal.config.model.TransientApplicationState;
-import org.exoplatform.portal.config.model.Page.PageSet;
-import org.exoplatform.portal.pom.spi.gadget.Gadget;
+import org.exoplatform.portal.config.model.UnmarshalledObject;
+import org.exoplatform.portal.config.model.Version;
 import org.exoplatform.portal.pom.spi.portlet.Portlet;
 import org.exoplatform.portal.pom.spi.portlet.PortletBuilder;
+import org.gatein.common.util.Tools;
 import org.jibx.runtime.BindingDirectory;
 import org.jibx.runtime.IBindingFactory;
 import org.jibx.runtime.IMarshallingContext;
@@ -38,6 +42,8 @@
 
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
+import java.util.ArrayList;
+import java.util.Locale;
 
 /**
  * Thu, May 15, 2003 @   
@@ -90,12 +96,14 @@
       assertEquals("portal", pageNavigation.getOwnerType());
       assertEquals("classic", pageNavigation.getOwnerId());
 
+/*
       IMarshallingContext mctx = bfact.createMarshallingContext();
       mctx.setIndent(2);
       mctx.marshalDocument(obj, "UTF-8", null, new FileOutputStream("target/navigation.xml"));
 
       obj = uctx.unmarshalDocument(new FileInputStream("target/navigation.xml"), null);
       assertEquals(PageNavigation.class, obj.getClass());
+*/
    }
 
    public void testPortletPreferencesMapping() throws Exception
@@ -127,20 +135,65 @@
       assertEquals(new PortletBuilder().add("template", "template_value").build(), preferences);
    }
 
-   public void testGadgetApplicationMapping() throws Exception
+   public void testSimpleNavigationMapping() throws Exception
    {
-      IBindingFactory bfact = BindingDirectory.getFactory(PortalConfig.class);
-      IUnmarshallingContext uctx = bfact.createUnmarshallingContext();
-      @SuppressWarnings("unchecked")
-      Application<Gadget> app =
-         (Application<Gadget>)uctx.unmarshalDocument(new FileInputStream(
-            "src/test/resources/jibx/gadget-application.xml"), null);
+      UnmarshalledObject<PageNavigation> obj = ModelUnmarshaller.unmarshall(PageNavigation.class, new FileInputStream("src/test/resources/jibx/simple-navigation.xml"));;
+      PageNavigation nav = obj.getObject();
+      assertEquals(Version.V_1_1, obj.getVersion());
 
-      assertEquals(ApplicationType.GADGET, app.getType());
-         TransientApplicationState gadgetState = (TransientApplicationState) app.getState();
-      assertNotNull(gadgetState);
-      assertEquals("Calendar", gadgetState.getContentId());
-      assertNull(gadgetState.getContentState());
-      // Add test for user-prefs when supported...
+      //
+      PageNode bar = nav.getNode("bar");
+      assertEquals("bar_label", bar.getLabel());
+      ArrayList<LocalizedValue> barLabels =  bar.getLabels();
+      assertNotNull(barLabels);
+      assertEquals(1, barLabels.size());
+      assertEquals("bar_label", barLabels.get(0).getValue());
+      assertEquals(null, barLabels.get(0).getLang());
+      assertEquals(null, bar.getLocalizedLabel(Locale.ENGLISH));
    }
+
+   public void testExtendedNavigationMapping() throws Exception
+   {
+      UnmarshalledObject<PageNavigation> obj = ModelUnmarshaller.unmarshall(PageNavigation.class, new FileInputStream("src/test/resources/jibx/extended-navigation.xml"));;
+      PageNavigation nav = obj.getObject();
+      assertEquals(Version.V_1_2, obj.getVersion());
+
+      //
+      PageNode foo = nav.getNode("foo");
+      assertEquals("foo_label", foo.getLabel());
+      ArrayList<LocalizedValue> fooLabels =  foo.getLabels();
+      assertNotNull(fooLabels);
+      assertEquals(3, fooLabels.size());
+      assertEquals("foo_label_en", fooLabels.get(0).getValue());
+      assertEquals(Locale.ENGLISH, fooLabels.get(0).getLang());
+      assertEquals("foo_label", fooLabels.get(1).getValue());
+      assertEquals(null, fooLabels.get(1).getLang());
+      assertEquals("foo_label_fr", fooLabels.get(2).getValue());
+      assertEquals(Locale.FRENCH, fooLabels.get(2).getLang());
+      assertEquals(Tools.toSet(Locale.ENGLISH, Locale.FRENCH), foo.getLocalizedLabel(Locale.ENGLISH).keySet());
+      assertEquals(Tools.toSet(Locale.ENGLISH, Locale.FRENCH, Locale.GERMAN), foo.getLocalizedLabel(Locale.GERMAN).keySet());
+
+      //
+      PageNode bar = nav.getNode("bar");
+      assertEquals("bar_label", bar.getLabel());
+      ArrayList<LocalizedValue> barLabels =  bar.getLabels();
+      assertNotNull(barLabels);
+      assertEquals(1, barLabels.size());
+      assertEquals("bar_label", barLabels.get(0).getValue());
+      assertEquals(null, barLabels.get(0).getLang());
+      assertEquals(null, bar.getLocalizedLabel(Locale.ENGLISH));
+
+      //
+      PageNode juu = nav.getNode("juu");
+      assertEquals(null, juu.getLabel());
+      ArrayList<LocalizedValue> juuLabels =  juu.getLabels();
+      assertNotNull(juuLabels);
+      assertEquals(3, juuLabels.size());
+      assertEquals("juu_label_en", juuLabels.get(0).getValue());
+      assertEquals(Locale.ENGLISH, juuLabels.get(0).getLang());
+      assertEquals("juu_label_fr", juuLabels.get(1).getValue());
+      assertEquals(Locale.FRENCH, juuLabels.get(1).getLang());
+      assertEquals("juu_label_fr_FR", juuLabels.get(2).getValue());
+      assertEquals(Locale.FRANCE, juuLabels.get(2).getLang());
+   }
 }

Modified: portal/trunk/component/portal/src/test/java/org/exoplatform/portal/config/importer/TestNavigationImporter.java
===================================================================
--- portal/trunk/component/portal/src/test/java/org/exoplatform/portal/config/importer/TestNavigationImporter.java	2011-07-01 06:44:15 UTC (rev 6783)
+++ portal/trunk/component/portal/src/test/java/org/exoplatform/portal/config/importer/TestNavigationImporter.java	2011-07-01 07:05:25 UTC (rev 6784)
@@ -19,12 +19,20 @@
 
 package org.exoplatform.portal.config.importer;
 
+import org.exoplatform.portal.config.model.LocalizedValue;
 import org.exoplatform.portal.config.model.PageNavigation;
+import org.exoplatform.portal.mop.Described;
 import org.exoplatform.portal.mop.SiteKey;
 import org.exoplatform.portal.mop.navigation.*;
+import org.gatein.common.util.Tools;
 import org.gatein.mop.api.workspace.ObjectType;
 import org.gatein.mop.core.api.MOPService;
 
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Locale;
+import java.util.Map;
+
 import static org.exoplatform.portal.config.importer.Builder.*;
 
 /**
@@ -62,7 +70,7 @@
       PageNavigation src = navigation(name).build();
       src.setPriority(2);
       src.setOwnerId(name);
-      NavigationImporter merge = new NavigationImporter(mode, src, service);
+      NavigationImporter merge = new NavigationImporter(Locale.ENGLISH, mode, false, src, service, descriptionService);
       merge.perform();
 
       //
@@ -85,7 +93,7 @@
       //
       PageNavigation src = builder.build();
       src.setOwnerId("merge_create");
-      NavigationImporter merge = new NavigationImporter(ImportMode.MERGE, src, service);
+      NavigationImporter merge = new NavigationImporter(Locale.ENGLISH, ImportMode.MERGE, false, src, service, descriptionService);
       merge.perform();
 
       //
@@ -113,7 +121,7 @@
       //
       PageNavigation src = builder.build();
       src.setOwnerId("merge_nested");
-      NavigationImporter merge = new NavigationImporter(ImportMode.MERGE, src, service);
+      NavigationImporter merge = new NavigationImporter(Locale.ENGLISH, ImportMode.MERGE, false, src, service, descriptionService);
       merge.perform();
 
       //
@@ -159,7 +167,7 @@
       //
       PageNavigation src = builder.build();
       src.setOwnerId(name);
-      NavigationImporter merge = new NavigationImporter(ImportMode.CONSERVE, src, service);
+      NavigationImporter merge = new NavigationImporter(Locale.ENGLISH, ImportMode.CONSERVE, false, src, service, descriptionService);
       merge.perform();
 
       //
@@ -178,7 +186,7 @@
       builder = navigation(name).add(node("a").add(node("d"))).add(node("c"));
       src = builder.build();
       src.setOwnerId(name);
-      merge = new NavigationImporter(importMode, src, service);
+      merge = new NavigationImporter(Locale.ENGLISH, importMode, false, src, service, descriptionService);
       merge.perform();
 
       //
@@ -250,7 +258,7 @@
       //
       PageNavigation src = navigation("merge_order").add(node("a"), node("b"), node("c")).build();
       src.setOwnerId("merge_order");
-      NavigationImporter merge = new NavigationImporter(ImportMode.MERGE, src, service);
+      NavigationImporter merge = new NavigationImporter(Locale.ENGLISH, ImportMode.MERGE, false, src, service, descriptionService);
       merge.perform();
 
       //
@@ -261,4 +269,94 @@
       assertEquals("b", node.get(1).getName());
       assertEquals("c", node.get(2).getName());
    }
+
+   public void testExtendedLabel()
+   {
+      MOPService mop = mgr.getPOMService();
+      mop.getModel().getWorkspace().addSite(ObjectType.PORTAL_SITE, "importer_extended_label");
+      sync(true);
+
+      //
+      assertNull(service.loadNavigation(SiteKey.portal("importer_extended_label")));
+
+      //
+      PageNavigation src = navigation("importer_extended_label").add(node("a"), node("b"), node("c")).build();
+      src.getNode("a").setLabels(new ArrayList<LocalizedValue>(Arrays.asList(new LocalizedValue("a_en", Locale.ENGLISH), new LocalizedValue("a_fr", Locale.FRENCH))));
+      src.getNode("b").setLabels(new ArrayList<LocalizedValue>(Arrays.asList(new LocalizedValue("b_en"), new LocalizedValue("b_fr", Locale.FRENCH))));
+      src.getNode("c").setLabels(new ArrayList<LocalizedValue>(Arrays.asList(new LocalizedValue("c_en"))));
+      src.setOwnerId("importer_extended_label");
+      NavigationImporter importer = new NavigationImporter(Locale.ENGLISH, ImportMode.REIMPORT, true, src, service, descriptionService);
+      importer.perform();
+
+      //
+      NavigationContext ctx = service.loadNavigation(SiteKey.portal("importer_extended_label"));
+      NodeContext<?> node = service.loadNode(NodeModel.SELF_MODEL, ctx, Scope.ALL, null).getNode();
+
+      // The fully explicit case
+      NodeContext<?> a = (NodeContext<?>)node.getNode("a");
+      Map<Locale, Described.State> aDesc = descriptionService.getDescriptions(a.getId());
+      assertNotNull(aDesc);
+      assertEquals(Tools.toSet(Locale.ENGLISH, Locale.FRENCH), aDesc.keySet());
+      assertEquals(new Described.State("a_en", null), aDesc.get(Locale.ENGLISH));
+      assertEquals(new Described.State("a_fr", null), aDesc.get(Locale.FRENCH));
+      assertNull(a.getState().getLabel());
+
+      // No explicit language means to use the portal locale
+      NodeContext<?> b = (NodeContext<?>)node.getNode("b");
+      Map<Locale, Described.State> bDesc = descriptionService.getDescriptions(b.getId());
+      assertNotNull(bDesc);
+      assertEquals(Tools.toSet(Locale.ENGLISH, Locale.FRENCH), bDesc.keySet());
+      assertEquals(new Described.State("b_en", null), bDesc.get(Locale.ENGLISH));
+      assertEquals(new Described.State("b_fr", null), bDesc.get(Locale.FRENCH));
+      assertNull(b.getState().getLabel());
+
+      // The simple use case : one single label without the xml:lang attribute
+      NodeContext<?> c = (NodeContext<?>)node.getNode("c");
+      Map<Locale, Described.State> cDesc = descriptionService.getDescriptions(c.getId());
+      assertNotNull(cDesc);
+      assertEquals(Tools.toSet(Locale.ENGLISH), cDesc.keySet());
+      assertEquals(new Described.State("c_en", null), cDesc.get(Locale.ENGLISH));
+      assertEquals(null, c.getState().getLabel());
+   }
+
+   public void testSimpleLabel()
+   {
+      MOPService mop = mgr.getPOMService();
+      mop.getModel().getWorkspace().addSite(ObjectType.PORTAL_SITE, "importer_simple_label");
+      sync(true);
+
+      //
+      assertNull(service.loadNavigation(SiteKey.portal("importer_simple_label")));
+
+      //
+      PageNavigation src = navigation("importer_simple_label").add(node("a"), node("b"), node("c")).build();
+      src.getNode("a").setLabels(new ArrayList<LocalizedValue>(Arrays.asList(new LocalizedValue("a_en", Locale.ENGLISH), new LocalizedValue("a_fr", Locale.FRENCH))));
+      src.getNode("b").setLabels(new ArrayList<LocalizedValue>(Arrays.asList(new LocalizedValue("b_en"), new LocalizedValue("b_fr", Locale.FRENCH))));
+      src.getNode("c").setLabels(new ArrayList<LocalizedValue>(Arrays.asList(new LocalizedValue("c_en"))));
+      src.setOwnerId("importer_simple_label");
+      NavigationImporter importer = new NavigationImporter(Locale.ENGLISH, ImportMode.REIMPORT, false, src, service, descriptionService);
+      importer.perform();
+
+      //
+      NavigationContext ctx = service.loadNavigation(SiteKey.portal("importer_simple_label"));
+      NodeContext<?> node = service.loadNode(NodeModel.SELF_MODEL, ctx, Scope.ALL, null).getNode();
+
+      // The fully explicit case
+      NodeContext<?> a = (NodeContext<?>)node.getNode("a");
+      Map<Locale, Described.State> aDesc = descriptionService.getDescriptions(a.getId());
+      assertNull(aDesc);
+      assertEquals("a_en", a.getState().getLabel());
+
+      // No explicit language means to use the portal locale
+      NodeContext<?> b = (NodeContext<?>)node.getNode("b");
+      Map<Locale, Described.State> bDesc = descriptionService.getDescriptions(b.getId());
+      assertNull(bDesc);
+      assertEquals("b_en", b.getState().getLabel());
+
+      // The simple use case : one single label without the xml:lang attribute
+      NodeContext<?> c = (NodeContext<?>)node.getNode("c");
+      Map<Locale, Described.State> cDesc = descriptionService.getDescriptions(c.getId());
+      assertNull(cDesc);
+      assertEquals("c_en", c.getState().getLabel());
+   }
 }

Added: portal/trunk/component/portal/src/test/java/org/exoplatform/portal/i18n/A.java
===================================================================
--- portal/trunk/component/portal/src/test/java/org/exoplatform/portal/i18n/A.java	                        (rev 0)
+++ portal/trunk/component/portal/src/test/java/org/exoplatform/portal/i18n/A.java	2011-07-01 07:05:25 UTC (rev 6784)
@@ -0,0 +1,36 @@
+/**
+ * Copyright (C) 2009 eXo Platform SAS.
+ * 
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ * 
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.portal.i18n;
+
+import org.chromattic.api.annotations.MixinType;
+import org.chromattic.api.annotations.Property;
+
+/**
+ * @author <a href="mailto:khoi.nguyen at exoplatform.com">Nguyen Duc Khoi</a>
+ * Apr 22, 2011
+ */
+
+ at MixinType(name = "gtn:a")
+public abstract class A
+{
+   @Property(name = "description")
+   public abstract void setDescription(String description);
+   
+   public abstract String getDescription();
+}

Added: portal/trunk/component/portal/src/test/java/org/exoplatform/portal/i18n/B.java
===================================================================
--- portal/trunk/component/portal/src/test/java/org/exoplatform/portal/i18n/B.java	                        (rev 0)
+++ portal/trunk/component/portal/src/test/java/org/exoplatform/portal/i18n/B.java	2011-07-01 07:05:25 UTC (rev 6784)
@@ -0,0 +1,32 @@
+/**
+ * Copyright (C) 2011 eXo Platform SAS.
+ * 
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ * 
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.portal.i18n;
+
+import org.chromattic.api.annotations.MixinType;
+
+/**
+ * @author <a href="mailto:khoi.nguyen at exoplatform.com">Nguyen Duc Khoi</a>
+ * Apr 26, 2011
+ */
+
+ at MixinType(name = "gtn:b")
+public class B
+{
+
+}

Added: portal/trunk/component/portal/src/test/java/org/exoplatform/portal/i18n/Described.java
===================================================================
--- portal/trunk/component/portal/src/test/java/org/exoplatform/portal/i18n/Described.java	                        (rev 0)
+++ portal/trunk/component/portal/src/test/java/org/exoplatform/portal/i18n/Described.java	2011-07-01 07:05:25 UTC (rev 6784)
@@ -0,0 +1,41 @@
+/**
+ * Copyright (C) 2009 eXo Platform SAS.
+ * 
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ * 
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.portal.i18n;
+
+import org.chromattic.api.annotations.MixinType;
+import org.chromattic.api.annotations.Property;
+
+/**
+ * @author <a href="mailto:khoi.nguyen at exoplatform.com">Nguyen Duc Khoi</a>
+ * Apr 21, 2011
+ */
+
+ at MixinType(name = "gtn:described")
+public abstract class Described
+{
+   @Property(name = "gtn:name")
+   public abstract String getName();
+
+   public abstract void setName(String name);
+
+   @Property(name = "gtn:description")
+   public abstract String getDescription();
+
+   public abstract void setDescription(String description);
+}

Added: portal/trunk/component/portal/src/test/java/org/exoplatform/portal/i18n/NavigationNode.java
===================================================================
--- portal/trunk/component/portal/src/test/java/org/exoplatform/portal/i18n/NavigationNode.java	                        (rev 0)
+++ portal/trunk/component/portal/src/test/java/org/exoplatform/portal/i18n/NavigationNode.java	2011-07-01 07:05:25 UTC (rev 6784)
@@ -0,0 +1,31 @@
+/**
+ * Copyright (C) 2009 eXo Platform SAS.
+ * 
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ * 
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.portal.i18n;
+
+import org.chromattic.api.annotations.PrimaryType;
+
+/**
+ * @author <a href="mailto:khoi.nguyen at exoplatform.com">Nguyen Duc Khoi</a>
+ * Apr 21, 2011
+ */
+ at PrimaryType(name = "gtn:node")
+public abstract class NavigationNode
+{
+   
+}

Added: portal/trunk/component/portal/src/test/java/org/exoplatform/portal/i18n/TestI18NFramework.java
===================================================================
--- portal/trunk/component/portal/src/test/java/org/exoplatform/portal/i18n/TestI18NFramework.java	                        (rev 0)
+++ portal/trunk/component/portal/src/test/java/org/exoplatform/portal/i18n/TestI18NFramework.java	2011-07-01 07:05:25 UTC (rev 6784)
@@ -0,0 +1,179 @@
+/**
+ * Copyright (C) 2009 eXo Platform SAS.
+ * 
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ * 
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.portal.i18n;
+
+import org.exoplatform.commons.chromattic.ChromatticLifeCycle;
+import org.exoplatform.commons.chromattic.ChromatticManager;
+import org.exoplatform.component.test.AbstractKernelTest;
+import org.exoplatform.component.test.ConfigurationUnit;
+import org.exoplatform.component.test.ConfiguredBy;
+import org.exoplatform.component.test.ContainerScope;
+import org.exoplatform.container.PortalContainer;
+import org.exoplatform.portal.mop.i18n.Injector;
+
+import org.chromattic.api.ChromatticSession;
+
+/**
+ * @author <a href="mailto:khoi.nguyen at exoplatform.com">Nguyen Duc Khoi</a>
+ * Apr 21, 2011
+ */
+
+ at ConfiguredBy(
+{@ConfigurationUnit(scope = ContainerScope.PORTAL, path = "conf/exo.portal.component.test.jcr-configuration.xml"),
+      @ConfigurationUnit(scope = ContainerScope.PORTAL, path = "conf/test-i18nframework-configuration.xml")})
+public class TestI18NFramework extends AbstractKernelTest
+{
+   private ChromatticLifeCycle lifeCycle;
+
+   private ChromatticManager chromatticManager;
+
+   @Override
+   protected void setUp() throws Exception
+   {
+/*
+      PortalContainer container = PortalContainer.getInstance();
+      chromatticManager = (ChromatticManager) container.getComponentInstanceOfType(ChromatticManager.class);
+      lifeCycle = chromatticManager.getLifeCycle("i18n");
+      lifeCycle.openContext();
+*/
+   }
+
+   private <E> ChromatticSession createSampleData(String nodeName)
+   {
+      ChromatticSession session = lifeCycle.getChromattic().openSession();
+      session.addEventListener(new Injector(session));
+      NavigationNode node = session.insert(NavigationNode.class, nodeName);
+      Described described = session.getEmbedded(node, Described.class);
+      if (described == null)
+      {
+         described = session.create(Described.class);
+      }
+
+      A a = session.getEmbedded(node, A.class);
+      if (a == null)
+      {
+         a = session.create(A.class);
+      }
+
+      session.setEmbedded(node, Described.class, described);
+      session.setEmbedded(node, A.class, a);
+
+      return session;
+   }
+
+   public void testFoo()
+   {
+
+   }
+
+/*
+   public void testI18N()
+   {
+      String homepage_en = "Homepage";
+      String homepage_vi = "Trangchu";
+      String description_en = "This is the homepage";
+
+      ChromatticSession session = createSampleData("node1");
+      NavigationNode node = session.findByPath(NavigationNode.class, "node1");
+
+      I18NFramework framework = new I18NFramework(session);
+      Described describe_en = framework.putMixin(node, Described.class, "en");
+      describe_en.setName(homepage_en);
+
+      Described describe_vi = framework.putMixin(node, Described.class, "vi");
+      describe_vi.setName(homepage_vi);
+
+      Language language = session.findByPath(Language.class, "node1/gtn:languages/en");
+      assertNotNull(language);
+      Described describe_en_new = session.getEmbedded(language, Described.class);
+      assertEquals(describe_en_new.getName(), homepage_en);
+
+      language = session.findByPath(Language.class, "node1/gtn:languages/vi");
+      assertNotNull(language);
+      Described describe_vi_new = session.getEmbedded(language, Described.class);
+      assertEquals(describe_vi_new.getName(), homepage_vi);
+
+      A a_en = framework.putMixin(node, A.class, "en");
+      a_en.setDescription(description_en);
+
+      a_en = framework.getMixin(node, A.class, "en");
+      assertEquals(description_en, a_en.getDescription());
+      session.save();
+      session.close();
+   }
+
+   public void testNotEmbedded()
+   {
+      String nodeTest = "testNotEmbedded";
+      ChromatticSession session = this.createSampleData(nodeTest);
+      NavigationNode node = session.findByPath(NavigationNode.class, nodeTest);
+      I18NFramework framework = new I18NFramework(session);
+      try
+      {
+         framework.putMixin(node, B.class, "en");
+         fail();
+      }
+      catch (IllegalStateException e)
+      {
+         e.printStackTrace();
+      }
+      
+      try
+      {
+         framework.getMixin(node, B.class, "en");
+         fail();
+      }
+      catch(IllegalStateException e)
+      {
+         e.printStackTrace();
+      }
+   }
+   
+   public void testGetDefaultLanguage()
+   {
+      String nodeTest = "testGetDefaultLanguage";
+      String name_en = "homepage";
+      String name_vi = "trangchu";
+      ChromatticSession session = this.createSampleData(nodeTest);
+      NavigationNode node = session.findByPath(NavigationNode.class, nodeTest);
+      Described described = session.getEmbedded(node, Described.class);
+      described.setName(name_en);
+      
+      I18NFramework framework = new I18NFramework(session);
+      described = framework.putMixin(node, Described.class, "vi");
+      described.setName(name_vi);
+      
+      described = framework.getMixin(node, Described.class, "en");
+      assertNotNull(described);
+      assertEquals(described.getName(), name_en);
+      
+      described = framework.getMixin(node, Described.class, "vi");
+      assertNotNull(described);
+      assertEquals(described.getName(), name_vi);
+   }
+*/
+
+   @Override
+   protected void tearDown() throws Exception
+   {
+/*
+      lifeCycle.closeContext(false);
+*/
+   }
+}

Added: portal/trunk/component/portal/src/test/java/org/exoplatform/portal/i18n/package-info.java
===================================================================
--- portal/trunk/component/portal/src/test/java/org/exoplatform/portal/i18n/package-info.java	                        (rev 0)
+++ portal/trunk/component/portal/src/test/java/org/exoplatform/portal/i18n/package-info.java	2011-07-01 07:05:25 UTC (rev 6784)
@@ -0,0 +1,22 @@
+/**
+ * Copyright (C) 2009 eXo Platform SAS.
+ * 
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ * 
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+
+ at NodeTypeDefs package org.exoplatform.portal.i18n;
+
+import org.chromattic.api.annotations.NodeTypeDefs;

Added: portal/trunk/component/portal/src/test/java/org/exoplatform/portal/mop/description/TestDescriptionService.java
===================================================================
--- portal/trunk/component/portal/src/test/java/org/exoplatform/portal/mop/description/TestDescriptionService.java	                        (rev 0)
+++ portal/trunk/component/portal/src/test/java/org/exoplatform/portal/mop/description/TestDescriptionService.java	2011-07-01 07:05:25 UTC (rev 6784)
@@ -0,0 +1,295 @@
+/*
+ * Copyright (C) 2011 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+
+package org.exoplatform.portal.mop.description;
+
+import org.exoplatform.container.PortalContainer;
+import org.exoplatform.portal.config.AbstractPortalTest;
+import org.exoplatform.portal.mop.Described;
+import org.exoplatform.portal.mop.i18n.I18Nized;
+import org.exoplatform.portal.mop.navigation.NavigationServiceImpl;
+import org.exoplatform.portal.pom.config.POMSessionManager;
+import org.gatein.common.util.Tools;
+import org.gatein.mop.api.workspace.Navigation;
+import org.gatein.mop.api.workspace.ObjectType;
+import org.gatein.mop.api.workspace.Site;
+import org.gatein.mop.core.api.MOPService;
+
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+/**
+ * @author <a href="mailto:julien.viet at exoplatform.com">Julien Viet</a>
+ */
+public class TestDescriptionService extends AbstractPortalTest
+{
+
+   /** . */
+   protected POMSessionManager mgr;
+
+   /** . */
+   protected NavigationServiceImpl service;
+
+   @Override
+   protected void setUp() throws Exception
+   {
+      super.setUp();
+
+      //
+      PortalContainer container = PortalContainer.getInstance();
+      mgr = (POMSessionManager)container.getComponentInstanceOfType(POMSessionManager.class);
+      service = new NavigationServiceImpl(mgr);
+//      dataStorage = (DataStorage)container.getComponentInstanceOfType(DataStorage.class);
+
+      // Clear the cache for each test
+      service.clearCache();
+
+      //
+      begin();
+   }
+
+   @Override
+   protected void tearDown() throws Exception
+   {
+      end();
+      super.tearDown();
+   }
+
+   public void testResolveNoDescription() throws Exception
+   {
+      DescriptionService svc = new DescriptionServiceImpl(mgr);
+      MOPService mop = mgr.getPOMService();
+      Site portal = mop.getModel().getWorkspace().addSite(ObjectType.PORTAL_SITE, "foo");
+      Navigation nav = portal.getRootNavigation().addChild("default");
+      String id = nav.getObjectId();
+
+      //
+      assertEquals(null, svc.resolveDescription(id, null, Locale.ENGLISH));
+   }
+
+   public void testResolveDefaultDescription() throws Exception
+   {
+      DescriptionService svc = new DescriptionServiceImpl(mgr);
+      MOPService mop = mgr.getPOMService();
+      Site portal = mop.getModel().getWorkspace().addSite(ObjectType.PORTAL_SITE, "foo");
+      Navigation nav = portal.getRootNavigation().addChild("default");
+      Described described = nav.adapt(Described.class);
+      described.setName("foo_name");
+      String id = nav.getObjectId();
+
+      //
+      assertEquals(null, svc.resolveDescription(id, null, Locale.ENGLISH));
+   }
+
+   public void testResolveLocalizedDescription() throws Exception
+   {
+      DescriptionService svc = new DescriptionServiceImpl(mgr);
+      MOPService mop = mgr.getPOMService();
+      Site portal = mop.getModel().getWorkspace().addSite(ObjectType.PORTAL_SITE, "foo");
+      Navigation nav = portal.getRootNavigation().addChild("default");
+      I18Nized i18nized = nav.adapt(I18Nized.class);
+      Described described = i18nized.getMixin(Described.class, Locale.ENGLISH, true);
+      described.setName("name_en");
+      described = i18nized.getMixin(Described.class, Locale.UK, true);
+      described.setName("name_en_GB");
+      String id = nav.getObjectId();
+
+      //
+      assertEquals(null, svc.resolveDescription(id, null, Locale.GERMAN));
+      assertEquals(new Described.State("name_en", null), svc.resolveDescription(id, Locale.ENGLISH, Locale.GERMAN));
+      assertEquals(new Described.State("name_en_GB", null), svc.resolveDescription(id, Locale.UK, Locale.GERMAN));
+      assertEquals(new Described.State("name_en", null), svc.resolveDescription(id, Locale.US, Locale.GERMAN));
+      assertEquals(new Described.State("name_en", null), svc.resolveDescription(id, null, Locale.ENGLISH));
+      assertEquals(new Described.State("name_en", null), svc.resolveDescription(id, null, Locale.US));
+      assertEquals(new Described.State("name_en_GB", null), svc.resolveDescription(id, null, Locale.UK));
+   }
+
+   public void testResolveDescription() throws Exception
+   {
+      DescriptionService svc = new DescriptionServiceImpl(mgr);
+      MOPService mop = mgr.getPOMService();
+      Site portal = mop.getModel().getWorkspace().addSite(ObjectType.PORTAL_SITE, "foo");
+      Navigation nav = portal.getRootNavigation().addChild("default");
+      Described described = nav.adapt(Described.class);
+      described.setName("name");
+      I18Nized i18nized = nav.adapt(I18Nized.class);
+      described = i18nized.getMixin(Described.class, Locale.ENGLISH, true);
+      described.setName("name_en");
+      described = i18nized.getMixin(Described.class, Locale.UK, true);
+      described.setName("name_en_GB");
+      String id = nav.getObjectId();
+
+      //
+      assertEquals(null, svc.resolveDescription(id, null, Locale.GERMAN));
+      assertEquals(new Described.State("name_en", null), svc.resolveDescription(id, Locale.ENGLISH, Locale.GERMAN));
+      assertEquals(new Described.State("name_en_GB", null), svc.resolveDescription(id, Locale.UK, Locale.GERMAN));
+      assertEquals(new Described.State("name_en", null), svc.resolveDescription(id, Locale.US, Locale.GERMAN));
+      assertEquals(new Described.State("name_en", null), svc.resolveDescription(id, null, Locale.ENGLISH));
+      assertEquals(new Described.State("name_en", null), svc.resolveDescription(id, null, Locale.US));
+      assertEquals(new Described.State("name_en_GB", null), svc.resolveDescription(id, null, Locale.UK));
+   }
+
+   public void testGetDefaultDescription() throws Exception
+   {
+      DescriptionService svc = new DescriptionServiceImpl(mgr);
+      MOPService mop = mgr.getPOMService();
+      Site portal = mop.getModel().getWorkspace().addSite(ObjectType.PORTAL_SITE, "foo");
+      Navigation nav = portal.getRootNavigation().addChild("default");
+      String id = nav.getObjectId();
+      Described described = nav.adapt(Described.class);
+      described.setName("foo_name");
+
+      //
+      assertEquals(new Described.State("foo_name", null), svc.getDescription(id));
+   }
+
+   public void testSetDefaultDescription() throws Exception
+   {
+      DescriptionService svc = new DescriptionServiceImpl(mgr);
+      MOPService mop = mgr.getPOMService();
+      Site portal = mop.getModel().getWorkspace().addSite(ObjectType.PORTAL_SITE, "foo");
+      Navigation nav = portal.getRootNavigation().addChild("default");
+      String id = nav.getObjectId();
+
+      //
+      assertNull(svc.getDescription(id));
+
+      //
+      svc.setDescription(id, new Described.State("foo_name", null));
+
+      //
+      assertTrue(nav.isAdapted(Described.class));
+      Described described = nav.adapt(Described.class);
+      assertEquals("foo_name", described.getName());
+   }
+
+   public void testRemoveDefaultDescription() throws Exception
+   {
+      DescriptionService svc = new DescriptionServiceImpl(mgr);
+      MOPService mop = mgr.getPOMService();
+      Site portal = mop.getModel().getWorkspace().addSite(ObjectType.PORTAL_SITE, "foo");
+      Navigation nav = portal.getRootNavigation().addChild("default");
+      String id = nav.getObjectId();
+      Described described = nav.adapt(Described.class);
+      described.setName("foo_name");
+
+      //
+      svc.setDescription(id, null);
+   }
+
+   public void testSetLocalizedDescription() throws Exception
+   {
+      DescriptionService svc = new DescriptionServiceImpl(mgr);
+      MOPService mop = mgr.getPOMService();
+      Site portal = mop.getModel().getWorkspace().addSite(ObjectType.PORTAL_SITE, "foo");
+      Navigation nav = portal.getRootNavigation().addChild("default");
+
+      //
+      svc.setDescription(nav.getObjectId(), Locale.ENGLISH, new Described.State("foo_english", null));
+
+      //
+      assertTrue(nav.isAdapted(I18Nized.class));
+      I18Nized ized = nav.adapt(I18Nized.class);
+      Described desc = ized.getMixin(Described.class, Locale.ENGLISH, false);
+      assertNotNull(desc);
+      assertEquals("foo_english", desc.getName());
+   }
+
+   public void testAddLocalizedDescription() throws Exception
+   {
+      DescriptionService svc = new DescriptionServiceImpl(mgr);
+      MOPService mop = mgr.getPOMService();
+      Site portal = mop.getModel().getWorkspace().addSite(ObjectType.PORTAL_SITE, "foo");
+      Navigation nav = portal.getRootNavigation().addChild("default");
+      I18Nized i18nized = nav.adapt(I18Nized.class);
+      Described desc = i18nized.getMixin(Described.class, Locale.ENGLISH, true);
+      desc.setName("add_english");
+
+      //
+      svc.setDescription(nav.getObjectId(), Locale.FRENCH, new Described.State("add_french", null));
+
+      //
+      assertTrue(nav.isAdapted(I18Nized.class));
+      I18Nized ized = nav.adapt(I18Nized.class);
+      desc = ized.getMixin(Described.class, Locale.ENGLISH, false);
+      assertNotNull(desc);
+      assertEquals("add_english", desc.getName());
+      desc = ized.getMixin(Described.class, Locale.FRENCH, false);
+      assertNotNull(desc);
+      assertEquals("add_french", desc.getName());
+   }
+
+   public void testGetDescriptions() throws Exception
+   {
+      DescriptionService svc = new DescriptionServiceImpl(mgr);
+      MOPService mop = mgr.getPOMService();
+      Site portal = mop.getModel().getWorkspace().addSite(ObjectType.PORTAL_SITE, "foo");
+      Navigation nav = portal.getRootNavigation().addChild("default");
+
+      //
+      assertNull(svc.getDescriptions(nav.getObjectId()));
+
+      //
+      I18Nized i18nized = nav.adapt(I18Nized.class);
+      Described described = i18nized.getMixin(Described.class, Locale.ENGLISH, true);
+      described.setName("foo_english");
+      described = i18nized.getMixin(Described.class, Locale.FRENCH, true);
+      described.setName("foo_french");
+
+      //
+      Map<Locale, Described.State> description = svc.getDescriptions(nav.getObjectId());
+      assertEquals(Tools.toSet(Locale.ENGLISH, Locale.FRENCH), description.keySet());
+      assertEquals(new Described.State("foo_english", null), description.get(Locale.ENGLISH));
+      assertEquals(new Described.State("foo_french", null), description.get(Locale.FRENCH));
+   }
+
+   public void testSetDescriptions() throws Exception
+   {
+      DescriptionService svc = new DescriptionServiceImpl(mgr);
+      MOPService mop = mgr.getPOMService();
+      Site portal = mop.getModel().getWorkspace().addSite(ObjectType.PORTAL_SITE, "foo");
+      Navigation nav = portal.getRootNavigation().addChild("default");
+
+      //
+      assertNull(svc.getDescriptions(nav.getObjectId()));
+
+      //
+      Map<Locale, Described.State> description = new HashMap<Locale, Described.State>();
+      description.put(Locale.ENGLISH, new Described.State("bar_english", null));
+      description.put(Locale.FRENCH, new Described.State("bar_french", null));
+      svc.setDescriptions(nav.getObjectId(), description);
+
+      //
+      description = svc.getDescriptions(nav.getObjectId());
+      assertEquals(Tools.toSet(Locale.ENGLISH, Locale.FRENCH), description.keySet());
+      assertEquals(new Described.State("bar_english", null), description.get(Locale.ENGLISH));
+      assertEquals(new Described.State("bar_french", null), description.get(Locale.FRENCH));
+
+      //
+      description = new HashMap<Locale, Described.State>();
+      description.put(Locale.ENGLISH, new Described.State("bar_english_2", null));
+      svc.setDescriptions(nav.getObjectId(), description);
+
+      //
+      description = svc.getDescriptions(nav.getObjectId());
+      assertEquals(Tools.toSet(Locale.ENGLISH), description.keySet());
+      assertEquals(new Described.State("bar_english_2", null), description.get(Locale.ENGLISH));
+   }
+}

Modified: portal/trunk/component/portal/src/test/java/org/exoplatform/portal/mop/navigation/AbstractTestNavigationService.java
===================================================================
--- portal/trunk/component/portal/src/test/java/org/exoplatform/portal/mop/navigation/AbstractTestNavigationService.java	2011-07-01 06:44:15 UTC (rev 6783)
+++ portal/trunk/component/portal/src/test/java/org/exoplatform/portal/mop/navigation/AbstractTestNavigationService.java	2011-07-01 07:05:25 UTC (rev 6784)
@@ -23,6 +23,8 @@
 import org.exoplatform.container.PortalContainer;
 import org.exoplatform.portal.config.AbstractPortalTest;
 import org.exoplatform.portal.config.DataStorage;
+import org.exoplatform.portal.mop.description.DescriptionService;
+import org.exoplatform.portal.mop.description.DescriptionServiceImpl;
 import org.exoplatform.portal.pom.config.POMSessionManager;
 
 /**
@@ -40,6 +42,9 @@
    /** . */
    protected DataStorage dataStorage;
 
+   /** . */
+   protected DescriptionService descriptionService;
+
    @Override
    protected void setUp() throws Exception
    {
@@ -49,6 +54,7 @@
       PortalContainer container = PortalContainer.getInstance();
       mgr = (POMSessionManager)container.getComponentInstanceOfType(POMSessionManager.class);
       service = new NavigationServiceImpl(mgr);
+      descriptionService = new DescriptionServiceImpl(mgr);
       dataStorage = (DataStorage)container.getComponentInstanceOfType(DataStorage.class);
 
       // Clear the cache for each test
@@ -58,18 +64,6 @@
       begin();
    }
 
-   protected void sync()
-   {
-      end();
-      begin();
-   }
-
-   protected void sync(boolean save)
-   {
-      end(save);
-      begin();
-   }
-
    @Override
    protected void end(boolean save)
    {

Added: portal/trunk/component/portal/src/test/java/org/exoplatform/portal/mop/user/SimpleUserPortalContext.java
===================================================================
--- portal/trunk/component/portal/src/test/java/org/exoplatform/portal/mop/user/SimpleUserPortalContext.java	                        (rev 0)
+++ portal/trunk/component/portal/src/test/java/org/exoplatform/portal/mop/user/SimpleUserPortalContext.java	2011-07-01 07:05:25 UTC (rev 6784)
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2011 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+
+package org.exoplatform.portal.mop.user;
+
+import org.exoplatform.portal.mop.SiteKey;
+
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+import java.util.ResourceBundle;
+
+/**
+ * A simple implementation for unit tests.
+ *
+ * @author <a href="mailto:julien.viet at exoplatform.com">Julien Viet</a>
+ */
+class SimpleUserPortalContext implements UserPortalContext
+{
+
+   /** . */
+   private final Map<SiteKey, ResourceBundle> bundles;
+
+   /** . */
+   private final Locale locale;
+
+   public SimpleUserPortalContext(Locale locale)
+   {
+      this.locale = locale;
+      this.bundles = new HashMap<SiteKey, ResourceBundle>();
+   }
+
+   void add(SiteKey key, ResourceBundle bundle)
+   {
+      bundles.put(key, bundle);
+   }
+
+   public ResourceBundle getBundle(UserNavigation navigation)
+   {
+      return bundles.get(navigation.getKey());
+   }
+
+   public Locale getUserLocale()
+   {
+      return locale;
+   }
+}

Modified: portal/trunk/component/portal/src/test/java/org/exoplatform/portal/mop/user/TestUserPortal.java
===================================================================
--- portal/trunk/component/portal/src/test/java/org/exoplatform/portal/mop/user/TestUserPortal.java	2011-07-01 06:44:15 UTC (rev 6783)
+++ portal/trunk/component/portal/src/test/java/org/exoplatform/portal/mop/user/TestUserPortal.java	2011-07-01 07:05:25 UTC (rev 6784)
@@ -48,6 +48,7 @@
 import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.ResourceBundle;
 import java.util.TimeZone;
@@ -469,23 +470,12 @@
       {
          public void execute() throws Exception
          {
-            UserPortalContext userPortalContext = new UserPortalContext()
-            {
-               final MapResourceBundle bundle;
-
-               {
-                  Map<String, Object> map = new HashMap<String, Object>();
-                  map.put("portal.classic.home", "foo");
-                  map.put("portal.classic.emoh", "bar");
-                  bundle = new MapResourceBundle(map);
-               }
-
-               public ResourceBundle getBundle(UserNavigation navigation)
-               {
-                  return bundle;
-               }
-            };
-            UserPortalConfig userPortalCfg = userPortalConfigSer_.getUserPortalConfig("classic", getUserId(), userPortalContext);
+            SimpleUserPortalContext ctx = new SimpleUserPortalContext(Locale.ENGLISH);
+            Map<String, Object> map = new HashMap<String, Object>();
+            map.put("portal.classic.home", "foo");
+            map.put("portal.classic.emoh", "bar");
+            ctx.add(SiteKey.portal("classic"), new MapResourceBundle(map));
+            UserPortalConfig userPortalCfg = userPortalConfigSer_.getUserPortalConfig("classic", getUserId(), ctx);
             UserPortal userPortal = userPortalCfg.getUserPortal();
 
             //
@@ -501,6 +491,33 @@
       }.execute("root");
    }
 
+   public void testExtendedLabel()
+   {
+      new UnitTest()
+      {
+         public void execute() throws Exception
+         {
+            UserPortalContext ctx = new SimpleUserPortalContext(Locale.ENGLISH);
+            UserPortal portal = userPortalConfigSer_.getUserPortalConfig("extended", getUserId(), ctx).getUserPortal();
+            UserNode path = portal.resolvePath(null, "/bar");
+            assertEquals(null, path.getLabel());
+            assertEquals("bar_label_en", path.getResolvedLabel());
+
+            // Now test transient node
+            UserNode juu = path.addChild("juu");
+            assertEquals(null, juu.getLabel());
+            assertEquals("juu", juu.getResolvedLabel());
+
+            //
+            ctx = new SimpleUserPortalContext(Locale.FRENCH);
+            portal = userPortalConfigSer_.getUserPortalConfig("extended", getUserId(), ctx).getUserPortal();
+            path = portal.resolvePath(null, "/bar");
+            assertEquals(null, path.getLabel());
+            assertEquals("bar_label_fr", path.getResolvedLabel());
+         }
+      }.execute("root");
+   }
+
    public void testLoadNode()
    {
       new UnitTest()

Modified: portal/trunk/component/portal/src/test/resources/conf/exo.portal.component.portal-configuration1.xml
===================================================================
--- portal/trunk/component/portal/src/test/resources/conf/exo.portal.component.portal-configuration1.xml	2011-07-01 06:44:15 UTC (rev 6783)
+++ portal/trunk/component/portal/src/test/resources/conf/exo.portal.component.portal-configuration1.xml	2011-07-01 07:05:25 UTC (rev 6784)
@@ -111,6 +111,11 @@
   </component>
 
   <component>
+    <key>org.exoplatform.portal.mop.description.DescriptionService</key>
+    <type>org.exoplatform.portal.mop.description.DescriptionServiceImpl</type>
+  </component>
+
+  <component>
     <key>org.exoplatform.portal.config.UserPortalConfigService</key>
     <type>org.exoplatform.portal.config.UserPortalConfigService</type>
   </component>
@@ -201,6 +206,9 @@
           <value>org.exoplatform.portal.mop.Described</value>
           <value>org.exoplatform.portal.mop.Visible</value>
           <value>org.exoplatform.portal.config.SampleMixin</value>
+          <value>org.exoplatform.portal.mop.i18n.I18Nized</value>
+          <value>org.exoplatform.portal.mop.i18n.LanguageSpace</value>
+          <value>org.exoplatform.portal.mop.i18n.Language</value>
         </values-param>
       </init-params>
     </component-plugin>

Modified: portal/trunk/component/portal/src/test/resources/conf/exo.portal.component.portal-configuration2.xml
===================================================================
--- portal/trunk/component/portal/src/test/resources/conf/exo.portal.component.portal-configuration2.xml	2011-07-01 06:44:15 UTC (rev 6783)
+++ portal/trunk/component/portal/src/test/resources/conf/exo.portal.component.portal-configuration2.xml	2011-07-01 07:05:25 UTC (rev 6784)
@@ -98,6 +98,9 @@
                 <value>
                   <string>large</string>
                 </value>
+                <value>
+                  <string>extended</string>
+                </value>
               </collection>
             </field>
             <field name="ownerType">

Added: portal/trunk/component/portal/src/test/resources/conf/test-i18nframework-configuration.xml
===================================================================
--- portal/trunk/component/portal/src/test/resources/conf/test-i18nframework-configuration.xml	                        (rev 0)
+++ portal/trunk/component/portal/src/test/resources/conf/test-i18nframework-configuration.xml	2011-07-01 07:05:25 UTC (rev 6784)
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+  ~ Copyright (C) 2011 eXo Platform SAS.
+  ~
+  ~ This is free software; you can redistribute it and/or modify it
+  ~ under the terms of the GNU Lesser General Public License as
+  ~ published by the Free Software Foundation; either version 2.1 of
+  ~ the License, or (at your option) any later version.
+  ~
+  ~ This software is distributed in the hope that it will be useful,
+  ~ but WITHOUT ANY WARRANTY; without even the implied warranty of
+  ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  ~ Lesser General Public License for more details.
+  ~
+  ~ You should have received a copy of the GNU Lesser General Public
+  ~ License along with this software; if not, write to the Free
+  ~ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+  ~ 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+  -->
+<configuration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+   xsi:schemaLocation="http://www.exoplaform.org/xml/ns/kernel_1_0.xsd http://www.exoplaform.org/xml/ns/kernel_1_0.xsd"
+   xmlns="http://www.exoplaform.org/xml/ns/kernel_1_0.xsd">
+
+   <component>
+      <key>org.exoplatform.commons.chromattic.ChromatticManager</key>
+      <type>org.exoplatform.commons.chromattic.ChromatticManager</type>
+   </component>
+   
+   <external-component-plugins>
+      <target-component>org.exoplatform.commons.chromattic.ChromatticManager</target-component>
+      <component-plugin>
+         <name>Chromattic</name>
+         <set-method>addLifeCycle</set-method>
+         <type>org.exoplatform.commons.chromattic.ChromatticLifeCycle</type>
+         <init-params>
+            <value-param>
+               <name>domain-name</name>
+               <value>i18n</value>
+            </value-param>
+            <value-param>
+               <name>workspace-name</name>
+               <value>portal-test</value>
+            </value-param>
+            <values-param>
+               <name>entities</name>
+               <value>org.exoplatform.portal.i18n.A</value>
+               <value>org.exoplatform.portal.i18n.B</value>
+               <value>org.exoplatform.portal.i18n.Described</value>
+               <value>org.exoplatform.portal.i18n.NavigationNode</value>
+               <value>org.exoplatform.portal.mop.i18n.I18Nized</value>
+               <value>org.exoplatform.portal.mop.i18n.LanguageSpace</value>
+               <value>org.exoplatform.portal.mop.i18n.Language</value>
+            </values-param>
+         </init-params>
+      </component-plugin>
+   </external-component-plugins>
+
+   <external-component-plugins>
+      <target-component>org.exoplatform.services.jcr.RepositoryService</target-component>
+      <component-plugin>
+         <name>add.namespaces</name>
+         <set-method>addPlugin</set-method>
+         <type>org.exoplatform.services.jcr.impl.AddNamespacesPlugin</type>
+         <init-params>
+            <properties-param>
+               <name>namespaces</name>
+               <property name="gtn" value="http://www.gatein.org/jcr/gatein/1.0/" />
+            </properties-param>
+         </init-params>
+      </component-plugin>
+      <component-plugin>
+         <name>add.nodeType</name>
+         <set-method>addPlugin</set-method>
+         <type>org.exoplatform.services.jcr.impl.AddNodeTypePlugin
+         </type>
+         <init-params>
+            <values-param>
+               <name>autoCreatedInNewRepository</name>
+               <description>Node types configuration file</description>
+               <value>jar:/org/exoplatform/portal/i18n/nodetypes.xml</value>
+               <value>jar:/org/exoplatform/portal/mop/i18n/nodetypes.xml</value>
+            </values-param>
+         </init-params>
+      </component-plugin>
+   </external-component-plugins>
+</configuration>
\ No newline at end of file

Added: portal/trunk/component/portal/src/test/resources/jibx/extended-navigation.xml
===================================================================
--- portal/trunk/component/portal/src/test/resources/jibx/extended-navigation.xml	                        (rev 0)
+++ portal/trunk/component/portal/src/test/resources/jibx/extended-navigation.xml	2011-07-01 07:05:25 UTC (rev 6784)
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright (C) 2011 eXo Platform SAS.
+  ~
+  ~ This is free software; you can redistribute it and/or modify it
+  ~ under the terms of the GNU Lesser General Public License as
+  ~ published by the Free Software Foundation; either version 2.1 of
+  ~ the License, or (at your option) any later version.
+  ~
+  ~ This software is distributed in the hope that it will be useful,
+  ~ but WITHOUT ANY WARRANTY; without even the implied warranty of
+  ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  ~ Lesser General Public License for more details.
+  ~
+  ~ You should have received a copy of the GNU Lesser General Public
+  ~ License along with this software; if not, write to the Free
+  ~ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+  ~ 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+  -->
+
+<node-navigation
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://www.gatein.org/xml/ns/gatein_objects_1_2 http://www.gatein.org/xml/ns/gatein_objects_1_2"
+    xmlns="http://www.gatein.org/xml/ns/gatein_objects_1_2">
+  <priority>1</priority>
+
+  <page-nodes>
+    <node>
+      <uri>bar</uri>
+      <name>bar</name>
+      <label>bar_label</label>
+    </node>
+	  <node>
+      <uri>foo</uri>
+	    <name>foo</name>
+	    <label xml:lang="en">foo_label_en</label>
+      <label>foo_label</label>
+	    <label xml:lang="fr">foo_label_fr</label>
+	  </node>
+    <node>
+      <uri>juu</uri>
+      <name>juu</name>
+      <label xml:lang="en">juu_label_en</label>
+      <label xml:lang="fr">juu_label_fr</label>
+      <label xml:lang="fr-FR">juu_label_fr_FR</label>
+    </node>
+  </page-nodes>
+</node-navigation>

Added: portal/trunk/component/portal/src/test/resources/jibx/simple-navigation.xml
===================================================================
--- portal/trunk/component/portal/src/test/resources/jibx/simple-navigation.xml	                        (rev 0)
+++ portal/trunk/component/portal/src/test/resources/jibx/simple-navigation.xml	2011-07-01 07:05:25 UTC (rev 6784)
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright (C) 2011 eXo Platform SAS.
+  ~
+  ~ This is free software; you can redistribute it and/or modify it
+  ~ under the terms of the GNU Lesser General Public License as
+  ~ published by the Free Software Foundation; either version 2.1 of
+  ~ the License, or (at your option) any later version.
+  ~
+  ~ This software is distributed in the hope that it will be useful,
+  ~ but WITHOUT ANY WARRANTY; without even the implied warranty of
+  ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  ~ Lesser General Public License for more details.
+  ~
+  ~ You should have received a copy of the GNU Lesser General Public
+  ~ License along with this software; if not, write to the Free
+  ~ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+  ~ 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+  -->
+
+<node-navigation
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://www.gatein.org/xml/ns/gatein_objects_1_1 http://www.gatein.org/xml/ns/gatein_objects_1_1"
+    xmlns="http://www.gatein.org/xml/ns/gatein_objects_1_1">
+  <priority>1</priority>
+
+  <page-nodes>
+    <node>
+      <uri>bar</uri>
+      <name>bar</name>
+      <label>bar_label</label>
+    </node>
+  </page-nodes>
+</node-navigation>

Added: portal/trunk/component/portal/src/test/resources/portal/portal/extended/navigation.xml
===================================================================
--- portal/trunk/component/portal/src/test/resources/portal/portal/extended/navigation.xml	                        (rev 0)
+++ portal/trunk/component/portal/src/test/resources/portal/portal/extended/navigation.xml	2011-07-01 07:05:25 UTC (rev 6784)
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright (C) 2011 eXo Platform SAS.
+  ~
+  ~ This is free software; you can redistribute it and/or modify it
+  ~ under the terms of the GNU Lesser General Public License as
+  ~ published by the Free Software Foundation; either version 2.1 of
+  ~ the License, or (at your option) any later version.
+  ~
+  ~ This software is distributed in the hope that it will be useful,
+  ~ but WITHOUT ANY WARRANTY; without even the implied warranty of
+  ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  ~ Lesser General Public License for more details.
+  ~
+  ~ You should have received a copy of the GNU Lesser General Public
+  ~ License along with this software; if not, write to the Free
+  ~ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+  ~ 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+  -->
+
+<node-navigation
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://www.gatein.org/xml/ns/gatein_objects_1_2 http://www.gatein.org/xml/ns/gatein_objects_1_2"
+    xmlns="http://www.gatein.org/xml/ns/gatein_objects_1_2">
+  <priority>1</priority>
+  <page-nodes>
+	  <node>
+      <uri>foo</uri>
+	    <name>foo</name>
+	    <label>foo_label</label>
+	  </node>
+    <node>
+      <uri>bar</uri>
+      <name>bar</name>
+      <label xml:lang="en">bar_label_en</label>
+      <label xml:lang="fr">bar_label_fr</label>
+    </node>
+  </page-nodes>
+</node-navigation>

Added: portal/trunk/component/portal/src/test/resources/portal/portal/extended/portal.xml
===================================================================
--- portal/trunk/component/portal/src/test/resources/portal/portal/extended/portal.xml	                        (rev 0)
+++ portal/trunk/component/portal/src/test/resources/portal/portal/extended/portal.xml	2011-07-01 07:05:25 UTC (rev 6784)
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+  ~ Copyright (C) 2011 eXo Platform SAS.
+  ~
+  ~ This is free software; you can redistribute it and/or modify it
+  ~ under the terms of the GNU Lesser General Public License as
+  ~ published by the Free Software Foundation; either version 2.1 of
+  ~ the License, or (at your option) any later version.
+  ~
+  ~ This software is distributed in the hope that it will be useful,
+  ~ but WITHOUT ANY WARRANTY; without even the implied warranty of
+  ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  ~ Lesser General Public License for more details.
+  ~
+  ~ You should have received a copy of the GNU Lesser General Public
+  ~ License along with this software; if not, write to the Free
+  ~ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+  ~ 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+  -->
+
+<portal-config>
+  <portal-name>extended</portal-name>
+  <locale>en</locale>
+  <access-permissions>Everyone</access-permissions>
+  <edit-permission>*:/platform/administrators</edit-permission>
+ 	<portal-layout>
+  </portal-layout>
+</portal-config>

Modified: portal/trunk/pom.xml
===================================================================
--- portal/trunk/pom.xml	2011-07-01 06:44:15 UTC (rev 6783)
+++ portal/trunk/pom.xml	2011-07-01 07:05:25 UTC (rev 6784)
@@ -48,13 +48,13 @@
       <org.gatein.pc.version>2.3.0-Beta04</org.gatein.pc.version>
       <org.picketlink.idm>1.3.0.Alpha03</org.picketlink.idm>
       <org.gatein.wsrp.version>2.1.0-Beta04</org.gatein.wsrp.version>
-      <org.gatein.mop.version>1.1.0-Beta03</org.gatein.mop.version>
+      <org.gatein.mop.version>1.1.0-Beta05</org.gatein.mop.version>
       <org.slf4j.version>1.5.8</org.slf4j.version>
       <commons-pool.version>1.5.5</commons-pool.version>
       <rhino.version>1.6R5</rhino.version>
       <org.codehaus.groovy.version>1.7.6</org.codehaus.groovy.version>
       <javax.servlet.version>2.5</javax.servlet.version>
-      <version.chromattic>1.1.0-beta5</version.chromattic>
+      <version.chromattic>1.1.0-beta6</version.chromattic>
       <version.reflext>1.1.0-beta12</version.reflext>
       <jcip.version>1.0</jcip.version>
 

Modified: portal/trunk/portlet/exoadmin/src/main/java/org/exoplatform/navigation/webui/TreeNode.java
===================================================================
--- portal/trunk/portlet/exoadmin/src/main/java/org/exoplatform/navigation/webui/TreeNode.java	2011-07-01 06:44:15 UTC (rev 6783)
+++ portal/trunk/portlet/exoadmin/src/main/java/org/exoplatform/navigation/webui/TreeNode.java	2011-07-01 07:05:25 UTC (rev 6784)
@@ -1,17 +1,19 @@
 package org.exoplatform.navigation.webui;
 
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-
+import org.exoplatform.portal.mop.Described.State;
 import org.exoplatform.portal.mop.Visibility;
-import org.exoplatform.portal.mop.navigation.NavigationServiceException;
 import org.exoplatform.portal.mop.navigation.NodeChangeListener;
 import org.exoplatform.portal.mop.navigation.NodeState;
 import org.exoplatform.portal.mop.user.UserNavigation;
 import org.exoplatform.portal.mop.user.UserNode;
+import org.exoplatform.portal.webui.util.Util;
 
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
 /**
  * A wrapper class of {@link UserNode} for manipulation in WebUI part
  * 
@@ -35,6 +37,8 @@
    private String id;
 
    private List<TreeNode> children;
+   
+   private Map<Locale, State> i18nizedLabels;
 
    public TreeNode(UserNavigation nav, UserNode node)
    {
@@ -50,7 +54,7 @@
       this.nav = nav;
       this.node = node;
    }
-
+   
    public List<TreeNode> getChildren()
    {
       if (children == null)
@@ -205,6 +209,26 @@
 
    public String getEncodedResolvedLabel()
    {
+      if (getLabel() == null)
+      {
+         if (i18nizedLabels != null)
+         {
+            Locale locale = Util.getPortalRequestContext().getLocale();
+            for (Locale key  : i18nizedLabels.keySet())
+            {
+               if (key.equals(locale))
+               {
+                  String label = i18nizedLabels.get(key).getName();
+                  if (label == null || label.trim().length() == 0)
+                  {
+                     return node.getName();
+                  }
+
+                  return label;
+               }
+            }
+         }
+      }
       String encodedLabel = node.getEncodedResolvedLabel();
       return encodedLabel == null ? "" : encodedLabel;
    }
@@ -360,4 +384,14 @@
       fromTreeNode.children = null;
       toTreeNode.children = null;
    }
+
+   public void setI18nizedLabels(Map<Locale, State> labels)
+   {
+      this.i18nizedLabels = labels;
+   }
+
+   public Map<Locale, State> getI18nizedLabels()
+   {
+      return i18nizedLabels;
+   }
 }

Modified: portal/trunk/portlet/exoadmin/src/main/java/org/exoplatform/navigation/webui/component/UIGroupNavigationManagement.java
===================================================================
--- portal/trunk/portlet/exoadmin/src/main/java/org/exoplatform/navigation/webui/component/UIGroupNavigationManagement.java	2011-07-01 06:44:15 UTC (rev 6783)
+++ portal/trunk/portlet/exoadmin/src/main/java/org/exoplatform/navigation/webui/component/UIGroupNavigationManagement.java	2011-07-01 07:05:25 UTC (rev 6784)
@@ -50,6 +50,7 @@
 import org.exoplatform.webui.event.Event;
 import org.exoplatform.webui.event.Event.Phase;
 import org.exoplatform.webui.event.EventListener;
+
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
@@ -71,6 +72,8 @@
    @ComponentConfig(type = UIPageNodeForm.class, lifecycle = UIFormLifecycle.class, template = "system:/groovy/webui/form/UIFormTabPane.gtmpl", events = {
       @EventConfig(listeners = UIPageNodeForm.SaveActionListener.class),
       @EventConfig(listeners = UIGroupNavigationManagement.BackActionListener.class, phase = Phase.DECODE),
+      @EventConfig(listeners = UIPageNodeForm.ChangeLanguageActionListener.class, phase = Phase.DECODE),
+      @EventConfig(listeners = UIPageNodeForm.SwitchLabelModeActionListener.class, phase = Phase.DECODE),
       @EventConfig(listeners = UIPageNodeForm.SwitchPublicationDateActionListener.class, phase = Phase.DECODE),
       @EventConfig(listeners = UIPageNodeForm.SwitchVisibleActionListener.class, phase = Phase.DECODE),
       @EventConfig(listeners = UIPageNodeForm.ClearPageActionListener.class, phase = Phase.DECODE),
@@ -298,6 +301,7 @@
          uiNavigationPopup.setRendered(true);
          event.getRequestContext().addUIComponentToUpdateByAjax(uiNavigationPopup.getParent());
          
+         selector.getUserNodeLabels().put(uiPageNodeForm.getPageNode().getId(), uiPageNodeForm.getPageNode().getI18nizedLabels());
          selector.createEvent("NodeModified", Phase.PROCESS, event.getRequestContext()).broadcast();
       }
 

Modified: portal/trunk/portlet/exoadmin/src/main/java/org/exoplatform/navigation/webui/component/UINavigationNodeSelector.java
===================================================================
--- portal/trunk/portlet/exoadmin/src/main/java/org/exoplatform/navigation/webui/component/UINavigationNodeSelector.java	2011-07-01 06:44:15 UTC (rev 6783)
+++ portal/trunk/portlet/exoadmin/src/main/java/org/exoplatform/navigation/webui/component/UINavigationNodeSelector.java	2011-07-01 07:05:25 UTC (rev 6784)
@@ -19,16 +19,16 @@
 
 package org.exoplatform.navigation.webui.component;
 
-import java.util.Collection;
-
 import org.exoplatform.navigation.webui.TreeNode;
 import org.exoplatform.portal.application.PortalRequestContext;
 import org.exoplatform.portal.config.DataStorage;
 import org.exoplatform.portal.config.UserACL;
 import org.exoplatform.portal.config.UserPortalConfigService;
 import org.exoplatform.portal.config.model.Page;
+import org.exoplatform.portal.mop.Described.State;
 import org.exoplatform.portal.mop.SiteKey;
 import org.exoplatform.portal.mop.Visibility;
+import org.exoplatform.portal.mop.description.DescriptionService;
 import org.exoplatform.portal.mop.navigation.NavigationError;
 import org.exoplatform.portal.mop.navigation.NavigationServiceException;
 import org.exoplatform.portal.mop.navigation.Scope;
@@ -60,6 +60,11 @@
 import org.exoplatform.webui.event.EventListener;
 import org.gatein.common.util.ParameterValidation;
 
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
 /** Copied by The eXo Platform SARL Author May 28, 2009 3:07:15 PM */
 @ComponentConfigs({
    @ComponentConfig(template = "system:/groovy/portal/webui/navigation/UINavigationNodeSelector.gtmpl", events = {
@@ -94,6 +99,8 @@
    private UserPortal userPortal;
 
    private UserNodeFilterConfig filterConfig;
+   
+   private Map<String, Map<Locale, State>> userNodeLabels;
 
    private static final Scope NODE_SCOPE = Scope.GRANDCHILDREN;
 
@@ -116,8 +123,20 @@
       uiPopupMenu.setActions(new String[]{"AddNode", "EditPageNode", "EditSelectedNode", "CopyNode", "CloneNode",
          "CutNode", "DeleteNode", "MoveUp", "MoveDown"});
       uiTree.setUIRightClickPopupMenu(uiPopupMenu);
+      
+      userNodeLabels = new HashMap<String, Map<Locale,State>>();
    }
 
+   public void setUserNodeLabels(Map<String, Map<Locale, State>> labels)
+   {
+      this.userNodeLabels = labels;
+   }
+   
+   public Map<String, Map<Locale, State>> getUserNodeLabels()
+   {
+      return this.userNodeLabels;
+   }
+   
    /**
     * Init the UITree wrapped in UINavigationNodeSelector
     * 
@@ -216,7 +235,23 @@
       WebuiRequestContext context = WebuiRequestContext.getCurrentInstance();
       try 
       {
-         userPortal.saveNode(getRootNode().getNode(), null);
+         userPortal.saveNode(getRootNode().getNode(), getRootNode());
+         DescriptionService descriptionService = getApplicationComponent(DescriptionService.class);
+         Map<String, Map<Locale, State>> i18nizedLabels = this.userNodeLabels;
+         
+         for (String treeNodeId : i18nizedLabels.keySet())
+         {
+            TreeNode node = findNode(treeNodeId);
+            if (node != null)
+            {
+               Map<Locale, State> labels = i18nizedLabels.get(treeNodeId);
+               if (labels != null && labels.size() > 0)
+               {
+                  descriptionService.setDescriptions(node.getNode().getId(), labels);
+               }
+            }
+            
+         }
       }
       catch (NavigationServiceException ex)
       {           
@@ -269,6 +304,21 @@
       }
       return getRootNode().findNode(nodeID);
    }
+   
+   private void invokeI18NizedLabels(TreeNode node)
+   {
+      DescriptionService descriptionService = this.getApplicationComponent(DescriptionService.class);
+      try
+      {
+         Map<Locale, State> labels = descriptionService.getDescriptions(node.getId());
+         node.setI18nizedLabels(labels);
+      }
+      catch(NullPointerException npe)
+      {
+         // set label list is null if Described mixin has been removed or not exists.
+         node.setI18nizedLabels(null);
+      }
+   }
 
    static public abstract class BaseActionListener<T> extends EventListener<T>
    {
@@ -283,6 +333,8 @@
          TreeNode rebased = selector.rebaseNode(node, scope);
          if (rebased == null)
          {
+            selector.getUserNodeLabels().remove(node.getId());
+            
             context.getUIApplication().addMessage(new ApplicationMessage("UINavigationNodeSelector.msg.staleData", null,
                ApplicationMessage.WARNING));
             selector.selectNode(selector.getRootNode());
@@ -294,6 +346,7 @@
       protected void handleError(NavigationError error, UINavigationNodeSelector selector) throws Exception
       {
          selector.initTreeData();
+         selector.getUserNodeLabels().clear();
          if (selector.getRootNode() != null)
          {
             WebuiRequestContext context = WebuiRequestContext.getCurrentInstance();
@@ -496,7 +549,12 @@
                return;
             }
          }
-
+         
+         if (node.getI18nizedLabels() == null)
+         {
+            uiNodeSelector.invokeI18NizedLabels(node);
+         }
+         
          UIPopupWindow uiManagementPopup = uiNodeSelector.getAncestorOfType(UIPopupWindow.class);
          UIPageNodeForm uiNodeForm = uiApp.createUIComponent(UIPageNodeForm.class, null, null);
          uiManagementPopup.setUIComponent(uiNodeForm);
@@ -532,6 +590,10 @@
          }
 
          node.setDeleteNode(false);
+         if (node.getI18nizedLabels() == null)
+         {
+            uiNodeSelector.invokeI18NizedLabels(node);
+         }
          uiNodeSelector.setCopyNode(node);
          event.getSource().setActions(
             new String[]{"AddNode", "EditPageNode", "EditSelectedNode", "CopyNode", "CloneNode", "CutNode",
@@ -585,6 +647,11 @@
          String nodeID = event.getRequestContext().getRequestParameter(UIComponent.OBJECTID);
          if (currNode != null && currNode.getId().equals(nodeID))
             currNode.setCloneNode(true);
+         
+         if (currNode.getI18nizedLabels() == null)
+         {
+            uiNodeSelector.invokeI18NizedLabels(currNode);
+         }
       }
    }
 
@@ -684,7 +751,9 @@
          {
             pasteNode(child, node, isClone);
          }
-
+         
+         node.setI18nizedLabels(sourceNode.getI18nizedLabels());
+         uiNodeSelector.getUserNodeLabels().put(node.getId(), node.getI18nizedLabels());
          return node;
       }
 
@@ -809,8 +878,8 @@
             uiApp.addMessage(new ApplicationMessage("UINavigationNodeSelector.msg.systemnode-delete", null));
             return;
          }
-
-         parentNode.removeChild(childNode);
+         uiNodeSelector.getUserNodeLabels().remove(childNode.getId()); 
+         parentNode.removeChild(childNode); 
          uiNodeSelector.selectNode(parentNode);
       }
    }

Modified: portal/trunk/portlet/exoadmin/src/main/java/org/exoplatform/navigation/webui/component/UIPageNodeForm.java
===================================================================
--- portal/trunk/portlet/exoadmin/src/main/java/org/exoplatform/navigation/webui/component/UIPageNodeForm.java	2011-07-01 06:44:15 UTC (rev 6783)
+++ portal/trunk/portlet/exoadmin/src/main/java/org/exoplatform/navigation/webui/component/UIPageNodeForm.java	2011-07-01 07:05:25 UTC (rev 6784)
@@ -19,6 +19,8 @@
 
 package org.exoplatform.navigation.webui.component;
 
+import org.exoplatform.container.ExoContainer;
+import org.exoplatform.container.ExoContainerContext;
 import org.exoplatform.navigation.webui.TreeNode;
 import org.exoplatform.portal.application.PortalRequestContext;
 import org.exoplatform.portal.config.DataStorage;
@@ -26,6 +28,7 @@
 import org.exoplatform.portal.config.model.ModelObject;
 import org.exoplatform.portal.config.model.Page;
 import org.exoplatform.portal.config.model.PortalConfig;
+import org.exoplatform.portal.mop.Described;
 import org.exoplatform.portal.mop.Visibility;
 import org.exoplatform.portal.mop.user.UserNavigation;
 import org.exoplatform.portal.webui.page.UIPageSelector;
@@ -33,11 +36,16 @@
 import org.exoplatform.portal.webui.portal.UIPortal;
 import org.exoplatform.portal.webui.util.Util;
 import org.exoplatform.portal.webui.workspace.UIPortalApplication;
+import org.exoplatform.services.resources.LocaleConfig;
+import org.exoplatform.services.resources.LocaleConfigService;
+import org.exoplatform.services.resources.ResourceBundleService;
 import org.exoplatform.web.application.ApplicationMessage;
 import org.exoplatform.webui.application.WebuiRequestContext;
+import org.exoplatform.webui.application.portlet.PortletRequestContext;
 import org.exoplatform.webui.core.UIApplication;
 import org.exoplatform.webui.core.UIComponent;
 import org.exoplatform.webui.core.UIPopupWindow;
+import org.exoplatform.webui.core.model.SelectItemOption;
 import org.exoplatform.webui.event.Event;
 import org.exoplatform.webui.event.Event.Phase;
 import org.exoplatform.webui.event.EventListener;
@@ -47,6 +55,7 @@
 import org.exoplatform.webui.form.UIFormInputBase;
 import org.exoplatform.webui.form.UIFormInputIconSelector;
 import org.exoplatform.webui.form.UIFormInputSet;
+import org.exoplatform.webui.form.UIFormSelectBox;
 import org.exoplatform.webui.form.UIFormStringInput;
 import org.exoplatform.webui.form.UIFormTabPane;
 import org.exoplatform.webui.form.validator.DateTimeValidator;
@@ -57,9 +66,17 @@
 
 import java.util.ArrayList;
 import java.util.Calendar;
+import java.util.Collections;
+import java.util.Comparator;
 import java.util.Date;
 import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.Iterator;
 import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
 
 /**
  * Author : Dang Van Minh, Pham Tuan minhdv81 at yahoo.com Jun 14, 2006
@@ -83,21 +100,47 @@
    final private static String END_PUBLICATION_DATE = "endPublicationDate";
    
    final private static String VISIBLE = "visible";
+   
+   private Map<String, Described.State> cachedLabels;
+   
+   private String selectedLocale;
 
+   private static final String I18N_LABEL = "i18nizedLabel";
+   
+   private static final String LANGUAGES = "languages";
+   
+   private static final String LANGUAGES_ONCHANGE = "ChangeLanguage";
+
+   private static final String SWITCH_MODE = "switchmode";
+
+   private static final String SWITCH_MODE_ONCHANGE = "SwitchLabelMode";
+
+   private static final String LABEL = "label";
+
    public UIPageNodeForm() throws Exception
    {
       super("UIPageNodeForm");
-
+      
       UIFormInputSet uiSettingSet = new UIFormInputSet("PageNodeSetting");
       UIFormCheckBoxInput<Boolean> uiDateInputCheck =
          new UIFormCheckBoxInput<Boolean>(SHOW_PUBLICATION_DATE, null, false);
       UIFormCheckBoxInput<Boolean> uiVisibleCheck = new UIFormCheckBoxInput<Boolean>(VISIBLE, null, true);
+      UIFormCheckBoxInput<Boolean> uiSwitchLabelMode = new UIFormCheckBoxInput<Boolean>(SWITCH_MODE, null, true);
       
       uiDateInputCheck.setOnChange("SwitchPublicationDate");
       uiVisibleCheck.setOnChange("SwitchVisible");
+      uiSwitchLabelMode.setOnChange(SWITCH_MODE_ONCHANGE);
+      
+      UIFormSelectBox uiFormLanguagesSelectBox = new UIFormSelectBox(LANGUAGES, null, null);
+      initLanguageSelectBox(uiFormLanguagesSelectBox);
+      uiFormLanguagesSelectBox.setOnChange(LANGUAGES_ONCHANGE);
+      
       uiSettingSet.addUIFormInput(new UIFormStringInput("URI", "URI", null).setEditable(false))
       				.addUIFormInput(new UIFormStringInput("name", "name", null).addValidator(MandatoryValidator.class).addValidator(StringLengthValidator.class, 3, 30).addValidator(IdentifierValidator.class))
-      				.addUIFormInput(new UIFormStringInput("label", "label", null).addValidator(StringLengthValidator.class, 3, 120))
+      				.addUIFormInput(uiSwitchLabelMode)
+      				.addUIFormInput(new UIFormStringInput(LABEL, LABEL, null).addValidator(StringLengthValidator.class, 3, 120))
+      				.addUIFormInput(uiFormLanguagesSelectBox)
+      				.addUIFormInput(new UIFormStringInput(I18N_LABEL, null, null).setMaxLength(255).addValidator(StringLengthValidator.class, 3, 120))
       				.addUIFormInput(uiVisibleCheck.setChecked(true))
       				.addUIFormInput(uiDateInputCheck)
       				.addUIFormInput(new UIFormDateTimeInput(START_PUBLICATION_DATE, null, null).addValidator(DateTimeValidator.class))
@@ -114,7 +157,7 @@
       addUIFormInput(uiIconSelector);
       setActions(new String[]{"Save", "Back"});
    }
-
+   
    public TreeNode getPageNode()
    {
       return pageNode_;
@@ -123,27 +166,134 @@
    public void setValues(TreeNode pageNode) throws Exception
    {
       pageNode_ = pageNode;
+      selectedLocale = getUIFormSelectBox(LANGUAGES).getValue();
+      cachedLabels = new HashMap<String, Described.State>();
       if (pageNode == null)
       {
          getUIStringInput("name").setEditable(UIFormStringInput.ENABLE);
          getChild(UIFormInputIconSelector.class).setSelectedIcon("Default");
          setShowPublicationDate(false);
+         switchLabelMode(false);
          return;
       }
       getUIStringInput("name").setEditable(UIFormStringInput.DISABLE);
       invokeGetBindingBean(pageNode_);
    }
 
+   private void initLanguageSelectBox(UIFormSelectBox langSelectBox)
+   {
+      List<SelectItemOption<String>> lang = new ArrayList<SelectItemOption<String>>();
+      LocaleConfigService localeService = getApplicationComponent(LocaleConfigService.class);
+      Locale currentLocale = ((PortletRequestContext) WebuiRequestContext.getCurrentInstance()).getLocale();
+      Iterator<LocaleConfig> i = localeService.getLocalConfigs().iterator();
+      String displayName = null;
+      String language = null;
+      String country = null;
+      String defaultValue = null;
+      SelectItemOption<String> option;
+      while (i.hasNext())
+      {
+         LocaleConfig config = i.next();
+         Locale locale = config.getLocale();
+
+         language = locale.getLanguage();
+         country = locale.getCountry();
+         if (country != null && country.length() > 0)
+         {
+            language = language + "_" + country;
+         }
+
+         ResourceBundle localeResourceBundle;
+
+         displayName = null;
+         try
+         {
+            localeResourceBundle = getResourceBundle(currentLocale);
+            String key = "Locale." + language;
+            String translation = localeResourceBundle.getString(key);
+            displayName = translation;
+         }
+         catch (MissingResourceException e)
+         {
+            displayName = capitalizeFirstLetter(locale.getDisplayName(currentLocale));
+         }
+         catch (Exception e)
+         {
+
+         }
+
+         option = new SelectItemOption<String>(displayName, language);
+         if (locale.getDisplayName().equals(currentLocale.getDisplayName()))
+         {
+            option.setSelected(true);
+            defaultValue = language;
+         }
+
+         lang.add(option);
+      }
+
+      Collections.sort(lang, new LanguagesComparator());
+      langSelectBox.setOptions(lang);
+      langSelectBox.setValue(defaultValue);
+   }
+   private ResourceBundle getResourceBundle(Locale locale) throws Exception
+   {
+      ExoContainer appContainer = ExoContainerContext.getCurrentContainer();
+      ResourceBundleService service =
+         (ResourceBundleService)appContainer.getComponentInstanceOfType(ResourceBundleService.class);
+      ResourceBundle res = service.getResourceBundle("locale.portal.webui", locale);
+      return res;
+   }
+
+   private String capitalizeFirstLetter(String word)
+   {
+      if (word == null)
+      {
+         return null;
+      }
+      if (word.length() == 0)
+      {
+         return word;
+      }
+      StringBuilder result = new StringBuilder(word);
+      result.replace(0, 1, result.substring(0, 1).toUpperCase());
+      return result.toString();
+   }
+
+   private class LanguagesComparator implements Comparator<SelectItemOption<String>>
+   {
+      public int compare(SelectItemOption<String> o1, SelectItemOption<String> o2)
+      {
+         return o1.getLabel().compareToIgnoreCase(o2.getLabel());
+      }
+   }
+
    public void invokeGetBindingBean(Object bean) throws Exception
    {
       super.invokeGetBindingBean(bean);
+
       TreeNode pageNode = (TreeNode)bean;
 
       String icon = pageNode.getIcon();
       if (icon == null || icon.length() < 0)
          icon = "Default";
       getChild(UIFormInputIconSelector.class).setSelectedIcon(icon);
-      getUIStringInput("label").setValue(pageNode.getLabel());
+      getUIStringInput(LABEL).setValue(pageNode.getLabel());
+      Map<Locale, Described.State> i18nizedLabels = pageNode.getI18nizedLabels();
+      if (i18nizedLabels != null)
+      {
+         for (Locale key : i18nizedLabels.keySet())
+         {
+            String locale = key.getCountry() != "" ? key.getLanguage() + "_" + key.getCountry() : key.getLanguage();
+            cachedLabels.put(locale, i18nizedLabels.get(key));
+         }
+      }
+      
+      if (cachedLabels.get(selectedLocale) != null)
+      {
+         getUIStringInput(I18N_LABEL).setValue(cachedLabels.get(selectedLocale).getName());
+      }
+
       if(pageNode.getVisibility() == Visibility.SYSTEM)
       {
          UIFormInputSet uiSettingSet = getChildById("PageNodeSetting");
@@ -175,6 +325,15 @@
          else
             getUIFormDateTimeInput(END_PUBLICATION_DATE).setValue(null);
       }
+      
+      boolean isExtendedMode = true;
+      if (pageNode.getNode().getLabel() != null && pageNode.getNode().getLabel().trim().length() > 0)
+      {
+         isExtendedMode = false;
+      }
+      
+      getUIFormCheckBoxInput(SWITCH_MODE).setChecked(isExtendedMode);
+      this.switchLabelMode(isExtendedMode);
    }
 
    public void invokeSetBindingBean(Object bean) throws Exception
@@ -203,14 +362,46 @@
          date = (cal != null) ? cal.getTime() : null;
          node.setEndPublicationTime(date == null ? -1 : date.getTime());
       }
+
+
+      cachedLabels.put(getUIFormSelectBox(LANGUAGES).getValue(), new Described.State(getUIStringInput(I18N_LABEL).getValue(), null));
+      Map<Locale, Described.State> labels = new HashMap<Locale, Described.State>(cachedLabels.size());
+      getUIFormSelectBox(LANGUAGES).getValue();
+      for (String strLocale : cachedLabels.keySet())
+      {
+         Locale locale;
+         if (strLocale.contains("_"))
+         {
+            String[] arr = strLocale.split("_");
+            if (arr.length > 2)
+            {
+               locale = new Locale(arr[0], arr[1], arr[2]);
+            }
+            else
+            {
+               locale = new Locale(arr[0], arr[1]);
+            }
+         }
+         else
+         {
+            locale = new Locale(strLocale);
+         }
+         
+         labels.put(locale, cachedLabels.get(strLocale));
+      }
+      
+      node.setI18nizedLabels(labels);
+      
+      if (getUIFormCheckBoxInput(SWITCH_MODE).getValue().toString().equals("true"))
+         node.setLabel(null);
    }
 
    public void setShowCheckPublicationDate(boolean show)
    {
-   	getUIFormCheckBoxInput(VISIBLE).setChecked(show);
-   	UIFormCheckBoxInput<Boolean> uiForm = getUIFormCheckBoxInput(SHOW_PUBLICATION_DATE);
-   	uiForm.setRendered(show);
-   	setShowPublicationDate(show && uiForm.isChecked());
+      getUIFormCheckBoxInput(VISIBLE).setChecked(show);
+      UIFormCheckBoxInput<Boolean> uiForm = getUIFormCheckBoxInput(SHOW_PUBLICATION_DATE);
+      uiForm.setRendered(show);
+      setShowPublicationDate(show && uiForm.isChecked());
    }
    
    public void setShowPublicationDate(boolean show)
@@ -323,6 +514,7 @@
          if (pageNode == null)
          {
             pageNode = selectedParent.addChild(nodeName);
+            uiPageNodeForm.pageNode_ = pageNode;
          } 
 
 
@@ -341,17 +533,17 @@
                pageSelector.setValue(page.getPageId());
             }
          }
+
+         if (pageNode.getLabel() == null)
+            pageNode.setLabel(pageNode.getName());
+         uiPageNodeForm.invokeSetBindingBean(pageNode);
          
          UIFormInputIconSelector uiIconSelector = uiPageNodeForm.getChild(UIFormInputIconSelector.class);
          if (uiIconSelector.getSelectedIcon().equals("Default"))
             pageNode.setIcon(null);
          else
             pageNode.setIcon(uiIconSelector.getSelectedIcon());
-         if (pageNode.getLabel() == null)
-            pageNode.setLabel(pageNode.getName());
          
-         uiPageNodeForm.invokeSetBindingBean(pageNode);
-
          uiPageNodeForm.createEvent("Back", Phase.DECODE, ctx).broadcast();
       }
    }
@@ -361,10 +553,51 @@
 
       public void execute(Event<UIPageNodeForm> event) throws Exception
       {
+         
       }
+   }
+   
+   public static class ChangeLanguageActionListener extends EventListener<UIPageNodeForm>
+   {
+      @Override
+      public void execute(Event<UIPageNodeForm> event) throws Exception
+      {
+         UIPageNodeForm uiForm = event.getSource();
+         UIFormSelectBox languageSelection = uiForm.getUIFormSelectBox(LANGUAGES);
+         UIFormStringInput label = uiForm.getUIStringInput(I18N_LABEL);
+         uiForm.updateCachedLabels(uiForm.getSelectedLocale(), label.getValue());
+         
+         uiForm.setSelectedLocale(languageSelection.getValue());
+         label.setValue(uiForm.getLabelOnLocale(uiForm.getSelectedLocale()));
+      }
+   }
+   
+   private String getLabelOnLocale(String locale)
+   {
+      if (cachedLabels.get(locale) != null)
+      {
+         return cachedLabels.get(locale).getName();
+      }
+      
+      return null;
+   }
+   
+   private void updateCachedLabels(String locale, String label)
+   {
+      cachedLabels.put(locale, new Described.State(label, null));
+   }
 
+
+   public void setSelectedLocale(String selectedLocale)
+   {
+      this.selectedLocale = selectedLocale;
    }
 
+   public String getSelectedLocale()
+   {
+      return selectedLocale;
+   }
+
    static public class SwitchPublicationDateActionListener extends EventListener<UIPageNodeForm>
    {
       public void execute(Event<UIPageNodeForm> event) throws Exception
@@ -387,6 +620,18 @@
 			event.getRequestContext().addUIComponentToUpdateByAjax(uiForm);
 		}
    }
+   
+   static public class SwitchLabelModeActionListener extends EventListener<UIPageNodeForm>
+   {
+      @Override
+      public void execute(Event<UIPageNodeForm> event) throws Exception
+      {
+         UIPageNodeForm uiForm = event.getSource();
+         boolean isExtendedMode = uiForm.getUIFormCheckBoxInput(SWITCH_MODE).isChecked();
+         uiForm.switchLabelMode(isExtendedMode);
+         event.getRequestContext().addUIComponentToUpdateByAjax(uiForm);
+      }
+   }
 
    static public class ClearPageActionListener extends EventListener<UIPageNodeForm>
    {
@@ -492,4 +737,11 @@
          pageSelector.setPage(page);
       }
    }
+   
+   private void switchLabelMode(boolean isExtendedMode)
+   {
+      getUIStringInput(LABEL).setRendered(!isExtendedMode);
+      getUIStringInput(I18N_LABEL).setRendered(isExtendedMode);
+      getUIFormSelectBox(LANGUAGES).setRendered(isExtendedMode);
+   }
 }

Modified: portal/trunk/portlet/exoadmin/src/main/java/org/exoplatform/navigation/webui/component/UISiteManagement.java
===================================================================
--- portal/trunk/portlet/exoadmin/src/main/java/org/exoplatform/navigation/webui/component/UISiteManagement.java	2011-07-01 06:44:15 UTC (rev 6783)
+++ portal/trunk/portlet/exoadmin/src/main/java/org/exoplatform/navigation/webui/component/UISiteManagement.java	2011-07-01 07:05:25 UTC (rev 6784)
@@ -54,12 +54,14 @@
 import org.exoplatform.webui.event.Event;
 import org.exoplatform.webui.event.Event.Phase;
 import org.exoplatform.webui.event.EventListener;
+
 import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.Comparator;
 import java.util.Iterator;
 import java.util.List;
 import java.util.UUID;
+
 import javax.servlet.http.HttpServletRequest;
 
 @ComponentConfigs({
@@ -69,7 +71,9 @@
       @EventConfig(listeners = UISiteManagement.DeletePortalActionListener.class, confirm = "UIPortalBrowser.deletePortal")}),
    @ComponentConfig(type = UIPageNodeForm.class, lifecycle = UIFormLifecycle.class, template = "system:/groovy/webui/form/UIFormTabPane.gtmpl", events = {
       @EventConfig(listeners = UIPageNodeForm.SaveActionListener.class),
+      @EventConfig(listeners = UIPageNodeForm.ChangeLanguageActionListener.class, phase = Phase.DECODE),
       @EventConfig(listeners = UISiteManagement.BackActionListener.class, phase = Phase.DECODE),
+      @EventConfig(listeners = UIPageNodeForm.SwitchLabelModeActionListener.class, phase = Phase.DECODE),
       @EventConfig(listeners = UIPageNodeForm.SwitchPublicationDateActionListener.class, phase = Phase.DECODE),
       @EventConfig(listeners = UIPageNodeForm.SwitchVisibleActionListener.class, phase = Phase.DECODE),
       @EventConfig(listeners = UIPageNodeForm.ClearPageActionListener.class, phase = Phase.DECODE),
@@ -407,6 +411,7 @@
          uiNavigationPopup.setWindowSize(400, 400);
          context.addUIComponentToUpdateByAjax(uiNavigationPopup.getParent());
          
+         selector.getUserNodeLabels().put(uiPageNodeForm.getPageNode().getId(), uiPageNodeForm.getPageNode().getI18nizedLabels());
          selector.createEvent("NodeModified", Phase.PROCESS, context).broadcast();
       }
 

Modified: portal/trunk/web/eXoResources/src/main/webapp/skin/DefaultSkin/webui/component/UIWizard/Stylesheet.css
===================================================================
--- portal/trunk/web/eXoResources/src/main/webapp/skin/DefaultSkin/webui/component/UIWizard/Stylesheet.css	2011-07-01 06:44:15 UTC (rev 6783)
+++ portal/trunk/web/eXoResources/src/main/webapp/skin/DefaultSkin/webui/component/UIWizard/Stylesheet.css	2011-07-01 07:05:25 UTC (rev 6784)
@@ -259,7 +259,7 @@
 
 .UIWizard .UIWizardPageSetInfo .UIFormWithTitle .HorizontalLayout {
 	background: white;
-	height: 175px;
+	height: auto;
 }
 
 .UIWizard .UIWizardPageSetInfo .UIFormWithTitle textarea {

Modified: portal/trunk/web/portal/src/main/webapp/WEB-INF/classes/locale/portal/webui_en.properties
===================================================================
--- portal/trunk/web/portal/src/main/webapp/WEB-INF/classes/locale/portal/webui_en.properties	2011-07-01 06:44:15 UTC (rev 6783)
+++ portal/trunk/web/portal/src/main/webapp/WEB-INF/classes/locale/portal/webui_en.properties	2011-07-01 07:05:25 UTC (rev 6784)
@@ -542,6 +542,9 @@
 UIPageNodeForm.label.startPublicationDate=Start Publication Date:
 UIPageNodeForm.label.endPublicationDate=End Publication Date:
 UIPageNodeForm.label.pageName=Name:
+UIPageNodeForm.label.i18nizedLabel=#{word.label}:
+UIPageNodeForm.label.languages=#{word.language}:
+UIPageNodeForm.label.switchmode=Extended label mode:
 UIPageNodeForm.Icon.title.SetDefault=Get Default
 UIPageNodeForm.tab.label.PageNodeSetting=Page Node Setting
 UIPageNodeForm.tab.label.Icon=#{word.icon}
@@ -744,6 +747,9 @@
 UIWizardPageSetInfo.label.showPublicationDate=Publication date & time
 UIWizardPageSetInfo.label.startPublicationDate=Start Publication Date
 UIWizardPageSetInfo.label.endPublicationDate=End Publication Date
+UIWizardPageSetInfo.label.i18nizedLabel=Display Name
+UIWizardPageSetInfo.label.languages=#{word.language}
+UIWizardPageSetInfo.label.switchmode=Extended label mode
 UIWizardPageSetInfo.action.Save=#{word.save}
 UIWizardPageSetInfo.msg.null=No page not found.
 UIWizardPageSetInfo.msg.node.deleted=Concurrent modification error : The node you select has been deleted

Modified: portal/trunk/web/portal/src/main/webapp/WEB-INF/classes/locale/portal/webui_vi.properties
===================================================================
--- portal/trunk/web/portal/src/main/webapp/WEB-INF/classes/locale/portal/webui_vi.properties	2011-07-01 06:44:15 UTC (rev 6783)
+++ portal/trunk/web/portal/src/main/webapp/WEB-INF/classes/locale/portal/webui_vi.properties	2011-07-01 07:05:25 UTC (rev 6784)
@@ -496,6 +496,7 @@
 UIPageNodeForm.label.creator=Người khởi tạo trang
 UIPageNodeForm.label.modifier=Người chỉnh sửa trang
 UIPageNodeForm.label.label=#{word.label}:
+UIPageNodeForm.label.switchmode=Chế độ nhãn mở rộng:
 UIPageNodeForm.label.visible=Hiển thị:
 UIPageNodeForm.label.showPublicationDate=Thời gian hiển thị
 UIPageNodeForm.label.startPublicationDate=Thời gian bắt đầu
@@ -693,6 +694,8 @@
 UIWizardPageSetInfo.label.curentSelectedNodeInfo=Node vừa chọn
 UIWizardPageSetInfo.label.pageName=Tên Node
 UIWizardPageSetInfo.label.pageDisplayName=Tên node hiển thị
+UIWizardPageSetInfo.label.switchmode=Chế độ nhãn mở rộng
+UIWizardPageSetInfo.label.i18nizedLabel=Tên node hiển thị
 UIWizardPageSetInfo.label.visible=Hiển thị
 UIWizardPageSetInfo.label.showPublicationDate=Thời gian hiển thị
 UIWizardPageSetInfo.label.startPublicationDate=Thời gian bắt đầu

Modified: portal/trunk/web/portal/src/main/webapp/WEB-INF/conf/portal/portal/classic/navigation.xml
===================================================================
--- portal/trunk/web/portal/src/main/webapp/WEB-INF/conf/portal/portal/classic/navigation.xml	2011-07-01 06:44:15 UTC (rev 6783)
+++ portal/trunk/web/portal/src/main/webapp/WEB-INF/conf/portal/portal/classic/navigation.xml	2011-07-01 07:05:25 UTC (rev 6784)
@@ -22,36 +22,106 @@
 
 <node-navigation
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-    xsi:schemaLocation="http://www.gatein.org/xml/ns/gatein_objects_1_1 http://www.gatein.org/xml/ns/gatein_objects_1_1"
-    xmlns="http://www.gatein.org/xml/ns/gatein_objects_1_1">
+    xsi:schemaLocation="http://www.gatein.org/xml/ns/gatein_objects_1_2 http://www.gatein.org/xml/ns/gatein_objects_1_2"
+    xmlns="http://www.gatein.org/xml/ns/gatein_objects_1_2">
   <priority>1</priority>
   <page-nodes>
 	  <node>
 	    <name>home</name>
-	    <label>#{portal.classic.home}</label>
-	    <page-reference>portal::classic::homepage</page-reference>	    
+      <label xml:lang="en">Home</label>
+      <label xml:lang="fr">Accueil</label>
+      <label xml:lang="es">Inicio</label>
+      <label xml:lang="de">Startseite</label>
+      <label xml:lang="it">Home</label>
+      <label xml:lang="nl">Home</label>
+      <label xml:lang="pt-BR">Principal</label>
+      <label xml:lang="ja">&#x30db;&#x30fc;&#x30e0;</label>
+      <label xml:lang="ne">&#x0917;&#x0943;&#x0939; &#x092a;&#x0943;&#x0937;&#x094d;&#x200d;&#x0920;</label>
+      <label xml:lang="ru">Главная</label>
+      <label xml:lang="uk">Додому</label>
+      <label xml:lang="ar">ترحيب</label>
+      <label xml:lang="ko">홈</label>
+      <label xml:lang="vi">Trang chủ</label>
+      <label xml:lang="zh">主页</label>
+      <label xml:lang="zh-TW">首頁</label>
+	    <page-reference>portal::classic::homepage</page-reference>
 	  </node>   
     <node>
       <name>sitemap</name>
-      <label>#{portal.classic.sitemap}</label>
+      <label xml:lang="en">SiteMap</label>
+      <label xml:lang="fr">SiteMap</label>
+      <label xml:lang="es">Mapa del Sitio</label>
+      <label xml:lang="de">Seiten&#x00fc;bersicht</label>
+      <label xml:lang="it">Mappa del Sito</label>
+      <label xml:lang="nl">Sitemap</label>
+      <label xml:lang="pt-BR">Mapa do Site</label>
+      <label xml:lang="ja">&#x30b5;&#x30a4;&#x30c8;&#x30de;&#x30c3;&#x30d7;</label>
+      <label xml:lang="ne">&#x0938;&#x093e;&#x0908;&#x091f;&#x092e;&#x094d;&#x092f;&#x093e;&#x092a;</label>
+      <label xml:lang="ru">SiteMap</label>
+      <label xml:lang="ar">خريطة الموقع</label>
+      <label xml:lang="ko">사이트맵</label>
+      <label xml:lang="vi">Sơ đồ</label>
+      <label xml:lang="zh">网站地图</label>
+      <label xml:lang="zh-TW">網站導覽</label>
       <visibility>DISPLAYED</visibility>
       <page-reference>portal::classic::sitemap</page-reference>
     </node>
 	  <node>
 	    <name>groupnavigation</name>
-	    <label>#{portal.classic.groupnavigation}</label>
+      <label xml:lang="en">Group Navigation</label>
+      <label xml:lang="fr">Group Navigation</label>
+      <label xml:lang="es">Navegaci&#x00f3;n por Grupos</label>
+      <label xml:lang="de">Gruppennavigation</label>
+      <label xml:lang="it">Navigazione dei Gruppi</label>
+      <label xml:lang="nl">Groep navigatie</label>
+      <label xml:lang="pt-BR">Navegação do Grupo</label>
+      <label xml:lang="ja">&#x30b0;&#x30eb;&#x30fc;&#x30d7;&#x30ca;&#x30d3;&#x30b2;&#x30fc;&#x30b7;&#x30e7;&#x30f3;</label>
+      <label xml:lang="ne">&#x0938;&#x092e;&#x0941;&#x0939; &#x0928;&#x094d;&#x092f;&#x093e;&#x092d;&#x093f;&#x0917;&#x0947;&#x0938;&#x0928;</label>
+      <label xml:lang="ru">Навигация по группам</label>
+      <label xml:lang="uk">Навігація груп</label>
+      <label xml:lang="ar">مجموعة الملاحة</label>
+      <label xml:lang="ko">그룹 내비게이션</label>
+      <label xml:lang="vi">Group Navigation</label>
+      <label xml:lang="zh">组导航</label>
+      <label xml:lang="zh-TW">瀏覽群組</label>
       <visibility>SYSTEM</visibility>
 	    <page-reference>portal::classic::groupnavigation</page-reference>
 	  </node>
 	  <node>
 	    <name>portalnavigation</name>
-	    <label>#{portal.classic.portalnavigation}</label>
+      <label xml:lang="en">Portal Navigation</label>
+      <label xml:lang="fr">Portal Navigation</label>
+      <label xml:lang="es">Navegaci&#x00f3;n por Portales</label>
+      <label xml:lang="de">Portalnavigation</label>
+      <label xml:lang="it">Navigazione del Portale</label>
+      <label xml:lang="nl">Portaal navigatie</label>
+      <label xml:lang="pt-BR">Navegação do Portal</label>
+      <label xml:lang="ja">&#x30dd;&#x30fc;&#x30bf;&#x30eb;&#x30ca;&#x30d3;&#x30b2;&#x30fc;&#x30b7;&#x30e7;&#x30f3;</label>
+      <label xml:lang="ne">&#x092a;&#x094b;&#x0930;&#x094d;&#x091f;&#x0932; &#x0928;&#x094d;&#x092f;&#x093e;&#x092d;&#x093f;&#x0917;&#x0947;&#x0938;&#x0928;</label>
+      <label xml:lang="ru">Навигация по порталу</label>
+      <label xml:lang="uk">Навігація порталу</label>
+      <label xml:lang="ar">بوابة الملاحة</label>
+      <label xml:lang="ko">포탈 내비게이션</label>
+      <label xml:lang="vi">Portal Navigation</label>
+      <label xml:lang="zh">门户导航</label>
+      <label xml:lang="zh-TW">瀏覽入口網</label>
       <visibility>SYSTEM</visibility>
 	    <page-reference>portal::classic::portalnavigation</page-reference>
 	  </node>
 	  <node>
 	    <name>register</name>
-	    <label>#{portal.classic.register}</label>
+      <label xml:lang="en">Register</label>
+      <label xml:lang="es">Registrarse</label>
+      <label xml:lang="de">Registrieren</label>
+      <label xml:lang="it">Registrazione</label>
+      <label xml:lang="nl">Registreren</label>
+      <label xml:lang="pt-BR">Cadastrar-se</label>
+      <label xml:lang="ja">&#x767b;&#x9332;</label>
+      <label xml:lang="ne">&#x0926;&#x0930;&#x094d;&#x0924;&#x093e;</label>
+      <label xml:lang="ko">등록</label>
+      <label xml:lang="vi">Đăng ký</label>
+      <label xml:lang="zh">注册</label>
+      <label xml:lang="zh-TW">註冊</label>
       <visibility>SYSTEM</visibility>
 	    <page-reference>portal::classic::register</page-reference>	    
 	  </node>

Modified: portal/trunk/web/portal/src/main/webapp/WEB-INF/conf/portal/portal-configuration.xml
===================================================================
--- portal/trunk/web/portal/src/main/webapp/WEB-INF/conf/portal/portal-configuration.xml	2011-07-01 06:44:15 UTC (rev 6783)
+++ portal/trunk/web/portal/src/main/webapp/WEB-INF/conf/portal/portal-configuration.xml	2011-07-01 07:05:25 UTC (rev 6784)
@@ -94,11 +94,24 @@
   </component>
   
   <component>
+    <key>org.exoplatform.portal.mop.navigation.DataCache</key>
+    <type>org.exoplatform.portal.mop.navigation.ExoDataCache</type>
+  </component>
+  <component>
     <key>org.exoplatform.portal.mop.navigation.NavigationService</key>
     <type>org.exoplatform.portal.mop.navigation.NavigationServiceWrapper</type>
   </component>
 
   <component>
+    <key>org.exoplatform.portal.mop.description.DataCache</key>
+    <type>org.exoplatform.portal.mop.description.ExoDataCache</type>
+  </component>
+  <component>
+    <key>org.exoplatform.portal.mop.description.DescriptionService</key>
+    <type>org.exoplatform.portal.mop.description.DescriptionServiceImpl</type>
+  </component>
+
+  <component>
     <key>org.exoplatform.portal.config.UserPortalConfigService</key>
     <type>org.exoplatform.portal.config.UserPortalConfigService</type>
     <component-plugins>           
@@ -275,6 +288,9 @@
           <value>org.exoplatform.portal.mop.ProtectedResource</value>
           <value>org.exoplatform.portal.mop.Described</value>
           <value>org.exoplatform.portal.mop.Visible</value>
+          <value>org.exoplatform.portal.mop.i18n.I18Nized</value>
+          <value>org.exoplatform.portal.mop.i18n.LanguageSpace</value>
+          <value>org.exoplatform.portal.mop.i18n.Language</value>
         </values-param>
         <properties-param>
           <name>options</name>
@@ -287,6 +303,8 @@
 
   <external-component-plugins>
     <target-component>org.exoplatform.services.cache.CacheService</target-component>
+
+    <!-- MOPSessionManager configuration -->
     <component-plugin>
       <name>addExoCacheConfig</name>
       <set-method>addExoCacheConfig</set-method>
@@ -333,6 +351,8 @@
         </object-param>
       </init-params>
     </component-plugin>
+
+    <!-- NavigationService configuration -->
     <component-plugin>
       <name>addExoCacheConfig</name>
       <set-method>addExoCacheConfig</set-method>
@@ -382,6 +402,57 @@
         </object-param>
       </init-params>
     </component-plugin>
+
+    <!-- DescriptionService configuration -->
+    <component-plugin>
+      <name>addExoCacheConfig</name>
+      <set-method>addExoCacheConfig</set-method>
+      <type>org.exoplatform.services.cache.ExoCacheConfigPlugin</type>
+      <description>add Exo Cache Config</description>
+      <init-params>
+        <object-param>
+          <name>cache.config.NavigationService</name>
+          <description>The JBoss Cache configuration for the dezcription service</description>
+          <object type="org.exoplatform.services.cache.ExoCacheConfig">
+            <field name="name">
+              <string>DescriptionService</string>
+            </field>
+            <field name="maxSize">
+              <int>5000</int>
+            </field>
+            <field name="liveTime">
+              <long>600</long>
+            </field>
+          </object>
+        </object-param>
+      </init-params>
+    </component-plugin>
+    <component-plugin profiles="cluster">
+      <name>addExoCacheConfig</name>
+      <set-method>addExoCacheConfig</set-method>
+      <type>org.exoplatform.services.cache.ExoCacheConfigPlugin</type>
+      <description>add Exo Cache Config</description>
+      <init-params>
+        <object-param>
+          <name>cache.config.ConfigurationService</name>
+          <description>The JBoss Cache configuration for the description service</description>
+          <object type="org.exoplatform.services.cache.impl.jboss.ea.EAExoCacheConfig">
+            <field name="name">
+              <string>DescriptionService</string>
+            </field>
+            <field name="expirationTimeout">
+              <long>600000</long>
+            </field>
+            <field name="maxNodes">
+             <int>5000</int>
+            </field>
+            <field name="distributed">
+              <boolean>true</boolean>
+            </field>
+          </object>
+        </object-param>
+      </init-params>
+    </component-plugin>
   </external-component-plugins>
 
 </configuration>

Modified: portal/trunk/webui/portal/src/main/java/org/exoplatform/portal/application/PortalRequestContext.java
===================================================================
--- portal/trunk/webui/portal/src/main/java/org/exoplatform/portal/application/PortalRequestContext.java	2011-07-01 06:44:15 UTC (rev 6783)
+++ portal/trunk/webui/portal/src/main/java/org/exoplatform/portal/application/PortalRequestContext.java	2011-07-01 07:05:25 UTC (rev 6784)
@@ -501,7 +501,10 @@
             navigation.getKey().getTypeName(),
             navigation.getKey().getName());
       }
+
+      public Locale getUserLocale()
+      {
+         return Util.getPortalRequestContext().getLocale();
+      }
    };
-
-
 }

Modified: portal/trunk/webui/portal/src/main/java/org/exoplatform/portal/webui/page/UIPageCreationWizard.java
===================================================================
--- portal/trunk/webui/portal/src/main/java/org/exoplatform/portal/webui/page/UIPageCreationWizard.java	2011-07-01 06:44:15 UTC (rev 6783)
+++ portal/trunk/webui/portal/src/main/java/org/exoplatform/portal/webui/page/UIPageCreationWizard.java	2011-07-01 07:05:25 UTC (rev 6784)
@@ -21,12 +21,17 @@
 
 import java.util.Calendar;
 import java.util.Date;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
 
 import org.exoplatform.portal.application.PortalRequestContext;
 import org.exoplatform.portal.config.DataStorage;
 import org.exoplatform.portal.config.UserACL;
 import org.exoplatform.portal.config.model.Page;
 import org.exoplatform.portal.config.model.PortalConfig;
+import org.exoplatform.portal.mop.Described;
+import org.exoplatform.portal.mop.description.DescriptionService;
 import org.exoplatform.portal.mop.navigation.NavigationServiceException;
 import org.exoplatform.portal.mop.user.UserNavigation;
 import org.exoplatform.portal.mop.user.UserNode;
@@ -47,6 +52,7 @@
 import org.exoplatform.webui.event.Event;
 import org.exoplatform.webui.event.EventListener;
 import org.exoplatform.webui.form.UIFormStringInput;
+import org.exoplatform.webui.form.UIFormCheckBoxInput;
 
 /** Created by The eXo Platform SARL Author : Dang Van Minh minhdv81 at yahoo.com Jun 23, 2006 */
 @ComponentConfigs(@ComponentConfig(template = "system:/groovy/webui/core/UIWizard.gtmpl", events = {
@@ -103,9 +109,37 @@
       dataService.create(page);
 
       UserPortal userPortal = Util.getUIPortalApplication().getUserPortalConfig().getUserPortal();
-      userPortal.saveNode(selectedNode, null);      
+      userPortal.saveNode(selectedNode, null);
+      
+      DescriptionService descriptionService = getApplicationComponent(DescriptionService.class);
+      Map<Locale, Described.State> descriptions = new HashMap<Locale, Described.State>();
+      Map<String, String> cachedLabels = uiPageInfo.getCachedLabels();
+      
+      for (String strLocale : cachedLabels.keySet())
+      {
+         Locale locale;
+         if (strLocale.contains("_"))
+         {
+            String[] arr = strLocale.split("_");
+            if (arr.length > 2)
+            {
+               locale = new Locale(arr[0], arr[1], arr[2]);
+            }
+            else
+            {
+               locale = new Locale(arr[0], arr[1]);
+            }
+         }
+         else
+         {
+            locale = new Locale(strLocale);
+         }
+         
+         descriptions.put(locale, new Described.State(cachedLabels.get(strLocale), null));
+      }
+      
+      descriptionService.setDescriptions(createdNode.getId(), descriptions);
       return createdNode;
-
    }
 
    /**
@@ -182,7 +216,7 @@
             return;
          }
 
-         if (uiPageSetInfo.getUIFormCheckBoxInput(UIWizardPageSetInfo.SHOW_PUBLICATION_DATE).isChecked())
+         if (((UIFormCheckBoxInput)uiPageSetInfo.getUIInput(UIWizardPageSetInfo.SHOW_PUBLICATION_DATE)).isChecked())
          {
          	
          	Calendar currentCalendar = Calendar.getInstance();
@@ -221,6 +255,10 @@
                return;
             }
          }
+         
+         // Update the last value of selected locale to cached labels
+         UIFormStringInput label = uiPageSetInfo.getUIStringInput(UIWizardPageSetInfo.I18N_LABEL);
+         uiPageSetInfo.updateCachedLabels(uiPageSetInfo.getSelectedLocale(), label.getValue());
       }
       
    }

Modified: portal/trunk/webui/portal/src/main/java/org/exoplatform/portal/webui/page/UIWizardPageSetInfo.java
===================================================================
--- portal/trunk/webui/portal/src/main/java/org/exoplatform/portal/webui/page/UIWizardPageSetInfo.java	2011-07-01 06:44:15 UTC (rev 6783)
+++ portal/trunk/webui/portal/src/main/java/org/exoplatform/portal/webui/page/UIWizardPageSetInfo.java	2011-07-01 07:05:25 UTC (rev 6784)
@@ -19,33 +19,50 @@
 
 package org.exoplatform.portal.webui.page;
 
+import org.exoplatform.container.ExoContainer;
+import org.exoplatform.container.ExoContainerContext;
 import org.exoplatform.portal.config.model.PortalConfig;
-import java.util.Calendar;
-
 import org.exoplatform.portal.mop.Visibility;
 import org.exoplatform.portal.mop.navigation.NavigationServiceException;
 import org.exoplatform.portal.mop.user.UserNode;
 import org.exoplatform.portal.webui.navigation.UIPageNodeSelector;
 import org.exoplatform.portal.webui.util.Util;
+import org.exoplatform.services.resources.LocaleConfig;
+import org.exoplatform.services.resources.LocaleConfigService;
+import org.exoplatform.services.resources.ResourceBundleService;
 import org.exoplatform.web.application.ApplicationMessage;
 import org.exoplatform.webui.application.WebuiRequestContext;
 import org.exoplatform.webui.config.annotation.ComponentConfig;
 import org.exoplatform.webui.config.annotation.EventConfig;
 import org.exoplatform.webui.core.UIWizard;
 import org.exoplatform.webui.core.lifecycle.UIFormLifecycle;
+import org.exoplatform.webui.core.model.SelectItemOption;
 import org.exoplatform.webui.event.Event;
 import org.exoplatform.webui.event.EventListener;
 import org.exoplatform.webui.event.Event.Phase;
 import org.exoplatform.webui.form.UIForm;
-import org.exoplatform.webui.form.UIFormCheckBoxInput;
 import org.exoplatform.webui.form.UIFormDateTimeInput;
 import org.exoplatform.webui.form.UIFormInputBase;
+import org.exoplatform.webui.form.UIFormSelectBox;
 import org.exoplatform.webui.form.UIFormStringInput;
+import org.exoplatform.webui.form.UIFormCheckBoxInput;
 import org.exoplatform.webui.form.validator.DateTimeValidator;
 import org.exoplatform.webui.form.validator.IdentifierValidator;
 import org.exoplatform.webui.form.validator.MandatoryValidator;
 import org.exoplatform.webui.form.validator.StringLengthValidator;
 
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
 /**
  * Created by The eXo Platform SARL
  * Author : Nguyen Thi Hoa
@@ -55,10 +72,14 @@
 @ComponentConfig(lifecycle = UIFormLifecycle.class, template = "system:/groovy/portal/webui/page/UIWizardPageSetInfo.gtmpl", events = {
    @EventConfig(listeners = UIWizardPageSetInfo.ChangeNodeActionListener.class, phase = Phase.DECODE),
    @EventConfig(listeners = UIWizardPageSetInfo.SwitchVisibleActionListener.class, phase = Phase.DECODE),
-   @EventConfig(listeners = UIWizardPageSetInfo.SwitchPublicationDateActionListener.class, phase = Phase.DECODE)})
+   @EventConfig(listeners = UIWizardPageSetInfo.SwitchPublicationDateActionListener.class, phase = Phase.DECODE),
+   @EventConfig(listeners = UIWizardPageSetInfo.ChangeLanguageActionListener.class, phase = Phase.DECODE),
+   @EventConfig(listeners = UIWizardPageSetInfo.SwitchLabelModeActionListener.class, phase = Phase.DECODE)
+})
 public class UIWizardPageSetInfo extends UIForm
 {
 
+   
    final public static String PAGE_NAME = "pageName";
 
    final public static String PAGE_DISPLAY_NAME = "pageDisplayName";
@@ -70,24 +91,47 @@
    final public static String START_PUBLICATION_DATE = "startPublicationDate";
 
    final public static String END_PUBLICATION_DATE = "endPublicationDate";
+   
+   public static final String I18N_LABEL = "i18nizedLabel";
+   
+   private static final String LANGUAGES = "languages";
+   
+   private static final String LANGUAGES_ONCHANGE = "ChangeLanguage";
 
+   private static final String SWITCH_MODE = "switchmode";
+
+   private static final String SWITCH_MODE_ONCHANGE = "SwitchLabelMode";
+
    private boolean isEditMode = false;
 
    private boolean firstTime = true;
+   
+   private String selectedLocale;
 
+   private Map<String, String> cachedLabels;
+
    public UIWizardPageSetInfo() throws Exception
    {
-      UIFormCheckBoxInput<Boolean> uiDateInputCheck =
-         new UIFormCheckBoxInput<Boolean>(SHOW_PUBLICATION_DATE, null, false);
-      UIFormCheckBoxInput<Boolean> uiVisibleCheck = new UIFormCheckBoxInput<Boolean>(VISIBLE, null, false);
+      UIFormCheckBoxInput uiDateInputCheck =
+         new UIFormCheckBoxInput(SHOW_PUBLICATION_DATE, null, false);
+      UIFormCheckBoxInput uiVisibleCheck = new UIFormCheckBoxInput(VISIBLE, null, false);
+      UIFormCheckBoxInput uiSwitchLabelMode = new UIFormCheckBoxInput(SWITCH_MODE, null, true);
       uiDateInputCheck.setOnChange("SwitchPublicationDate");
       uiVisibleCheck.setOnChange("SwitchVisible");
+      uiSwitchLabelMode.setOnChange(SWITCH_MODE_ONCHANGE);
+      
+      UIFormSelectBox uiFormLanguagesSelectBox = new UIFormSelectBox(LANGUAGES, null, null);
+      initLanguageSelectBox(uiFormLanguagesSelectBox);
+      uiFormLanguagesSelectBox.setOnChange(LANGUAGES_ONCHANGE);
 
       addChild(UIPageNodeSelector.class, null, null);
       addUIFormInput(new UIFormStringInput(PAGE_NAME, "name", null).addValidator(MandatoryValidator.class)
          .addValidator(StringLengthValidator.class, 3, 30).addValidator(IdentifierValidator.class));
+      addUIFormInput(uiSwitchLabelMode);
       addUIFormInput(new UIFormStringInput(PAGE_DISPLAY_NAME, "label", null).setMaxLength(255).addValidator(
          StringLengthValidator.class, 3, 120));
+      addUIFormInput(uiFormLanguagesSelectBox);
+      addUIFormInput(new UIFormStringInput(I18N_LABEL, null, null).setMaxLength(255).addValidator(StringLengthValidator.class, 3, 120));
       addUIFormInput(uiVisibleCheck.setChecked(true));
       addUIFormInput(uiDateInputCheck);
       UIFormInputBase<String> startPubDateInput = new UIFormDateTimeInput(START_PUBLICATION_DATE, null, null).addValidator(DateTimeValidator.class);
@@ -103,6 +147,10 @@
          startPubDateInput.setRendered(false);
          endPubDateInput.setRendered(false);
       }
+      
+      this.selectedLocale = getUIFormSelectBox(LANGUAGES).getValue();
+      cachedLabels = new HashMap<String, String>();
+      switchLabelMode(true);
    }
 
    //TODO: it looks like this method is not used
@@ -117,6 +165,16 @@
    {
       return isEditMode;
    }
+   
+   public Map<String, String> getCachedLabels()
+   {
+      return cachedLabels;
+   }
+   
+   public String getSelectedLocale()
+   {
+      return selectedLocale;
+   }
 
    public void invokeSetBindingBean(Object bean) throws Exception
    {
@@ -128,10 +186,19 @@
 
       UserNode node = (UserNode)bean;
       
+      if (((UIFormCheckBoxInput)getUIInput(SWITCH_MODE)).isChecked())
+      {
+         node.setLabel(null);
+      }
+      else if (node.getLabel() == null || node.getLabel().trim().length() == 0)
+      {
+         node.setLabel(node.getName());
+      }
+      
       Visibility visibility;
-      if (getUIFormCheckBoxInput(VISIBLE).isChecked())
+      if (((UIFormCheckBoxInput)getUIInput(VISIBLE)).isChecked())
       {
-         UIFormCheckBoxInput showPubDate = getUIFormCheckBoxInput(SHOW_PUBLICATION_DATE);
+         UIFormCheckBoxInput showPubDate = getUIInput(SHOW_PUBLICATION_DATE);
          visibility = showPubDate.isChecked() ?  Visibility.TEMPORAL : Visibility.DISPLAYED;
       }
       else
@@ -155,17 +222,13 @@
       
       UserNode child = parent.addChild(nodeName);
       invokeSetBindingBean(child);
-      if (child.getLabel() == null || child.getLabel().trim().length() == 0)
-      {
-         child.setLabel(child.getName());
-      }
       return child;
    }
 
    public void setShowCheckPublicationDate(boolean show)
    {
-      getUIFormCheckBoxInput(VISIBLE).setChecked(show);
-      UIFormCheckBoxInput<Boolean> uiForm = getUIFormCheckBoxInput(SHOW_PUBLICATION_DATE);
+      ((UIFormCheckBoxInput)getUIInput(VISIBLE)).setChecked(show);
+      UIFormCheckBoxInput uiForm = getUIInput(SHOW_PUBLICATION_DATE);
       uiForm.setRendered(show);
       setShowPublicationDate(show && uiForm.isChecked());
    }
@@ -198,7 +261,116 @@
    {
       this.firstTime = firstTime;
    }
+   
+   private void initLanguageSelectBox(UIFormSelectBox langSelectBox)
+   {
+      List<SelectItemOption<String>> lang = new ArrayList<SelectItemOption<String>>();
+      LocaleConfigService localeService = getApplicationComponent(LocaleConfigService.class);
+      Locale currentLocale = WebuiRequestContext.getCurrentInstance().getLocale();
+      Iterator<LocaleConfig> i = localeService.getLocalConfigs().iterator();
+      String displayName = null;
+      String language = null;
+      String country = null;
+      String defaultValue = null;
+      SelectItemOption<String> option;
+      while (i.hasNext())
+      {
+         LocaleConfig config = i.next();
+         Locale locale = config.getLocale();
 
+         language = locale.getLanguage();
+         country = locale.getCountry();
+         if (country != null && country.length() > 0)
+         {
+            language = language + "_" + country;
+         }
+
+         ResourceBundle localeResourceBundle;
+
+         displayName = null;
+         try
+         {
+            localeResourceBundle = getResourceBundle(currentLocale);
+            String key = "Locale." + language;
+            String translation = localeResourceBundle.getString(key);
+            displayName = translation;
+         }
+         catch (MissingResourceException e)
+         {
+            displayName = capitalizeFirstLetter(locale.getDisplayName(currentLocale));
+         }
+         catch (Exception e)
+         {
+
+         }
+
+         option = new SelectItemOption<String>(displayName, language);
+         if (locale.getDisplayName().equals(currentLocale.getDisplayName()))
+         {
+            option.setSelected(true);
+            defaultValue = language;
+         }
+
+         lang.add(option);
+      }
+
+      Collections.sort(lang, new LanguagesComparator());
+      langSelectBox.setOptions(lang);
+      langSelectBox.setValue(defaultValue);
+   }
+
+   private ResourceBundle getResourceBundle(Locale locale) throws Exception
+   {
+      ExoContainer appContainer = ExoContainerContext.getCurrentContainer();
+      ResourceBundleService service = (ResourceBundleService) appContainer
+            .getComponentInstanceOfType(ResourceBundleService.class);
+      ResourceBundle res = service.getResourceBundle("locale.portal.webui", locale);
+      return res;
+   }
+
+   private String capitalizeFirstLetter(String word)
+   {
+      if (word == null)
+      {
+         return null;
+      }
+      if (word.length() == 0)
+      {
+         return word;
+      }
+      StringBuilder result = new StringBuilder(word);
+      result.replace(0, 1, result.substring(0, 1).toUpperCase());
+      return result.toString();
+   }
+
+   private class LanguagesComparator implements Comparator<SelectItemOption<String>>
+   {
+      public int compare(SelectItemOption<String> o1, SelectItemOption<String> o2)
+      {
+         return o1.getLabel().compareToIgnoreCase(o2.getLabel());
+      }
+   }
+   
+   private void switchLabelMode(boolean isExtendedMode)
+   {
+      getUIStringInput(PAGE_DISPLAY_NAME).setRendered(!isExtendedMode);
+      getUIStringInput(I18N_LABEL).setRendered(isExtendedMode);
+      getUIFormSelectBox(LANGUAGES).setRendered(isExtendedMode);
+   }
+   
+   private String getLabelOnLocale(String locale)
+   {
+      return cachedLabels.get(locale);
+   }
+   
+   public void updateCachedLabels(String locale, String label)
+   {
+      if (label != null)
+      {
+         cachedLabels.put(locale, label);
+      }
+   }
+   
    static public class ChangeNodeActionListener extends EventListener<UIWizardPageSetInfo>
    {
       public void execute(Event<UIWizardPageSetInfo> event) throws Exception
@@ -233,7 +405,7 @@
       public void execute(Event<UIWizardPageSetInfo> event) throws Exception
       {
          UIWizardPageSetInfo uiForm = event.getSource();
-         boolean isCheck = uiForm.getUIFormCheckBoxInput(SHOW_PUBLICATION_DATE).isChecked();
+         boolean isCheck = ((UIFormCheckBoxInput)uiForm.getUIInput(SHOW_PUBLICATION_DATE)).isChecked();
          uiForm.getUIFormDateTimeInput(START_PUBLICATION_DATE).setRendered(isCheck);
          uiForm.getUIFormDateTimeInput(END_PUBLICATION_DATE).setRendered(isCheck);
          UIWizard uiWizard = uiForm.getAncestorOfType(UIWizard.class);
@@ -248,10 +420,43 @@
       public void execute(Event<UIWizardPageSetInfo> event) throws Exception
       {
          UIWizardPageSetInfo uiForm = event.getSource();
-         boolean isCheck = uiForm.getUIFormCheckBoxInput(VISIBLE).isChecked();
+         boolean isCheck = ((UIFormCheckBoxInput)uiForm.getUIInput(VISIBLE)).isChecked();
          uiForm.setShowCheckPublicationDate(isCheck);
          event.getRequestContext().addUIComponentToUpdateByAjax(uiForm);
       }
    }
-
+   
+   /**
+    * Update the transient label from cache to I18N_LABEL field and add value in this field to the cached labels.
+    */
+   static public class ChangeLanguageActionListener extends EventListener<UIWizardPageSetInfo>
+   {
+      @Override
+      public void execute(Event<UIWizardPageSetInfo> event) throws Exception
+      {
+         UIWizardPageSetInfo uiForm = event.getSource();
+         UIFormSelectBox languageSelection = uiForm.getUIFormSelectBox(LANGUAGES);
+         UIFormStringInput label = uiForm.getUIStringInput(I18N_LABEL);
+         uiForm.updateCachedLabels(uiForm.selectedLocale, label.getValue());
+         
+         uiForm.selectedLocale = languageSelection.getValue();
+         label.setValue(uiForm.getLabelOnLocale(uiForm.selectedLocale));
+         event.getRequestContext().addUIComponentToUpdateByAjax(uiForm);
+      }
+   }
+   
+   /**
+    * Change between simple and extended mode of label.
+    */
+   static public class SwitchLabelModeActionListener extends EventListener<UIWizardPageSetInfo>
+   {
+      @Override
+      public void execute(Event<UIWizardPageSetInfo> event) throws Exception
+      {
+         UIWizardPageSetInfo uiForm = event.getSource();
+         boolean isExtendedMode = ((UIFormCheckBoxInput)uiForm.getUIInput(SWITCH_MODE)).isChecked();
+         uiForm.switchLabelMode(isExtendedMode);
+         event.getRequestContext().addUIComponentToUpdateByAjax(uiForm);
+      }
+   }
 }



More information about the gatein-commits mailing list