Jump to content

Two languages to choose


kurt.santo

Recommended Posts

Having two languages: How do you pass the information from a "choose language link" to navigation and text area, so relevant language is displayed? It is the same website, just one is in English where the other one is in German. On whatever page the user is, clicking onto "German" should show the same page in German. From this point onwards the user will navigate through the German section and only return if he clicks onto "English". All data should be stored in a database. Kurt

Link to comment
Share on other sites

I use a session variable for that and have the language links put a variable onto the querystring. If the $_GET language variable is set then I update the session with whatever the value is, and get the appropriate text to put on the page. You'll need one or more files that contains all of the text in the various languages you want to have, and the output pages will need to read the language from the session and include the appropriate text.

Link to comment
Share on other sites

Justsomeguy, thank you for your reply. To understand could you help me with the following:querystring = is the querystring the url (for example the url as product.php?lang="dt")?if the $_GET language variable is set = meaning that the language link was clicked? also meaning that as long as language link is not clicked language is standard (English)?then I update the session with whatever the value is = how do you update or create a session?one or more files that contains all of the text in the various languages = is this a better option to keeping the text inside a database? can one file contain the text for all different pages? if yes, how do you separate the the different sections/pages?output pages will need to read the language from the session and include the appropriate text = how do you do this?I am sorry to be such a pain, but I really want to understand to be able to implement what you adviced...Kurt

Link to comment
Share on other sites

The query string is the part of the URL after the "?". In your sample, that would be '?lang="dt"' (note that the quotes aren't really needed).When you pass this variable, you'll get it with the $_GET variable, and not only set the language to that page, but also overwrite whatever sort of utility you use for tracking the user's preferences (be it a cookie or a session).I'd also append all links with the new language.I believe the best approach involves all three stages with no session being involved. In this order:1. If the query string variable is available, use that value, create (or update) a cookie containing the preference (if needed) and append all links.This is noticeably quicker in my case, as I use XSLT, so appending all links involves the passing of a single parameter to the XSLT processor. In "pure PHP driven" sites that embed PHP in HTML, you'll have to have a function that does that, and it may be arguable whether this will be efficient.2. If no variable is available, check if there is a cookie. If there is, use whatever setting it stores.3. If no cookie is available, perform language negotiation, use the result and create a cookie with the negotiated result. The language negotiation settings themselves should provide a default in case there's no match.Unfortunatly, since the PHP has already started, you can't do that with Apache, and there's no way with PHP... not natively at least. But the PECL HTTP extension is just marvelous for this job with it's http_negotiate_language() function. If you can't use that extension for whatever reason, you'll have to provide a default only, with no negotiation.At all levels, if the language is not supported (for example, if the user typed "lang=ru" in the query string or has a cookie with this value but you don't have a russian version), fallback to 3.Also, I still need to check the things up for efficiency on that. I think the language negotiation may be the most performance intensive of all three, which is why I leave it as a last resort, but I really have no proof. It may turn out that not providing cookies and just doing negotiation unless there's a query string variable is faster.

Link to comment
Share on other sites

The querystring is the part that comes after the question mark in the URL.

if the $_GET language variable is set = meaning that the language link was clicked? also meaning that as long as language link is not clicked language is standard (English)?
If the querystring contains a language variable then you update the session (or cookie) language variable with the one from the querystring. When you decide which language to show, you use the session (or cookie) variable. If neither variable is set, then you use a default language. At least that's the way I do it, you can make it work how you want it to.Check the session handling reference on php.net, you need to use the session_start function on any page you want to use the session, and then you can use the $_SESSION array for all the values.It would seem easiest to have each language be in its own file, and have the same variables declared in every file. Then you include the appropriate language file before you print the variables. If you want everything in one file then you need a way to specify which language each one is, like an array.$strings['en']['text1'] = "....";$strings['gr']['text1'] = "....";Text files would be better then a database because the data isn't changing much, and it's easy to include one file and have all the language variables defined.
Link to comment
Share on other sites

I will check out the session handling on php.net. But did not get why I need to create sessions?Then if I create a text file as:

$strings['en']['heading1'] = "Welcome";$strings['gr']['heading1'] = "Willkommen";$strings['en']['text1'] = "I am glad you visit my site, blah, blah, blah";$strings['gr']['text1'] = "Super, dass Sie meine Site besuchen und blah, blah, blah";$strings['en']['heading2'] = "About us";$strings['gr']['heading2'] = "Ueber uns";$strings['en']['text2'] = "We like to ask a lot of silly questions, mainly because we do not have a clue, blah, blah, blah";$strings['gr']['text2'] = "Wir fragen so viele dumme Fragen, weil wir keine Ahnung haben, blah, blah, blah";

and name it webContent.txt for example. How would I print the German text2 to a page? How do I include $_GET in the print command?Kurt

Link to comment
Share on other sites

Use a session if you want the language setting to persist on a "user that is logged in" basis i.e. if a single computer on the net can have various settings, but requires each user on that computer to log in to receive their settings. The settings are removed as the user logs out or the session expires.Use a cookie if you want the language settings to persist on a "everyone on this computer" basis i.e. anyone that uses a certain PC will receive those settings, regardless of who (s)he is. The settings are removed if the user cleans their cookies or the cookie expires.There's no "must" in this. You choose the basis on which you'll base the language settings.I think you create a PHP file instead, though I'm not sure. You can get the language by just replacing the key of course, like for example

$lang = $_GET['lang'];echo $strings[$lang]['heading1'];

will get english if the value of the supplied "lang" query string variable is "en" and the german if the value is "de".Of course it's not as simple as that. You also need to ensure the value of the $_GET['lang'] points to an existing language. You can do that with array_key_exists() like so:

$lang = (array_key_exists($_GET['lang'], $strings) ? $_GET['lang'] : 'en');

where "en" is your preferred default language (English in this case).

Link to comment
Share on other sites

Is this the "best"/normal approach on multi languages sites in php?(to separate all relevant text in one file, includes it, and call for the string that contains the chosen language where you want the text to appear. As kurt shows in the text file here:

$strings['en']['heading1'] = "Welcome";$strings['gr']['heading1'] = "Willkommen";

and then print it out like stated over
$lang = $_GET['lang'];echo $strings[$lang]['heading1'];

)Are there other reasonable ways to do this (without using machine translation) ?
Link to comment
Share on other sites

Is this the "best"/normal approach on multi languages sites in php?(to separate all relevant text in one file, includes it, and call for the string that contains the chosen language where you want the text to appear. As kurt shows in the text file here:and then print it out like stated over)Are there other reasonable ways to do this (without using machine translation) ?
Well, the way I do it is to store the various languages in different folders containing the translated files and choose the folder based on the language. Thus, the languages are completely separated, and their selection is still transparent.If you store your content in a database, you may create a new table with languages, associating each language with a particular text (a one-to-may relation).It all depends on how you store your content. The negotiation mechanisms are the same. The difference is only in how you fetch the selected content.
Link to comment
Share on other sites

Most people probably store each language in a separate file. That makes it easy to add new languages without needing to edit a certain file, you just make a new one. If you have files like lang.en.php, lang.fr.php, etc then you just include the appropriate file and start using the variables.

include 'lang.' . $lang . '.php';echo $welcome;

assuming you define a variable called $welcome in the language file.

Link to comment
Share on other sites

this is great stuff guys (love to learn form real cases).What about client side code (js), different includes for those also?aka

if ($lang == en) {echo "<script src=\"myjavascript_en.js\" type=\"text/javascript\"></script>";} else {echo "<script src=\"myjavascript_fr.js\" type=\"text/javascript\"></script>";}

or are there other ways?(js will contain relevant text, like feedback from form handling and so on)

Link to comment
Share on other sites

That's pretty much it. If you have a variable that contains the language to show to the user, and you have filenames or folders with the language in it, then you can subsitute the variable for the language in the name to include whatever is appropriate.echo "<script src=\"myjavascript_{$lang}.js\" type=\"text/javascript\"></script>";

Link to comment
Share on other sites

Guys, your input is amazing. I certainly learned a lot. Unfortunately (as usual) it would be great if you could give me another hand. I am still lost in how to apply the knowledge. As adviced I created two separate files, one for English, one for German. The content for the English one called english.txt is (german.txt has same structure):

$strings['heading1'] = "Welcome";$strings['text1'] = "I am glad you visit my site, blah, blah, blah";$strings['heading2'] = "About us";$strings['text2'] = "We like to ask a lot of silly questions, mainly because we do not have a clue, blah, blah, blah";

I got lost in if I should create a text or php file for that purpose?The relevant page content would be sth as:

<div><ul><li><a href="languages.php">home</a></li><li><a href="about.php">about</a></li><li class="language">language selection: <a href="what to put in here?">standard english</a> <a href="what to put in here?">german</a></li></ul></div><div>Relevant text comes here</div>

What do I exactly need to put into the links at the language selection area? And how do I update links/link text? Where exactly would I need to put "$lang = (array_key_exists($_GET['lang'], $strings) ? $_GET['lang'] : 'en');?I realise that my questions are really basic to you, but I really have to ask so many sillly questions to understand and apply... Kurt

Link to comment
Share on other sites

I got lost in if I should create a text or php file for that purpose?
A PHP file, as you want the arrays to be parsed.
<a href="what to put in here?">

<a href="?lang=en">

And how do I update links/link text?
//Your english content file is content_en.php, the german one is content_dt$lang = (isset($_GET['lang']) ? $_GET['lang'] : 'en');include("content_{$lang}.php");//More codeecho "<h1>{$strings['heading1']}</h1>\n{$strings['text1']}";echo "<h1>{$strings['heading2']}</h1>\n{$strings['text2']}";

Where exactly would I need to put "$lang = (array_key_exists($_GET['lang'], $strings) ? $_GET['lang'] : 'en');?
Right at the top of your document, but with your implementation it is not needed, use the assignment in the above code snippet instead.
Link to comment
Share on other sites

$lang = (isset($_GET['lang']) ? $_GET['lang'] : 'en');include("content_{$lang}.php");-> where do I put this line?I did it as (mercy to a poor soul as me;-)...

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml">$lang = (isset($_GET['lang']) ? $_GET['lang'] : 'en');include("content_{$lang}.php");<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><title>Language Selection Test</title><style type="text/css">ul	{list-style-type:none;}li	{display:inline; margin-right:20px;}li.language	{margin-left:200px;}.language a	{ color:#FF0000; padding-left:20px;}</style></head><body><div><ul><li><a href="languages.php">home</a></li><li><a href="about.php">about</a></li><li class="language">language selection: <a href="?lang=en">standard english</a> <a href="?lang=de">german</a></li></ul></div><div>echo "<h1>{$strings['heading1']}</h1>\n{$strings['text1']}";echo "<h1>{$strings['heading2']}</h1>\n{$strings['text2']}";</div></body></html>

and created content_en.php (german one accordingly) as:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><title>Untitled Document</title></head><body>$strings['heading1'] = "Welcome";$strings['text1'] = "I am glad you visit my site, blah, blah, blah";$strings['heading2'] = "About us";$strings['text2'] = "We like to ask a lot of silly questions, mainly because we do not have a clue, blah, blah, blah";</body></html>

I completely messed up. How do I put it right?Kurt

Link to comment
Share on other sites

You're creating XHTML files. This is your display file:

<?php$lang = (isset($_GET['lang']) ? $_GET['lang'] : 'en');include("content_{$lang}.php");?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml">  <head>	<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />	<title>Language Selection Test</title>	<style type="text/css">	ul	{list-style-type:none;}	li	{display:inline; margin-right:20px;}	li.language	{margin-left:200px;}	.language a	{ color:#FF0000; padding-left:20px;}	</style>  </head>  <body>	<div>	  <ul>		<li><a href="languages.php">home</a></li>		<li><a href="about.php">about</a></li>		<li class="language">language selection: <a href="?lang=en">standard english</a> <a href="?lang=de">german</a></li>	  </ul>	</div>	<div>	  <h1><?php echo $strings['heading1']; ?></h1>	  <?php echo $strings['text1']; ?>	  <h1><?php echo $strings['heading2']; ?></h1>	  <?php echo $strings['text2']; ?>	</div>  </body></html>

And this is the include file:

<?php$strings['heading1'] = "Welcome";$strings['text1'] = "I am glad you visit my site, blah, blah, blah";$strings['heading2'] = "About us";$strings['text2'] = "We like to ask a lot of silly questions, mainly because we do not have a clue, blah, blah, blah";?>

Link to comment
Share on other sites

I know it may be too early, but still... am I the only one that sees a problem with allowing the user to enter an arbitary string as a language?Just try to use for example "?lang=ru" (i.e. a language you don't have) and you'll see the page is all messed up. Why not fallback to the default language in those cases?On the very least, ensure the language matched with the rest of the filename will truly lead to an existing file.In other words, replace

<?php$lang = (isset($_GET['lang']) ? $_GET['lang'] : 'en');include("content_{$lang}.php");?>

(if a variable is set, directly use it's value and iclude the respective file)with either

<?php$lang = (isset($_GET['lang']) ? $_GET['lang'] : 'en');if (is_file("content_{$lang}.php")) {include "content_{$lang}.php";}else {include "content_en.php";}?>

(check the resulting path resolves to any existing file, and if it doesn't, include the default page)or

<?phpinclude "content_en.php";$lang = (isset($_GET['lang']) ? $_GET['lang'] : 'en');include_once "content_{$lang}.php";?>

(include the english variables first. If a new file containg them is included, those values will be overrided. If not, those values would be used, since they'll be included already. The "_once" addition is added to ensure the english variant is not needlessly added twice)or my personal favorite

<?php$lang = (ereg('[a-z]{2}\-?[a-z]', $_GET['lang']) && is_file("content_{$_GET['lang']}.php") ? $_GET['lang'] : 'en');include "content_{$lang}.php";?>

(check if the string is even a language code, and if it is, whether it points to an exising file. If so, use it as a value. Otherwise fallback to the "en" value, and thus include the english variant)

Link to comment
Share on other sites

<?php$lang = (ereg('[a-z]{2}\-?[a-z]', $_GET['lang']) && is_file("content_{$_GET['lang']}.php") ? $_GET['lang'] : 'en');include "content_{$lang}.php";?>

boen_robot,You reckon I should use the above code to make sure the user does not manually enter any unavailable languages to the querystring. My experience is quite limited (as everyone knows in this forum;-)), so if that is the way to do it I will certainly adopt your model. Did you personally have bad experience not using those precautionary messures?Kurt

Link to comment
Share on other sites

Any language you want to change goes in the language file as a variable.
justsomeguy,It works well. Thank you!I need your advice in one more issue: In addition to my global navigation at the top I want to have a sub-nav. So, if the user selects "About" at the top the left bar will show a nav with "About Kurt", "About Sonja", "About Minti". And when you click onto Photos "Landscape", "Portrait", "Other" would show. Would that be a thing to put into the database? Or could I achieve the same thing with the include files? Each time there is a new sub-section (new webpage) I want this to be "automatically" added to the sub-nav bar...Kurt
Link to comment
Share on other sites

<?php$lang = (ereg('[a-z]{2}\-?[a-z]', $_GET['lang']) && is_file("content_{$_GET['lang']}.php") ? $_GET['lang'] : 'en');include "content_{$lang}.php";?>

boen_robot,You reckon I should use the above code to make sure the user does not manually enter any unavailable languages to the querystring. My experience is quite limited (as everyone knows in this forum;-)), so if that is the way to do it I will certainly adopt your model. Did you personally have bad experience not using those precautionary messures?Kurt

As a site maker, I haven't had any problems. The reason is simply that I've only made one site with two languages, and that site is not even live yet :) . As a user though, I've had a bad experience.Often different sites show "lang" variable in their query string, but it's not always easy to find the language switch. So I, as a computer savvy user, knowing enough about query string variables, edit the value myself, expecting to get ideally my language preference or at least the page in it's default language. What I sometimes get though is a messed up page, or an error message in the default language (and thank god that language is often English... imagine if I didn't knew it... I'll be wondering if this is even an error message).I must say Wikipedia are pretty close to making ideal error messages on that (which is not possible for smaller sites). If you manually try to swtich from an english article to a language in which there isn't this same article, you get an error message in your own language saying there's no such article. Now if they only putted links to the other languages in which the article was written, they'd be perfect.For smaller sites (that have only a few languages, rather than trying to have an article in every language known to man), the best approach is to simply use the default language if a non existing one is provided. For "partial" cases, it's best (though hard to do) to only give an error message in a good language and offer links on the other available languages (or the page directly if there's only one option).By "partial" I mean that, say you have the core system and error messages translated in say English and German. All of the other content however is not completely translated. There are pages that are only available in English, some only in German and some in both languages. If the user asks for a page in a language that doesn't exist, he should get the page with the default language with visible links that show in which languages that particular article is available in. If the user requests "English" for an article that's only in German, show the German article with an English error message. And if the user requests "German" for an article that's only in English, show the English article, with a German error message.This is all of course just usability theory. Actually implementing it like that is hard. Nevertheless, point stands that messed up pages are the worst kind of impression a multy language site could make. You need to insure you don't get into THAT situation. The localized error messages can wait.By the way, I have a slight error. It should be
<?php$lang = (ereg('[a-z]{2}(\-[a-z]{2})?', $_GET['lang']) && is_file("content_{$_GET['lang']}.php") ? $_GET['lang'] : 'en');include "content_{$lang}.php";?>

instead, as language codes' secondary part also has two letters, and with what I had, not only was one letter only allowed, but just having for example "en-" was permitted. Now it's not.As for how would you make the submenu - yes, again in the included file. I'd personally include a different file for each page + common content. To put some code into my words:

<?php$defaultLang = 'en';$lang = (ereg('[a-z]{2}(\-[a-z]{2})?', $_GET['lang']) && is_file("_common_{$_GET['lang']}.php") ? $_GET['lang'] : $defaultLang);include "_common_{$lang}.php"; //common content$page = (eregi('^[a-z0-9]+$',$_GET['page']) ? $_GET['page'] : '_404');include (is_file("{$page}_{$lang}.php") ? "{$page}_{$lang}.php" : (is_file("{$page}_{$defaultLang}.php") ? "{$page}_{$defaultLang}.php" : (is_file("_404_{$lang}.php") ? "_404_{$lang}.php" : "_404_{$defaultLang}.php"))); //page specific content?>

(detect the language as already desribed, and include the common content corresponding to the selected language. Then check if the value of yet another query string variable (called "page" in this case) consists of only letters and numbers. If so, use it as a value. If not, load the "File not found - 404" page in the selected language. If it does, check if there's a page in that language and if not, if the specified page is at least available in the default language. If that too fails, show a "File not found - 404" page in the specified language, and if there isn't a 404 page in that language, use the 404 page with the default language.)That last line is long and complex, I know. But it's the best model I could imagine so far. At least one that follows your way of storing data. AND it provides localized error messages too.Note that the 404 pages and the common files intentionally don't follow the naming convention and are prefixed with "_". This would allow you to have an actual article named "404" or "common" and reference it from the query string. In the case of "common" this also means the "common" content won't be accidently referred to as per-page content.Also, the naming convention of "page" is not a must. You can extend it to include other characters as well. Note that some characters (notably slashes) could be used to fetch arbitary files, leading to possible security issues and also that some characters (slashes, greather then and less then, colon, etc.) are not allowed in file names. Allowing only letters and numbers seems the safest to me.

Link to comment
Share on other sites

not only was one letter only allowed, but just having for example "en-" was permitted
I understand the difference in your given code, but I do not understand why there is a second language part... Then, tried with and without your code to manually change the querycode. You have more than a point! It really is a mess when I do not use your code. But have to say I never really thought about changing the querystrings myself... Good to know that I have to cater for the advanced web user;-)Now, it is getting complicated: I kind of got lost in the code for my sub-nav. Also, is it easy with your example to include/exclude sub-menu items to/from the top nav? Could you explain your code a bit deeper (sorry to be again a pain in the neck). If it was from a database I would have used a select clause, which would obviously only list the current list items for that top-nav item (hope you know what I mean)...Kurt
Link to comment
Share on other sites

I understand the difference in your given code, but I do not understand why there is a second language part...
With your two languages (en and de) it's not needed, but there are languages that use this form. Different variations of languages to be exact. For example, there's American English and British English. "en" means "any English" whereas "en-us" means "American English" and "en-gb" means "British English". If you at some point decide to store different variations of the same language, it's a good idea to keep this to allow yourself to do that.
Now, it is getting complicated: I kind of got lost in the code for my sub-nav. Also, is it easy with your example to include/exclude sub-menu items to/from the top nav? Could you explain your code a bit deeper (sorry to be again a pain in the neck). If it was from a database I would have used a select clause, which would obviously only list the current list items for that top-nav item (hope you know what I mean)...
Include everything common in the _common_{$lang}.php files, and everything specific in the {$page}_{$lang}.php files. The {$page}_{$lang}.php files can also unset() variables set in common_{$lang}.php since they are PHP files, so it should be reasonably easy to exclude items.However, make sure your display file acts accordingly when an item is or is not set, so that you get for example a missing list item, rather then a list item with no text.
Link to comment
Share on other sites

With your two languages (en and de) it's not needed, but there are languages that use this form. Different variations of languages to be exact. For example, there's American English and British English. "en" means "any English" whereas "en-us" means "American English" and "en-gb" means "British English". If you at some point decide to store different variations of the same language, it's a good idea to keep this to allow yourself to do that.Include everything common in the _common_{$lang}.php files, and everything specific in the {$page}_{$lang}.php files. The {$page}_{$lang}.php files can also unset() variables set in common_{$lang}.php since they are PHP files, so it should be reasonably easy to exclude items.However, make sure your display file acts accordingly when an item is or is not set, so that you get for example a missing list item, rather then a list item with no text.
Got the bit with the specific languages versions, thank you. Kind of getting closer to understand the second bit... Just to check:In the _common_de.php i put for example the German language link texts for nav and copyright, in _common_en.php i put the English link texts for nav and copyright. In addition I create home_en.php for my English home page text, home_de.php for my German home page text and about_en.php for my English about page text (and and and). So, if my webpage has 10 German and 10 English pages I shall have 20 different page include files and 2 common include files. Did I get this right? This would mean if there are 5 pages for each language under about for example I would have to go into 10 different files to change the relevant entries. Would it then not be better to have include files as subNav_en.php and subNav_de.php with the relevant entries? And if yes, how would you accomodate that each item in top nav could have a different count of sub-sections? And how would you acutally get the content onto the page (meaning how do you check which main section is clicked upon, so you are able to get the relevant sub-sections)?Kurt
Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.

×
×
  • Create New...