Completed
Push — 6.0 ( fba450...3d0b31 )
by yun
04:36
created

Lang::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 2
dl 0
loc 5
ccs 4
cts 4
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
// +----------------------------------------------------------------------
3
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
4
// +----------------------------------------------------------------------
5
// | Copyright (c) 2006~2019 http://thinkphp.cn All rights reserved.
6
// +----------------------------------------------------------------------
7
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
8
// +----------------------------------------------------------------------
9
// | Author: liu21st <[email protected]>
10
// +----------------------------------------------------------------------
11
declare (strict_types = 1);
12
13
namespace think;
14
15
/**
16
 * 多语言管理类
17
 */
18
class Lang
19
{
20
    /**
21
     * 配置参数
22
     * @var array
23
     */
24
    protected $config = [
25
        // 默认语言
26
        'default_lang'    => 'zh-cn',
27
        // 允许的语言列表
28
        'allow_lang_list' => [],
29
        // 是否使用Cookie记录
30
        'use_cookie'      => true,
31
        // 扩展语言包
32
        'extend_list'     => [],
33
        // 多语言cookie变量
34
        'cookie_var'      => 'think_lang',
35
        // 多语言自动侦测变量名
36
        'detect_var'      => 'lang',
37
        // Accept-Language转义为对应语言包名称
38
        'accept_language' => [
39
            'zh-hans-cn' => 'zh-cn',
40
        ],
41
        // 是否支持语言分组
42
        'allow_group'     => false,
43
    ];
44
45
    /**
46
     * 多语言信息
47
     * @var array
48
     */
49
    private $lang = [];
0 ignored issues
show
Coding Style introduced by
Private member variable "lang" must be prefixed with an underscore
Loading history...
50
51
    /**
52
     * 当前语言
53
     * @var string
54
     */
55
    private $range = 'zh-cn';
0 ignored issues
show
Coding Style introduced by
Private member variable "range" must be prefixed with an underscore
Loading history...
56
57
    /**
58
     * Request对象
59
     * @var Request
60
     */
61
    protected $request;
62
63
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $request should have a doc-comment as per coding-style.
Loading history...
Coding Style introduced by
Parameter $config should have a doc-comment as per coding-style.
Loading history...
64
     * 构造方法
65
     * @access public
66
     */
67 6
    public function __construct(Request $request, array $config = [])
68
    {
69 6
        $this->request = $request;
70 6
        $this->config  = array_merge($this->config, array_change_key_case($config));
71 6
        $this->range   = $this->config['default_lang'];
72 6
    }
73
74 6
    public static function __make(Request $request, Config $config)
2 ignored issues
show
Coding Style introduced by
Missing doc comment for function __make()
Loading history...
Coding Style introduced by
Method name "Lang::__make" is invalid; only PHP magic methods should be prefixed with a double underscore
Loading history...
Coding Style introduced by
Public method name "Lang::__make" must not be prefixed with an underscore
Loading history...
75
    {
76 6
        return new static($request, $config->get('lang'));
0 ignored issues
show
Bug introduced by
It seems like $config->get('lang') can also be of type null; however, parameter $config of think\Lang::__construct() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

76
        return new static($request, /** @scrutinizer ignore-type */ $config->get('lang'));
Loading history...
77
    }
78
79
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $lang should have a doc-comment as per coding-style.
Loading history...
80
     * 设置当前语言
81
     * @access public
82
     * @param  string $name 语言
0 ignored issues
show
Coding Style introduced by
Doc comment for parameter $name does not match actual variable name $lang
Loading history...
83
     * @return void
84
     */
85
    public function setLangSet(string $lang): void
86
    {
87
        $this->range = $lang;
88
    }
89
90
    /**
91
     * 获取当前语言
92
     * @access public
93
     * @return string
94
     */
95
    public function getLangSet(): string
96
    {
97
        return $this->range;
98
    }
99
100
    /**
101
     * 获取默认语言
102
     * @access public
103
     * @return string
104
     */
105 6
    public function defaultLangSet()
106
    {
107 6
        return $this->config['default_lang'];
108
    }
109
110
    /**
111
     * 加载语言定义(不区分大小写)
112
     * @access public
113
     * @param  string|array $file   语言文件
0 ignored issues
show
Coding Style introduced by
Expected 2 spaces after parameter name; 3 found
Loading history...
114
     * @param  string       $range  语言作用域
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
115
     * @return array
116
     */
117 6
    public function load($file, $range = ''): array
118
    {
119 6
        $range = $range ?: $this->range;
120 6
        if (!isset($this->lang[$range])) {
121 6
            $this->lang[$range] = [];
122
        }
123
124 6
        $lang = [];
125
126 6
        foreach ((array) $file as $_file) {
127 1
            if (is_file($_file)) {
128 1
                $result = $this->parse($_file);
129 1
                $lang   = array_change_key_case($result) + $lang;
130
            }
131
        }
132
133 6
        if (!empty($lang)) {
134 1
            $this->lang[$range] = $lang + $this->lang[$range];
135
        }
136
137 6
        return $this->lang[$range];
138
    }
139
140
    /**
141
     * 解析语言文件
142
     * @access protected
143
     * @param  string $file 语言文件名
144
     * @return array
145
     */
146 1
    protected function parse(string $file): array
147
    {
148 1
        $type = pathinfo($file, PATHINFO_EXTENSION);
149
150
        switch ($type) {
151 1
            case 'php':
152 1
                $result = include $file;
153 1
                break;
154
            case 'yml':
155
            case 'yaml':
156
                if (function_exists('yaml_parse_file')) {
157
                    $result = yaml_parse_file($file);
158
                }
159
                break;
160
        }
161
162 1
        return isset($result) && is_array($result) ? $result : [];
163
    }
164
165
    /**
166
     * 判断是否存在语言定义(不区分大小写)
167
     * @access public
168
     * @param  string|null $name 语言变量
0 ignored issues
show
Coding Style introduced by
Expected 2 spaces after parameter name; 1 found
Loading history...
169
     * @param  string      $range 语言作用域
170
     * @return bool
171
     */
172
    public function has(string $name, string $range = ''): bool
173
    {
174
        $range = $range ?: $this->range;
175
176
        if ($this->config['allow_group'] && strpos($name, '.')) {
177
            list($name1, $name2) = explode('.', $name, 2);
178
            return isset($this->lang[$range][strtolower($name1)][$name2]);
179
        }
180
181
        return isset($this->lang[$range][strtolower($name)]);
182
    }
183
184
    /**
185
     * 获取语言定义(不区分大小写)
186
     * @access public
187
     * @param  string|null $name 语言变量
0 ignored issues
show
Coding Style introduced by
Expected 2 spaces after parameter name; 1 found
Loading history...
188
     * @param  array       $vars 变量替换
0 ignored issues
show
Coding Style introduced by
Expected 2 spaces after parameter name; 1 found
Loading history...
189
     * @param  string      $range 语言作用域
190
     * @return mixed
191
     */
192
    public function get(string $name = null, array $vars = [], string $range = '')
193
    {
194
        $range = $range ?: $this->range;
195
196
        // 空参数返回所有定义
197
        if (is_null($name)) {
198
            return $this->lang[$range] ?? [];
199
        }
200
201
        if ($this->config['allow_group'] && strpos($name, '.')) {
202
            list($name1, $name2) = explode('.', $name, 2);
203
204
            $value = $this->lang[$range][strtolower($name1)][$name2] ?? $name;
205
        } else {
206
            $value = $this->lang[$range][strtolower($name)] ?? $name;
207
        }
208
209
        // 变量解析
210
        if (!empty($vars) && is_array($vars)) {
211
            /**
212
             * Notes:
213
             * 为了检测的方便,数字索引的判断仅仅是参数数组的第一个元素的key为数字0
214
             * 数字索引采用的是系统的 sprintf 函数替换,用法请参考 sprintf 函数
215
             */
216
            if (key($vars) === 0) {
217
                // 数字索引解析
218
                array_unshift($vars, $value);
219
                $value = call_user_func_array('sprintf', $vars);
220
            } else {
221
                // 关联索引解析
222
                $replace = array_keys($vars);
223
                foreach ($replace as &$v) {
224
                    $v = "{:{$v}}";
225
                }
226
                $value = str_replace($replace, $vars, $value);
227
            }
228
        }
229
230
        return $value;
231
    }
232
233
    /**
234
     * 自动侦测设置获取语言选择
235
     * @access public
236
     * @return string
237
     */
238
    public function detect(): string
239
    {
240
        // 自动侦测设置获取语言选择
241
        $langSet = '';
242
243
        if ($this->request->get($this->config['detect_var'])) {
244
            // url中设置了语言变量
245
            $langSet = strtolower($this->request->get($this->config['detect_var']));
246
        } elseif ($this->request->cookie($this->config['cookie_var'])) {
247
            // Cookie中设置了语言变量
248
            $langSet = strtolower($this->request->cookie($this->config['cookie_var']));
249
        } elseif ($this->request->server('HTTP_ACCEPT_LANGUAGE')) {
250
            // 自动侦测浏览器语言
251
            preg_match('/^([a-z\d\-]+)/i', $this->request->server('HTTP_ACCEPT_LANGUAGE'), $matches);
252
            $langSet = strtolower($matches[1]);
253
254
            if (isset($this->config['accept_language'][$langSet])) {
255
                $langSet = $this->config['accept_language'][$langSet];
256
            }
257
        }
258
259
        if (empty($this->config['allow_lang_list']) || in_array($langSet, $this->config['allow_lang_list'])) {
260
            // 合法的语言
261
            $this->range = $langSet;
262
        }
263
264
        return $this->range;
265
    }
266
267
    /**
268
     * 保存当前语言到Cookie
269
     * @access public
270
     * @param  Cookie $cookie Cookie对象
271
     * @return void
272
     */
273
    public function saveToCookie(Cookie $cookie)
274
    {
275
        if ($this->config['use_cookie']) {
276
            $cookie->set($this->config['cookie_var'], $this->range);
277
        }
278
    }
279
280
}
281