vigetlabs / craft-localeredirector

Craft plugin for detecting user language preferences and redirecting to the appropriate locale.
MIT License
24 stars 4 forks source link

Browser locale is being forced #4

Closed dowadidi closed 7 years ago

dowadidi commented 7 years ago

Hi,

The plugin seems to force the browser language. It's impossible to switch languages. I'm using the latest version of Craft and the plugin on a multi-environment setup.

If you want, I could give you access to the code and/or backend.

dowadidi commented 7 years ago

I did some debugging. It seems the cookie 'locale' isn't being updated. Eg. When I browse to the homepage, the locale cookie is being set to 'en'. When switching to 'fr', the cookie stays 'en'.

When manually changing the cookie itself to 'de', any page is getting redirected to the german version.

jeremyfrank commented 7 years ago

If you have a language switcher menu implemented in your template, which allows users to manually set their language preference (via cookie), then the language setting saved in the cooke will be used by the plugin for redirection.

dowadidi commented 7 years ago

The language switching html looks like this. And it works like expected.

<ul>
    <li><a href="http://localhost:8888/en/about-us" class="active">English</a></li>
    <li><a href="http://localhost:8888/nl/over-ons" class="">Nederlands</a></li>
    <li><a href="http://localhost:8888/fr/a-propos" class="">Français</a></li>
    <li><a href="http://localhost:8888/de/uber-uns" class="">Deutsch</a></li>
    <li><a href="http://localhost:8888/pl/o-nas" class="">Polski</a></li>
    <li><a href="http://localhost:8888/ru/о-нас" class="">русский</a></li>
</ul>

In the config file:

'siteUrl' => array(
    'nl' => 'http://localhost:8888/nl/',
    'fr' => 'http://localhost:8888/fr/',
    'en' => 'http://localhost:8888/en/',
    'de' => 'http://localhost:8888/de/',
    'pl' => 'http://localhost:8888/pl/',
    'ru' => 'http://localhost:8888/ru/',
)

So everything worked perfectly. Not all sections have a public url configured. So we wrote the language switcher ourselves using twig. Without the need of using cookies.

So, the localeredirector plugin doesn't set cookies, but uses cookie information from another plugin?

jeremyfrank commented 7 years ago

The plugin depends on a language preferences first being set by the user (via js). If none have been set (e.g. for the first visit) it will set a cookie based on finding a match between the browser's configured language settings and the locales configured for the site in Craft. On subsequent visits, it will also reset the cookie to the same value, but only for the purposes of extending the expires date.

thaoms commented 7 years ago

Hey @DiederikVanHoorebeke

Did you manage to fix this? I got the same issue.

jeremyfrank commented 7 years ago

Along with linking to fr/a-propos in the language switcher, you need to set the language cookie to fr via js onclick. Then the plugin will have a cookie to read.

dowadidi commented 7 years ago

I've used a combination https://github.com/nystudio107/cookies and two small plugins I wrote.

This is my template code:

{% if getCookie( 'locale' ) is empty and entry.id == 12 and not isCrawler() %}
    {% set languateToRedirectTo = getLocaleToRedirectTo() %}
    {% if languateToRedirectTo is empty %} {% set languateToRedirectTo = getPrimaryLanguage() %} {% endif %}
    {{ setCookie( 'locale', languateToRedirectTo ) }}
    {% if languateToRedirectTo != craft.locale %}
        {% set redirectEntry = craft.entries.id(entry.id).locale(languateToRedirectTo).first %}
        {% redirect redirectEntry.getUrl() %}
    {% endif %}
{% else %}
    {{ setCookie( "locale", craft.locale ) }}
{% endif %}

The and entry.id == 12 part in the code makes shure the redirect woks only on the homepage. 12 is the id of the homepage single.

To prevent redirecting crawlers, I created the isCrawler() function, using https://packagist.org/packages/jaybizzle/crawler-detect.

getLocaleToRedirectTo() function is a Twig extension plugin matching the first browser language that exists within the craft locales enabled in the backend:

public function getLocaleToRedirectToFilter()
    {
        $browserLanguages = craft()->request->getBrowserLanguages();
        $craftLanguages = craft()->i18n->getSiteLocaleIds();

        foreach ($browserLanguages as $browserLanguage) {
            if (in_array($browserLanguage, $craftLanguages)) {
                return $browserLanguage;
            }
        }

        return null;
    }

If no results found, it looks for the first locale configured in the backend, using getPrimaryLanguage()

    public function getPrimaryLanguageFilter()
    {
        $craftLanguages = craft()->i18n->getSiteLocaleIds();
        return $craftLanguages[0];
    }
jeremyfrank commented 7 years ago

In your template code, it looks like you're doing essentially the same (or similar) thing that the localeredirector plugin is doing: checking for a cookie, finding a language match, setting a cookie, then performing a redirect if necessary. So my initial thought is that the localeredirector plugin and the template code are trying to do the same thing; potentially conflicting and causing issues.

I'd recommend letting the localeredirector plugin handle the detection/matching/cookie, or just roll your own template based detection/redirection since it seems like your needs are fairly custom with restricting to the homepage and detecting/preventing crawlers.

dowadidi commented 7 years ago

Making sure that the redirect would also work without the use of javascript to set the cookie, I'm using my own template based detection/redirection.

bennobo commented 7 years ago

Is there any code example for seeting the language cookie to a locale via onclick? I am having trouble getting this to work. Probably also worth adding this issue to the documentation.

thaoms commented 7 years ago

I did it with this js cookie plugin, but I guess there are a lot of ways do this thing.

$('.lang-switch a').click(function(e){ Cookies.set('locale', $(this).attr('data-lang')); });

I do have an language data attribute on my element. <li class="nav-item"><a class="nav-link" data-lang="{{ locale }}" href="{{ craft.config.siteUrl[locale] }}">{{ locale }}</a></li>

jeremyfrank commented 7 years ago

@bennobo Good call on adding a code sample for setting cookies via js. I have some time today so I'll try to put something together in the readme, or link to some external sources. Otherwise, the js cookie plugin that @thomasvankerckvoorde mentioned is a great start.

jeremyfrank commented 7 years ago

Check the readme now. I've added an important notes section with some info on language links and setting cookies.