From your directives, I assume your .htaccess
file is located inside the /bb
subdirectory.
RewriteCond ^(fr|en|ar)/?(.*)?$ !-d
RewriteRule ^en/?(.*)?$ ./$1?lang=English [L,QSA]
RewriteRule ^fr/?(.*)?$ ./$1?lang=French [L,QSA]
RewriteRule ^ar/?(.*)?$ ./$1?lang=Arabic [L,QSA]
Whilst these directives might be "working perfectly", they are not "correct".
The RewriteCond
directive is always successful, since ^(fr|en|ar)/?(.*)?$
(which is a literal string) will never map to a directory. You probably meant to use %{REQUEST_FILENAME}
here. However, since you state that the sub-folder language is "fake", the request could never map to a real directory anyway (providing it matched the RewriteRule
pattern) so this could probably just be removed. Also, the RewriteCond
directive only applies to the first RewriteRule
that follows, so the 2nd and 3rd rules are working unconditionally anyway.
Also, the substitution string should not be prefixed with ./
(to signify the current directory) - it still works because the OS is able to resolve this, but otherwise it is just "bloat". eg. This would otherwise become /bb/./foo?lang=English
, which is the same as /bb/foo?lang=English
.
With the sub-regex (.*)?
- the trailing ?
is not required since (.*)
is optional by definition (0 or more instances of .
).
if no language is selected and the user is on the url : localhost/bb/
or localhost/bb/index.php
it should redirect...
Your attempts seem to focus on testing that no language is in the URL, but if the user is on /bb/
or /bb/index.php
then no language is present anyway - so just check for either of these two URLs? (Or have I missed something? Maybe if a URL of the form /bb/foo/bar
is requested - but you don't appear to have mentioned that?)
Try the following instead:
RewriteEngine on
RewriteBase /bb/
# Default to English (ie. /bb/en)
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^(index\.php)?$ en/ [R,L]
# Route language URLs
RewriteRule ^en/?(.*) $1?lang=English [L,QSA]
RewriteRule ^fr/?(.*) $1?lang=French [L,QSA]
RewriteRule ^ar/?(.*) $1?lang=Arabic [L,QSA]
The condition on the first rule is to ensure we don't get a redirect loop (after rewriting the URL later).
UPDATE:
...by changing the code a bit RewriteRule !^(fr|en|ar)/?(.*)$ en/$1 [R,L]
to avoid the loop...
Unless you still have the condition (RewriteCond
directive) that I included above, that rule by itself looks like it would result in a redirect loop if requesting a URL of the form /bb/en/
, since the later rewrite rewrites the URL to /bb/?lang=English
which would get caught by the earlier redirect (when the rewrite engine starts over)? Rinse and repeat... (?)
However, if this directive is working OK for you then it can be simplified...
- Negated (ie.
!
prefix) patterns cannot actually capture anything (by definition, they are non-matching), so the trailing capturing sub-pattern (.*)
is not capturing anything.
- Likewise, the
$1
backreference in the substitution string is always empty.
So, this could be rewritten like this:
RewriteRule !^(fr|en|ar)/? en/ [R,L]
anything after /fr/
will be a valid request or a valid file, like /bb/fr/?article=123
or bb/fr/contact.php
You could default the language if requesting /bb/<something>
eg. /bb/contact.php
redirect to /bb/en/contact.php
.
For example:
# Default to English (ie. /bb/en/<anything>)
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} ^/bb/(.*)
RewriteRule !^(en|fr|ar)/? en/%1 [R,L]
The %1
backreference (as opposed to $1
) is a backreference to the last matched CondPattern, ie. the part of the URL after /bb/
(if anything).
EDIT: I've added the filesystem conditions to exclude requests for actual directories and files.
if i request the link without the last slash like this: http://localhost/bb/en
it show me the page with broken images and css links
That actually answers a query I had... I wasn't sure whether the trailing slash on the language code was required or not (since it was optional in your RewriteRule
pattern) - so I had omitted it on the first redirect initially (I've since included the trailing slash after the "update").
The broken images and CSS links are most probably the result of using relative URL paths in your client-side HTML. You should use root-relative (or absolute) URLs when URL-rewriting to avoid issues like this. See my answer to the following Webmasters question for more detail on this:
The trailing slash shouldn't really be optional (it essentially creates two URLs that serve the same content). Which one do you link to - which is canonical? I assume a trailing slash is canonical... you could then enforce a trailing slash in .htaccess
, before the exitsing directives. For example:
# Force trailing slash on language code
RewriteRule ^(en|fr|ar)$ $1/ [R=301,L]
In Summary
Applying the recent points...
RewriteEngine on
RewriteBase /bb/
# Force trailing slash on language code
RewriteRule ^(en|fr|ar)$ $1/ [R=301,L]
# Default to English (ie. /bb/en/<anything>)
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} ^/bb/(.*)
RewriteRule !^(en|fr|ar)/? en/%1 [R,L]
# Route language URLs
RewriteRule ^en/(.*) $1?lang=English [QSA,L]
RewriteRule ^fr/(.*) $1?lang=French [QSA,L]
RewriteRule ^ar/(.*) $1?lang=Arabic [QSA,L]
/bb/fr/foo
, what is the expected result? Or is "foo" always expected to be a valid file?/fr/
will be a valid request or a valid file, like/bb/fr/?article=123
orbb/fr/contact.php