By now my site was only a one-language site.
I had my files on (suppose):
www.mysite.com/files/index.php
www.mysite.com/files/header.php
www.mysite.com/files/page1.php
www.mysite.com/files/page2.php
Now I added a multilanguage support to those files. All the words/texts are stored on the database and a php class complete the stuff.
By now I had (badly) on header.php
this line:
define('LNG', 'en');
and I had a header.php
file placed on each language directory:
www.mysite.com/en/header.php
www.mysite.com/de/header.php
...
and then I included the files depending on the LNG
constant, e.g.
include_once "/files/page1.php?l=".LNG
but I know this is a very bad practise!
How can I solve this problem? I would mantain my files on www.mysite.com/files/...
and then write the user language in the URL, so that the file can read the language from the url and load the right textes and words from the databases.
Sort of:
www.mysite.com/en/index.php
which in fact loads
www.mysite.com/index.php
with the correct language en
. I'm able to get the en
from the URL and define a constant on the page, but if I point to www.mysite.com/en/index.php
I obviously get a 404
...
Dealing with multi-language web-applications
LANGUAGE CONSTANTS
could be placed in language files within a language directory like this
/ languages
en.php
it.php
...
while language files may look as following
// en.php
define("THANK_YOU", "Thank you!");
define("PRODUCTS", "Products");
define("PRODUCT", "Product");
...
// it.php
define("THANK_YOU", "Grazie!");
define("PRODUCTS", "Prodotti");
define("PRODUCT", "Prodotto");
....
or they could be stored into database as shown below. I've used both but I prefer the first solution
+------------+------------+------------+-----
| constant | en | it | ...
+------------+------------+------------+-----
| THANK_YOU | Thank you! | Grazie! |
| PRODUCTS | Products | Prodotti |
| PRODUCT | Product | Prodotto |
| ... | ... | ... |
+------------+------------+------------+-----
FRIENDLY URLs
may look like these below
http://www.domain.com
http://www.domain.com/en
http://www.domain.com/it
http://www.domain.com/en/products
http://www.domain.com/it/prodotti
http://www.domain.com/en/product/our-best-product/555
http://www.domain.com/it/prodotto/il-nostro-miglior-prodotto/555
having in mind rules that should be defined in .htaccess
file
RewriteRule ^([a-z]+)(/)?$ index.php?lang=$1 [QSA,L]
RewriteRule ^([a-z]+)/(products|prodotti)(/)?$ index.php?lang=$1&action=$2 [NC,L]
RewriteRule ^([a-z]+)/(product|prodotto)/(.*)/([0-9]+)(/)?$ index.php?lang=$1&action=$2&id=$4&mode=details [NC,L]
# these rules are for a demonstration purpose; otherwise, all three directives
# could be written in one singe line / rule
or you can redirect the request (as following) to an entry point and parse it with parse_url()
.
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?param=$1 [QSA,L]
ACCESSING THE lang VARIABLE
- On multi-language projects variable lang
has a special significance, otherwise it would be treated and passed around just like any other variable using GET
, POST
, COOKIE
, XMLHttpRequest
, HTTP headers
, HTTP referer
, URL hash parameter
, database session
, APC (Alternative PHP Cache)
...
If you care about UX
and SEO
the lang
variable should be written within URL. I prefer using $_SESSION or $_GET and it should be pointed that some of the methods mentioned above doesn't work always or may get blocked by a Proxy.
The snippet below shows how to access it using $_SESSION or $_GET
// config.php
// ...
$cfgObj->default_language = "en";
// ...
$_SESSION["lang"] = isset($_GET["lang"]) ? $_GET["lang"] : $cfgObj->default_lang;
include($cfgObj->dir_languages . $_SESSION["lang"] . ".php");
// index.php
switch(isset($_GET["action"]) ? $_GET["action"] : "default"){
case PRODUCTS: case PRODUCT: case 3:
// deal with products
break:
case ARTICLES: case ARTICLE: case 5:
// deal with articles
break:
default:
// deal with short-links
// domain.com/3/555 <-- this would retrieve product with id 555
break;
}
DATABASE SCHEMA
could be designed like following
+-----------------+ +-----------------------+ +--------------------+
| products | | products_to_languages | | languages |
+-----------------+ +-----------------------+ +--------------------+
| product_id [PK] |---| | ptl_id [PK] | |---| language_id [PK] |
| price | |---| product_id [FK] | | | language_code |
| status | | languge_id [FK] |---| +--------------------+
| ... | | product_name |
+-----------------+ | product_description |
+-----------------------+
* I use language_code as a primary key as well, and an index on all foreign keys