Answers.Body: <p>Little addition with a fallback to the homepage and check if entry exist.
  currentSite is a global variable already defined in craft3 <a href="https://docs.craftcms.com/v3/templating/global-variables.html#currentsite" rel="noreferrer">https://docs.craftcms.com/v3/templating/global-variables.html#currentsite</a></p>
  
  <pre><code>&lt;ul&gt;
    {% for site in currentSite.group.sites %}
      &lt;li class="{% if currentSite.id == site.id %} is-active{% endif %}"&gt;
        {% set url = alias(site.baseUrl) %}
        {% if entry is defined %}
          {% set entryForOtherSite = craft.entries.id(entry.id).site(site).one() %}
          {% if entryForOtherSite %}
            {% set url = entryForOtherSite.getUrl() %}
          {% endif %}
        {% endif %}
        &lt;a href="{{ url }}"&gt;{{ site.name }}&lt;/a&gt;
      &lt;/li&gt;
    {% endfor %}
  &lt;/ul&gt;
  </code></pre>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2018-05-31T08:04:03.033Z
Answers.LastActivityDate: 2018-05-31T08:04:03.033Z
Answers.UserDisplayName: Jeroen
Answers.Body: <p>As of today, <strong>Site Switcher</strong> is now available in the plugin store! *</p>
  
  <p>It was called "Language Link" in Craft 2, but the premise is the same... It allows you to switch between sites while staying on the same page.</p>
  
  <pre class="lang-html prettyprint-override"><code>{% set element = (category ?? entry ?? null) %}
  
  &lt;ul&gt;
      &lt;li&gt;&lt;a href="{{ siteSwitcher('english', element) }}"&gt;English&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="{{ siteSwitcher('spanish', element) }}"&gt;Español&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="{{ siteSwitcher('french', element) }}"&gt;Français&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="{{ siteSwitcher('german', element) }}"&gt;Deutsch&lt;/a&gt;&lt;/li&gt;
  &lt;/ul&gt;
  </code></pre>
  
  <blockquote>
    <p><a href="https://github.com/doublesecretagency/craft-siteswitcher" rel="nofollow noreferrer">https://github.com/doublesecretagency/craft-siteswitcher</a></p>
  </blockquote>
  
  <p><em>* Disclaimer: I am the author of Site Switcher.</em></p>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2018-08-30T20:59:54.907Z
Answers.LastActivityDate: 2018-08-30T20:59:54.907Z
Answers.UserDisplayName: Lindsey D
Answers.Body: <p>If you're using <a href="https://github.com/nystudio107/craft-seomatic" rel="nofollow noreferrer">SEOmatic</a> for Craft CMS 3, there's a built-in function that will make it super easy to do: </p>
  
  <p><strong><code>seomatic.helper.getLocalizedUrls(URI, SITE_ID)</code></strong> - Return a list of localized URLs for a given <code>URI</code> that are in the <code>SITE_ID</code> site's group. Both <code>URI</code> and <code>SITE_ID</code> are optional, and will use the current request's <code>URI</code> and the current site's <code>SITE_ID</code> if omitted.</p>
  
  <p>c.f.: <a href="https://github.com/nystudio107/craft-seomatic#helper-functions-seomatichelper" rel="nofollow noreferrer">https://github.com/nystudio107/craft-seomatic#helper-functions-seomatichelper</a></p>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2018-05-09T21:13:22.690Z
Answers.Text: Any chance any of you knows how to output the language's name instead of code?  English instead of EN, like we could do with locale.nativeName.
Answers.UserDisplayName: Eric Chantigny
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2018-03-31T21:33:49.513Z
Answers.LastActivityDate: 2018-03-31T21:33:49.513Z
Answers.UserDisplayName: andrew.welch
Answers.Body: <p>Here is my language switcher for Craft CMS 3:</p>
  
  <p><a href="http://craftsnippets.com/articles/universal-language-switcher-for-craft-cms?s=s" rel="nofollow noreferrer">http://craftsnippets.com/articles/universal-language-switcher-for-craft-cms?s=s</a></p>
  
  <p>It works for Entries, categories and other elements with their own URLs and has an option for an automatic appending country flag to language links.</p>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2019-08-24T20:37:36.637Z
Answers.LastActivityDate: 2019-08-24T20:37:36.637Z
Answers.UserDisplayName: Piotr Pogorzelski
Answers.Body: <p>The concept of localization has changed in Craft 3, there are not only <code>locales</code> anymore - now you have different sites and site groups.</p>
  
  <p><strong>Example without multisite - only different locals</strong></p>
  
  <p>You can get all available sites for an entry with </p>
  
  <pre><code>{% set supportedSites = entry.getSupportedSites %}
  </code></pre>
  
  <p>This will return you an array of all supported sites for the entry.</p>
  
  <pre><code>{% for siteForEntry in entry.getSupportedSites %}
      {# get the site #}
      {% set site = craft.app.getSites.getSiteById(siteForEntry.siteId) %}
      {# check if it's the current site #}
      {% if site.id == entry.siteId %}
          active site = {{ site.id }} {{ site.language }} 
      {% else %}
          {# if it's not the current site, get the entry for this site #}
          {% set entryForOtherSite = craft.entries.id(entry.id).site(site).one() %}
          link to site with id {{ entryForOtherSite.siteId }} &lt;a href="{{ entryForOtherSite.getUrl() }}"&gt;{{ site.language }} - {{ entryForOtherSite.title }}&lt;/a&gt;
      {% endif %}
  {% endfor %}
  </code></pre>
  
  <p>When you take a look at your <code>/admin/utilities/deprecation-errors</code> you'll see many records because all your <code>locale</code> functions will do this </p>
  
  <pre><code>public function locale(string $value)
  {
      Craft::$app-&gt;getDeprecator()-&gt;log('ElementQuery::locale()', 'The “locale” element query param has been deprecated. Use “site” or “siteId” instead.');
      $this-&gt;site($value);
  
      return $this;
  }
  </code></pre>
  
  <p>They tell you: "This function is deprecated, use "site" instead" </p>
  
  <p><strong>Example with multisite - different sites and locales</strong></p>
  
  <p>If you are going to have multiple different sites with multiple locales you can manage each site in one group and insert all the locales for these sites in each group. </p>
  
  <pre><code>- Site group A
      - language A (siteId 1)
      - Language B (siteId 2)
  - Site group B
      - Language A (siteId 3)
      - Language C (siteId 4)
  </code></pre>
  
  <p>For Example if the user is in site group A you want to show only language A and language B but not Language C even if the entry exists in all sites.
  So you can grab the group of the current site and loop through all sites of the group.</p>
  
  <pre><code>{% set currentSite = craft.app.sites.currentSite %}
  {% for siteInGroup in currentSite.getGroup.getSites() %}
      {% if siteInGroup.id == entry.siteId %}
          active site = {{ siteInGroup.id }}{{ siteInGroup.language }}
      {% else %}
          {% set entryForOtherSite = craft.entries.id(entry.id).site(siteInGroup).one() %}
          link to site {{ entryForOtherSite.siteId }} &lt;a href="{{ entryForOtherSite.getUrl() }}"&gt;{{ siteInGroup.language }} - {{ entryForOtherSite.title }}&lt;/a&gt;
      {% endif %}
  {% endfor %}
  </code></pre>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2018-05-14T13:05:11.610Z
Answers.Text: I really like this answer, however often you don't have an entry available in the templates. So you should check for entry, category and maybe fallback to the homepage?
Answers.UserDisplayName: Jan_dh
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2019-02-01T16:29:26.453Z
Answers.Text: It's great that you have to come to StackExchange to figure out how to use a core feature.
Answers.UserDisplayName: joep
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2018-02-05T09:29:43.837Z
Answers.LastActivityDate: 2018-02-05T16:12:08.620Z
Answers.LastEditDate: 2018-02-05T16:12:08.620Z
Answers.UserDisplayName: Robin Schambach
Body: <p>Does anybody successfully implemented a language switch run Craft 3? Trying the Craft 2 variant slightly adjusted but still running into issues: Invalid site handle: nl</p>
  
  <pre><code>&lt;ul&gt;
  {% set otherLocales = craft.app.i18n.siteLocaleIds|without(craft.locale) %}
  {% for locale in otherLocales %}
     {% set localeEntry = craft.entries.id(entry.id).locale(locale).one() %}
      {#  set localeCategory = craft.categories.group('worksCat').locale(locale).first #}
      {% if localeEntry.locale is defined and localeEntry.locale == locale %}
      &lt;li&gt;
          &lt;a href="{{ localeEntry.getUrl() }}"&gt;
              &lt;img src="/{{ craft.app.i18n.getLocaleById(locale) }}.svg"  {{ craft.app.i18n.getLocaleById(locale).nativeName }}
          &lt;/a&gt;
      &lt;/li&gt;
      {% else %}
      &lt;li&gt;
          &lt;a href="{{ localeCategory.getUrl() }}"&gt;
              &lt;img src="/{{ craft.app.i18n.getLocaleById(locale) }}.svg" &gt; {{ craft.app.i18n.getLocaleById(locale).nativeName }}
          &lt;/a&gt;
      &lt;/li&gt;
      {% endif %}
  {% endfor %}
  </code></pre>
  
  <p></p>
  
Tags: <localization><craft3><multi-site>
Title: Craft 3 language switcher
ThreadText: # Craft 3 language switcher
  
  (Asked by: username_0 on 2018-02-01)
  
  Does anybody successfully implemented a language switch run Craft 3? Trying the Craft 2 variant slightly adjusted but still running into issues: Invalid site handle: nl
  
  ```
  <ul>
  {% set otherLocales = craft.app.i18n.siteLocaleIds|without(craft.locale) %}
  {% for locale in otherLocales %}
     {% set localeEntry = craft.entries.id(entry.id).locale(locale).one() %}
      {#  set localeCategory = craft.categories.group('worksCat').locale(locale).first #}
      {% if localeEntry.locale is defined and localeEntry.locale == locale %}
      <li>
          <a href="{{ localeEntry.getUrl() }}">
              <img src="/{{ craft.app.i18n.getLocaleById(locale) }}.svg"  {{ craft.app.i18n.getLocaleById(locale).nativeName }}
          </a>
      </li>
      {% else %}
      <li>
          <a href="{{ localeCategory.getUrl() }}">
              <img src="/{{ craft.app.i18n.getLocaleById(locale) }}.svg" > {{ craft.app.i18n.getLocaleById(locale).nativeName }}
          </a>
      </li>
      {% endif %}
  {% endfor %}
  
  ```
  
  **Tags:** localization, craft3, multi-site
  
  
  ---
  
  ## 5 answers
  
  ### Answer by username_6 on 2018-02-05. Score: 15 | Accepted answer
  
  The concept of localization has changed in Craft 3, there are not only `locales` anymore - now you have different sites and site groups.
  
  **Example without multisite - only different locals**
  
  You can get all available sites for an entry with
  
  ```
  {% set supportedSites = entry.getSupportedSites %}
  
  ```
  
  This will return you an array of all supported sites for the entry.
  
  ```
  {% for siteForEntry in entry.getSupportedSites %}
      {# get the site #}
      {% set site = craft.app.getSites.getSiteById(siteForEntry.siteId) %}
      {# check if it's the current site #}
      {% if site.id == entry.siteId %}
          active site = {{ site.id }} {{ site.language }} 
      {% else %}
          {# if it's not the current site, get the entry for this site #}
          {% set entryForOtherSite = craft.entries.id(entry.id).site(site).one() %}
          link to site with id {{ entryForOtherSite.siteId }} <a href="{{ entryForOtherSite.getUrl() }}">{{ site.language }} - {{ entryForOtherSite.title }}</a>
      {% endif %}
  {% endfor %}
  
  ```
  
  When you take a look at your `/admin/utilities/deprecation-errors` you'll see many records because all your `locale` functions will do this
  
  ```
  public function locale(string $value)
  {
      Craft::$app->getDeprecator()->log('ElementQuery::locale()', 'The “locale” element query param has been deprecated. Use “site” or “siteId” instead.');
      $this->site($value);
  
      return $this;
  }
  
  ```
  
  They tell you: "This function is deprecated, use "site" instead"
  
  **Example with multisite - different sites and locales**
  
  If you are going to have multiple different sites with multiple locales you can manage each site in one group and insert all the locales for these sites in each group.
  
  ```
  - Site group A
      - language A (siteId 1)
      - Language B (siteId 2)
  - Site group B
      - Language A (siteId 3)
      - Language C (siteId 4)
  
  ```
  
  For Example if the user is in site group A you want to show only language A and language B but not Language C even if the entry exists in all sites.
  So you can grab the group of the current site and loop through all sites of the group.
  
  ```
  {% set currentSite = craft.app.sites.currentSite %}
  {% for siteInGroup in currentSite.getGroup.getSites() %}
      {% if siteInGroup.id == entry.siteId %}
          active site = {{ siteInGroup.id }}{{ siteInGroup.language }}
      {% else %}
          {% set entryForOtherSite = craft.entries.id(entry.id).site(siteInGroup).one() %}
          link to site {{ entryForOtherSite.siteId }} <a href="{{ entryForOtherSite.getUrl() }}">{{ siteInGroup.language }} - {{ entryForOtherSite.title }}</a>
      {% endif %}
  {% endfor %}
  
  ```
  
  > **Comments:**
  > **username_7**: I really like this answer, however often you don't have an entry available in the templates. So you should check for entry, category and maybe fallback to the homepage?  
  > **username_8**: It's great that you have to come to StackExchange to figure out how to use a core feature.  
  
  ---
  
  ### Answer by username_1 on 2018-05-31. Score: 5
  
  Little addition with a fallback to the homepage and check if entry exist.
  currentSite is a global variable already defined in craft3 <https://docs.craftcms.com/v3/templating/global-variables.html#currentsite>
  
  ```
  <ul>
    {% for site in currentSite.group.sites %}
      <li class="{% if currentSite.id == site.id %} is-active{% endif %}">
        {% set url = alias(site.baseUrl) %}
        {% if entry is defined %}
          {% set entryForOtherSite = craft.entries.id(entry.id).site(site).one() %}
          {% if entryForOtherSite %}
            {% set url = entryForOtherSite.getUrl() %}
          {% endif %}
        {% endif %}
        <a href="{{ url }}">{{ site.name }}</a>
      </li>
    {% endfor %}
  </ul>
  
  ```
  
  
  ---
  
  ### Answer by username_2 on 2018-08-30. Score: 4
  
  As of today, **Site Switcher** is now available in the plugin store! \*
  
  It was called "Language Link" in Craft 2, but the premise is the same... It allows you to switch between sites while staying on the same page.
  
  ```html
  {% set element = (category ?? entry ?? null) %}
  
  <ul>
      <li><a href="{{ siteSwitcher('english', element) }}">English</a></li>
      <li><a href="{{ siteSwitcher('spanish', element) }}">Español</a></li>
      <li><a href="{{ siteSwitcher('french', element) }}">Français</a></li>
      <li><a href="{{ siteSwitcher('german', element) }}">Deutsch</a></li>
  </ul>
  
  ```
  
  > <https://github.com/doublesecretagency/craft-siteswitcher>
  
  *\* Disclaimer: I am the author of Site Switcher.*
  
  
  ---
  
  ### Answer by username_3 on 2018-03-31. Score: 3
  
  If you're using [SEOmatic](https://github.com/nystudio107/craft-seomatic) for Craft CMS 3, there's a built-in function that will make it super easy to do:
  
  **`seomatic.helper.getLocalizedUrls(URI, SITE_ID)`** - Return a list of localized URLs for a given `URI` that are in the `SITE_ID` site's group. Both `URI` and `SITE_ID` are optional, and will use the current request's `URI` and the current site's `SITE_ID` if omitted.
  
  c.f.: <https://github.com/nystudio107/craft-seomatic#helper-functions-seomatichelper>
  
  > **Comments:**
  > **username_4**: Any chance any of you knows how to output the language's name instead of code?  English instead of EN, like we could do with locale.nativeName.  
  
  ---
  
  ### Answer by username_5 on 2019-08-24. Score: 1
  
  Here is my language switcher for Craft CMS 3:
  
  <http://craftsnippets.com/articles/universal-language-switcher-for-craft-cms?s=s>
  
  It works for Entries, categories and other elements with their own URLs and has an option for an automatic appending country flag to language links.
  
  
  ---
  
  