.htaccess: Add optional language parameter to all pages

Viewed 178

I have a .htaccess file rewriting all URLs. For example:

# Special urls
RewriteRule ^(article)/([^/]*)(?:/[^/]*)?$ /index.php?page=$1&keyword=$2 [L,QSA,NC]
RewriteRule ^(privacy)$ /index.php?page=legal&type=$1 [L,QSA,NC]
RewriteRule ^(imprint)$ /index.php?page=legal&type=$1 [L,QSA,NC]

# All urls
RewriteRule ^([0-9a-zA-Z\s]+)$ /index.php?page=$1 [QSA]

Now I want to integrate a language parameter in my URL. For example

  • example.com/test ➡ /index.php?page=test
  • example.com/en/test ➡ /index.php?lang=en&page=test

How would I accomplish this without having to edit all RewriteRules? Is there a way to check if the part after example.com matches a regex, append a query parameter and handle all future rules normally?

1 Answers

Yes, this is possible. Add the following rule before your existing rules:

# Add optional language URL param if present in the first path segment
RewriteRule ^(\w\w)/(.*) $2?lang=$1 [QSA,DPI]

UPDATE: The DPI flag discards the original path-info that would otherwise be appended to the URL-path after the rewrite. This would result in the directives that immediately follow from failing to match, until the next round of processing. (See update below that goes into more detail.)

This assumes that the language code is always 2 characters.

The URL is rewritten to remove the language path segment from the URL-path and appends this as a lang URL parameter. The L flag is specifically omitted so the following rules are left to match the URL-path without the language code.

Since the following rules already have the QSA flag then the lang= URL parameter is appended.

Note, however, that the lang=en parameter is appended at the end of the query string, not prefixed to the beginning, as in your example.


UPDATE: It seems like not only the language gets appended, but also the page name. For example: example.com/de/index results in index?lang=de/index
Solved by adding DPI to [QSA] ➡ [QSA,DPI]

Hhhmmm, yes and no... given only the directives as stated in the question this should still "work" without the DPI flag (although not as efficiently). In fact, index?lang=de/index does not seem to be possible as a resulting URL (there's no page URL parameter)? It's possible that other directives are perhaps resulting in the path-info being appended to the query string? One thing of note is that the last rule stated in the question is missing the L flag, so any directives that follow are perhaps being unnecessarily processed (and even conflicting). However, the DPI flag is certainly an improvement here and should be added.

In detail...

Given a request of the form /de/index, and /de does not exist as a physical directory, then the /index part on the end of the requested URL-path is additional pathname information (path-info) and this is appended to the URL-path after the rewrite above (which is indeed undesirable). So, a request of the form /de/index is rewritten to index?lang=de, which becomes index/index?lang=de after the path-info is re-appended (note that it's not appended to the query string).

The resulting URL-path index/index (with appended path-info) fails to match the RewriteRule directives that follow. However, the rewrite engine then starts over, at which point the path-info that was (unnecessarily) added is then naturally discarded before the next round of processing. This results in the "correct" index?lang=de URL being used as the input for the second round of processing. This matches the last rule stated in the question and the request is finally rewritten to /index.php?page=index&lang=de.

So, the DPI flag shouldn't strictly be necessary here for it to "work". However, it is certainly recommended as it avoids the unnecessary 2nd pass through the rewrite engine. With the DPI flag, the path-info is not appended after the first rewrite, so the URL-path would match the appropriate rule on the first pass.

Related