美文网首页
语言包解决方案

语言包解决方案

作者: phpdi | 来源:发表于2019-02-12 20:38 被阅读0次

    前言

    以前使用过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);
    

    相关文章

      网友评论

          本文标题:语言包解决方案

          本文链接:https://www.haomeiwen.com/subject/oufleqtx.html