Switching languages on a website with PHP - php

I'm just looking for some advice. I'm creating a website that offers (at least) 2 languages.
The way I'm setting it up is by using XML files for the language, PHP to retrieve the values in the XML nodes.
Say you have any XML file, being loaded as follows:
<?php
$lang = "en";
$xmlFile = simplexml_load_file("$lang/main.xml");
?>
Once the file contents are available, I just output each node into an HTML tag like so:
<li><?php echo $xmlFile->navigation->home; ?></li>
which in turn is equal to : <li>Home</li>
as a nav bar link.
Now, the way in which I'm switching languages is by changing the value of the "$lang" variable, through a "$_POST", like so:
if(isset($_POST['es'])){
$lang = "es";
}elseif(isset($_POST['en'])){
$lang = "en";
}
The value of the "$lang" variable is reset and the new file is loaded, loading as well all the new nodes from the new XML file, hence changing the language.
I'm just wondering if there is another way to reset the "$lang" variable using something else, other than "$_POST" or "$_GET". I don't want to use query string either.
I know I could use JavaScript or jQuery to achieve this, but I'd like to make the site not too dependable on JavaScript.
I'd appreciate any ideas or advice.
Thanks

I would go for session variable.
At the beginning of your pages you'll have:
if (!isset($_SESSION['language']))
$_SESSION['language'] = "en";
Then you'll have some links to change the language
Español
Français
Changelanguage.php simply is something like
$language = $_GET['lang'];
// DO SOME CHECK HERE TO ENSURE A CORRECT LANGUAGE HAS BEEN PASSED
// OTHERWISE REVERT TO DEFAULT
$_SESSION['language'] = $language;
header("Location:index.php"); // Or wherever you want to redirect

Have you thought about using $_SERVER["HTTP_ACCEPT_LANGUAGE"]? Something like this:
if ($_SERVER["HTTP_ACCEPT_LANGUAGE"]) {
$langs = explode(",", $_SERVER["HTTP_ACCEPT_LANGUAGE"]);
for ($i = 0; $i < count($langs); $i++) {
if ($langs[$i] == "en") {
$lang = "en";
break;
}
elseif($langs[$i] == "es") {
$lang = "es";
break;
}
}
}
Of course, a switch statement might fit a bit better here, and there's more ways to say English than only en, but this should work without the user having to do a thing. If they manually change, store it in a cookie as per Ben's answer.

The most common way would be to use it as part of the url and extract it when a page loads:
http://www.your-site.com/en/somepage
Are you using a framework?

The most common way to pass a language identifier is subdomain.
http://en.wikipedia.com/
both subdomains should point to the same directory and actual language can be easily extracted from the HTTP_HOST
and for storing language files the solution is gettext

Related

Selecting different languages from SQL database with PHP

I'm having a 2 issues with my website.
It's a multi language one (german, english).
I always kept the translations in an XML document like this
<?xml version="1.0" encoding="utf-8"?>
<root>
<les>
<en>Lesson</en>
<de>Lektion</de>
</les>
Then I converted those XML vars into php ones and echo'd them where needed like this
$xml=simplexml_load_file("langindex.xml") or die("xml not found!");
$les = $xml->les->$lang;
<?php echo $les;?>
Problem 1 is that no language is set as default when I open the Website so I always have to select a language first, even though I included that !isset. If I don't select anything, some images will be streched and it gives me the error that no language is set.
<?php
session_start();
$page = 0;
$lang = $_GET['lang'];
$langArray = array('en','de');
$found = false;
if(in_array($lang, $langArray))
$found = true;
if(!$found)
$lang = 'en';
if(!isset($_SESSION['lang']))
$_SESSION['lang'] = 'en';
if(isset($_GET['lang']) && in_array($_GET['lang'], array('en', 'de')))
$_SESSION['lang'] = $_GET['lang'];
include '../nihongo/php/dbconnect.php';
My language switch works with a simple <a href="?lang=X"> and that ?lang=X will be shown in the URL as well.
Enough of that.
Since XML is pretty inpractical I wanted to switch the whole thing up to an SQL database.
I've created a table with the columns ID, german and english and connected the db sucessfully.
Now I want PHP to tell SQL to get only the text of the session language with a select like this for example.
SELECT german FROM texts WHERE ID = '1'
SELECT english FROM texts WHERE ID = '2'
My problem is that I really don't know how to do that with PHP.
I would think that I'd either have to throw a PHP var into the statement somehow, or select the whole row and let PHP decide which one should be displayed.
Every advice/suggestion is welcome!
Thanks in advance!
I like the way OpenCart implemented this, because it's simple and doesn't add additional calls to the DB. Take a look at their implementation. You learn a lot investigating and learning from Open Source projects.
They have a php script per language and module with an array that contains all the strings. It just include or load the scripts to get access to the strings, for example: en-gb. Loading a string by its key with this method:
language->get('heading_title');

PHP Dynamic URL in Multilengual Web

Hi everybody and tks in advance for your help!
I have a multilengual site made in a similar way to this example. Everything is working just fine, but now I want to make that the URL change according to the languague selected. For example, if my page is called perfil.php when I select english languague, should be profile.php, and all the links in the web should translate to english too. I was surfing another questions but the majority offers a solution through htaccess. This should work, but I need to store that configuration (or translations) into my database so the user can change it when they want to.
Any ideas?
Thank you again!
You can use constants in some files called language files and then require/include them by language selected:
english.php
const PROFILE = "profile";
spanish.php
const PROFILE = "perfil";
main file:
require $language_selected . ".php";
echo '<a href="' . PROFILE . '.php">';
This part should be a comment (but its a bit long)
The method described in the link you provided is a reasonable way to implement the choice of language, but a poor way to detect the choice.
Your browser already tells servers what language(s) it thinks they should respond in. And most webservers have a mechanism for multiplexing different language content. However the latter means hard-wiring the choice of the browser without providing an easy means for overriding the behaviour.
The approach I have used before is something like this:
$use_lang='en-GB';
if (isset($_COOKIE['userlang'])
&& is_language_supported($_COOKIE['userlang'])) {
$use_lang=$_COOKIE['userlang'];
} else if ($proposedlang=supported_lang_in($_SERVER['Accept-Language'])) {
$use_lang=$proposedlang;
}
function supported_lang_in($str)
{
$l=array();
$opts=explode(',', $str);
foreach ($opts as $v) {
list($p, $weight)=explode(';', $v);
if ($weight) {
list($dummy, $weight)=explode('=', $weight);
$weight=float($weight);
}
if (!$weight) {
$weight=1.0;
}
if (isset($l[$weight])) {
$weight-=0.001;
}
$l[$weight]=$p;
}
krsort($p); // preferred first
foreach ($p as $proposed) {
if ('*'==$proposed) {
return false;
}
if (is_language_supported($proposed)) {
return $lang;
}
}
return false;
}
Now on to the problem you asked about....
Maintaining different URLs to reference the same content then dereference the language within the content seems a very byzantine solution to the problem. Not only do you have to map the input to the URL but you need to rewrite any URLs in the output to the appropriate representation.
While having semantically meaningful URLs is a definite bonus, going to great length to tailor these dynamically is not perhaps not the best use of your time.

PHP language selector

I'm pretty sure this was working before, so I don't know what happened to the code I had in place for a language selector I've been using for a site in development. Here is the php:
<?php
session_start();
if(isset($_POST['language'])) {
$_SESSION['language'] = $_POST['language'];
}
$language = (isset($_SESSION['language']) ? $_SESSION['language'] : "english");
include('/Languages/'.$language.'.php');
?>
The HTML:
<form method="post">
<input type="image" name="language" value="english" src="Images/english.png"/>
<input type="image" name="language" value="spanish" src="Images/spanish.png"/>
...
</form>
The PHP in each 'dictionary' file:
<?php
$content = array(
"identifier1"=>'content with html to be included',
"identifier2"=>'more content to be included'
);
?>
And finally, the code on the actual page to call the right language:
<?php echo $content['identifier1']; ?>
So this is supposed to work by having the user click one of the images in the form. The form sends the value of the clicked image, which is the name of the language file that should be opened. The PHP, which is in the head of the page, then takes this value, and includes the dictionary file (eg, english.php), which can then be referred to in the HTML from the echo above.
However, I cannot get this to work. When I click on the image, the page reloads. I've tried doing a <?php echo 'stuff'; ?>, and that works, so my PHP should be working. This means that something must be wrong with the code.
Okay, apologies for taking so long to reply. It took me a while to do some further research into this, along with other links provided here by others. In any case, I found a better solution which uses cookies instead of a single session as follows:
Before beginning your HTML (or at the very least, before your body tag), add the following PHP code:
<?php
$lang = "YOUR DEFAULT LANGUAGE";
$allowedlangs = array(
"AVAILABLE LANGUAGES 1",
"AVAILABLE LANGUAGESS 2"
);
if (!empty($_GET["lang"])) {
$rlang = $_GET["lang"];
} else if (!empty($_COOKIE["lang"])) {
$rlang = $_COOKIE["lang"];
}
if (isset($rlang) && !empty($rlang) && in_array($rlang, $allowedlangs)) {
$lang = $rlang;
setcookie("lang", $lang,time()+31536000);
}
$langmaps = array(
"AVAILABLE LANGUAGES 1" => "FILE PATH TO LANGUAGE 1 FILE.php",
"AVAILABLE LANGUAGES 2" => "FILE PATH TO LANGUAGE 1 FILE.php"
);
include($langmaps[$lang]);
?>
So $lang is a variable that initially defines the language you want a new visitor to see. That is, the default language. Whatever value $lang takes, it must be from the array on the next line. It doesn't matter what you call your languages, as long as you can identify them for yourself. The code doesn't care. Call the English language "english", "en", "lang1", "TeaAndCrumpets", or anything you want. Make a new line for each additional language you want to have.
Further down you have the line with $langmaps. The lines in this array will match the names of your languages to the file path that contains your language values. For example, if your English language is "TeaAndCrumpets", the code would be:
"TeaAndCrumpets" => "FILE PATH TO LANGUAGE 1 FILE.php"
Then just type in the file path to the English file, which, again, can be named anything, as long as you point to the right file.
After this, you just need the buttons. No forms needed. Just an for each language you want. In this case, I use images wrapped in tags like so:
<img src="/images/english.png" title="English" alt="English">
<img src="/images/russian.png" title="Russian" alt="Russian">
This will simply add the URL variable to the address bar, and the PHP kicks in. Make sure whatever value in the href you have for the lang variable matches one of the names in your $allowedlangs array, and that your title and alt attributes make sense to your visitors.
Ok, a couple of things:
1) Why are you using an associative array for something that is innherently an indexed system? Why not use a regular array?
2) Try debugging. Echo $_SESSION['language'] and make sure the value is even making it through.
Also, try doing a var_dump($content) and see what that gives you after you've included the language file.
Updates:
Add an action to your form. Even if it's empty. That could be having an effect.
Did you try a var_dump on your $_POST value?
Also, try
var_dump("/Languages".$language.".php");
However, I would specify the location of your language file via a base directory. Usually in projects I have a global application object store that value as a constant like this:
define("BASEDIR", __DIR__ . "/");
You would, of course, add the appropriate number of "../" or additional filepath information to the end of that if necessary.
From there, I use that as the "base directory" for ALL file includes. So, if your language file is at
[base project directory]/Languages/english.php
then you'd include it like so:
include(BASEDIR . "Languages/" . $language . ".php");
Of course, make sure that your base dir constant has a trailing slash, or add one here (I prefer terminating all directory names with a trailing slash).

Access control of page in php

I want to control the access in php website.
I have a solution right now with switch case.
<?php
$obj = $_GET['obj'];
switch ($obj)
{
case a:
include ('a.php');
break;
default:
include ('f.php');
}
?>
But when i have so many pages, it becomes difficult to manage them. Do you have better solutions?
Right now, i develop the application using php4. And i want to use php5. Do you have any suggestions when i develop it using php5?
Thanks
$obj = $_GET['obj'];
$validArray = array('a','b','c','d','e');
if (in_array($obj,$validArray)) {
include ($obj.'.php');
} else {
include ('f.php');
}
The more pages you have the harder it will be to control this.
Your best off using a framework of some sort, my personal preference is CodeIgniter.
why not just address a page itself?
first page
another page
I am not saying that this is the best solution, but years ago I used to have a website which used a database to manage the key, the page to be included, and some informations like additional css for instance.
So the code was something like:
<?php
$page = htmlspecialchars($_GET['page']);
$stuffs = $db->query('select include,css from pages where pageid = "' . $page . '" LIMIT 1');
?>
So when we needed to add a page, we just created a new field in the database. That let us close a part of the website too: we could have a "available = {0,1}" field, and if zero, display a static page saying that this page was under maintenance.

Including pages with $_GET

I want url's like index.php?showuser=512, index.php?shownews=317 for pages i get content from db... and for regular pages index.php?page=about and so on WITHOUT mod-rewrite.
Invision Power Board has urls like this. I have looked through their code but I can't figure out how they do it.
I could do it like this:
if (ctype_digit($_GET['shownews'])) include('shownews.php');
elseif (ctype_digit($_GET['showuser'])) include('showuser.php');
// regular pages
elseif ($_GET['page'] == 'about') include('about.php');
elseif ($_GET['page'] == 'help') include('help.php');
elseif ($_GET['page'] == 'login') include('login.php');
But this feels too messy.
Just curious how IPB does this. Is there a better way do to this? WITHOUT any mod-rewrite. Any one know? I doubt they do it like the above.
I can't do:
if (preg_match('/^[a-z0-9]+$/', $_GET['page'])) include('$_GET['page']');
Then I would get links like index.php?showuser&id=512 and that I dont like. (i know its not safe just showing the princip)
I like it this way, it's not the best but i like it so please be quiet about template engines, frameworks etc. Just be kind and answer my question... I just want to know how IPB does this.
Thanks
Tomek
I don't know how IPB does this, let's get that out of the way. But, this is how I would approach this problem:
First, I recognize that there are two kinds of GET parameters: page/identifier, and just page. These would get tested separately.
Second, I recognize that all all get parameters match their filenames sans the php-suffix, so we can use this to our advantage.
One of the most important things to remember is to never let GET-parameters affect our code unsanitized. In this case, we know which types of pages we can and want to show, so we can create a white-list out of these.
So, onto the pseudo-y dispatcher code:
$pagesWithId = array("shownews", "showuser", "showwhatever");
$justPages = array("about", "help", "login");
foreach ($pagesWithId as $page) {
if (isset($_GET[$page])) {
$id = (int)$_GET[$page];
include($page.'.php');
die();
}
}
if (in_array($_GET['page'], $justPages)) {
include($_GET['page'].'.php');
die();
}
// page not found
show404OrHandleOtherwise();
For pages you just use a simple array.
if (isset($pages[$_GET['page']])) include $pages[$_GET['page']];
For shownews=317 You could make a simple conversion in your app. Depending on how you want to prioritize page or shownews etc:
if (isset($pages[$_GET['page']])) {
include $pages[$_GET['page']];
} else {
$possiblePages = array_filter(array_intersect_key($_GET, $pagesWithId), 'ctype_digit');
if (!empty($possiblePages)) {
$id = reset($possiblePages);
$pageName = key($possiblePages);
$page = $pagesWithId[$pageName];
include $page;
} else {
//no valid pages
}
}
Note: page "names" are array keys, and the value is the path, file and extension to include. More customizable.

Categories