Craft 3 language switcher 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

&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 %}
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 }} &lt;a href="{{ entryForOtherSite.getUrl() }}"&gt;{{ site.language }} - {{ entryForOtherSite.title }}&lt;/a&gt;
    {% 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-&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;
}


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 }} &lt;a href="{{ entryForOtherSite.getUrl() }}"&gt;{{ siteInGroup.language }} - {{ entryForOtherSite.title }}&lt;/a&gt;
    {% endif %}
{% endfor %}