I have a web presentation with some typical url adresses. Now I need to add a rewriterule for a different languages, examples:

domain/club -> do not change
domain/club/path -> do not change
domain/club/path?search=somethingelse -> do not change
domain/en/club -> domain/club?lang=en
domain/en/club/path -> domain/club/path?lang=en
domain/en/club/path?search=something -> domain/club/path?search=something&lang=endomain

My idea was to break it into groups domain/language/club/path?search=something and then write

RewriteRule \/(?<language>[a-zA-Z]{2})\/club\/?(?<path>.*)\?(?<search>.*)   /club/$1?search=$2&lang=$3

but this will not consider strings without ?. I also do not know how to solve the difference with two cases ?lang= and &lang=. I did not find anything online.

I am doing this on existing PHP framework (not any of the standards) and therefore I have to do it this way (understand with those specific urls).

  • I assume by "add a rewriterule" that you wish to internally rewrite the request as opposed to externally redirect? (RewriteRule does both.)
    – MrWhite
    Commented Oct 19, 2020 at 17:49

1 Answer 1


It looks like you are making this more complex than it actually is. Unless you need to be specific about matching "club", it looks like you just need to remove the first path segment when it looks like a 2-letter language code and move this to the lang URL parameter in the query string instead.

For this you can do the following, near the top of your .htaccess file:

RewriteRule ^([a-z]{2})/(.+) $2?lang=$1 [QSA,L]

A request for /en/club will be rewritten to /club?lang=en and /en/club/path?search=something to /club/path?lang=en&search=something (note the lang URL parameter is first).


  • The RewriteRule pattern matches against the URL-path only, not the query string. The URL-path that is matched also does not have a slash prefix.
  • ([a-z]{2}) - matches the 2-letter (lowercase) language code. (Although in your regex, you allowed uppercase as well?) This is a capturing subpattern, so is naturally stored in the (first) $1 backreference.
  • The (.+) matches everything in the URL-path that follows the language code path segment (and slash). Note that this matches something, not nothing. So it won't be successful for a request to /en/, only /en/<something>. (If this needs to be successful for /en/ only as well then change this subpattern to (.*).) This is also capturing and stored in the (second) $2 backreference. eg. Request /en/club/path and $2 holds club/path.
  • The QSA flag appends any query string that might be present on the initial request and handles the "merging" with any query string in the substitution string. eg. search=something. However, a slight difference with your example is that the lang URL parameter will be first, not last - although that shouldn't be a problem.

However, whether this works or not is still dependent on how your "PHP framework" routes URLs. For instance, if it's like WordPress and looks at the $_SERVER['REQUEST_URI'] PHP superglobal then this will still see the URL-path before the rewrite.

You presumably have other rewrites that follow this?

RewriteRule \/(?<language>[a-zA-Z]{2})\/club\/?(?<path>.*)\?(?<search>.*) /club/$1?search=$2&lang=$3

but this will not consider strings without ?. I also do not know how to solve the difference with two cases ?lang= and &lang=. I did not find anything online.

There are a number of issues here:

  • The regex is not anchored to the start of the URL-path, so it matches /<anything>/en/etc.
  • As noted above, the URL-path matched by the RewriteRule pattern does not start with a slash.
  • "this will not consider strings without ?" - the URL matched by the RewriteRule pattern is the URL-path only. This does not include the query string. So, attempting to match the query string here will simply fail. (If you needed to match the query string then you need an additional RewriteCond directive and match against the QUERY_STRING server variable.)
  • Not an error, but there is no need to backslash-escape slashes in the regex since the slash carries no special meaning here (spaces are regex/argument delimiters in Apache config files). As noted, this is not strictly an error, just as you can backslash-escape most characters, but it does complicate the regex and makes it harder to read.
  • You are using named-captured groups (supported in Apache 2.4.8+) but you are using numeric backreferences in the substitution string. You can't use both. (It's easier to stay with numeric backreferences IMO.)
  • The backreferences in the substitution string appear to be in the wrong order. $1 is the language code. eg. it should be more like /club/$2?search=$3&lang=$1 (although this still isn't correct).
  • "how to solve the difference with two cases ?lang= and &lang=" - The QSA (Query String Append) flag does this for you. Except that the query string is appended, not prefixed.
  • 1
    This is so perfect, thank you very much for you patience and explantion :) Commented Oct 19, 2020 at 23:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.