2

I want to redirect example.com/?lang=en to example.com/en/.

I am using Python Django and my server running Plesk / Nginx.

I try to redirect on my webpage like this. But it's don't work;

rewrite ^/?lang=en$ /en/ redirect;

But if i remove question mark rewrite is worked.

I tried many methods but I couldn't find a solution.

Thank You.

Ivan Shatsky
  • 13,267
  • 2
  • 21
  • 37
Aytek
  • 224
  • 4
  • 16
  • `rewrite` matches its regular expression against a normalised URI which does not include the `?` or the query string which follows it. You could use a solution similar [to this](https://stackoverflow.com/questions/49191594/nginx-rewrite-a-lot-2000-of-urls-with-parameters/49192527#49192527). – Richard Smith Jun 30 '20 at 12:36

1 Answers1

4

The most simple is

if ($arg_lang = en) {
    return 301 /en$uri;
}

However if you'd have any other query arguments, they would lost with this redirection rule. To preserve all the other query arguments you can do the following:

if ($args ~ (.*)(^|&)lang=en(\2|$)&?(.*)) {
    set $args $1$3$4;
    return 301 /en$uri$is_args$args;
}

To support several languages the first solution came to mind is

if ($args ~ (.*)(^|&)lang=([^&]*)(\2|$)&?(.*)) {
    set $args $1$4$5;
    return 301 /$3$uri$is_args$args;
}

However if you'd have some malformed lang query argument value it would lead to redirection to non-existent page. To filter lang values for supported languages only you can use the map directive:

map $arg_lang $prefix {
    en    /en;
    de    /de;
    ...
    # if none matched, value of $prefix variable would be an empty string
}
map $args $stripped_args {
    # remove "lang" query argument if exists
    ~(.*)(^|&)lang=[^&]*(\2|$)&?(.*)  $1$3$4;
    default                           $args;
}
server {
    ...
    if ($prefix) {
        set $args $stripped_args;
        return 301 $prefix$uri$is_args$args;
    }
    ...
}

If your URI language prefix is the same as the lang query argument value (or can be derived from it through some regular expression), the first map block could be simplified:

map $arg_lang $prefix {
    ~^(en|de|...)$    /$1;
}

Update

As OP states, there could be a caveat when we've got a request like example.com/de/some/path/?lang=en which would be redirected to non-existent page example.com/en/de/some/path/. To avoid it we could define additional map block and strip the language prefix from the URI:

map $arg_lang $prefix {
    ~^(en|de|...)$    /$1;
}
map $args $stripped_args {
    # remove "lang" query argument if exists
    ~(.*)(^|&)lang=[^&]*(\2|$)&?(.*)  $1$3$4;
    default                           $args;
}
map $uri $stripped_uri {
    # remove language prefix from URI if one exists
    ~^/(en|de|...)(/.*)$  $2;
    default               $uri;
}
server {
    ...
    if ($prefix) {
        set $args $stripped_args;
        return 301 $prefix$stripped_uri$is_args$args;
    }
    ...
}
Ivan Shatsky
  • 13,267
  • 2
  • 21
  • 37
  • Ivan Its awesome answer. Its work awesome. Thanks a lot! I use your several languages solution and its work perfect. I just ask something. ex: example.com/?lang=en working perfect. but example.com/de/something1/somethin2/something3/?lang=en redirect to example.com/en/de/something1.... so its meaning 404 page. how can i push just change /de/ section on the your several languages solution? thank you so much! – Aytek Jun 30 '20 at 20:17
  • 1
    @Aytek You're right, I didn't thought about this situation, check an update to the answer. – Ivan Shatsky Jun 30 '20 at 20:49
  • You are awesome. Thanks a lot! Its work but its working like this: example.com/fr/something1/something2?lang=en change to example.com/en/fr/something1/something2... but after this try example.com/en/fr/something1/something2?lang=de its turn to example.com/de/fr/something1/something2... i dont know maybe its problem on my django. you can check my website onlinepoll.me (also i want to added your name about>thanks section // if you say okay ofc) – Aytek Jun 30 '20 at 21:02
  • 1
    @Aytek Maybe this redirect got cached by your browser? Clear your browser cache or try it from incognito window. / of course you can ) – Ivan Shatsky Jun 30 '20 at 21:08
  • Ivan sorry its my fault, i pass to add other lang to en|de|... section. its worked now awesome. Thanks a lot. This helped me a lot. I add everyone who helped me with my project on the thank you page. If you have permission, I want add you. – Aytek Jun 30 '20 at 21:14
  • @Aytek Glad to hear everything is worked as expected now. Of course you can add my name if you want :) – Ivan Shatsky Jun 30 '20 at 21:29
  • I added :) https://onlinepoll.me/en/about-us/ Thank you so much again! – Aytek Jun 30 '20 at 21:49
  • 1
    @Aytek I added some optimization to the answer, you could check an edit history if you're interested. – Ivan Shatsky Jul 06 '20 at 04:19