语言包解决方案

2019-02-12  本文已影响0人  phpdi

前言

以前使用过ecshop,语言包,需要先去定义映射,然后才能使用,这样开发起来非常繁琐,现在的项目需要用到语言包用到的一个方案,记录一下。

大致思路

1.用中文作为键,翻译的语言包作为值。定义语言包文件

2.写一个递归函数来翻译变量。

3.php 中在向前端分配变量的时候,统一调用这个函数,这样保证php所有渲染过的数据,都是被翻译过的。

4.html中同样用这个递归函数去翻译中文

注意的地方。

在我们开发项目的时候,中文全部使用单引号,包括js,php。 这样,我们可以用扫描脚本的方式,将中文导出,不需要人工去查找。

PHP中,代码如下

<?php /**
 * 语言包对象,单例
 * Created by PhpStorm.
 * User: cy
 * Date: 18-8-3
 * Time: 下午12:45
 */

class Lang
{
    const LANG_COOKIE_NAME = 'lang_cookie_name';//语言包名称
    const REPLACE_STRING = 'XX';//需要替换的文字

    public static $langData;//语言包数据

    public $outData = [];//存放导出中文的数据php文件中的数据
    public $outHtml = [];//存放导出中文的数据html文件中的数据


    private $local;//语言环境

    private $fileHtml;//为html页面提供的语言包文件

    private static $instance;//自身实例


    private function __construct($local = '')
    {
        //初始化语言
        $this->initLocal($local);
    }

    /**
     * 直接访问属性
     * @param $name
     * @return mixed
     */
    public function __get($name)
    {
        return $this->$name;
    }

    /**
     * 获取实例
     *
     * @return object
     */
    public static function getInstance()
    {
        if (!self::$instance instanceof self) {
            self::$instance = new self;
        }
        return self::$instance;
    }


    /**
     * 为html页面提供语言支持
     */
    public function langHtml($key, $replace = null)
    {

        $str = val(self::$langData, trim($key), $key);

        //转数组
        $replaceArr=is_array($replace)?$replace:[$replace];

        if(!is_null($replace)){
            foreach($replaceArr as $v){
                $str = preg_replace('/'.self::REPLACE_STRING.'/', $v, $str,1);
            }
        }

        return $str;
    }

    /**
     * 递归处理数组翻译
     * @param $arr
     * @param int $mode 0=翻译key和value,1=翻译value,2=翻译key
     */
    public function langArray($arr,$mode=0)
    {
        if(is_array($arr)){
            foreach ($arr as $k=>$v){
                if($mode==1){
                    //只翻译value
                    $arr[$k]=$this->langArray($v,$mode);
                }else{
                    //翻译key
                    $kLang=langHtml($k);
                    $arr[$kLang]=$this->langArray($v,$mode);
                    if($kLang!=$k) unset($arr[$k]);
                }

            }
        }else{
            if(in_array($mode,[0,1])){
                //需要翻译value
                $arr=$this->langHtml($arr,$mode);
            }
        }

        return $arr;
    }


    /**
     * 将csv文件导成前端语言包文件,生成in-en-html.php
     */
    public function makeLangHtmlFileFromCsv()
    {
        self::$langData=[];

        $arrFile = ['operate_manage.csv', 'app_api.csv','caiwu.csv'];//html csv源文件
        foreach ($arrFile as $v) {
            $file = fopen(dirname(__FILE__) . '/in-en/' . $v, "r");
            while (!feof($file)) {
                $tmp = fgetcsv($file);

                if (empty($tmp[0]) || empty($tmp[1])) continue;

                //文件理没有出现过,且没有被翻译过
                self::$langData[$tmp[0]] = $tmp[1];

            }
            fclose($file);
        }
        $content = '<?php ' . PHP_EOL . '//前端页面语言包 印尼文' . PHP_EOL . 'return ';
        $content .= var_export(self::$langData, true);
        $content .= ';';

        file_put_contents(dirname(__FILE__) . '/in-en/in-en-html.php', $content);

    }


    /**
     * 设置当前语言包环境
     */
    public function setLangToCookie($lang)
    {
        GetOB('Util.Cookie')->addCookie(self::LANG_COOKIE_NAME, $lang);
    }

    /**
     * 获取当前的语言环境
     * @return string
     * @throws Exception
     */
    public function getLangFromCookie()
    {
        return GetOB('Util.Cookie')->getCookie(self::LANG_COOKIE_NAME);
    }


    //防止克隆
    private function __clone()
    {
    }


    /**
     * 扫描目录,导出需要翻译的中文
     * @param bool $diff
     *
     */
    public function scanDir($diff = true)
    {
        $projectDir = $this->getProjectRoot();//项目目录
        $scanDir = ['/api/OB', '/account_manage/App','/operate_manage/App'];//需要文件目录'operate_manage/App'


        foreach ($scanDir as $v) {
            $dir = $projectDir . $v;
            $this->scanFile($dir);
        }

        if ($diff) {
            //去掉翻译过的
            $inEnData = include dirname(__FILE__) . '/in-en/in-en-html.php';
            $keyInEnData = array_keys($inEnData);
            foreach ($this->outData as $k => $v) {
                if (in_array($v, $keyInEnData)) {
                    unset($this->outData[$k]);
                }
            }

            foreach ($this->outHtml as $k => $v) {
                if (in_array($v, $keyInEnData)) {
                    unset($this->outHtml[$k]);
                }
            }
        }

        $data=[$this->outData,$this->outHtml];
        foreach ($data as $k=>$v){
            $v= array_unique($v);
            switch ($k){
                case 0: $filename='zh-cn-p.csv';break;
                case 1: $filename='zh-cn-h.csv';break;
            }

            $fileDir=dirname(__FILE__)."/tmp";
            if(!is_dir($fileDir))mkdir($fileDir);

            $zhcnFile = fopen($fileDir. "/$filename", "w");


            //组装导出数据
            foreach ($v as $key => $value) {

                fputcsv($zhcnFile, [$value], ',');
            }
            fclose($zhcnFile);
        }

        die;

    }

    /**
     * 递归扫描文件
     * @param $dir
     * @return bool
     */
    private function scanFile($dir)
    {

        $projectRoot = $this->getProjectRoot();
        $skipDir = [$projectRoot . '/api/OB/Lang'];//跳过的文件目录

        $skipFile = [
            $projectRoot . '/api/OB/Util/MathUtil.class.php',
            $projectRoot . '/api/OB/Util/DateUtil.class.php',
            $projectRoot . '/api/OB/Util/Sms.class.php',
            $projectRoot . '/api/OB/Util/SendMail.class.php',
            $projectRoot . '/api/OB/Api/BluePay.class.php',
            $projectRoot . '/api/OB/Api/Auth.class.php',
            $projectRoot . '/api/OB/Api/ApiAction.class.php',
            $projectRoot . '/operate_manage/App/View/useradmin/show.html',
            $projectRoot . '/operate_manage/App/View/index/modal.html',

        ];//跳过的文件
        if (!is_dir($dir) || in_array($dir, $skipDir)) return false;
        $handle = opendir($dir);
        if ($handle) {
            while (($fl = readdir($handle)) !== false) {
                $temp = $dir . DIRECTORY_SEPARATOR . $fl;
                //如果不加  $fl!='.' && $fl != '..'  则会造成把$dir的父级目录也读取出来
                if (is_dir($temp) && $fl != '.' && $fl != '..') {
                    $this->scanFile($temp);
                } else {
                    if ($fl != '.' && $fl != '..' && !in_array($temp, $skipFile)) {

                        if (strpos($temp, '.php')) {
                            $content = file_get_contents($temp);
                            if (preg_match_all("/['\"]([\x{4e00}-\x{9fa5}!!,,a-zA-Z_]+[\x{4e00}-\x{9fa5}]+[\x{4e00}-\x{9fa5}!!,,a-zA-Z_0-9]*)['\"]/u", $content, $outArr)) {
                                $this->outData = array_merge($this->outData, $outArr[1]);
                            }
                        } elseif (strpos($temp, '.html')) {
                            $content = file_get_contents($temp);
                            if (preg_match_all("/([\x{4e00}-\x{9fa5}!!,,a-zA-Z_\/\/\\%,\[\],\(\)a-zA-Z_0-9\&\;\s:]*)/u", $content, $outArr)) {
                                foreach ($outArr[1] as $k => $v) {
                                    //去掉注释
                                    if (preg_match('/[\/\/\<!--\s]+/', $v)) {
                                        unset($outArr[1][$k]);
                                    }
                                }
                                $this->outHtml = array_merge($this->outHtml, $outArr[1]);
                            }
                        }
                    }
                }
            }
        }
    }

    /**
     * 设置语言
     */
    private function initLocal($local = null)
    {
        //读取配置文件
        $this->local = defined('LOCAL_LANG') ? LOCAL_LANG : LOCAL_LANG_DEFAULT;

        //传值优先
        if ($local) {
            $this->local = $local;

        } elseif ($this->getLangFromCookie()) {
            //cookie设置值
            $this->local = $this->getLangFromCookie();
        } else {
            //根据前端邀请返回相应语言
            $controller = SystemParams::get('OB');
            if (!empty($controller->input['language']) && in_array($controller->input['language'], [LOCAL_LANG_CHINA, LOCAL_LANG_INDONESIA])) {
                $this->local = $controller->input['language'];
            }
        }

        //获取语言包数据
        $this->initData();

    }

    /**
     * 初始化语言包数据
     */
    private function initData()
    {
        $this->fileHtml = dirname(__FILE__) . '/' . $this->local . '/' . $this->local . '-html.php';

        if (!file_exists($this->fileHtml)) {
            self::$langData = [];
        } else {
            self::$langData = require_once $this->fileHtml;
        }
    }

    /**
     * 获取项目根目录,由于入口文件位置没有定义,所以在这里定义一个函数取一下
     */
    private function getProjectRoot()
    {
        return str_replace('/api/OB/Lang','',__DIR__);
    }


}


js中,我们从后台接口获取翻译数据源

用ajax,进行异步加载,然后翻译


    //待翻译的对象
    var langTrans={
        transBtns:['确定','取消'],
        transTitle:'提示',
        transMsgConfirm:'信息确认',
        transConfirmCancle:'确定要取消?',
        transChoiceData:'请选择数据',
        transQueryError:'请求出错!',
        transReceConfirm:'收款确认',
        transIsDelMember:'是否删除当前成员',
        transChoiceOne:'至少选择一项',
    };


    //翻译对象
    function language(needTrans) {
        var language=$(this);
        //存放语言包数据
        language.langData={};

        //请求后台语言包数据
        language.getLangData=function () {
            $.ajax({
                type: "GET",
                url: "/index/langJson",
                dataType: "json",
                success: function(data){
                    language.langData=data.data;
                    needTrans=language.langHtml(needTrans);
                }
            });
        };

        //递归翻译函数
        language.langHtml=function(key){
            if(typeof(key)=="string"){
                if (key in language.langData) {
                    key=eval('language.langData.'+key);
                }
            }else{
                for (var value in key){
                    key[value]=language.langHtml(key[value]);
                }
            }

            return key;
        };

        //构造数据
        language.getLangData();

        return language;
    }
    language(langTrans);
上一篇下一篇

猜你喜欢

热点阅读