Rugalmas nyelvkezelés

Gyakran van szükség arra, hogy egy weboldalt több nyelven jelenítsünk meg.
Ennek ma már több formája is létezik. Az egyik, amikor minden nyelvnek külön fájlt hozunk létre egy languages mappában, és abban egy asszociatív tömbben felsoroljuk az egyes tartalmakat.
Ezzel a módszerrel mutatom meg, hogyan lehet úgy kezelni a nyelveket, hogy amennyiben az alapértelmezett nyelven minden szöveg definiálva van, azon a nyelven jelenjen meg a tartalom, ha a kiválasztott nyelven nem létezik még, vagy szándékosan nem definiáltunk egy értéket. Esetleg maga a nyelv sem létezik, amit megadtunk.

Először is feltételezzük, hogy a nyelvi fájlok nevei en.php, hu.php. Lehetne bármi a nevük. Csak tudni kell, hogy a .php előtti rész lesz a nyelvkód. Amivel hivatkozni lehet az adott nyelvre.

Ehhez két osztályra van szükségünk. Meglepő módon Language és Languages nevet adtam nekik.

Languages osztály:

class Languages implements ArrayAccess
{
        private static $instance = null;
        private $lang = array();
        private $default = 'hu';
        private $languageDir = 'languages';

        public static function getInstance()
        {
                if (self::$instance === null)
                {
                        $class = __CLASS__;
                        self::$instance = new $class();
                }
                return self::$instance;
        }

        private function  __construct()
        {

        }

        public function getLanguageDir()
        {
                return $this->languageDir;
        }

        public function setLanguageDir($dir)
        {
                $this->languageDir = $dir;
        }

        public function getDefault()
        {
                return $this->default;
        }

        public function setDefault($langcode)
        {
                $this->default = $langcode;
        }

        public function getLanguage($langcode)
        {
                 return new Language($langcode);
        }

        public function offsetExists($offset)
        {
                $offset = strtolower($offset);
                return file_exists(rtrim($this->languageDir,'/').'/'.$offset.'.php');
        }
       
        public function offsetGet($offset)
        {
                $offset = strtolower($offset);
                $dir = rtrim($this->languageDir,'/').'/';
                if (!isset($this->lang[$offset]))
                {
                        if (!file_exists($dir.$offset.'.php'))
                        {
                                $offset = $this->default;
                        }
                        if (!isset($this->lang[$offset]))
                        {
                                require_once $dir.$offset.'.php';
                        }
                        else
                        {
                                $lang = $this->lang[$offset];
                        }
                        $this->lang[$offset] = $lang;
                }
                return $this->lang[$offset];

        }

        public function offsetSet($offset, $value)
        {
                throw new Exception('Nem módosítható');
        }

        public function offsetUnset($offset)
        {
                throw new Exception('Nem módosítható');
        }
}

Ez az osztály használja a Language osztályt is. gyakorlatilag nem lenne muszáj neki, de talán egyszerűbb, hogy egy getLanguage() metódussal érjük el nyelvet, és csak a Languages osztályra kell koncentrálni.

Használat szempontjából 3 fontosabb metódusa van:

  • getInstance()
    Visszaad egy Languages példányt. Csak egyetlen példánya lehet. A new kulcsszóval nem is lehet példányosítani. 
  • setDefault()
    Beállítja az alapértelmezett nyelvet. Paraméterként a nyelvkódot várja. Ami ugye a php fájlunk neve is. Leszámítva a kiterjesztést. 
  • setLanguageDir()
    Beállítja a mappát, ahol a nyelvi fájlok találhatók. Alapértelmezetten ez a languages lesz, de ezzel akárhova tehetjük a fájlokat. 

Language osztály:

class Language implements ArrayAccess
{
        private $langcode;

        public function  __construct($langcode)
        {
                $this->langcode = $langcode;
        }

        public function offsetExists($offset)
        {
                $langs = Languages::getInstance();
                return isset($langs[$this->langcode][$offset]);
        }

        public function offsetGet($offset)
        {
                $langs = Languages::getInstance();
                return (isset($langs[$this->langcode][$offset])) ?
                                $langs[$this->langcode][$offset] :
                                $langs[$langs->getDefault()][$offset];
        }

        public function offsetSet($offset, $value)
        {
                throw new Exception('Nem módosítható');
        }

        public function offsetUnset($offset)
        {
                throw new Exception('Nem módosítható');
        }
}

Ennek az osztálynak gyakorlatilag nincs más szerepe, mint egy neki megadott nyelvet (nyelvkód alapján) kiválasztani alapértelmezettnek, és amikor olyan azonosítót kap lekérdezéskor, ami az adott nyelven nem elérhető, akkor a Language osztály alapértelmezett nyelvéből próbálja a tartalmat visszaadni.

Mindkét osztály megvalósítja az ArrayAcces interface-t. Így a belőlük létrejött példányokat használhatjuk egyszerűen úgy, mintha csak tömbök lennének.

Vagyis a következő két nyelvi fájlt használva:
hu.php:

$lang['hello'] = 'Szia';
$lang['logout'] = 'Kilépés';
$lang['magyar'] = 'magyarban van csak';

en.php:

$lang['hello'] = 'Hello';
$lang['logout'] = 'logout';

A következő módon tudjuk felhasználni az osztályokat:
index.php:

require_once 'class/Languages.class.php';
$languages = Languages::getInstance();
$languages->setLanguageDir('languages');
$languages->setDefault('hu');

print $languages['hu']['hello'].'<br />';
print $languages['en']['hello'].'<br />';
print $languages['ens']['magyar'].'<br />';
//kimenet:
//Szia
//Hello
//magyarban van csak

$lang = $languages->getLanguage('en');
print $lang['hello'].'<br />';
print $lang['magyar'].'<br />';
//kimenet:
//Hello
//magyarban van csak

$lang = $languages->getLanguage('ens');
print $lang['hello'].'<br />';
print $lang['magyar'].'<br />';
//kimenet:
//Hello
//magyarban van csak

A fent leírt példák, és az osztály dokumentációval együtt letölthető a következő linken: Letöltés

Kategóriák: 
Megosztás/Mentés

Hozzászólások

Bella Kristóf képe

szia. bocsi a kérdésért még kezdő vagyok a php-ben és akárhogyan tanulmányozom a kódot nemjövök rá hogy milyen linkkel tudom módosítani a nyelvet :O tudnál nekem segíteni?

Rimelek képe

Szia

Az nem része a bejegyzésnek, hogy milyen linkkel lehet nyelvet váltani. De találhatsz arról is a neten leírásokat. Vagy az url-ben mindig elküldöd a nyelvet is, vagy csak egyszer elküldöd és elmented sütibe vagy session-be. Utána csak azt a nyelvet kell megadnod a getLanguage() metódusban.

Bella Kristóf képe

akkor már értem köszi szépen nagyon hasznos volt !

geld77 képe

A rugalmas nyelvkezelést milyen módon célszerű össze simítani a R.E. Login 2.0-ás rendszerrel? És utána zászlók kiválasztásával lépkedni a nyelvek között?

<a href="<?php echo $_SERVER['PHP_SELF'];?>?lang=hu"><img src="<?=IMAGE ?>hu.gif" /><a>
<a href="<?php echo $_SERVER['PHP_SELF'];?>?lang=en"><img src="<?=IMAGE ?>en.gif" /><a>
<a href="<?php echo $_SERVER['PHP_SELF'];?>?lang=de"><img src="<?=IMAGE ?>de.gif" /><a>

pl egy ilyesmi modon?

Rimelek képe

A html tag-eket rosszul zárod. </a> a helyes. A $languages változót pedig beteheted bárhova, ahol elérhető mindenhonnan (Pl a loginnál emlegetett System osztály). A nyelvválasztást már gyakorlatilag megoldottad. Most ennél többre nekem késő van.

geld77 képe

Be tettem a system.classes.php-ba a Language.class.php tartalmát, a languages fájlok elérési utjába szeretném a segitségedet kérni mit irjak át hogy stimmeljen a relogin2 rendszerhez?

Rimelek képe

Semmit nem kell átírnod. A bejegyzésben írtam, hogy a setLanguagedir() metódussal beállítható a mappa, ahol a nyelvi fájlok vannak. Ez a példakódban is benne van. Vagyis csak ott kell beállítanod ennek a könyvtárnak a helyét, ahol példányosítod a Languages osztályt. És hogy hova rakod ezt a könyvtárat, az megint rajtad áll.

geld77 képe

Lehet valamit nem jól csináltam! Hogy kell megadni az elérési utat? A relogin2 könyvtárba van a languages könyvtár amibe vannak a nyelvek.

Rimelek képe

Attól függ, melyik fájlban csinálod.De init.php-ben

$languages->setLanguagedir(dirname(__FILE__) . '/relogin2/languages');

Vagy php 5.3-tól:

$languages->setLanguagedir(__DIR__ . '/relogin2/languages');
geld77 képe

ezt a hiba üzenetet kapom:

Notice: Undefined variable: languages in D:\AppServ\www\init.php on line 29

Fatal error: Call to a member function setLanguagedir() on a non-object in D:\AppServ\www\init.php on line 29

Rimelek képe

Én nem tudom, hogy hogyan próbálkoztál eddig. Csak a mappa beállítását mutattam meg a létező objektumon. Hogy az neked hol van, nem tudom. Ott használd a kódot, ahol a többit is írtad! a lényeg az, hogy az aktuális fájlhoz képest add meg a mappa útvonalát. És ehhez kell a dirname és függvény __FILE__ konstans vagy __DIR__ konstans.

pisti87 képe

sikerült belöni ime a trükk gyökér index.phpban

 <?php
/*
 * Alap sablon az R.E. Login 2.0 -hoz.
 *
 * Szerző: Takács Ákos (Rimelek)
 * E-mail: programmer kukac rimelek.hu
 * Weboldal: http://rimelek.hu
 * Login weboldala: http://rimelek.hu/meghivos-loginrendszer-r-e-login-v2-0
 *
 * Ikonokat a következő weboldalakról töltöttem le:
 * http://www.freeiconsweb.com/
 * http://sixrevisions.com/resources/40-beautiful-free-icon-sets/
 */

require_once 'init.php';
include 'nyelv/lang.php';

require_once 'includes/header.php';
?>
               

<?php
require_once 'includes/footer.php';
?>

ez szerintem egyértelmű és a lang.php

<?php

$alap = 'magyar';
if(file_exists('lang/'.$_GET['lang'].'.php'))
{
include 'lang/'.$_GET['lang'].'.php';
}
else
{
include 'lang/'.$alap.'.php';
}

?>

ez a gyökérben található lang mapában van ezen belül lang mappa amiben angol.php és magyar.php most ehez már csak a kiválasztás lehetőség kéne header és footer cserélve van már megnézhető a demo oldal http://replikacms.ininet.hu oldalon nos a nyelv választást valahova a login környékére gondoltam és talán sessionba vagy sqlbe kéne hozzáadni az user táblához? valami egyszerű gyors megbízható ötlet nincs kéznél?

Rimelek képe

Már csak azt kéne belőni, hogy mit, hova írsz. A loginnál kezdted el, majd itt folytattad. De ez meg inkább login téma, mint a fenti nyelvkezelő megoldással kapcsolatos. De mivel baromi macerás áthelyeznem egy hozzászólást és mert az utolsó két kérdésed általános nyelvkezelés téma, itt hagyom.

Viszont, bár az az én hibám, hogy a forrásokba így írtam bele az e-mail címemet, arra kérlek, ezeket írd át a már általam módosított módon vagy töröld a komment részt, hogy ne támadjanak rám jobban a spam robotok.

A kérdésedre: Ez tőled függ. Akár mindkettőt megteheted. A session-öst a vendégeknek, a belépett tagoknak meg jöhet a nyelv a profilban beállított értékből. De ehhez sima cookie is elég session helyett.

Egyébként: Azt az időt, amit te megspórolsz azzal, hogy ennyire helytelenül írsz, én veszítem el az értelmezéskor. Kérlek, figyelj oda erre jobban, mert amúgy sincs sok időm. Pedig nem szeretek senkit válasz nélkül hagyni. Ezer köszönet!

pisti87 képe

rendben igyekszem bár egy kis konkrét segítséget példát írhatnál a profilnál való beállításnál hogy végülis merre tudnék tovább indulni.
mint irtam még kezdő vagyok a témában.
van mire nem ugy találok megoldást mint ahogy szeretném de azért nem adom fel.
érdekel és tanulni szeretnék ha meg szintaktikai hibába ütközökk adig próbálgatom a lehetőségeim míg rá nem jövök.
igaz a php hasonlít a javához, de android appot írni és phpval programozni ég és föld.
még ha elég sok közös fügvényt is találok benne.

Rimelek képe

Nem tudok konkrétabb segítséget adni. Tudom, hogy kezdő vagy, de a login leírásában az is áll, hogy a loginhoz szükséges PHP ismeret. Ahhoz, amiket te szeretnél, pedig több PHP ismeret. Az irányt megadtam. A konkrétabb válaszhoz konkrétabb kérdés kell. Sajnos elfoglalt vagyok és a korábbi válaszadási sebességem és a válaszaim hossza nem általánosak. A logint megírtam. Már szinte el is felejtettem. Megtisztelő, hogy mások nem, de nincs kapacitásom az új igényeken gondolkodni és azok megoldási menetét részletesen leírni. Ha már tudsz java-ban programozni, akkor biztos vagyok benne, hogy meg fogod tudni oldani a problémákat és eléred a célod. Nem a nyelvek hasonlóságai miatt, hanem mert minden új dolog megtanulásához kitartás kell. Ha azt sikerült megtanulnod, ez is menni fog. Persze nem tudom, az android programozást milyen szinten űzöd. De mindkét témához gondolkodni kell.

Ha a proflban akarsz nyelvet menteni, nyilván kell egy mező a táblában. Módosítani kel a profilmódosító oldalt. Az űrlapot és a feltöltést. Vagy úgy döntesz, hogy egyszerűbben oldod meg és csinálsz egy
új oldalt a nyelv kiválasztására és olyan módon update-eled a táblát, ahogy tudod. Nem kell a login megoldásait követned. Mert például már a benne használt mysql_* függvények is elavultnak számítanak.

pisti87 képe

szia Ákos léci nézd meg ezt az oldalt átköltöztettem máshova captcha megy mailt nem néztem még avatárok futnak nyelv 75% ban kész legalábis a magyar az angol még 35% os nos anyelv váltásra még ki kell találni valamit ugyanezek a beállítások viszont nem futnak az inineten a cím amin megnézhető http://jurgeen.gowihost.biz amint kész a nyelv pár új funkciót is raknék bele mint admin felületen oldalszerkesztő gallériát meg pár apróságot csak jussak el a nyelv végére. kérlek azlért bogarászd át kicsit hogy nem e maradt ki valami eddig

Rimelek képe

Bogarászni nincs időm. Egy szép napon talán majd ismét tengernyi unatkozó percem lesz és akkor szívesen bogarászom bárki kódját, weblapját :) Ha nem találok jobb elfoglaltságot. Sajnálom. Azért sok sikert!

pisti87 képe

lenne egy ilyen az user és a search phpben hogy

? $user->T_user_usermail    :  "Rejtett"; ?>

ennek hogy adhatom be ezt a hivatkozást? <?php echo $lang['hidden']; ?> mármint a nyelvi rész és még lenne olyan hogy adminban nem minden angol pl a jogoknál admin user ezekre gondolok. van valami ötleted?

Rimelek képe

Ha jól értem, ezt akarod:

$user->T_user_usermail    :  $lang['hidden'];

A felhasználói rangok neve pedig adatbázisban van. Így annak fordítását ott kellene megoldanod új mezőkkel akár. De az nagyon nem rugalmas, ha már itt tartunk és ide írtad, nem a login rendszerhez.

Vagy kihagyhatod az adatbázist és a "varname" mezőjének értékét használhatod fel a nyelvtömb indexeléséhez. Csak akkor meg a "name" mező felesleges lesz és kioperálhatod a rendszerből. Vagy hagyhatod ott szemétként. Esetleg alapértelmezett feliratként megtartod, ha nincs semmilyen fordítás a tömbben hozzá. Mivel ez csak egy egyszerű feltétel, a megoldását nem részletezem.

Megjegyzés:
Minden új üzenetről kapok emailt, amit ráadásul előbb olvasok mint facebookot, így nem kell ott is jelezned. Amint van időm, válaszolok a kérdésekre.

pisti87 képe

rendben és köszönöm ezt a megoldást kerestem a belső részt még nem igazán tanulmányoztam át legalábis nem mélyrehatóan szóval ha már bele kell mászni akkor át is tanulmányozom

pisti87 képe

sziasztok sikerült megcsinálnom a nyelvkezelést ami azt illeti a megoldásom nem túl dinamikus de ami anyelv bővítést illeti az már dinamikusra sikerült nagyon jó lett magyar 100% ban befejezve már csak az angol van hátra ha lesz több időm kap tőbb nyelvet is