Index: t3lib/config_default.php
===================================================================
--- t3lib/config_default.php	(Revision 3041)
+++ t3lib/config_default.php	(Revision 3042)
@@ -175,7 +175,8 @@
 		'AJAX' => array(				// array of key-value pairs for a unified use of AJAX calls in the TYPO3 backend. Keys are the unique ajaxIDs where the value will be resolved to call a method in an object. See ajax.php and the classes/class.typo3ajax.php for more information.
 			'SC_alt_db_navframe::expandCollapse'   => 'typo3/alt_db_navframe.php:SC_alt_db_navframe->ajaxExpandCollapse',
 			'SC_alt_file_navframe::expandCollapse' => 'typo3/alt_file_navframe.php:SC_alt_file_navframe->ajaxExpandCollapse',
-			't3lib_TCEforms_inline::createNewRecord'		    => 't3lib/class.t3lib_tceforms_inline.php:t3lib_TCEforms_inline->processAjaxRequest',
+			't3lib_TCEforms_inline::createNewRecord'		=> 't3lib/class.t3lib_tceforms_inline.php:t3lib_TCEforms_inline->processAjaxRequest',
+			't3lib_TCEforms_inline::synchronizeLocalizeRecords'	=> 't3lib/class.t3lib_tceforms_inline.php:t3lib_TCEforms_inline->processAjaxRequest',
 			't3lib_TCEforms_inline::setExpandedCollapsedState'	=> 't3lib/class.t3lib_tceforms_inline.php:t3lib_TCEforms_inline->processAjaxRequest',
 			'ShortcutMenu::getGroups'              => 'typo3/classes/class.shortcutmenu.php:ShortcutMenu->getAjaxShortcutGroups',
 			'ShortcutMenu::saveShortcut'           => 'typo3/classes/class.shortcutmenu.php:ShortcutMenu->setAjaxShortcut',
Index: t3lib/class.t3lib_tceforms.php
===================================================================
--- t3lib/class.t3lib_tceforms.php	(Revision 3041)
+++ t3lib/class.t3lib_tceforms.php	(Revision 3042)
@@ -2,7 +2,7 @@
 /***************************************************************
 *  Copyright notice
 *
-*  (c) 1999-2006 Kasper Skaarhoj (kasperYYYY@typo3.com)
+*  (c) 1999-2008 Kasper Skaarhoj (kasperYYYY@typo3.com)
 *  All rights reserved
 *
 *  This script is part of the TYPO3 project. The TYPO3 project is
@@ -357,7 +357,7 @@
 			'check' => array('cols', 'showIfRTE'),
 			'select' => array('size', 'autoSizeMax', 'maxitems', 'minitems'),
 			'group' => array('size', 'autoSizeMax', 'max_size', 'show_thumbs', 'maxitems', 'minitems'),
-			'inline' => array('appearance', 'foreign_label', 'foreign_selector', 'foreign_unique', 'maxitems', 'minitems', 'size', 'autoSizeMax', 'symmetric_label'),
+			'inline' => array('appearance', 'behaviour', 'foreign_label', 'foreign_selector', 'foreign_unique', 'maxitems', 'minitems', 'size', 'autoSizeMax', 'symmetric_label'),
 		);
 
 			// Create instance of t3lib_TCEforms_inline only if this a non-IRRE-AJAX call: 
@@ -3150,19 +3150,21 @@
 			$dLVal = t3lib_BEfunc::getProcessedValue($table,$field,$this->defaultLanguageData[$table.':'.$row['uid']][$field],0,1);
 			$fCfg = $GLOBALS['TCA'][$table]['columns'][$field];
 
-			if (strcmp($dLVal,''))	{
-				$item.='<div class="typo3-TCEforms-originalLanguageValue">'.$this->getLanguageIcon($table,$row,0).$this->previewFieldValue($dLVal,$fCfg).'&nbsp;</div>';
-			}
+				// Don't show content if it's for IRRE child records:
+			if (isset($fCfg['config']['type']) && $fCfg['config']['type']!='inline') {
+				if (strcmp($dLVal,''))	{
+					$item.='<div class="typo3-TCEforms-originalLanguageValue">'.$this->getLanguageIcon($table,$row,0).$this->previewFieldValue($dLVal,$fCfg).'&nbsp;</div>';
+				}
 
-			$prLang = $this->getAdditionalPreviewLanguages();
-			foreach($prLang as $prL)	{
-				$dlVal = t3lib_BEfunc::getProcessedValue($table,$field,$this->additionalPreviewLanguageData[$table.':'.$row['uid']][$prL['uid']][$field],0,1);
+				$prLang = $this->getAdditionalPreviewLanguages();
+				foreach($prLang as $prL)	{
+					$dlVal = t3lib_BEfunc::getProcessedValue($table,$field,$this->additionalPreviewLanguageData[$table.':'.$row['uid']][$prL['uid']][$field],0,1);
 
-				if(strcmp($dlVal, '')) {
-					$item.= '<div class="typo3-TCEforms-originalLanguageValue">'.$this->getLanguageIcon($table, $row, 'v'.$prL['ISOcode']).$this->previewFieldValue($dlVal, $fCfg).'&nbsp;</div>';
+					if(strcmp($dlVal, '')) {
+						$item.= '<div class="typo3-TCEforms-originalLanguageValue">'.$this->getLanguageIcon($table, $row, 'v'.$prL['ISOcode']).$this->previewFieldValue($dlVal, $fCfg).'&nbsp;</div>';
+					}
 				}
 			}
-
 		}
 
 		return $item;
Index: t3lib/jsfunc.inline.js
===================================================================
--- t3lib/jsfunc.inline.js	(Revision 3041)
+++ t3lib/jsfunc.inline.js	(Revision 3042)
@@ -9,7 +9,7 @@
 *
 *  Copyright notice
 *
-*  (c) 2006-2007 Oliver Hader <oh@inpublica.de>
+*  (c) 2006-2008 Oliver Hader <oh@inpublica.de>
 *  All rights reserved
 *
 *  This script is part of the TYPO3 project. The TYPO3 project is
@@ -102,10 +102,10 @@
 		if (ucFormObj.length) ucFormObj[0].value = value;
 	},
 
-	createNewRecord: function(objectId,prevRecordUid) {
+	createNewRecord: function(objectId, recordUid) {
 		if (this.isBelowMax(objectId)) {
-			if (prevRecordUid) {
-				objectId += '['+prevRecordUid+']';
+			if (recordUid) {
+				objectId += '['+recordUid+']';
 			}
 			this.makeAjaxCall('createNewRecord', [this.getNumberOfRTE(), objectId], true);
 		} else {
@@ -114,6 +114,11 @@
 		return false;
 	},
 
+	synchronizeLocalizeRecords: function(objectId, type) {
+		var parameters = [this.getNumberOfRTE(), objectId, type];
+		this.makeAjaxCall('synchronizeLocalizeRecords', parameters, true);
+	},
+
 	setExpandedCollapsedState: function(objectId, expand, collapse) {
 		this.makeAjaxCall('setExpandedCollapsedState', [objectId, expand, collapse]);
 	},
@@ -597,18 +602,18 @@
 		if (this.data.unique && this.data.unique[objectPrefix]) {
 			var unique = this.data.unique[objectPrefix];
 			var fieldObj = elName ? document.getElementsByName(elName+'['+unique.field+']') : null;
-	
+
 			if (unique.type == 'select') {
 				if (fieldObj && fieldObj.length) {
 					delete(this.data.unique[objectPrefix].used[recordUid])
-	
+
 					if (unique.selector == 'select') {
 						if (!isNaN(fieldObj[0].value)) {
 							var selector = $(objectPrefix+'_selector');
 							this.readdSelectOption(selector, fieldObj[0].value, unique);
 						}
 					}
-	
+
 					if (!(unique.selector && unique.max == -1)) {
 						var formName = this.prependFormFieldNames+this.parseFormElementName('parts', objectPrefix, 3, 1);
 						var formObj = document.getElementsByName(formName);
@@ -646,7 +651,7 @@
 		return false;
 	},
 
-	deleteRecord: function(objectId) {
+	deleteRecord: function(objectId, options) {
 		var i, j, inlineRecords, records, childObjectId, childTable;
 		var objectPrefix = this.parseFormElementName('full', objectId, 0 , 1);
 		var elName = this.parseFormElementName('full', objectId, 2);
@@ -677,8 +682,8 @@
 		}
 
 			// If the record is new and was never saved before, just remove it from DOM:
-		if (this.isNewRecord(objectId)) {
-			new Effect.Fade(objectId+'_div', { afterFinish: function() { Element.remove(objectId+'_div'); }	});
+		if (this.isNewRecord(objectId) || options && options.forceDirectRemoval) {
+			this.fadeAndRemove(objectId+'_div');
 			// If the record already exists in storage, mark it to be deleted on clicking the save button:
 		} else {
 			document.getElementsByName('cmd'+shortName+'[delete]')[0].disabled = false;
@@ -879,6 +884,12 @@
   			md5 = this.data.config[objectPrefix].md5;
   		}
   		return md5
+  	},
+
+  	fadeAndRemove: function(element) {
+  		if ($(element)) {
+			new Effect.Fade(element, { afterFinish: function() { Element.remove(element); }	});
+		}
   	}
 }
 
Index: t3lib/class.t3lib_befunc.php
===================================================================
--- t3lib/class.t3lib_befunc.php	(Revision 3041)
+++ t3lib/class.t3lib_befunc.php	(Revision 3042)
@@ -441,6 +441,33 @@
 		return $outQ;
 	}
 
+	/**
+	 * Fetches the localization for a given record.
+	 *
+	 * @param	string		$table: Table name present in $TCA
+	 * @param	integer		$uid: The uid of the record
+	 * @param	ínteger		$language: The uid of the language record in sys_language
+	 * @param	string		$andWhereClause: Optional additional WHERE clause (default: '')
+	 * @return	mixed		Multidimensional array with selected records; if none exist, false is returned
+	 */
+	public function getRecordLocalization($table, $uid, $language, $andWhereClause='') {
+		$recordLocalization = false; 
+		if (isset($GLOBALS['TCA'][$table]['ctrl'])) {
+			$tcaCtrl =& $GLOBALS['TCA'][$table]['ctrl'];
+			if (isset($tcaCtrl['transOrigPointerField']) && isset($tcaCtrl['languageField'])) {
+				$recordLocalization = t3lib_BEfunc::getRecordsByField(
+					$table,
+					$tcaCtrl['transOrigPointerField'],
+					$uid,
+					'AND '.$tcaCtrl['languageField'].'='.intval($language).($andWhereClause ? ' '.$andWhereClause : ''),
+					'',
+					'',
+					'1'
+				);
+			}
+		}
+		return $recordLocalization;		
+	}
 
 
 
@@ -450,6 +477,7 @@
 
 
 
+
 	/*******************************************
 	 *
 	 * SQL-related, DEPRECATED functions
@@ -813,6 +841,47 @@
 	}
 
 	/**
+	 * Determines whether a table is localizable and has the languageField and transOrigPointerField set in $TCA.
+	 *
+	 * @param	string		$table: The table to check
+	 * @return	boolean		Whether a table is localizable
+	 */
+	public function isTableLocalizable($table) {
+		$isLocalizable = false;
+		if (isset($GLOBALS['TCA'][$table]['ctrl']) && is_array($GLOBALS['TCA'][$table]['ctrl'])) {
+			$tcaCtrl =& $GLOBALS['TCA'][$table]['ctrl'];
+			$isLocalizable = (isset($tcaCtrl['languageField']) && $tcaCtrl['languageField'] && isset($tcaCtrl['transOrigPointerField']) && $tcaCtrl['transOrigPointerField']);
+		}
+		return $isLocalizable;
+	}
+
+	/**
+	 * Returns the value of the property localizationMode in the given $config array ($TCA[<table>]['columns'][<field>]['config']).
+	 * If the table is prepared for localization and no localizationMode is set, 'select' is returned by default.
+	 * If the table is not prepared for localization or not defined at all in $TCA, false is returned.
+	 *
+	 * @param	string		$table: The name of the table to lookup in TCA
+	 * @param	mixed		$fieldOrConfig: The fieldname (string) or the configuration of the field to check (array) 
+	 * @return	mixed		If table is localizable, the set localizationMode is returned (if property is not set, 'select' is returned by default); if table is not localizable, false is returned 
+	 */
+	public function getInlineLocalizationMode($table, $fieldOrConfig) {
+		$localizationMode = false;
+		if (is_array($fieldOrConfig) && count($fieldOrConfig)) {	
+			$config = $fieldOrConfig;
+		} elseif (is_string($fieldOrConfig) && isset($GLOBALS['TCA'][$table]['columns'][$field]['config'])) {
+			$config = $GLOBALS['TCA'][$table]['columns'][$field]['config'];
+		}
+		if (is_array($config) && isset($config['type']) && $config['type']=='inline' && self::isTableLocalizable($table)) {
+			$localizationMode = (isset($config['behaviour']['localizationMode']) && $config['behaviour']['localizationMode'] ? $config['behaviour']['localizationMode'] : 'select');
+				// The mode 'select' is not possible when child table is not localizable at all:
+			if ($localizationMode=='select' && !self::isTableLocalizable($config['foreign_table'])) {
+				$localizationMode = false; 
+			}
+		}
+		return $localizationMode;
+	}
+
+	/**
 	 * Returns a page record (of page with $id) with an extra field "_thePath" set to the record path IF the WHERE clause, $perms_clause, selects the record. Thus is works as an access check that returns a page record if access was granted, otherwise not.
 	 * If $id is zero a pseudo root-page with "_thePath" set is returned IF the current BE_USER is admin.
 	 * In any case ->isInWebMount must return true for the user (regardless of $perms_clause)
Index: t3lib/class.t3lib_tceforms_inline.php
===================================================================
--- t3lib/class.t3lib_tceforms_inline.php	(Revision 3041)
+++ t3lib/class.t3lib_tceforms_inline.php	(Revision 3042)
@@ -2,7 +2,7 @@
 /***************************************************************
 *  Copyright notice
 *
-*  (c) 2006-2007 Oliver Hader <oh@inpublica.de>
+*  (c) 2006-2008 Oliver Hader <oh@inpublica.de>
 *  All rights reserved
 *
 *  This script is part of the TYPO3 project. The TYPO3 project is
@@ -141,7 +141,9 @@
 	 */
 	function getSingleField_typeInline($table,$field,$row,&$PA) {
 			// check the TCA configuration - if false is returned, something was wrong
-		if ($this->checkConfiguration($PA['fieldConf']['config']) === false) return false;
+		if ($this->checkConfiguration($PA['fieldConf']['config']) === false) {
+			return false;
+		}
 
 			// count the number of processed inline elements
 		$this->inlineCount++;
@@ -151,6 +153,9 @@
 		$foreign_table = $config['foreign_table'];
 		t3lib_div::loadTCA($foreign_table);
 
+		if (t3lib_BEfunc::isTableLocalizable($table)) {
+			$language = intval($row[$GLOBALS['TCA'][$table]['ctrl']['languageField']]);
+		}
 		$minitems = t3lib_div::intInRange($config['minitems'],0);
 		$maxitems = t3lib_div::intInRange($config['maxitems'],0);
 		if (!$maxitems)	$maxitems=100000;
@@ -186,10 +191,10 @@
 			// e.g. inline[<pid>][<table1>][<uid1>][<field1>][<table2>][<uid2>][<field2>]
 		$nameObject = $this->inlineNames['object'];
 			// get the records related to this inline record
-		$recordList = $this->getRelatedRecords($table,$field,$row,$PA,$config);
+		$relatedRecords = $this->getRelatedRecords($table,$field,$row,$PA,$config);
 			// set the first and last record to the config array
-		$config['inline']['first'] = $recordList[0]['uid'];
-		$config['inline']['last'] = $recordList[count($recordList)-1]['uid'];
+		$config['inline']['first'] = $relatedRecords['records'][0]['uid'];
+		$config['inline']['last'] = $relatedRecords['records'][$relatedRecords['count']-1]['uid'];
 
 			// Tell the browser what we have (using JSON later):
 		$top = $this->getStructureLevel(0);
@@ -214,7 +219,7 @@
 				// If uniqueness *and* selector are set, they should point to the same field - so, get the configuration of one:
 			$selConfig = $this->getPossibleRecordsSelectorConfig($config, $config['foreign_unique']);
 				// Get the used unique ids:
-			$uniqueIds = $this->getUniqueIds($recordList, $config, $selConfig['type']=='groupdb');
+			$uniqueIds = $this->getUniqueIds($relatedRecords['records'], $config, $selConfig['type']=='groupdb');
 			$possibleRecords = $this->getPossibleRecords($table,$field,$row,$config,'foreign_unique');
 			$uniqueMax = $config['appearance']['useCombination'] || $possibleRecords === false ? -1	: count($possibleRecords);
 			$this->inlineData['unique'][$nameObject.'['.$foreign_table.']'] = array(
@@ -244,27 +249,44 @@
 		$item .= '<div id="'.$nameObject.'">';
 
 			// define how to show the "Create new record" link - if there are more than maxitems, hide it
-		if (count($recordList) >= $maxitems || ($uniqueMax > 0 && count($recordList) >= $uniqueMax)) {
+		if ($relatedRecords['count'] >= $maxitems || ($uniqueMax > 0 && $relatedRecords['count'] >= $uniqueMax)) {
 			$config['inline']['inlineNewButtonStyle'] = 'display: none;';
 		}
-			// add the "Create new record" link before all child records
-		if (in_array($config['appearance']['newRecordLinkPosition'], array('both', 'top'))) {
-			$item .= $this->getNewRecordLink($nameObject.'['.$foreign_table.']', $config);
+
+			// Render the level links (create new record, localize all, synchronize):
+		if ($config['appearance']['levelLinksPosition']!='none') {
+			$levelLinks = $this->getLevelInteractionLink('newRecord', $nameObject.'['.$foreign_table.']', $config);
+			if ($language>0) {
+					// Add the "Localize all records" link before all child records:
+				if (isset($config['appearance']['showAllLocalizationLink']) && $config['appearance']['showAllLocalizationLink']) {
+					$levelLinks.= $this->getLevelInteractionLink('localize', $nameObject.'['.$foreign_table.']', $config);
+				} 
+					// Add the "Synchronize with default language" link before all child records:
+				if (isset($config['appearance']['showSynchronizationLink']) && $config['appearance']['showSynchronizationLink']) {
+					$levelLinks.= $this->getLevelInteractionLink('synchronize', $nameObject.'['.$foreign_table.']', $config);
+				}	
+			}
 		}
+			// Add the level links before all child records:
+		if (in_array($config['appearance']['levelLinksPosition'], array('both', 'top'))) {
+			$item.= $levelLinks;
+		}
 
 		$item .= '<div id="'.$nameObject.'_records">';
 		$relationList = array();
-		if (count($recordList)) {
-			foreach ($recordList as $rec) {
+		if (count($relatedRecords['records'])) {
+			foreach ($relatedRecords['records'] as $rec) {
 				$item .= $this->renderForeignRecord($row['uid'],$rec,$config);
-				$relationList[] = $rec['uid'];
+				if (!isset($rec['__virtual']) || !$rec['__virtual']) {
+					$relationList[] = $rec['uid'];
+				}
 			}
 		}
 		$item .= '</div>';
 
-			// add the "Create new record" link after all child records
-		if (in_array($config['appearance']['newRecordLinkPosition'], array('both', 'bottom'))) {
-			$item .= $this->getNewRecordLink($nameObject.'['.$foreign_table.']', $config);
+			// Add the level links after all child records:
+		if (in_array($config['appearance']['levelLinksPosition'], array('both', 'bottom'))) {
+			$item.= $levelLinks;
 		}
 
 			// add Drag&Drop functions for sorting to TCEforms::$additionalJS_post
@@ -307,21 +329,28 @@
 		$foreign_field = $config['foreign_field'];
 		$foreign_selector = $config['foreign_selector'];
 
+			// Register default localization content:
+		$parent = $this->getStructureLevel(-1);
+		if (isset($parent['localizationMode']) && $parent['localizationMode']!=false) {
+			$this->fObj->registerDefaultLanguageData($foreign_table, $rec);
+		}
 			// Send a mapping information to the browser via JSON:
 			// e.g. data[<curTable>][<curId>][<curField>] => data[<pid>][<parentTable>][<parentId>][<parentField>][<curTable>][<curId>][<curField>]
 		$this->inlineData['map'][$this->inlineNames['form']] = $this->inlineNames['object'];
 
 			// Set this variable if we handle a brand new unsaved record:
 		$isNewRecord = t3lib_div::testInt($rec['uid']) ? false : true;
+			// Set this variable if the record is virtual and only show with header and not editable fields:
+		$isVirtualRecord = (isset($rec['__virtual']) && $rec['__virtual']);
 			// If there is a selector field, normalize it:
 		if ($foreign_selector) {
 			$rec[$foreign_selector] = $this->normalizeUid($rec[$foreign_selector]);
 		}
 
-		$hasAccess = $this->checkAccess($isNewRecord?'new':'edit', $foreign_table, $rec['uid']);
+		if (!$this->checkAccess(($isNewRecord ? 'new' : 'edit'), $foreign_table, $rec['uid'])) {
+			return false;
+		}
 
-		if(!$hasAccess) return false;
-
 			// Get the current naming scheme for DOM name/id attributes:
 		$nameObject = $this->inlineNames['object'];
 		$appendFormFieldNames = '['.$foreign_table.']['.$rec['uid'].']';
@@ -329,31 +358,33 @@
 			// Put the current level also to the dynNestedStack of TCEforms:
 		$this->fObj->pushToDynNestedStack('inline', $this->inlineNames['object'].$appendFormFieldNames);
 
-		$header = $this->renderForeignRecordHeader($parentUid, $foreign_table, $rec, $config);
-		$combination = $this->renderCombinationTable($rec, $appendFormFieldNames, $config);
-		$fields = $this->renderMainFields($foreign_table, $rec);
-		$fields = $this->wrapFormsSection($fields);
+		$header = $this->renderForeignRecordHeader($parentUid, $foreign_table, $rec, $config, $isVirtualRecord);
+		if (!$isVirtualRecord) {
+			$combination = $this->renderCombinationTable($rec, $appendFormFieldNames, $config);
+			$fields = $this->renderMainFields($foreign_table, $rec);
+			$fields = $this->wrapFormsSection($fields);
 
-		if ($isNewRecord) {
-				// show this record expanded or collapsed
-			$isExpanded = is_array($config['appearance']) && $config['appearance']['collapseAll'] ? 1 : 0;
-				// get the top parent table
-			$top = $this->getStructureLevel(0);
-			$ucFieldName = 'uc['.$top['table'].']['.$top['uid'].']'.$appendFormFieldNames;
-				// set additional fields for processing for saving
-			$fields .= '<input type="hidden" name="'.$this->prependFormFieldNames.$appendFormFieldNames.'[pid]" value="'.$rec['pid'].'"/>';
-			$fields .= '<input type="hidden" name="'.$ucFieldName.'" value="'.$isExpanded.'" />';
+			if ($isNewRecord) {
+					// show this record expanded or collapsed
+				$isExpanded = is_array($config['appearance']) && $config['appearance']['collapseAll'] ? 1 : 0;
+					// get the top parent table
+				$top = $this->getStructureLevel(0);
+				$ucFieldName = 'uc['.$top['table'].']['.$top['uid'].']'.$appendFormFieldNames;
+					// set additional fields for processing for saving
+				$fields .= '<input type="hidden" name="'.$this->prependFormFieldNames.$appendFormFieldNames.'[pid]" value="'.$rec['pid'].'"/>';
+				$fields .= '<input type="hidden" name="'.$ucFieldName.'" value="'.$isExpanded.'" />';
 
-		} else {
-				// show this record expanded or collapsed
-			$isExpanded = $this->getExpandedCollapsedState($foreign_table, $rec['uid']);
-				// set additional field for processing for saving
-			$fields .= '<input type="hidden" name="'.$this->prependCmdFieldNames.$appendFormFieldNames.'[delete]" value="1" disabled="disabled" />';
+			} else {
+					// show this record expanded or collapsed
+				$isExpanded = $this->getExpandedCollapsedState($foreign_table, $rec['uid']);
+					// set additional field for processing for saving
+				$fields .= '<input type="hidden" name="'.$this->prependCmdFieldNames.$appendFormFieldNames.'[delete]" value="1" disabled="disabled" />';
+			}
+
+				// if this record should be shown collapsed
+			if (!$isExpanded) $appearanceStyleFields = ' style="display: none;"';
 		}
 
-			// if this record should be shown collapsed
-		if (!$isExpanded) $appearanceStyleFields = ' style="display: none;"';
-
 			// set the record container with data for output
 		$out = '<div id="'.$formFieldNames.'_header">'.$header.'</div>';
 		$out .= '<div id="'.$formFieldNames.'_fields"'.$appearanceStyleFields.'>'.$fields.$combination.'</div>';
@@ -400,9 +431,10 @@
 	 * @param	string		$foreign_table: The foreign_table we create a header for
 	 * @param	array		$rec: The current record of that foreign_table
 	 * @param	array		$config: content of $PA['fieldConf']['config']
+	 * @param	boolean		$isVirtualRecord: 
 	 * @return	string		The HTML code of the header
 	 */
-	function renderForeignRecordHeader($parentUid, $foreign_table, $rec, $config = array()) {
+	function renderForeignRecordHeader($parentUid, $foreign_table, $rec, $config, $isVirtualRecord=false) {
 			// Init:
 		$formFieldNames = $this->inlineNames['object'].'['.$foreign_table.']['.$rec['uid'].']';
 		$expandSingle = $config['appearance']['expandSingle'] ? 1 : 0;
@@ -453,19 +485,15 @@
 		}
 
 		$altText = t3lib_BEfunc::getRecordIconAltText($rec, $foreign_table);
-		$iconImg =
-			'<a href="#" onclick="'.htmlspecialchars($onClick).'">'.t3lib_iconWorks::getIconImage(
-				$foreign_table, $rec, $this->backPath,
-				'title="'.htmlspecialchars($altText).'" class="absmiddle"'
-			).'</a>';
+		$iconImg = t3lib_iconWorks::getIconImage($foreign_table, $rec, $this->backPath, 'title="'.htmlspecialchars($altText).'" class="absmiddle"');
+		$label = '<span id="'.$formFieldNames.'_label">'.$recTitle.'</span>';
+		if (!$isVirtualRecord) {
+			$iconImg = $this->wrapWithAnchor($iconImg, '#', array('onclick' => $onClick));
+			$label = $this->wrapWithAnchor($label, '#', array('onclick' => $onClick, 'style' => 'display: block;'));
+		}
 
-		$label =
-			'<a href="#" onclick="'.htmlspecialchars($onClick).'" style="display: block;">'.
-				'<span id="'.$formFieldNames.'_label">'.$recTitle.'</span>'.
-			'</a>';
+		$ctrl = $this->renderForeignRecordHeaderControl($parentUid, $foreign_table, $rec, $config, $isVirtualRecord);
 
-		$ctrl = $this->renderForeignRecordHeaderControl($parentUid, $foreign_table, $rec, $config);
-
 			// @TODO: Check the table wrapping and the CSS definitions
 		$header =
 			'<table cellspacing="0" cellpadding="0" border="0" width="100%" style="margin-right: '.$this->inlineStyles['margin-right'].'px;"'.
@@ -487,7 +515,7 @@
 	 * @param	array		$config: (modified) TCA configuration of the field
 	 * @return	string		The HTML code with the control-icons
 	 */
-	function renderForeignRecordHeaderControl($parentUid, $foreign_table, $rec, $config = array()) {
+	function renderForeignRecordHeaderControl($parentUid, $foreign_table, $rec, $config=array(), $isVirtualRecord=false) {
 			// Initialize:
 		$cells = array();
 		$isNewItem = substr($rec['uid'], 0, 3) == 'NEW';
@@ -518,14 +546,20 @@
 			// Icon to visualize that a required field is nested in this inline level:
 		$cells[] = '<img name="'.$nameObjectFtId.'_req" src="clear.gif" width="10" height="10" hspace="4" vspace="3" alt="" />';
 
+		if (isset($rec['__create'])) {
+			$cells[] = '<img'.t3lib_iconWorks::skinImg($this->backPath,'gfx/localize_green.gif','width="16" height="16"').' title="'.$GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_mod_web_list.xml:unHide'.($isPagesTable?'Page':''),1).'" alt="" />';
+		} elseif (isset($rec['__remove'])) {
+			$cells[] = '<img'.t3lib_iconWorks::skinImg($this->backPath,'gfx/localize_red.gif','width="16" height="16"').' title="'.$GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_mod_web_list.xml:unHide'.($isPagesTable?'Page':''),1).'" alt="" />';
+		}
+
 			// "Info": (All records)
-		if (!$isNewItem)
+		if (!$isNewItem) {
 			$cells[]='<a href="#" onclick="'.htmlspecialchars('top.launchView(\''.$foreign_table.'\', \''.$rec['uid'].'\'); return false;').'">'.
 				'<img'.t3lib_iconWorks::skinImg($this->backPath,'gfx/zoom2.gif','width="12" height="12"').' title="'.$GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_mod_web_list.xml:showInfo',1).'" alt="" />'.
 				'</a>';
-
+		}
 			// If the table is NOT a read-only table, then show these links:
-		if (!$tcaTableCtrl['readOnly'])	{
+		if (!$tcaTableCtrl['readOnly'] && !$isVirtualRecord)	{
 
 				// "New record after" link (ONLY if the records in the table are sorted by a "sortby"-row or if default values can depend on previous record):
 			if ($enableManualSorting || $tcaTableCtrl['useColumnsForDefaultValues'])	{
@@ -580,14 +614,20 @@
 			}
 
 				// "Delete" link:
-			if (
-				($isPagesTable && ($localCalcPerms&4)) || (!$isPagesTable && ($calcPerms&16))
-				)	{
+			if ($isPagesTable && $localCalcPerms&4 || !$isPagesTable && $calcPerms&16) {
 				$onClick = "inline.deleteRecord('".$nameObjectFtId."');";
 				$cells[]='<a href="#" onclick="'.htmlspecialchars('if (confirm('.$GLOBALS['LANG']->JScharCode($GLOBALS['LANG']->getLL('deleteWarning')).')) {	'.$onClick.' } return false;').'">'.
 						'<img'.t3lib_iconWorks::skinImg($this->backPath,'gfx/garbage.gif','width="11" height="12"').' title="'.$GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_mod_web_list.xml:delete',1).'" alt="" />'.
 						'</a>';
 			}
+			// If this is a virtual record offer a minimized set of icons for user interaction:
+		} elseif ($isVirtualRecord) {
+			if (isset($rec['__create'])) {
+				$onClick = "inline.synchronizeLocalizeRecords('".$nameObjectFt."', ".$rec['uid'].");";
+				$cells[] = '<a href="#" onclick="'.htmlspecialchars($onClick).'">' . 
+					'<img'.t3lib_iconWorks::skinImg($this->backPath,'gfx/localize_el.gif','width="16" height="16"').' title="'.$GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_misc.xml:localize', 1).'" alt="" />' .
+					'</a>';
+			}
 		}
 
 			// If the record is edit-locked	by another user, we will show a little warning sign:
@@ -783,35 +823,63 @@
 
 
 	/**
+	 * Creates the HTML code of a general link to be used on a level of inline children.
+	 * The possible keys for the parameter $type are 'newRecord', 'localize' and 'synchronize'.
+	 *
+	 * @param	string		$type: The link type, values are 'newRecord', 'localize' and 'synchronize'.
+	 * @param	string		$objectPrefix: The "path" to the child record to create (e.g. 'data[parten_table][parent_uid][parent_field][child_table]')
+	 * @param	array		$conf: TCA configuration of the parent(!) field
+	 * @return	string		The HTML code of the new link, wrapped in a div
+	 */
+	protected function getLevelInteractionLink($type, $objectPrefix, $conf=array()) {
+		$nameObject = $this->inlineNames['object'];
+		$attributes = array();
+		switch($type) {
+			case 'newRecord':
+				$title = $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xml:cm.createnew', 1);
+				$iconFile = 'gfx/new_el.gif';
+				// $iconAddon = 'width="11" height="12"';
+				$className = 'typo3-newRecordLink';
+				$attributes['class'] = 'inlineNewButton '.$this->inlineData['config'][$nameObject]['md5'];
+				$attributes['onclick'] = "return inline.createNewRecord('$objectPrefix')";
+				if (isset($conf['inline']['inlineNewButtonStyle']) && $conf['inline']['inlineNewButtonStyle']) {
+					$attributes['style'] = $conf['inline']['inlineNewButtonStyle'];
+				}
+				if (isset($conf['appearance']['newRecordLinkAddTitle']) && $conf['appearance']['newRecordLinkAddTitle']) {
+					$titleAddon = ' '.$GLOBALS['LANG']->sL($GLOBALS['TCA'][$conf['foreign_table']]['ctrl']['title'], 1);
+				}
+				break;
+			case 'localize':
+				$title = $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_misc.xml:localizeAllRecords', 1);
+				$iconFile = 'gfx/localize_el.gif';
+				$className = 'typo3-localizationLink';
+				$attributes['onclick'] = "return inline.synchronizeLocalizeRecords('$objectPrefix', 'localize')";
+				break;
+			case 'synchronize':
+				$title = $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_misc.xml:synchronizeWithOriginalLanguage', 1);
+				$iconFile = 'gfx/synchronize_el.gif';
+				$className = 'typo3-synchronizationLink';
+				$attributes['class'] = 'inlineNewButton '.$this->inlineData['config'][$nameObject]['md5'];
+				$attributes['onclick'] = "return inline.synchronizeLocalizeRecords('$objectPrefix', 'synchronize')";
+				break;
+		}
+			// Create the link:
+		$icon = ($iconFile ? '<img'.t3lib_iconWorks::skinImg($this->backPath, $iconFile, $iconAddon).' alt="'.htmlspecialchars($title.$titleAddon).'" />' : '');
+		$link = $this->wrapWithAnchor($icon.$title.$titleAddon, '#', $attributes);
+		return '<div'.($className ? ' class="'.$className.'"' : '').$link.'</div>';
+	}
+
+
+	/**
 	 * Creates a link/button to create new records
 	 *
 	 * @param	string		$objectPrefix: The "path" to the child record to create (e.g. '[parten_table][parent_uid][parent_field][child_table]')
 	 * @param	array		$conf: TCA configuration of the parent(!) field
 	 * @return	string		The HTML code for the new record link
+	 * @deprecated	since TYPO3 4.2.0-beta1
 	 */
 	function getNewRecordLink($objectPrefix, $conf = array()) {
-		$nameObject = $this->inlineNames['object'];
-		$class = ' class="inlineNewButton '.$this->inlineData['config'][$nameObject]['md5'].'"';
-
-		if ($conf['inline']['inlineNewButtonStyle']) {
-			$style = ' style="'.$conf['inline']['inlineNewButtonStyle'].'"';
-		}
-
-		$onClick = "return inline.createNewRecord('$objectPrefix')";
-		$title = $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:cm.createnew',1);
-
-		if ($conf['appearance']['newRecordLinkAddTitle']) {
-			$tableTitle .= ' '.$GLOBALS['LANG']->sL($GLOBALS['TCA'][$conf['foreign_table']]['ctrl']['title'],1);
-		}
-
-		$out = '
-				<div class="typo3-newRecordLink">
-					<a href="#" onClick="'.$onClick.'"'.$class.$style.' title="'.$title.$tableTitle.'">'.
-					'<img'.t3lib_iconWorks::skinImg($this->backPath,'gfx/new_el.gif','width="11" height="12"').' alt="'.$title.$tableTitle.'" />'.
-					$title.t3lib_div::fixed_lgd_cs($tableTitle, $this->fObj->titleLen).
-					'</a>
-				</div>';
-		return $out;
+		return $this->getLevelInteractionLink('newRecord', $objectPrefix, $conf);
 	}
 
 
@@ -851,7 +919,13 @@
 			$ajaxMethod = $ajaxIdParts[1];
 			switch ($ajaxMethod) {
 				case 'createNewRecord':
+				case 'synchronizeLocalizeRecords':
+					$this->isAjaxCall = true;
+						// Construct runtime environment for Inline Relational Record Editing:
 					$this->processAjaxRequestConstruct($ajaxArguments);
+						// Parse the DOM identifier (string), add the levels to the structure stack (array) and load the TCA config:
+					$this->parseStructureString($ajaxArguments[0], true);
+						// Render content:
 					$ajaxObj->setContentFormat('jsonbody');
 					$ajaxObj->setContent(
 						call_user_func_array(array(&$this, $ajaxMethod), $ajaxArguments)
@@ -924,6 +998,31 @@
 
 
 	/**
+	 * Determines and sets several script calls to a JSON array, that would have been executed if processed in non-AJAX mode.
+	 *
+	 * @param	array		&$jsonArray: Reference of the array to be used for JSON
+	 * @param	array		$config: The configuration of the IRRE field of the parent record
+	 * @return	void 
+	 */
+	protected function getCommonScriptCalls(&$jsonArray, $config) {
+			// Add data that would have been added at the top of a regular TCEforms call:
+		if ($headTags = $this->getHeadTags()) {
+			$jsonArray['headData'] = $headTags;
+		}
+			// Add the JavaScript data that would have been added at the bottom of a regular TCEforms call:
+		$jsonArray['scriptCall'][] = $this->fObj->JSbottom($this->fObj->formName, true);
+			// If script.aculo.us Sortable is used, update the Observer to know the record:
+		if ($config['appearance']['useSortable']) {
+			$jsonArray['scriptCall'][] = "inline.createDragAndDropSorting('".$this->inlineNames['object']."_records');";
+		}
+			// if TCEforms has some JavaScript code to be executed, just do it
+		if ($this->fObj->extJSCODE) {
+			$jsonArray['scriptCall'][] = $this->fObj->extJSCODE;
+		}
+	}
+
+
+	/**
 	 * Initialize environment for AJAX calls
 	 *
 	 * @param	string		$method: Name of the method to be called
@@ -948,9 +1047,6 @@
 	 * @return	array		An array to be used for JSON
 	 */
 	function createNewRecord($domObjectId, $foreignUid = 0) {
-		$this->isAjaxCall = true;
-			// parse the DOM identifier (string), add the levels to the structure stack (array) and load the TCA config
-		$this->parseStructureString($domObjectId, true);
 			// the current table - for this table we should add/import records
 		$current = $this->inlineStructure['unstable'];
 			// the parent table - this table embeds the current table
@@ -964,6 +1060,15 @@
 			// dynamically create a new record using t3lib_transferData
 		if (!$foreignUid || !t3lib_div::testInt($foreignUid) || $config['foreign_selector']) {
 			$record = $this->getNewRecord($this->inlineFirstPid, $current['table']);
+				// Set language of new child record to the language of the parent record:
+			if ($config['localizationMode']=='select') {
+				$parentRecord = $this->getRecord(0, $parent['table'], $parent['uid']);
+				$parentLanguageField = $GLOBALS['TCA'][$parent['table']]['ctrl']['languageField'];
+				$childLanguageField = $GLOBALS['TCA'][$current['table']]['ctrl']['languageField'];
+				if ($parentRecord[$languageField]>0) {
+					$record[$childLanguageField] = $parentRecord[$languageField];
+				}
+			}
 
 			// dynamically import an existing record (this could be a call from a select box)
 		} else {
@@ -1018,19 +1123,7 @@
 				)
 			);
 		}
-
-			// Add data that would have been added at the top of a regular TCEforms call:
-		if ($headTags = $this->getHeadTags()) {
-			$jsonArray['headData'] = $headTags;
-		}
-			// Add the JavaScript data that would have been added at the bottom of a regular TCEforms call:
-		$jsonArray['scriptCall'][] = $this->fObj->JSbottom($this->fObj->formName, true);
-			// if script.aculo.us Sortable is used, update the Observer to know the the record
-		if ($config['appearance']['useSortable'])
-			$jsonArray['scriptCall'][] = "inline.createDragAndDropSorting('".$this->inlineNames['object']."_records');";
-			// if TCEforms has some JavaScript code to be executed, just do it
-		if ($this->fObj->extJSCODE)
-			$jsonArray['scriptCall'][] = $this->fObj->extJSCODE;
+		$this->getCommonScriptCalls($jsonArray, $config);
 			// tell the browser to scroll to the newly created record
 		$jsonArray['scriptCall'][] = "Element.scrollTo('".$objectId."_div');";
 			// fade out and fade in the new record in the browser view to catch the user's eye
@@ -1045,6 +1138,94 @@
 
 
 	/**
+	 * Handle AJAX calls to localize all records of a parent, localize a single record or to synchronize with the original language parent.
+	 *
+	 * @param	string		$domObjectId: The calling object in hierarchy, that requested a new record.
+	 * @param	mixed		$type: Defines the type 'localize' or 'synchronize' (string) or a single uid to be localized (integer)
+	 * @return	array		An array to be used for JSON
+	 */
+	protected function synchronizeLocalizeRecords($domObjectId, $type) {
+		$jsonArray = false;
+		if (t3lib_div::inList('localize,synchronize', $type) || t3lib_div::testInt($type)) {
+				// The current level:
+			$current = $this->inlineStructure['unstable'];
+				// The parent level:
+			$parent = $this->getStructureLevel(-1);
+			$parentRecord = $this->getRecord(0, $parent['table'], $parent['uid']);
+
+			$cmd = array();
+			$cmd[$parent['table']][$parent['uid']]['inlineLocalizeSynchronize'] = $parent['field'].','.$type;
+
+			/* @var t3lib_TCEmain */
+			$tce = t3lib_div::makeInstance('t3lib_TCEmain');
+			$tce->stripslashes_values = false;
+			$tce->start(array(), $cmd);
+			$tce->process_cmdmap();
+			$newItemList = $tce->registerDBList[$parent['table']][$parent['uid']][$parent['field']];
+			unset($tce);
+
+			$jsonArray = $this->getExecuteChangesJsonArray($parentRecord[$parent['field']], $newItemList);
+			$this->getCommonScriptCalls($jsonArray, $parent['config']);
+		}
+		return $jsonArray;
+	}
+
+
+	/**
+	 * Generates a JSON array which executes the changes and thus updates the forms view.
+	 *
+	 * @param	string		$oldItemList: List of related child reocrds before changes were made (old)
+	 * @param	string		$newItemList: List of related child records after changes where made (new)
+	 * @return	array		An array to be used for JSON
+	 */
+	protected function getExecuteChangesJsonArray($oldItemList, $newItemList) {
+		$parent = $this->getStructureLevel(-1);
+		$current = $this->inlineStructure['unstable'];
+
+		$jsonArray = array('scriptCall' => array());
+		$jsonArrayScriptCall =& $jsonArray['scriptCall'];
+
+		$nameObject = $this->inlineNames['object'];
+		$nameObjectForeignTable = $nameObject.'['.$current['table'].']';
+			// Get the name of the field pointing to the original record:
+		$transOrigPointerField = $GLOBALS['TCA'][$current['table']]['ctrl']['transOrigPointerField'];
+			// Get the name of the field used as foreign selector (if any): 
+		$foreignSelector = (isset($parent['config']['foreign_selector']) && $parent['config']['foreign_selector'] ? $parent['config']['foreign_selector'] : false);
+			// Convert lists to array with uids of child records:
+		$oldItems = $this->getRelatedRecordsUidArray($oldItemList); 
+		$newItems = $this->getRelatedRecordsUidArray($newItemList);
+			// Determine the items that were localized or localized:
+		$removedItems = array_diff($oldItems, $newItems);
+		$localizedItems = array_diff($newItems, $oldItems);
+			// Set the items that should be removed in the forms view:
+		foreach ($removedItems as $item) {
+			$jsonArrayScriptCall[] = "inline.deleteRecord('".$nameObjectForeignTable.'['.$item.']'."', {forceDirectRemoval: true});";
+		}
+			// Set the items that should be added in the forms view:
+		foreach ($localizedItems as $item) {
+			$row = $this->getRecord($this->inlineFirstPid, $current['table'], $item);
+			$selectedValue = ($foreignSelector ? "'".$row[$foreignSelector]."'" : 'null');
+			$data.= $this->renderForeignRecord($parent['uid'], $row, $parent['config']);
+			$jsonArrayScriptCall[] = "inline.memorizeAddRecord('$nameObjectForeignTable', '".$item."', null, $selectedValue);";
+				// Remove possible virtual records in the form which showed that a child records could be localized:
+			if (isset($row[$transOrigPointerField]) && $row[$transOrigPointerField]) {
+				$jsonArrayScriptCall[] = "inline.fadeAndRemove('".$nameObjectForeignTable.'['.$row[$transOrigPointerField].']_div'."');";
+			}
+		}
+		if ($data) {
+			$data = $GLOBALS['LANG']->csConvObj->utf8_encode($data, $GLOBALS['LANG']->charSet);
+			$jsonArray['data'] = $data;
+			array_unshift(
+				$jsonArrayScriptCall,
+				"inline.domAddNewRecord('bottom', '".$nameObject."_records', '$nameObjectForeignTable', json.data);"
+			);
+		}
+
+		return $jsonArray;
+	}
+
+
+	/**
 	 * Save the expanded/collapsed state of a child record in the BE_USER->uc.
 	 *
 	 * @param	string		$domObjectId: The calling object in hierarchy, that requested a new record.
@@ -1095,31 +1276,133 @@
 
 	/**
 	 * Get the related records of the embedding item, this could be 1:n, m:n.
+	 * Returns an associative array with the keys records and count. 'count' contains only real existing records on the current parent record.
 	 *
 	 * @param	string		$table: The table name of the record
 	 * @param	string		$field: The field name which this element is supposed to edit
 	 * @param	array		$row: The record data array where the value(s) for the field can be found
 	 * @param	array		$PA: An array with additional configuration options.
 	 * @param	array		$config: (Redundant) content of $PA['fieldConf']['config'] (for convenience)
-	 * @return	array		The records related to the parent item
+	 * @return	array		The records related to the parent item as associative array.
 	 */
-	function getRelatedRecords($table,$field,$row,&$PA,$config) {
+	function getRelatedRecords($table, $field, $row, &$PA, $config) {
 		$records = array();
+		$pid = $row['pid'];
+		$elements = $PA['itemFormElValue'];
+		$foreignTable = $config['foreign_table'];
 
-			// Creating the label for the "No Matching Value" entry.
-		$nMV_label = isset($PA['fieldTSConfig']['noMatchingValue_label']) ? $this->fObj->sL($PA['fieldTSConfig']['noMatchingValue_label']) : '[ '.$this->fObj->getLL('l_noMatchingValue').' ]';
+		$localizationMode = t3lib_BEfunc::getInlineLocalizationMode($table, $config);
 
-			// Register the required number of elements:
-		# $this->fObj->requiredElements[$PA['itemFormElName']] = array($minitems,$maxitems,'imgName'=>$table.'_'.$row['uid'].'_'.$field);
+		if ($localizationMode!=false) {
+			$language = intval($row[$GLOBALS['TCA'][$table]['ctrl']['languageField']]);
+			$transOrigPointer = intval($row[$GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']]);
+			if ($language>0 && $transOrigPointer) {
+					// Localization in mode 'keep', isn't a real localization, but keeps the children of the original parent record:
+				if ($localizationMode=='keep') {
+					$transOrigRec = $this->getRecord(0, $table, $transOrigPointer);
+					$elements = $transOrigRec[$field];
+					$pid = $transOrigRec['pid'];
+					// Localization in modes 'select', 'all' or 'sync' offer a dynamic localization and synchronization with the original language record:
+				} elseif ($localizationMode=='select') {
+					$transOrigRec = $this->getRecord(0, $table, $transOrigPointer);
+					$pid = $transOrigRec['pid'];
+					$recordsOriginal = $this->getRelatedRecordsArray($pid, $foreignTable, $transOrigRec[$field]);
+				}
+			}
+		}
 
+		$records = $this->getRelatedRecordsArray($pid, $foreignTable, $elements);
+		$relatedRecords = array('records' => $records, 'count' => count($records));
+
+			// Merge original language with current localization and show differences:
+		if (is_array($recordsOriginal)) {
+			$options = array(
+				'showPossible' => (isset($config['appearance']['showPossibleLocalizationRecords']) && $config['appearance']['showPossibleLocalizationRecords']),
+				'showRemoved' => (isset($config['appearance']['showRemovedLocalizationRecords']) && $config['appearance']['showRemovedLocalizationRecords']),
+			);
+			if ($options['showPossible'] || $options['showRemoved']) {
+				$relatedRecords['records'] = $this->getLocalizationDifferences($foreignTable, $options, $recordsOriginal, $records); 
+			}
+		}
+
+		return $relatedRecords;
+	}
+
+
+	/**
+	 * Gets the related records of the embedding item, this could be 1:n, m:n.
+	 *
+	 * @param	integer		$pid: The pid of the parent record
+	 * @param	string		$table: The table name of the record
+	 * @param	string		$itemList: The list of related child records
+	 * @return	array		The records related to the parent item 
+	 */
+	protected function getRelatedRecordsArray($pid, $table, $itemList) {
+		$records = array();
+		$itemArray = $this->getRelatedRecordsUidArray($itemList);
 			// Perform modification of the selected items array:
-		$itemArray = t3lib_div::trimExplode(',',$PA['itemFormElValue'],1);
-		foreach($itemArray as $tk => $tv) {
-			$tvP = explode('|',$tv,2);
-				// get the records for this uid using t3lib_transferdata
-			$records[] = $this->getRecord($row['pid'], $config['foreign_table'], $tvP[0]);
+		foreach($itemArray as $uid) {
+				// Get the records for this uid using t3lib_transferdata:
+			$records[$uid] = $this->getRecord($pid, $table, $uid);
 		}
+		return $records;
+	}
 
+
+	/**
+	 * Gets an array with the uids of related records out of a list of items.
+	 * This list could contain more information than required. This methods just
+	 * extracts the uids.
+	 *
+	 * @param	string		$itemList: The list of related child records
+	 * @return	array		An array with uids 
+	 */
+	protected function getRelatedRecordsUidArray($itemList) {
+		$itemArray = t3lib_div::trimExplode(',', $itemList, 1);
+			// Perform modification of the selected items array:
+		foreach($itemArray as $key => &$value) {
+			$parts = explode('|', $value, 2);
+			$value = $parts[0];
+		}
+		return $itemArray;
+	}
+
+
+	/**
+	 * Gets the difference between current localized structure and the original language structure.
+	 * If there are records which once were localized but don't exist in the original version anymore, the record row is marked with '__remove'.
+	 * If there are records which can be localized and exist only in the original version, the record row is marked with '__create' and '__virtual'.
+	 *
+	 * @param	string		$table: The table name of the parent records
+	 * @param	array		$options: Options defining what kind of records to display
+	 * @param	array		$recordsOriginal: The uids of the child records of the original language
+	 * @param	array		$recordsLocalization: The uids of the child records of the current localization
+	 * @return	array		Merged array of uids of the child records of both versions
+	 */
+	protected function getLocalizationDifferences($table, array $options, array $recordsOriginal, array $recordsLocalization) {
+		$records = array();
+		$transOrigPointerField = $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField'];
+			// Compare original to localized version of the records:
+		foreach ($recordsLocalization as $uid => $row) {
+				// If the record points to a original translation which doesn't exist anymore, it could be removed: 
+			if (isset($row[$transOrigPointerField]) && $row[$transOrigPointerField]>0) {
+				$transOrigPointer = $row[$transOrigPointerField];
+				if (isset($recordsOriginal[$transOrigPointer])) {
+					unset($recordsOriginal[$transOrigPointer]);
+				} elseif ($options['showRemoved']) {
+					$row['__remove'] = true;
+				}
+			}
+			$records[$uid] = $row;
+		}
+			// Process the remaining records in the original unlocalized parent:
+		if ($options['showPossible']) {
+			foreach ($recordsOriginal as $uid => $row) {
+				$row['__create'] = true;
+				$row['__virtual'] = true;
+				$records[$uid] = $row;
+			}
+		}
 		return $records;
 	}
 
@@ -1145,16 +1428,16 @@
 		$foreignConfig = $this->getPossibleRecordsSelectorConfig($conf, $foreign_check);
 		$PA = $foreignConfig['PA'];
 		$config = $PA['fieldConf']['config'];
-		
+
 		if ($foreignConfig['type'] == 'select') {
 				// Getting the selector box items from the system
 			$selItems = $this->fObj->addSelectOptionsToItemArray($this->fObj->initItemArray($PA['fieldConf']),$PA['fieldConf'],$this->fObj->setTSconfig($table,$row),$field);
 			if ($config['itemsProcFunc']) $selItems = $this->fObj->procItems($selItems,$PA['fieldTSConfig']['itemsProcFunc.'],$config,$table,$row,$field);
-	
+
 				// Possibly remove some items:
 			$removeItems = t3lib_div::trimExplode(',',$PA['fieldTSConfig']['removeItems'],1);
 			foreach($selItems as $tk => $p)	{
-	
+
 					// Checking languages and authMode:
 				$languageDeny = $tcaTableCtrl['languageField'] && !strcmp($tcaTableCtrl['languageField'], $field) && !$GLOBALS['BE_USER']->checkLanguageAccess($p[1]);
 				$authModeDeny = $config['form_type']=='select' && $config['authMode'] && !$GLOBALS['BE_USER']->checkAuthMode($table,$field,$p[1],$config['authMode']);
@@ -1163,7 +1446,7 @@
 				} elseif (isset($PA['fieldTSConfig']['altLabels.'][$p[1]])) {
 					$selItems[$tk][0]=$this->fObj->sL($PA['fieldTSConfig']['altLabels.'][$p[1]]);
 				}
-	
+
 					// Removing doktypes with no access:
 				if ($table.'.'.$field == 'pages.doktype')	{
 					if (!($GLOBALS['BE_USER']->isAdmin() || t3lib_div::inList($GLOBALS['BE_USER']->groupData['pagetypes_select'],$p[1])))	{
@@ -1189,19 +1472,22 @@
 	function getUniqueIds($records, $conf=array(), $splitValue=false) {
 		$uniqueIds = array();
 
-		if ($conf['foreign_unique'] && count($records)) {
+		if (isset($conf['foreign_unique']) && $conf['foreign_unique'] && count($records)) {
 			foreach ($records as $rec) {
-				$value = $rec[$conf['foreign_unique']];
-					// Split the value and extract the table and uid:
-				if ($splitValue) {
-					$valueParts = t3lib_div::trimExplode('|', $value);
-					$itemParts = explode('_', $valueParts[0]);
-					$value = array(
-						'uid' => array_pop($itemParts),
-						'table' => implode('_', $itemParts)
-					);
+					// Skip virtual records (e.g. shown in localization mode):
+				if (!isset($rec['__virtual']) || !$rec['__virtual']) {
+					$value = $rec[$conf['foreign_unique']];
+						// Split the value and extract the table and uid:
+					if ($splitValue) {
+						$valueParts = t3lib_div::trimExplode('|', $value);
+						$itemParts = explode('_', $valueParts[0]);
+						$value = array(
+							'uid' => array_pop($itemParts),
+							'table' => implode('_', $itemParts)
+						);
+					}
+					$uniqueIds[$rec['uid']] = $value;
 				}
-				$uniqueIds[$rec['uid']] = $value;
 			}
 		}
 
@@ -1271,6 +1557,7 @@
 			'uid' => $uid,
 			'field' => $field,
 			'config' => $config,
+			'localizationMode' => t3lib_BEfunc::getInlineLocalizationMode($table, $config),
 		);
 		$this->updateStructureNames();
 	}
@@ -1377,10 +1664,10 @@
 	 *  - 'unstable': Containting partly filled data (e.g. only table and possibly field)
 	 *
 	 * @param	string		$domObjectId: The DOM object-id
-	 * @param	boolean		$loadConfig: Load the TCA configuration for that level
+	 * @param	boolean		$loadConfig: Load the TCA configuration for that level (default: true)
 	 * @return	void
 	 */
-	function parseStructureString($string, $loadConfig = false) {
+	function parseStructureString($string, $loadConfig=true) {
 		$unstable = array();
 		$vector = array('table', 'uid', 'field');
 		$pattern = '/^'.$this->prependNaming.'\[(.+?)\]\[(.+)\]$/';
@@ -1404,6 +1691,7 @@
 						if (!$TSconfig['disabled']) {
 							$unstable['config'] = $this->fObj->overrideFieldConf($unstable['config'], $TSconfig);
 						}
+						$unstable['localizationMode'] = t3lib_BEfunc::getInlineLocalizationMode($unstable['table'], $unstable['config']);
 					}
 					$this->inlineStructure['stable'][] = $unstable;
 					$unstable = array();
@@ -1427,6 +1715,9 @@
 	 * Does some checks on the TCA configuration of the inline field to render.
 	 *
 	 * @param	array		$config: Reference to the TCA field configuration
+	 * @param	string		$table: The table name of the record
+	 * @param	string		$field: The field name which this element is supposed to edit
+	 * @param	array		$row: The record data array of the parent
 	 * @return	boolean		If critical configuration errors were found, false is returned
 	 */
 	function checkConfiguration(&$config) {
@@ -1437,14 +1728,18 @@
 			return false;
 		}
 			// Init appearance if not set:
-		if (!is_array($config['appearance'])) {
+		if (!isset($config['appearance']) || !is_array($config['appearance'])) {
 			$config['appearance'] = array();
 		}
+			// 'newRecordLinkPosition' is deprecated since TYPO3 4.2.0-beta1, this is for backward compatibility: 
+		if (!isset($config['appearance']['levelLinksPosition']) && isset($config['appearance']['newRecordLinkPosition']) && $config['appearance']['newRecordLinkPosition']) {
+			$config['appearance']['levelLinksPosition'] = $config['appearance']['newRecordLinkPosition'];
+		}
 			// Set the position/appearance of the "Create new record" link:
-		if ($config['foreign_selector'] && !$config['appearance']['useCombination']) {
-			$config['appearance']['newRecordLinkPosition'] = 'none';
-		} elseif (!in_array($config['appearance']['newRecordLinkPosition'], array('top', 'bottom', 'both', 'none'))) {
-			$config['appearance']['newRecordLinkPosition'] = 'top';
+		if (isset($config['foreign_selector']) && $config['foreign_selector'] && (!isset($config['appearance']['useCombination']) || !$config['appearance']['useCombination'])) {
+			$config['appearance']['levelLinksPosition'] = 'none';
+		} elseif (!isset($config['appearance']['levelLinksPosition']) || !in_array($config['appearance']['levelLinksPosition'], array('top', 'bottom', 'both', 'none'))) {
+			$config['appearance']['levelLinksPosition'] = 'top';
 		}
 
 		return true;
@@ -1756,7 +2051,7 @@
 		$type = false;
 		$table = false;
 		$selector = false;
-		
+
 		if ($field) {
 			$PA = array();
 			$PA['fieldConf'] = $GLOBALS['TCA'][$foreign_table]['columns'][$field];
@@ -1772,7 +2067,7 @@
 				$selector = $type;
 			}
 		}
-		
+
 		return array(
 			'PA' => $PA,
 			'type' => $type,
@@ -1780,8 +2075,8 @@
 			'selector' => $selector,
 		);
 	}
-	
 
+
 	/**
 	 * Determine the type of a record selector, e.g. select or group/db.
 	 *
@@ -1797,8 +2092,8 @@
 		}
 		return $type;
 	}
-	
-	
+
+
 	/**
 	 * Check, if a field should be skipped, that was defined to be handled as foreign_field or foreign_sortby of
 	 * the parent record of the "inline"-type - if so, we have to skip this field - the rendering is done via "inline" as hidden field
@@ -1963,6 +2258,25 @@
 
 		return $headTags;
 	}
+
+
+	/**
+	 * Wraps a text with an anchor and returns the HTML representation.
+	 *
+	 * @param	string		$text: The text to be wrapped by an anchor
+	 * @param	string		$link: The link to be used in the anchor 
+	 * @param	array		$attributes: Array of attributes to be used in the anchor
+	 * @return	string		The wrapped texted as HTML representation
+	 */
+	protected function wrapWithAnchor($text, $link, $attributes=array()) {
+		$link = trim($link);
+		$result = '<a href="'.($link ? $link : '#').'"';
+		foreach ($attributes as $key => $value) {
+			$result.= ' '.$key.'="'.htmlspecialchars(trim($value)).'"';
+		}
+		$result.= '>'.$text.'</a>';
+		return $result;
+	}
 }
 
 
Index: t3lib/class.t3lib_tcemain.php
===================================================================
--- t3lib/class.t3lib_tcemain.php	(Revision 3041)
+++ t3lib/class.t3lib_tcemain.php	(Revision 3042)
@@ -2,7 +2,7 @@
 /***************************************************************
 *  Copyright notice
 *
-*  (c) 1999-2007 Kasper Skaarhoj (kasperYYYY@typo3.com)
+*  (c) 1999-2008 Kasper Skaarhoj (kasperYYYY@typo3.com)
 *  All rights reserved
 *
 *  This script is part of the TYPO3 project. The TYPO3 project is
@@ -1748,7 +1748,7 @@
 				$arrValue = t3lib_div::array_merge_recursive_overrule($currentValueArray,$arrValue);
 				$xmlValue = $this->checkValue_flexArray2Xml($arrValue,TRUE);
 			}
-		
+
 				// Action commands (sorting order and removals of elements)
 			$actionCMDs = t3lib_div::_GP('_ACTION_FLEX_FORMdata');
 			if (is_array($actionCMDs[$table][$id][$field]['data']))	{
@@ -1825,7 +1825,7 @@
 	 * @return	array		Modified $res array
 	 */
 	function checkValue_inline($res,$value,$tcaFieldConf,$PP,$field)	{
-		list($table,$id,$curValue,$status,$realPid,$recFID) = $PP;
+		list($table, $id, $curValue, $status, $realPid, $recFID) = $PP;
 
 		if (!$tcaFieldConf['foreign_table'])	{
 			return false;	// Fatal error, inline fields should always have a foreign_table defined
@@ -1843,17 +1843,14 @@
 		if(strpos($value, 'NEW') !== false || !t3lib_div::testInt($id)) {
 			$this->remapStackRecords[$table][$id] = array('remapStackIndex' => count($this->remapStack));
 			$this->remapStack[] = array(
-				'func' => 'checkValue_group_select_processDBdata',
-				'args' => array($valueArray,$tcaFieldConf,$id,$status,'inline',$table),
-				'pos' => array('valueArray' => 0, 'tcaFieldConf' => 1, 'id' => 2, 'table' => 5),
+				'func' => 'checkValue_inline_processDBdata',
+				'args' => array($valueArray, $tcaFieldConf, $id, $status, $table, $field),
+				'pos' => array('valueArray' => 0, 'tcaFieldConf' => 1, 'id' => 2, 'table' => 4),
 				'field' => $field
 			);
 			unset($res['value']);
 		} elseif($value || t3lib_div::testInt($id)) {
-			$newValueArray = $this->checkValue_group_select_processDBdata($valueArray,$tcaFieldConf,$id,$status,'inline', $table);
-				// Checking that the number of items is correct
-			$newVal = $this->checkValue_checkMax($tcaFieldConf, $newValueArray);
-			$res['value'] = implode(',',$newVal);
+			$res['value'] = $this->checkValue_inline_processDBdata($valueArray, $tcaFieldConf, $id, $status, $table, $field);
 		}
 
 		return $res;
@@ -2068,20 +2065,6 @@
 				$this->dbAnalysisStore[] = array($dbAnalysis,$tcaFieldConf['MM'],$id,$prep,$currentTable);	// This will be traversed later to execute the actions
 			}
 			$valueArray = $dbAnalysis->countItems();
-		} elseif ($type == 'inline') {
-			if ($tcaFieldConf['foreign_field']) {
-					// if the record was imported, sorting was also imported, so skip this
-				$skipSorting = $this->callFromImpExp ? true : false;
-					// update record in intermediate table (sorting & pointer uid to parent record)
-				$dbAnalysis->writeForeignField($tcaFieldConf, $id, 0, $skipSorting);
-				$valueArray = $dbAnalysis->countItems();
-			} else {
-				$valueArray = $dbAnalysis->getValueArray($prep);
-				if ($prep) {
-						// @TODO: Do we want to support relations to multiple tables in Comma Separated Lists?
-					$valueArray = $dbAnalysis->convertPosNeg($valueArray,$tcaFieldConf['foreign_table'],$tcaFieldConf['neg_foreign_table']);
-				}
-			}
 		} else {
 			$valueArray = $dbAnalysis->getValueArray($prep);
 			if ($type=='select' && $prep)	{
@@ -2312,8 +2295,66 @@
 		}
 	}
 
+	/**
+	 * Returns data for inline fields.
+	 *
+	 * @param	array		Current value array
+	 * @param	array		TCA field config
+	 * @param	integer		Record id
+	 * @param	string		Status string ('update' or 'new')
+	 * @param	string		Table name, needs to be passed to t3lib_loadDBGroup
+	 * @param	string		The current field the values are modified for
+	 * @return	string		Modified values
+	 */
+	protected function checkValue_inline_processDBdata($valueArray, $tcaFieldConf, $id, $status, $table, $field)	{
+		$newValue = '';
+		$foreignTable = $tcaFieldConf['foreign_table'];
 
+		/*
+		 * Fetch the related child records by using t3lib_loadDBGroup:
+		 * @var $dbAnalysis t3lib_loadDBGroup
+		 */
+		$dbAnalysis = t3lib_div::makeInstance('t3lib_loadDBGroup');
+		$dbAnalysis->start(implode(',', $valueArray), $foreignTable, '', 0, $table, $tcaFieldConf);
+			// If the localizazionMode is set to 'keep', the children for the localized parent are kept as in the original untranslated record:
+		$localizationMode = t3lib_BEfunc::getInlineLocalizationMode($table, $tcaFieldConf);
+		if ($localizationMode=='keep' && $status=='update') {
+				// Fetch the current record and determine the original record:
+			$row = t3lib_BEfunc::getRecordWSOL($table, $id);
+			if (is_array($row)) {
+				$language = intval($row[$GLOBALS['TCA'][$table]['ctrl']['languageField']]);
+				$transOrigPointer = intval($row[$GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']]);
+					// If language is set (e.g. 1) and also transOrigPointer (e.g. 123), use transOrigPointer as uid:
+				if ($language>0 && $transOrigPointer) {
+					$id = $transOrigPointer;
+						// If we're in active localizationMode 'keep', prevent from writing data to the field of the parent record:
+						// (on removing the localized parent, the original (untranslated) children would then also be removed)
+					$keepTranslation = true;
+				}
+			}
+		}
+			// IRRE with a pointer field (database normalization): 
+		if ($tcaFieldConf['foreign_field']) {
+				// if the record was imported, sorting was also imported, so skip this
+			$skipSorting = ($this->callFromImpExp ? true : false);
+				// update record in intermediate table (sorting & pointer uid to parent record)
+			$dbAnalysis->writeForeignField($tcaFieldConf, $id, 0, $skipSorting);
+			$newValue = ($keepTranslation ? 0 : $dbAnalysis->countItems(false));
+			// IRRE with comma separated values:
+		} else {
+			$valueArray = $dbAnalysis->getValueArray();
+				// Checking that the number of items is correct:
+			$valueArray = $this->checkValue_checkMax($tcaFieldConf, $valueArray);
+				// If a valid translation of the 'keep' mode is active, update relations in the original(!) record:
+			if ($keepTranslation) {
+				$this->updateDB($table, $transOrigPointer, array($field => implode(',', $valueArray)));
+			} else {
+				$newValue = implode(',', $valueArray);
+			}
+		}
 
+		return $newValue;
+	}
 
 
 
@@ -2328,6 +2369,7 @@
 
 
 
+
 	/*********************************************
 	 *
 	 * PROCESSING COMMANDS
@@ -2407,6 +2449,9 @@
 							case 'localize':
 								$this->localize($table,$id,$value);
 							break;
+							case 'inlineLocalizeSynchronize':
+								$this->inlineLocalizeSynchronize($table, $id, $value);
+							break;
 							case 'version':
 								switch ((string)$value['action'])	{
 									case 'new':
@@ -2536,9 +2581,10 @@
 	 * @param	boolean		$first is a flag set, if the record copied is NOT a 'slave' to another record copied. That is, if this record was asked to be copied in the cmd-array
 	 * @param	array		Associative array with field/value pairs to override directly. Notice; Fields must exist in the table record and NOT be among excluded fields!
 	 * @param	string		Commalist of fields to exclude from the copy process (might get default values)
+	 * @param	integer		Language ID (from sys_language table)
 	 * @return	integer		ID of new record, if any
 	 */
-	function copyRecord($table,$uid,$destPid,$first=0,$overrideValues=array(),$excludeFields='')	{
+	function copyRecord($table, $uid, $destPid, $first=0, $overrideValues=array(), $excludeFields='', $language=0) {
 		global $TCA;
 
 		$uid = $origUid = intval($uid);
@@ -2607,7 +2653,7 @@
 									$value = $this->getCopyHeader($table,$this->resolvePid($table,$destPid),$field,$this->clearPrefixFromValue($table,$value),0);
 								}
 									// Processing based on the TCA config field type (files, references, flexforms...)
-								$value = $this->copyRecord_procBasedOnFieldType($table,$uid,$field,$value,$row,$conf,$tscPID);
+								$value = $this->copyRecord_procBasedOnFieldType($table, $uid, $field, $value, $row, $conf, $tscPID, $language);
 							}
 
 								// Add value to array.
@@ -2895,11 +2941,12 @@
 	 * @param	array		Record array
 	 * @param	array		TCA field configuration
 	 * @param	integer		Real page id (pid) the record is copied to
+	 * @param	integer		Language ID (from sys_language table)
 	 * @return	mixed		Processed value. Normally a string/integer, but can be an array for flexforms!
 	 * @access private
 	 * @see copyRecord()
 	 */
-	function copyRecord_procBasedOnFieldType($table,$uid,$field,$value,$row,$conf,$realDestPid) {
+	function copyRecord_procBasedOnFieldType($table, $uid, $field, $value, $row, $conf, $realDestPid, $language=0) {
 		global $TCA;
 
 			// Process references and files, currently that means only the files, prepending absolute paths (so the TCEmain engine will detect the file as new and one that should be made into a copy)
@@ -2910,10 +2957,23 @@
 		if ($this->isReferenceField($conf) || $inlineSubType == 'mm')	{
 			$allowedTables = $conf['type']=='group' ? $conf['allowed'] : $conf['foreign_table'].','.$conf['neg_foreign_table'];
 			$prependName = $conf['type']=='group' ? $conf['prepend_tname'] : $conf['neg_foreign_table'];
-			if ($conf['MM'])	{
+			$localizeReferences = (isset($conf['foreign_table']) && t3lib_BEfunc::isTableLocalizable($conf['foreign_table']) && isset($conf['localizeReferencesAtParentLocalization']) && $conf['localizeReferencesAtParentLocalization']);
+			if ($conf['MM'] || $language>0 && $localizeReferences) {
 				$dbAnalysis = t3lib_div::makeInstance('t3lib_loadDBGroup');
 				/* @var $dbAnalysis t3lib_loadDBGroup */
-				$dbAnalysis->start('', $allowedTables, $conf['MM'], $uid, $table, $conf);
+				$dbAnalysis->start($value, $allowedTables, $conf['MM'], $uid, $table, $conf);
+				if (!$conf['MM']) {
+						// Localize referenced records of select fields:
+					foreach ($dbAnalysis->itemArray as $index => $item) {
+							// Since select fields can reference many records, check whether there's already a localization:
+						$recordLocalization = t3lib_BEfunc::getRecordLocalization($item['table'], $item['id'], $language);
+						if (!$recordLocalization) {
+							$dbAnalysis->itemArray[$index]['id'] = $this->localize($item['table'], $item['id'], $language);
+						} else {
+							$dbAnalysis->itemArray[$index]['id'] = $recordLocalization[0]['uid'];
+						}
+					}
+				}
 				$value = implode(',',$dbAnalysis->getValueArray($prependName));
 			}
 			if ($value)	{	// Setting the value in this array will notify the remapListedDBRecords() function that this field MAY need references to be corrected
@@ -2922,34 +2982,54 @@
 
 			// If another inline subtype is used (comma-separated-values or the foreign_field property):
 		} elseif ($inlineSubType !== false) {
-			$dbAnalysis = t3lib_div::makeInstance('t3lib_loadDBGroup');
-			/* @var $dbAnalysis t3lib_loadDBGroup */
-			$dbAnalysis->start($value, $conf['foreign_table'], '', $uid, $table, $conf);
+				// Get the localization mode for the current (parent) record (keep|select|all):
+			$localizazionMode = t3lib_BEfunc::getInlineLocalizationMode($table, $field);
+				// Localization in mode 'keep', isn't a real localization, but keeps the children of the original parent record:
+			if ($language>0 && $localizazionMode=='keep') {
+				$value = ($inlineSubType=='field' ? 0 : '');
+				// Execute copy or localization actions:
+			} else {
+				/*
+				 * Fetch the related child records by using t3lib_loadDBGroup:
+				 * @var $dbAnalysis t3lib_loadDBGroup
+				 */
+				$dbAnalysis = t3lib_div::makeInstance('t3lib_loadDBGroup');
+				$dbAnalysis->start($value, $conf['foreign_table'], '', $uid, $table, $conf);
 
-				// walk through the items, copy them and remember the new id
-			foreach ($dbAnalysis->itemArray as $k => $v) {
-				if (!t3lib_div::testInt($realDestPid)) {
-					$newId = $this->copyRecord($v['table'], $v['id'], -$v['id']);
-				} elseif ($realDestPid == -1) {
-					$newId = $this->versionizeRecord($v['table'], $v['id'], 'Auto-created for WS #'.$this->BE_USER->workspace);
-				} else {
-					$newId = $this->copyRecord_raw($v['table'], $v['id'], $realDestPid);
-				}
+					// Walk through the items, copy them and remember the new id:
+				foreach ($dbAnalysis->itemArray as $k => $v) {
+						// If language is set, this isn't a copy action but a localization of our parent/ancestor:
+					if ($language>0) {
+							// If children should be localized when the parent gets localized the first time, just do it:
+						if ($localizazionMode!=false && isset($conf['behaviour']['localizeChildrenAtParentLocalization']) && $conf['behaviour']['localizeChildrenAtParentLocalization']) {
+							$newId = $this->localize($v['table'], $v['id'], $language);
+						}
+						// If no language it set, this is a regular copy action:
+					} else {
+						if (!t3lib_div::testInt($realDestPid)) {
+							$newId = $this->copyRecord($v['table'], $v['id'], -$v['id']);
+						} elseif ($realDestPid == -1) {
+							$newId = $this->versionizeRecord($v['table'], $v['id'], 'Auto-created for WS #'.$this->BE_USER->workspace);
+						} else {
+							$newId = $this->copyRecord_raw($v['table'], $v['id'], $realDestPid);
+						}
+					}
 
-					// If the current field is set on a page record, update the pid of related child records:
-				if ($table == 'pages') {
-					$this->registerDBPids[$v['table']][$v['id']] = $uid;
-					// If the current field has ancestors that have a field on a page record, update the pid of related child records:
-				} elseif (isset($this->registerDBPids[$table][$uid])) {
-					$this->registerDBPids[$v['table']][$v['id']] = $this->registerDBPids[$table][$uid];
+						// If the current field is set on a page record, update the pid of related child records:
+					if ($table == 'pages') {
+						$this->registerDBPids[$v['table']][$v['id']] = $uid;
+						// If the current field has ancestors that have a field on a page record, update the pid of related child records:
+					} elseif (isset($this->registerDBPids[$table][$uid])) {
+						$this->registerDBPids[$v['table']][$v['id']] = $this->registerDBPids[$table][$uid];
+					}
+
+					$dbAnalysis->itemArray[$k]['id'] = $newId;
 				}
 
-				$dbAnalysis->itemArray[$k]['id'] = $newId;
+					// Store the new values, we will set up the uids for the subtype later on (exception keep localization from original record):
+				$value = implode(',',$dbAnalysis->getValueArray());
+				$this->registerDBList[$table][$uid][$field] = $value;
 			}
-
-				// store the new values, we will set up the uids for the subtype later on
-			$value = implode(',',$dbAnalysis->getValueArray());
-			$this->registerDBList[$table][$uid][$field] = $value;
 		}
 
 			// For "flex" fieldtypes we need to traverse the structure for two reasons: If there are file references they have to be prepended with absolute paths and if there are database reference they MIGHT need to be remapped (still done in remapListedDBRecords())
@@ -3522,11 +3602,12 @@
 	 * @param	string		Table name
 	 * @param	integer		Record uid (to be localized)
 	 * @param	integer		Language ID (from sys_language table)
-	 * @return	void
+	 * @return	mixed		The uid (integer) of the new translated record or false (boolean) if something went wrong
 	 */
-	function localize($table,$uid,$language)	{
+	function localize($table, $uid, $language) {
 		global $TCA;
 
+		$newId = false;
 		$uid = intval($uid);
 
 		if ($TCA[$table] && $uid)	{
@@ -3545,7 +3626,7 @@
 										$Ttable = 'pages_language_overlay';
 										t3lib_div::loadTCA($Ttable);
 									} else {
-										$pass = !t3lib_BEfunc::getRecordsByField($table,$TCA[$table]['ctrl']['transOrigPointerField'],$uid,'AND pid='.intval($row['pid']).' AND '.$TCA[$table]['ctrl']['languageField'].'='.intval($langRec['uid']));
+										$pass = !t3lib_BEfunc::getRecordLocalization($table, $uid, $langRec['uid'], 'AND pid='.intval($row['pid']));
 										$Ttable = $table;
 									}
 
@@ -3583,7 +3664,7 @@
 										if ($Ttable === $table)	{
 
 												// Execute the copy:
-											$this->copyRecord($table,$uid,-$uid,1,$overrideValues,implode(',',$excludeFields));
+											$newId = $this->copyRecord($table, $uid, -$uid, 1, $overrideValues, implode(',', $excludeFields), $language);
 										} else {
 
 												// Create new record:
@@ -3601,6 +3682,7 @@
 											if ($theNewSQLID)	{
 													// If is by design that $Ttable is used and not $table! See "l10nmgr" extension. Could be debated, but this is what I chose for this "pseudo case"
 												$this->copyMappingArray[$Ttable][$uid] = $theNewSQLID;
+												$newId = $theNewSQLID;
 											}
 										}
 									} else $this->newlog('Localization failed; There already was a localization for this language of the record!',1);
@@ -3611,13 +3693,106 @@
 				} else $this->newlog('Sys language UID "'.$language.'" not found valid!',1);
 			} else $this->newlog('Localization failed; "languageField" and "transOrigPointerField" must be defined for the table!',1);
 		}
+		return $newId;
 	}
 
 
+	/**
+	 * Performs localization or synchronization of child records.
+	 *
+	 * @param	string		$table: The table of the localized parent record
+	 * @param	integer		$id: The uid of the localized parent record
+	 * @param	mixed		$command: Defines the type 'localize' or 'synchronize' (string) or a single uid to be localized (integer)
+	 * @return	void
+	 */
+	protected function inlineLocalizeSynchronize($table, $id, $command) {
+			// <field>, (localize | synchronize | <uid>): 
+		$parts = t3lib_div::trimExplode(',', $command);
+		$field = $parts[0];
+		$type = $parts[1];
 
+		if ($field && (t3lib_div::inList('localize,synchronize', $type) || t3lib_div::testInt($type)) && isset($GLOBALS['TCA'][$table]['columns'][$field]['config'])) {
+			$config = $GLOBALS['TCA'][$table]['columns'][$field]['config'];
+			$foreignTable = $config['foreign_table'];
+			$localizationMode = t3lib_BEfunc::getInlineLocalizationMode($table, $config);
 
+			if ($localizationMode=='select') {
+				$parentRecord = t3lib_BEfunc::getRecordWSOL($table, $id);
+				$language = intval($parentRecord[$GLOBALS['TCA'][$table]['ctrl']['languageField']]);
+				$transOrigPointer = intval($parentRecord[$GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']]);
+				$childTransOrigPointerField = $GLOBALS['TCA'][$foreignTable]['ctrl']['transOrigPointerField'];
 
+				if ($parentRecord && is_array($parentRecord) && $language>0 && $transOrigPointer) {
+					$inlineSubType = $this->getInlineFieldType($config);
+					$transOrigRecord = t3lib_BEfunc::getRecordWSOL($table, $transOrigPointer);
 
+					if ($inlineSubType!==false) {
+						$removeArray = array();
+							// Fetch children from original language parent:
+							// @var $dbAnalysisOriginal t3lib_loadDBGroup
+						$dbAnalysisOriginal = t3lib_div::makeInstance('t3lib_loadDBGroup');
+						$dbAnalysisOriginal->start($transOrigRecord[$field], $foreignTable, '', $transOrigRecord['uid'], $table, $config);
+						$elementsOriginal = array();
+						foreach ($dbAnalysisOriginal->itemArray as $item) {
+							$elementsOriginal[$item['id']] = $item;
+						}
+						unset($dbAnalysisOriginal);
+							// Fetch children from current localized parent:
+							// @var $dbAnalysisCurrent t3lib_loadDBGroup
+						$dbAnalysisCurrent = t3lib_div::makeInstance('t3lib_loadDBGroup');
+						$dbAnalysisCurrent->start($parentRecord[$field], $foreignTable, '', $id, $table, $config);
+							// Perform synchronization: Possibly removal of already localized records:
+						if ($type=='synchronize') {
+							foreach ($dbAnalysisCurrent->itemArray as $index => $item) {
+								$childRecord = t3lib_BEfunc::getRecordWSOL($item['table'], $item['id']);
+								if (isset($childRecord[$childTransOrigPointerField]) && $childRecord[$childTransOrigPointerField]>0) {
+									$childTransOrigPointer = $childRecord[$childTransOrigPointerField];
+										// If snychronization is requested, child record was translated once, but original record does not exist anymore, remove it:
+									if (!isset($elementsOriginal[$childTransOrigPointer])) {
+										unset($dbAnalysisCurrent->itemArray[$index]);
+										$removeArray[$item['table']][$item['id']]['delete'] = 1;
+									}
+								}
+							}
+						}
+							// Perform synchronization/localization: Possibly add unlocalized records for original language: 
+						if (t3lib_div::testInt($type) && isset($elementsOriginal[$type])) {
+							$item = $elementsOriginal[$type];
+							$item['id'] = $this->localize($item['table'], $item['id'], $language);
+							$dbAnalysisCurrent->itemArray[] = $item; 
+						} elseif (t3lib_div::inList('localize,synchronize', $type)) {
+							foreach ($elementsOriginal as $originalId => $item) {
+								$item['id'] = $this->localize($item['table'], $item['id'], $language);
+								$dbAnalysisCurrent->itemArray[] = $item; 
+							}
+						}
+							// Store the new values, we will set up the uids for the subtype later on (exception keep localization from original record):
+						$value = implode(',', $dbAnalysisCurrent->getValueArray());
+						$this->registerDBList[$table][$id][$field] = $value;
+							// Remove child records (if synchronization requested it):
+						if (is_array($removeArray) && count($removeArray)) {
+							$tce = t3lib_div::makeInstance('t3lib_TCEmain');
+							$tce->stripslashes_values = false;
+							$tce->start(array(), $removeArray);
+							$tce->process_cmdmap();
+							unset($tce);
+						}
+							// Handle, reorder and store relations:
+						if ($inlineSubType=='list') {
+							$updateFields = array($field => $value);
+						} elseif ($inlineSubType=='field') {
+							$dbAnalysisCurrent->writeForeignField($config, $id);
+							$updateFields = array($field => $dbAnalysisCurrent->countItems(false));
+						}
+							// Update field referencing to child records of localized parent record:
+						if (is_array($updateFields) && count($updateFields)) {
+							$this->updateDB($table, $id, $updateFields);
+						}
+					}
+				}
+			}
+		}
+	}
 
 
 
@@ -3626,6 +3801,8 @@
 
 
 
+
+
 	/*********************************************
 	 *
 	 * Cmd: Deleting
@@ -4922,20 +5099,21 @@
 				}
 
 					// Process the arguments with the defined function:
-				$remapAction['args'][$remapAction['pos']['valueArray']] = call_user_func_array(
+				$newValue = call_user_func_array(
 					array($this, $remapAction['func']),
 					$remapAction['args']
 				);
-
-					// @TODO: Add option to disable count-field
-				$newVal = $this->checkValue_checkMax($tcaFieldConf, $remapAction['args'][$remapAction['pos']['valueArray']]);
-				$this->updateDB($table,$id,array($field => implode(',', $newVal)));
-
+					// If array is returned, check for maxitems condition, if string is returned this was already done:
+				if (is_array($newValue)) {
+					$newValue = implode(',', $this->checkValue_checkMax($tcaFieldConf, $newValue));
+				}
+					// Update in database (list of children (csv) or number of relations (foreign_field)):
+				$this->updateDB($table, $id, array($field => $newValue));
 					// Process waiting Hook: processDatamap_afterDatabaseOperations:
 				if (isset($this->remapStackRecords[$table][$rawId]['processDatamap_afterDatabaseOperations'])) {
 					$hookArgs = $this->remapStackRecords[$table][$rawId]['processDatamap_afterDatabaseOperations'];
 						// Update field with remapped data:
-					$hookArgs['fieldArray'][$field] = implode(',', $newVal);
+					$hookArgs['fieldArray'][$field] = $newValue;
 						// Process waiting hook objects:
 					$hookObjectsArr = $hookArgs['hookObjectsArr'];
 					foreach($hookObjectsArr as $hookObj)	{
@@ -6284,7 +6462,7 @@
 	 * @return	boolean		True if DB reference field (group/db or select with foreign-table)
 	 */
 	function isReferenceField($conf)	{
-		return ($conf['type']=='group' && $conf['internal_type']=='db') ||	($conf['type']=='select' && $conf['foreign_table']);
+		return ($conf['type']=='group' && $conf['internal_type']=='db' || $conf['type']=='select' && $conf['foreign_table']);
 	}
 
 	/**
@@ -6306,6 +6484,7 @@
 		return false;
 	}
 
+
 	/**
 	 * Get modified header for a copied record
 	 *
Index: typo3/stylesheet.css
===================================================================
--- typo3/stylesheet.css	(Revision 3041)
+++ typo3/stylesheet.css	(Revision 3042)
@@ -480,8 +480,8 @@
 TABLE#typo3-versionSelector { background-color: #ABBBB4; margin-top: 5px; margin-bottom: 5px; }
 TABLE#typo3-versionSelector TD { padding-left: 2px; padding-right: 2px; }
 
-DIV#typo3-newRecordLink, DIV.typo3-newRecordLink { margin: 5px 0px 5px 0px; font-weight: bold; }
-DIV#typo3-newRecordLink IMG, DIV.typo3-newRecordLink IMG { margin-right: 5px; vertical-align: middle; }
+DIV#typo3-newRecordLink, DIV.typo3-newRecordLink, DIV.typo3-localizationLink, DIV.typo3-synchronizationLink { margin: 5px 0px 5px 0px; font-weight: bold; }
+DIV#typo3-newRecordLink IMG, DIV.typo3-newRecordLink IMG, DIV.typo3-localizationLink IMG, DIV.typo3-synchronizationLink IMG { margin-right: 5px; vertical-align: middle; }
 
 INPUT.smallCheckboxes { vertical-align: middle; margin: 0px; padding: 0px; width: 12px; height: 12px; }
 DIV#typo3-listOptions { margin: 10px 0px 10px 0px; }
Index: typo3/sysext/lang/locallang_misc.xml
===================================================================
--- typo3/sysext/lang/locallang_misc.xml	(Revision 3041)
+++ typo3/sysext/lang/locallang_misc.xml	(Revision 3042)
@@ -56,6 +56,9 @@
 			<label index="CM_editPageProperties">Edit page properties</label>
 			<label index="CM_db_list">Web&gt;List module</label>
 			<label index="noEditPage">You asked to edit page &quot;%s&quot; but you cannot edit this page. Now loading backend as usual.</label>
+			<label index="localize">Localize</label>
+			<label index="localizeAllRecords">Localize all records</label>
+			<label index="synchronizeWithOriginalLanguage">Synchronize with original language</label>
 		</languageKey>
 	</data>
 </T3locallang>
\ Kein Zeilenvorschub am Ende der Datei
