1

I am looking to add multiple language support to my website. Is it possible to use the .htaccess file to change something like:

  • example.com/dir/?lang=en to example.com/en/dir/
  • example.com/main/?lang=de to example.com/de/main/
  • example.com/main/page.php?lang=de to example.com/de/main/page.php

Where this works with any possible directories - so if for instance later on I made a new directory, I wouldn't need to add to this. In the above example, I want the latter to be what the user types in/is in the address bar, and the start to be how it is used internally.

user3783243
  • 4,418
  • 5
  • 14
  • 34
  • 1
    What have you tried before? Which is your actual .htaccess? – Ad Fortia Apr 09 '21 at 14:20
  • @AdFortia currently my .htaccess is empty as I am starting again to completely overhaul. I am not sure how to even begin this - so I have tried nothing yet. – Danny Franklin Apr 09 '21 at 14:24
  • The only "correct" answer to the question is probably "yes" ... which isn't very helpful, I'll admit, but since we don't *really* know what you're doing, it's not possible to give a more specific answer. Normally you'd punt all requests to an application _routing_ file and let that sort things out. – CD001 Apr 09 '21 at 14:28
  • 1
    Does this answer your question? [Reference: mod\_rewrite, URL rewriting and "pretty links" explained](https://stackoverflow.com/questions/20563772/reference-mod-rewrite-url-rewriting-and-pretty-links-explained) – user3783243 Apr 09 '21 at 14:29
  • Capture everything before, `?lang=`, and then everything after that. Move everything after to the start, and append the before after it. – user3783243 Apr 09 '21 at 14:29
  • Also, you might want to have a look at how to specifically [capture the query string](https://stackoverflow.com/questions/2252238/how-can-i-match-query-string-variables-with-mod-rewrite). – nosurs Apr 09 '21 at 14:41
  • Yes, this is possible. Please share your attempts and where you're stuck – Nico Haase Apr 09 '21 at 15:51

1 Answers1

1

Is it possible to use the .htaccess file to change something like:

  • example.com/dir/?lang=en to example.com/en/dir/

Yes, except that you don't change the URL to example.com/en/dir/ in .htaccess. You change the URL to example.com/en/dir/ in your internal links in your application, before you change anything in .htaccess. This is the canonical URL and is "what the user types in/is in the address bar" - as you say.

You then use .htaccess to internally rewrite the request from example.com/en/dir/, back into the URL your application understands, ie. example.com/dir/?lang=en (or rather example.com/dir/index.php?lang=en - see below). This is entirely hidden from the user. The user only ever sees example.com/en/dir/ - even when they look at the HTML source.

So, we need to rewrite /<lang>/<url-path>/ to /<url-path>/?lang=<lang>. Where <lang> is assumed to be a 2 character lowercase language code. If you are offering only a small selection of languages then this should be explicitly stated to avoid conflicts. We can also handle any additional query string on the original request (if this is requried). eg. /<lang>/<url-path>/?<query-string> to /<url-path>/?lang=<lang>&<query-string>.

A slight complication here is that a URL of the form /dir/?lang=en is not strictly a valid endpoint and requires further rewriting. I expect you are relying on mod_dir to issue an internal subrequest for the DirectoryIndex, eg. index.php? So, really, this should be rewritten directly to /dir/index.php?lang=en - or whatever the DirectoryIndex document is defined as.

For example, in your root .htaccess file:

RewriteEngine On

# Rewrite "/<lang>/<directory>/" to `/<directory>/index.php?lang=<lang>"
RewriteCond %{DOCUMENT_ROOT}/$2/index.php -f
RewriteRule ^([a-z]{2})/(.*?)/?$ $2/index.php?lang=$1 [L]

# Rewrite "/<lang>/<directory>/<file>" to `/<directory>/<file>?lang=<lang>"
RewriteCond %{DOCUMENT_ROOT}/$2 -f
RewriteRule ^([a-z]{2})/(.+) $2?lang=$1 [L]

If you have just two languages (as in your example), or a small subset of known languages then change the ([a-z]{2}) subpattern to use alternation and explicitly identify each language code, eg. (en|de|ab|cd).

This does assume you don't have physical directories in the document root that consist of 2 lowercase letters (or match the specific language codes).

Only URLs where the destination directory (that contains index.php) or file exists are rewritten.

This will also rewrite requests for the document root (not explicitly stated in your examples). eg. example.com/en/ (trailing slash required here) is rewritten to /index.php?lang=en.

The regex could be made slightly more efficient if requests for directories always contain a trailing slash. In the above I've assumed the trailing slash is optional, although this does potentially create a duplicate content issue unless you resolve this in some other way (eg. rel="canonical" link element). So, in the code above, both example.com/en/dir/ (trailing slash) and example.com/en/dir (no trailing slash) are both accessible and both return the same resource, ie. /dir/index.php?lang=en.

MrWhite
  • 23,175
  • 4
  • 44
  • 71