Answers.Body: <p>There's no clear question here, instead you've thrown up a bunch of code and said that it's not working. My suggestion would be to double check that the entry fields are indeed being populated with the appropriate translations. So double check whether the following line is actually executed.</p>
  <pre class="lang-php prettyprint-override"><code>$entry-&gt;setFieldValue($field-&gt;handle, $translations[$lang]);
  </code></pre>
  <p>If it is, then I would expect the save to work. One thing to be aware of, is that the <code>saveElement</code> method accepts a boolean value as the third parameter which specifies whether to propagate the entry. This is <code>true</code> by default, meaning that the entry is propogated for each site each time you save it. Maybe consider setting it to <code>false</code> or better yet, modifying your saving strategy to be more performant.</p>
  <pre class="lang-php prettyprint-override"><code>if (('en' !== $lang) &amp;&amp; !$elements-&gt;saveElement($entry, true, false)) {
  </code></pre>
  <p>See the method signature at: <a href="https://github.com/craftcms/cms/blob/e55041d4c24ea827b13ee4367d3fae52df6ab80f/src/services/Elements.php#L746" rel="nofollow noreferrer">https://github.com/craftcms/cms/blob/e55041d4c24ea827b13ee4367d3fae52df6ab80f/src/services/Elements.php#L746</a></p>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2021-02-15T10:46:47.197Z
Answers.Text: I guess my question was: Am I correct in assuming that the only difference between the entries is indeed just the siteId, even when the entry id stays the same?
Answers.UserDisplayName: dustfeather
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2021-02-15T19:32:58.947Z
Answers.Text: In that case, yes.
Answers.UserDisplayName: Ben Croker
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2021-02-12T20:44:07.443Z
Answers.LastActivityDate: 2021-02-13T07:35:40.147Z
Answers.LastEditDate: 2021-02-13T07:35:40.147Z
Answers.UserDisplayName: Ben Croker
Body: <p>I'm trying to write a plugin that translate entries programmatically based on subsites that have different language setup.</p>
  <p>Normally what happens is this: you setup multi-site, set each sub-site as having a different language and a different url (like @web/de, @web/sv etc), you set a field as translatable by language, then you edit an entry on each of those sub-sites. And the system knows to separate entries by siteId.</p>
  <p>Now, I tried the same approach programmatically. I get all the entries for all the subsites like this:</p>
  <pre class="lang-php prettyprint-override"><code>$sites = Craft::$app-&gt;getSites()
                      -&gt;getAllSites();
  /** @var Entry[] $entries */
  $entries = [];
  foreach ($sites as $site) {
      /** @var Entry $entry */
      $entries[$site-&gt;language] = Entry::find()
                                       -&gt;id($id)
                                       -&gt;siteId($site-&gt;id)
                                       -&gt;one();
  }
  </code></pre>
  <p>The I go and get all the fields for the English entry (in my setup is safe to assume that all the sub-sites respect the same field layout/structure). To test this, I dumped the values to compare the English version of the field, with the Swedish version. Values were different, which means I'm looking at the correct fields for the correct sub-entry.</p>
  <pre class="lang-php prettyprint-override"><code>//this is how we get the english fields
  $fields = $entries['en']-&gt;getType()
                          -&gt;getFieldLayout()
                          -&gt;getFields();
  
  //this is how we translate each field for each language
  foreach ($fields as $field) {
      if ($field-&gt;translationMethod === \craft\base\Field::TRANSLATION_METHOD_LANGUAGE) {
          //get english value
          $enValue = $entries['en']-&gt;getFieldValue($field-&gt;handle);
          if (!empty($enValue)) {
              //translate in all languages
              $translations = $this-&gt;translate($enValue, array_keys($entries));
              foreach ($entries as $lang =&gt; $entry) {
                  $fieldValue = $entry-&gt;getFieldValue($field-&gt;handle);
                  //only translate if the destination language/field is in English (not translated yet)
                  if (('en' !== $lang) &amp;&amp; !empty($enValue) &amp;&amp; ($enValue === $fieldValue)) {
                      if (!empty($translations[$lang])) {
                          //setFieldValue for each language
                          $entry-&gt;setFieldValue($field-&gt;handle, $translations[$lang]);
                      }
                  }
              }
          }
      }
  }
  </code></pre>
  <p>This is how I try to save the entries at the end of it all</p>
  <pre class="lang-php prettyprint-override"><code>//save all non-eng entries
  $elements = new Elements();
  foreach ($entries as $lang =&gt; $entry) {
      if (('en' !== $lang) &amp;&amp; !$elements-&gt;saveElement($entry)) {
          echo json_encode($entry-&gt;getErrorSummary(true));
          die();
      }
  }
  </code></pre>
  <p>The issue is that it saves the last translated language in all the sub-sites, for some reason, and I don't understand what I'm doing wrong.</p>
  
Comments.ContentLicense: CC BY-SA 4.0
Comments.CreationDate: 2021-02-11T13:44:21.437Z
Comments.Text: `$elements->saveElement($entry, true, false)` does the same thing, by the way.
Comments.UserDisplayName: dustfeather
Comments.ContentLicense: CC BY-SA 4.0
Comments.CreationDate: 2021-02-11T18:33:43.857Z
Comments.Text: [This](https://craftcms.stackexchange.com/a/30113/1016) might be relevant (ie using ``enabledForSite``)...
Comments.UserDisplayName: RitterKnight
Comments.ContentLicense: CC BY-SA 4.0
Comments.CreationDate: 2021-02-11T23:40:24.470Z
Comments.Text: None of those 2 solutions work with my example, tested them both. Probably because I'm not saving a new entry, but an existing one, who has already been propagated on the first save (when it was created).
Comments.UserDisplayName: dustfeather
Comments.ContentLicense: CC BY-SA 4.0
Comments.CreationDate: 2021-02-12T15:02:18.827Z
Comments.Text: Have you checked that the site ID is correctly set on the entry before saving?
Comments.UserDisplayName: Ben Croker
Comments.ContentLicense: CC BY-SA 4.0
Comments.CreationDate: 2021-02-12T17:05:44.477Z
Comments.Text: @BenCroker shouldn't it already be set since I'm pulling an already saved entry from the DB?
Comments.UserDisplayName: dustfeather
Comments.ContentLicense: CC BY-SA 4.0
Comments.CreationDate: 2021-02-12T20:32:01.253Z
Comments.Text: Perhaps, but I would still check to be sure.
Comments.UserDisplayName: Ben Croker
Tags: <localization>
Title: How to programmatically translate an entry in craft 3
ThreadText: # How to programmatically translate an entry in craft 3
  
  (Asked by: username_0 on 2021-02-11)
  
  I'm trying to write a plugin that translate entries programmatically based on subsites that have different language setup.
  
  Normally what happens is this: you setup multi-site, set each sub-site as having a different language and a different url (like @web/de, @web/sv etc), you set a field as translatable by language, then you edit an entry on each of those sub-sites. And the system knows to separate entries by siteId.
  
  Now, I tried the same approach programmatically. I get all the entries for all the subsites like this:
  
  ```php
  $sites = Craft::$app->getSites()
                      ->getAllSites();
  /** @var Entry[] $entries */
  $entries = [];
  foreach ($sites as $site) {
      /** @var Entry $entry */
      $entries[$site->language] = Entry::find()
                                       ->id($id)
                                       ->siteId($site->id)
                                       ->one();
  }
  
  ```
  
  The I go and get all the fields for the English entry (in my setup is safe to assume that all the sub-sites respect the same field layout/structure). To test this, I dumped the values to compare the English version of the field, with the Swedish version. Values were different, which means I'm looking at the correct fields for the correct sub-entry.
  
  ```php
  //this is how we get the english fields
  $fields = $entries['en']->getType()
                          ->getFieldLayout()
                          ->getFields();
  
  //this is how we translate each field for each language
  foreach ($fields as $field) {
      if ($field->translationMethod === \craft\base\Field::TRANSLATION_METHOD_LANGUAGE) {
          //get english value
          $enValue = $entries['en']->getFieldValue($field->handle);
          if (!empty($enValue)) {
              //translate in all languages
              $translations = $this->translate($enValue, array_keys($entries));
              foreach ($entries as $lang => $entry) {
                  $fieldValue = $entry->getFieldValue($field->handle);
                  //only translate if the destination language/field is in English (not translated yet)
                  if (('en' !== $lang) && !empty($enValue) && ($enValue === $fieldValue)) {
                      if (!empty($translations[$lang])) {
                          //setFieldValue for each language
                          $entry->setFieldValue($field->handle, $translations[$lang]);
                      }
                  }
              }
          }
      }
  }
  
  ```
  
  This is how I try to save the entries at the end of it all
  
  ```php
  //save all non-eng entries
  $elements = new Elements();
  foreach ($entries as $lang => $entry) {
      if (('en' !== $lang) && !$elements->saveElement($entry)) {
          echo json_encode($entry->getErrorSummary(true));
          die();
      }
  }
  
  ```
  
  The issue is that it saves the last translated language in all the sub-sites, for some reason, and I don't understand what I'm doing wrong.
  
  **Tags:** localization
  
  > **Comments:**
  > **username_0**: `$elements->saveElement($entry, true, false)` does the same thing, by the way.  
  > **username_1**: [This](https://craftcms.stackexchange.com/a/30113/1016) might be relevant (ie using ``enabledForSite``)...  
  > **username_0**: None of those 2 solutions work with my example, tested them both. Probably because I'm not saving a new entry, but an existing one, who has already been propagated on the first save (when it was created).  
  > **username_2**: Have you checked that the site ID is correctly set on the entry before saving?  
  > **username_0**: @username_2 shouldn't it already be set since I'm pulling an already saved entry from the DB?  
  > **username_2**: Perhaps, but I would still check to be sure.  
  
  ---
  
  ## 1 answers
  
  ### Answer by username_2 on 2021-02-12. Score: 4 | Accepted answer
  
  There's no clear question here, instead you've thrown up a bunch of code and said that it's not working. My suggestion would be to double check that the entry fields are indeed being populated with the appropriate translations. So double check whether the following line is actually executed.
  
  ```php
  $entry->setFieldValue($field->handle, $translations[$lang]);
  
  ```
  
  If it is, then I would expect the save to work. One thing to be aware of, is that the `saveElement` method accepts a boolean value as the third parameter which specifies whether to propagate the entry. This is `true` by default, meaning that the entry is propogated for each site each time you save it. Maybe consider setting it to `false` or better yet, modifying your saving strategy to be more performant.
  
  ```php
  if (('en' !== $lang) && !$elements->saveElement($entry, true, false)) {
  
  ```
  
  See the method signature at: <https://github.com/craftcms/cms/blob/e55041d4c24ea827b13ee4367d3fae52df6ab80f/src/services/Elements.php#L746>
  
  > **Comments:**
  > **username_0**: I guess my question was: Am I correct in assuming that the only difference between the entries is indeed just the siteId, even when the entry id stays the same?  
  > **username_2**: In that case, yes.  
  
  ---
  
  