Multi locale, multi-domain Live Preview failing
Only setting headers in .htaccess doesn't fix the problem.
As Marion Newlevant points out in her answer the cross domain works with the headers set. But you still get a white page as a preview.

Looking further into the problem, I've found that the page tries to do a post request to the other domain.
It calls upon the action function actionPreviewEntry() in the EntriesController.php file (Location: /craft/app/controllers/ )

But because the user isn't logged in on the other domain and anonymous access isn't allowed for this action. You get redirected to /login to login on that domain.

I came up with a quick solution for the problem. It's a bit dirty for now, but the authors of Craft aren't coming with a solution either.

Solution


Delete (If you have set them) the headers for Access-Control-Allow in your .htaccess file. We don't need them.
Open the file EntriesController.php in the folder /craft/app/controllers/
Replace the code.

protected $allowAnonymous = array('actionViewSharedEntry');


With:

protected $allowAnonymous = array('actionViewSharedEntry','actionPreviewEntry');



Add the following code in the public function actionPreviewEntry():

// Set a boolean for logout admin user if cross-domain access
$crossDomainAccess = FALSE;

// Check if the user isn't logged in. Likely meaning that the action is called from another domain.
if ( !craft()-&gt;userSession-&gt;isLoggedIn() ) {

  // Get allowed origins
  $locales = array('en','nl');
  $allowedOrigins = array();
  foreach ( $locales as $locale ) {
    $allowedOrigins[] = craft()-&gt;config-&gt;getLocalized('siteUrl', $locale);
  }

  // Check origin and give access if allowed
  $httpOrigin = $_SERVER['HTTP_ORIGIN'];
  if ( in_array($httpOrigin, $allowedOrigins) ) {
    header('Access-Control-Allow-Origin: ' . $httpOrigin);
    header('Access-Control-Allow-Credentials: true');
    craft()-&gt;userSession-&gt;loginByUserId(1);
    $crossDomainAccess = TRUE;
  }
}



Explanation of the code:

As you can see I set the locales to en and nl. Because that's the only locales for my website.

$locales = array('en','nl');


The domains that are allowed to communicate with each other are set in the general config file under siteUrl. See step 4 of the localization guide for more information.
We will fetch them here and put them in an array for checking.

$allowedOrigins = array();
foreach ( $locales as $locale ) {
    $allowedOrigins[] = craft()-&gt;config-&gt;getLocalized('siteUrl', $locale);
}


We check the origin of the request and if it's allowed to communicate with this domain. If so, then set the header to allow cross-domain access.

And automatically login as the admin user to get full access for the preview page to load as if you are logged in on the other domain.

$httpOrigin = $_SERVER['HTTP_ORIGIN'];
if ( in_array($httpOrigin, $allowedOrigins) ) {
    header('Access-Control-Allow-Origin: ' . $httpOrigin);
    header('Access-Control-Allow-Credentials: true');
    craft()-&gt;userSession-&gt;loginByUserId(1);
    $crossDomainAccess = TRUE;
}



Next we need to logout the admin user on the other domain. Add the following code:

if ( $crossDomainAccess == TRUE ) {
  craft()->userSession->logout();
}


Before the line (In the same function, public function actionPreviewEntry()):

$this-&gt;_showEntry($entry);


And that's it. A quickfix for anyone that has come across this problem and wants to fix it quick but dirty for now.

Note: If you update your craft cms, then this code will get deleted, so you have to add it again after you updated.

If you're using baseCpUrl

Slight modification if you're using the baseCpUrl setting and/or have paths in your settings file:

if ( !craft()-&gt;userSession-&gt;isLoggedIn() ) {

  // Get allowed origins
  $allowedOrigins = array(
          parse_url(craft()-&gt;config-&gt;get('baseCpUrl'), PHP_URL_HOST),
          parse_url(craft()-&gt;config-&gt;getLocalized('siteUrl', 'en_us'), PHP_URL_HOST)
  );

  // Check origin and give access if allowed
  $httpOrigin = parse_url($_SERVER['HTTP_ORIGIN'], PHP_URL_HOST);
  if ( in_array($httpOrigin, $allowedOrigins) ) {
          header('Access-Control-Allow-Origin: ' . $_SERVER['HTTP_ORIGIN']);
          header('Access-Control-Allow-Credentials: true');
          craft()-&gt;userSession-&gt;loginByUserId(1);
          $crossDomainAccess = TRUE;
  }
}


Here I've hard-coded the language in, but it can be combined with the answer above instead.