Search code examples
phpgettextmultilingual

gettext not translating all utf-8 characters


test.php file echoes some greek letters for testing

<head>
<meta charset = "UTF-8" />
</head>
<?php
$language = "en_US";
$lang_path = "language";
putenv("LC_ALL=$language");
setlocale(LC_ALL, $language);
bindtextdomain("lang", $lang_path);
bind_textdomain_codeset("lang","UTF-8");
textdomain("lang");
echo gettext("α");
echo gettext("β");
echo gettext("γ");
echo gettext("δ");
echo gettext("ε");
echo gettext("ζ");
?>

My folders and files are structured like

 language/en_US/LC_MESSAGES/lang.mo and lang.po

mo file is correctly compiled, and it must translate to abcdez. In poedit i have used utf-8 everywhere. The code produces αβcδεζ , so only letter c is translated! I have restarted my server, i have en_US encoding installed in my system and i can't understand why only one letter is translated..


Solution

  • A simple implementation i wrote reading zend and cakephp code. It does not support plurals, and it simply replaces words, so you can replace not only from one language.

    test.php file

    <head>
    <meta charset = "UTF-8" />
    </head>
    <?php
        require_once "gettext.php";
        echo __("something");
        echo __("α");
        echo __("β");
        echo __("γ");
        echo __("δ");
        echo __("ε");
        echo __("ζ");
    ?>
    

    gettext.php file

    <?php
    define('APPPATH','/opt/lampp/htdocs/test/');
    /* please change APPPATH to an ultimate directory of the language folder */
    
    /**
     * Loads the binary .mo file and returns array of translations
     *
     * @param string $filename Binary .mo file to load
     * @return mixed Array of translations on success or false on failure
     */
        function loadMo($filename) {
            $translations = false;
    
            // @codingStandardsIgnoreStart
            // Binary files extracted makes non-standard local variables
            if ($data = file_get_contents($filename)) {
                $translations = array();
                $header = substr($data, 0, 20);
                $header = unpack("L1magic/L1version/L1count/L1o_msg/L1o_trn", $header);
                extract($header);
    
                if ((dechex($magic) == '950412de' || dechex($magic) == 'ffffffff950412de') && $version == 0) {
                    for ($n = 0; $n < $count; $n++) {
                        $r = unpack("L1len/L1offs", substr($data, $o_msg + $n * 8, 8));
                        $msgid = substr($data, $r["offs"], $r["len"]);
                        unset($msgid_plural);
    
                        if (strpos($msgid, "\000")) {
                            list($msgid, $msgid_plural) = explode("\000", $msgid);
                        }
                        $r = unpack("L1len/L1offs", substr($data, $o_trn + $n * 8, 8));
                        $msgstr = substr($data, $r["offs"], $r["len"]);
    
                        if (strpos($msgstr, "\000")) {
                            $msgstr = explode("\000", $msgstr);
                        }
                        $translations[$msgid] = $msgstr;
    
                        if (isset($msgid_plural)) {
                            $translations[$msgid_plural] =& $translations[$msgid];
                        }
                    }
                }
            }
            // @codingStandardsIgnoreEnd
    
            return $translations;
        }   
    
        /*
            Your system folder must be ULTIMATE_PATH/language/$language
            where language is a parametre like en,el,fr or english or whatever
            domain is the name of the mo file without mo extension e.g. default
            You can pass this parameteres with the __ function below
        */
        function translate($singular, $language = null, $domain = null) {
            $directory = APPPATH."language/"; // your path to language folder
            if (strpos($singular, "\r\n") !== false) {
                $singular = str_replace("\r\n", "\n", $singular);
            }
    
            if (is_null($language) ) { // default el
                $language = "el";
            }
    
            if (is_null($domain)) {
                $domain = "default";
            }
    
            $localeDef = $directory . $language;
            $file = $localeDef."/".$domain;
            $translations = null;
    
                    if (is_file($file . '.mo')) {
                        $translations = loadMo($file . '.mo');
                    }
    
            if (!empty($translations[$singular])) {
    
                    $trans = $translations[$singular];
    
                    if (strlen($trans)) {
                        return $trans;
                    }
                }
    
            return $singular;
        }
        /*
        take language (must be in language folder) from $_GET["lang"];
        */
        function __($singular) {
            if (!$singular) {
                return;
            }
            if (isset($_GET["lang"]) ) // you can use cookie, session etc
                $translated = translate($singular,$_GET["lang"]);
            else 
                $translated = translate($singular);
            return $translated;
        }
    ?>
    

    In my code i have default language el, and you get the language with GET['lang']. (You can change that to a COOKIE, SESSION etc. Also the mo files must be called default.mo. (You can change that also in the code). So you can have in your directory:

    test.php
    gettext.php
    language/el/deafult.mo
    language/en/default.mo
    

    default is el/default.mo and you can change to en with ?lang=en in your url.