So I just started web development on my new job, meaning I only have very basic knowledge of php, my html, css and js knowledge is a lot better. I'm trying to build a basic multiple language site via php sessions but I just can't get it to work the way I want. I have an index.php file and two more folders called EN and DE in which I have the Englisch.html and the Deutsch.html file. The html files only contain some text and it's my goal to have two buttons (or similar) at the top of my site called EN and DE which switch the session to include the files in said folders and display the text beneeth the buttons and keep the language switch function on every page if I had more then one file per language. By default I want the language to be english so load the Englisch.html first. I'm guessing I need to create an if else statement on every html file that checks the session so something like: if session EN include Englisch.html elseif session DE include Deutsch.html, and on the index.php I somehow need to set the parameters for the session so something like: startSession EN include Englisch.html startSession DE include Deutsch.html ? I have no idea how far off I am and any help, espacially actual code examples would be greatly appreciated. I hope this described my problem precisely enough.
问题:
回答1:
I agree with K0pernikus in that your solution won't scale well. You can write a simple translation library yourself in under an hour and you can then test it to see if it will be robust enough for your needs.
The idea is to have language files without any logic in them. You simply call the file you need. All the logic about which language, file, translation key etc. is contained in your library.
I'll keep it very simple and down to a single file; of course, the actual translations will each need to be stored in a file too.
Directory structure:
- /locale/en/messages.php
- /locale/fr/messages.php
- /locale/../messages.php
- translator.php (this is the main library file and needs to be included on every page)
Within each messages.php
file you need to return an array of translation keys and their respective translation. The translation keys are what you will use in your views. These files will become large with many hundreds or thousands of lines for larger applications. If you intend to keep this home-grown solution you'll need to implement caching. That being said, I have files with hundreds of translations and don't notice any significant performance hit.
<?php
// en
return array(
'applicationName' => 'My name is Dank',
...
<?php
// fr
return array(
'applicationName' => 'je m\'appelle Dank',
...
Next, you need a library to read these translations and return the actual translation text to you. This file could simply be a collection of helper functions or a full-blown OOP class. For simplicity, here is a collection of helper methods that get the job done. It does not implement parameterized substitution and you can add that feature relatively easily by making t()
accept a 2nd argument, but that is a whole different topic for another time.
The main method in here is t()
. It is very simple and accepts a single translation key. Ex. applicationName
or greeting
.
Caveat - I wrote this logic rather hastily last year and make no apologies if it doesn't work for you.
Firstly, it tries to determine which language to use. It does this in a sequence of priority: URL, session, browser, fallback.
- It first tries to get the language/locale from the URL by looking for
a query string parameter named
lang
. If you think about it, that makes sense because a user intends to switch their language by clicking a link that says "English" or "French". - If it doesn't find one in the URL it then moves on to check for one in the session. Again, if it finds it there it uses it.
- If it finds it neither in the URL nor the session, then it checks the browser/headers from the request.
- Finally, if it isn't found in any of those 3 locations then it falls
back to the default language as specified in
$defaultLanguage
.
Once a language has been found, it puts it into the session so the next request doesn't need to go through all that again. It also loads the appropriate messages.php
file based on the discovered language.
Finally, once the language has been found and right file has been loaded into memory it searches for the given $key
and returns the appropriate translation. If the $key
is not found then it simply returns the given $key
which will show up in your views so you know something went horribly wrong and you need to start debugging.
<?php
/**
* Performs the actual translation based on the given key. This is the method that is used
* in the actual views to translate a message.
*
* @param $key
* @return mixed
* @throws Exception
*/
function t($key)
{
$language = getLanguage();
$messages = require "{$_SERVER['DOCUMENT_ROOT']}/locale/{$language}/messages.php";
return (array_key_exists($key, $messages))
? $messages[$key]
: $key;
}
/**
* Returns the language as defined by either the URL, session, or browser setting.
* If a language could not be determined, or is not in a list of supported languages, the default
* language passed in to this method will be returned.
*
* @param string $defaultLanguage
* @return string
*/
function getLanguage($defaultLanguage = 'en')
{
$language = null;
if (isset($_REQUEST['lang'])) {
$language = $_REQUEST['lang'];
} elseif (isset($_SESSION['LANG'])) {
$language = $_SESSION['LANG'];
} else {
$language = getLanguageFromBrowser('en');
}
// If the language given to us is not in our list of supported languages, use the default language.
if (!isset($language) || !in_array($language, getSupportedLanguages())) {
$language = $defaultLanguage;
}
// Store the current language to the session for future use.
$_SESSION['LANG'] = $language;
return $language;
}
/**
* Returns the language that the client's browser is set to use. If we're unable to
* determine a language from the browser this will return the default language passed
* in.
*
* @param string $defaultLanguage
* @return int|string
*/
function getLanguageFromBrowser($defaultLanguage = 'en')
{
$languages = [];
if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
// break up string into pieces (languages and q factors)
preg_match_all('/([a-z]{1,8}(-[a-z]{1,8})?)\s*(;\s*q\s*=\s*(1|0\.[0-9]+))?/i', $_SERVER['HTTP_ACCEPT_LANGUAGE'], $lang_parse);
if (count($lang_parse[1])) {
// create a list like "en" => 0.8
$languages = array_combine($lang_parse[1], $lang_parse[4]);
// set default to 1 for any without q factor
foreach ($languages as $lang => $val) {
if ($val === '') $languages[$lang] = 1;
}
// sort list based on value
arsort($languages, SORT_NUMERIC);
}
}
$supportedLanguages = getSupportedLanguages();
foreach ($languages as $locale => $weighting) {
// We're dealing with locale: Ex. en-US
if (preg_match("/[a-z]{2}-[A-Z]{2}/", $locale)) {
$browserLanguage = substr($locale, 0, 2);
} else {
// Probably dealing with a language: Ex. en
$browserLanguage = $locale;
}
if (in_array($browserLanguage, $supportedLanguages)) {
return $browserLanguage;
}
}
return $defaultLanguage;
}
/**
* Returns an array of languages this web application supports.
*
* @return array
*/
function getSupportedLanguages()
{
return [
'en',
'fr'
];
}
To use it, save these methods into a file called translator.php
and then include that file in every page you want to use translations.
Sample:
<?php
session_start();
require_once('translator.php');
// Output your language switcheroo-gadget
if (getLanguage() === 'en') {
echo '<a href="' . $_SERVER['PHP_SELF'] . '?lang=fr">French</a>';
} else {
echo '<a href="' . $_SERVER['PHP_SELF'] . '?lang=en">English</a>';
}
// Your code... blah blah
// Ahh.. Finally, a translation!
echo '<h1>' . t('applicationName') . '</h1>';
Edit
The last thing I will say is that there is a whole world out there of localization, internationalization (often abbreviated as i18n) which you can learn about.
In my example, I simplistically called it language but often people referer to it as locale but that has a different meaning and syntax. For example, there is a difference between en_CA and en_US and en_GB; all of which are English but have regional differences.
echo t('salutation');
回答2:
Your attempted solution is going to bite you in the long run.
It may seem like an easy solution to switch between different files for different languages, yet assume that your website becomes more dynamic, instead of *.html files you want to deal with *.php files, and then would need to have the same logic inside each of your localized files. It doesn't scale well.
I recommend using a translation libary, there are many available, I had good success with symfony's translation, that you can also include in any php project.
Then translation becomes:
$translatedString = $translator->trans("My content");
And the translation can then be maintained in yaml files and depending on the locale, the right language is chosen and each untranslated string will default to English.
And now, whenever your logic changes it is just at one place where you need to adapt it.