Passed
Pull Request — 6.0 (#2394)
by
unknown
11:17
created

Lang::saveToCookie()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
cc 2
eloc 2
nc 2
nop 1
dl 0
loc 4
ccs 0
cts 0
cp 0
crap 6
rs 10
c 0
b 0
f 0
1
<?php
2
// +----------------------------------------------------------------------
3
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
4
// +----------------------------------------------------------------------
5
// | Copyright (c) 2006~2021 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
 * @package think
18
 */
19
class Lang
20
{
21
    protected $app;
22
23
    /**
24
     * 配置参数
25
     * @var array
26
     */
27
    protected $config = [
28
        // 默认语言
29
        'default_lang'    => 'zh-cn',
30
        // 允许的语言列表
31
        'allow_lang_list' => [],
32
        // 是否使用Cookie记录
33
        'use_cookie'      => true,
34
        // 扩展语言包
35
        'extend_list'     => [],
36
        // 多语言cookie变量
37
        'cookie_var'      => 'think_lang',
38
        // 多语言header变量
39
        'header_var'      => 'think-lang',
40
        // 多语言自动侦测变量名
41
        'detect_var'      => 'lang',
42
        // Accept-Language转义为对应语言包名称
43
        'accept_language' => [
44
            'zh-hans-cn' => 'zh-cn',
45
        ],
46
        // 是否支持语言分组
47
        'allow_group'     => false,
48
    ];
49
50
    /**
51
     * 多语言信息
52
     * @var array
53
     */
54
    private $lang = [];
55
56
    /**
57
     * 当前语言
58
     * @var string
59
     */
60
    private $range = 'zh-cn';
61
62
    /**
63
     * 构造方法
64
     * @access public
65 3
     * @param array $config
66
     */
67 3
    public function __construct(App $app, array $config = [])
68 3
    {
69 3
        $this->config = array_merge($this->config, array_change_key_case($config));
70
        $this->range  = $this->config['default_lang'];
71 3
        $this->app    = $app;
72
    }
73 3
74
    public static function __make(App $app, Config $config)
75
    {
76
        return new static($app, $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($app, /** @scrutinizer ignore-type */ $config->get('lang'));
Loading history...
77
    }
78
79
    /**
80
     * 获取当前语言配置
81
     * @access public
82
     * @return array
83
     */
84
    public function getConfig(): array
85
    {
86
        return $this->config;
87
    }
88
89
    /**
90
     * 设置当前语言
91
     * @access public
92
     * @param string $lang 语言
93
     * @return void
94
     */
95
    public function setLangSet(string $lang): void
96
    {
97
        $this->range = $lang;
98
    }
99
100
    /**
101
     * 获取当前语言
102 3
     * @access public
103
     * @return string
104 3
     */
105
    public function getLangSet(): string
106
    {
107
        return $this->range;
108
    }
109
110
    /**
111
     * 获取默认语言
112
     * @access public
113
     * @return string
114 3
     */
115
    public function defaultLangSet()
116 3
    {
117 3
        return $this->config['default_lang'];
118 3
    }
119
120
    /**
121 3
     * 切换语言
122
     * @access public
123 3
     * @param string $langset 语言
124 3
     * @return void
125 3
     */
126 3
    public function switchLangSet(string $langset)
127
    {
128
        if (empty($langset)) {
129
            return;
130 3
        }
131 3
132
        // 加载系统语言包
133
        $this->load([
134 3
            $this->app->getThinkPath() . 'lang' . DIRECTORY_SEPARATOR . $langset . '.php',
135
        ]);
136
137
        // 加载系统语言包
138
        $files = glob($this->app->getAppPath() . 'lang' . DIRECTORY_SEPARATOR . $langset . '.*');
139
        $this->load($files);
140
141
        // 加载扩展(自定义)语言包
142
        $list = $this->app->config->get('lang.extend_list', []);
143 3
144
        if (isset($list[$langset])) {
145 3
            $this->load($list[$langset]);
146
        }
147 2
    }
148 3
149 3
    /**
150 3
     * 加载语言定义(不区分大小写)
151
     * @access public
152
     * @param string|array $file  语言文件
153
     * @param string       $range 语言作用域
154
     * @return array
155
     */
156
    public function load($file, $range = ''): array
157
    {
158
        $range = $range ?: $this->range;
159
        if (!isset($this->lang[$range])) {
160
            $this->lang[$range] = [];
161
        }
162
163
        $lang = [];
164
165
        foreach ((array) $file as $name) {
166
            if (is_file($name)) {
167
                $result = $this->parse($name);
168
                $lang   = array_change_key_case($result) + $lang;
169
            }
170
        }
171 3
172
        if (!empty($lang)) {
173
            $this->lang[$range] = $lang + $this->lang[$range];
174
        }
175
176
        return $this->lang[$range];
177
    }
178
179
    /**
180
     * 解析语言文件
181
     * @access protected
182
     * @param string $file 语言文件名
183
     * @return array
184
     */
185
    protected function parse(string $file): array
186
    {
187
        $type = pathinfo($file, PATHINFO_EXTENSION);
188
189
        switch ($type) {
190
            case 'php':
191
                $result = include $file;
192
                break;
193
            case 'yml':
194
            case 'yaml':
195
                if (function_exists('yaml_parse_file')) {
196
                    $result = yaml_parse_file($file);
197
                }
198
                break;
199
            case 'json':
200
                $data = file_get_contents($file);
201
202
                if (false !== $data) {
203
                    $data = json_decode($data, true);
204
205
                    if (json_last_error() === JSON_ERROR_NONE) {
206
                        $result = $data;
207
                    }
208
                }
209
210
                break;
211
        }
212
213
        return isset($result) && is_array($result) ? $result : [];
214
    }
215
216
    /**
217
     * 判断是否存在语言定义(不区分大小写)
218
     * @access public
219
     * @param string|null $name  语言变量
220
     * @param string      $range 语言作用域
221
     * @return bool
222
     */
223
    public function has(string $name, string $range = ''): bool
224
    {
225
        $range = $range ?: $this->range;
226
227
        if ($this->config['allow_group'] && strpos($name, '.')) {
228
            [$name1, $name2] = explode('.', $name, 2);
229
            return isset($this->lang[$range][strtolower($name1)][$name2]);
230
        }
231
232
        return isset($this->lang[$range][strtolower($name)]);
233
    }
234
235
    /**
236
     * 获取语言定义(不区分大小写)
237
     * @access public
238
     * @param string|null $name  语言变量
239
     * @param array       $vars  变量替换
240
     * @param string      $range 语言作用域
241
     * @return mixed
242
     */
243
    public function get(string $name = null, array $vars = [], string $range = '')
244
    {
245
        $range = $range ?: $this->range;
246
247
        if (!isset($this->lang[$range])) {
248
            $this->switchLangSet($range);
249
        }
250
251
        // 空参数返回所有定义
252
        if (is_null($name)) {
253
            return $this->lang[$range] ?? [];
254
        }
255
256
        if ($this->config['allow_group'] && strpos($name, '.')) {
257
            $value = $this->lang[$range];
258
            foreach (explode('.', $name) as $segment) {
259
                if (is_array($value) && array_key_exists($segment, $value)) {
260
                    $value = $value[$segment];
261
                } else {
262
                    $value = $name;
263
                }
264
            }
265
        } else {
266
            $value = $this->lang[$range][strtolower($name)] ?? $name;
267
        }
268
269
        // 变量解析
270
        if (!empty($vars) && is_array($vars)) {
271
            /**
272
             * Notes:
273
             * 为了检测的方便,数字索引的判断仅仅是参数数组的第一个元素的key为数字0
274
             * 数字索引采用的是系统的 sprintf 函数替换,用法请参考 sprintf 函数
275
             */
276
            if (key($vars) === 0) {
277
                // 数字索引解析
278
                array_unshift($vars, $value);
279
                $value = call_user_func_array('sprintf', $vars);
280
            } else {
281
                // 关联索引解析
282
                $replace = array_keys($vars);
283
                foreach ($replace as &$v) {
284
                    $v = "{:{$v}}";
285
                }
286
                $value = str_replace($replace, $vars, $value);
287
            }
288
        }
289
290
        return $value;
291
    }
292
293
    /**
294
     * 自动侦测设置获取语言选择
295
     * @deprecated
296
     * @access public
297
     * @param Request $request
298
     * @return string
299
     */
300
    public function detect(Request $request): string
301
    {
302
        // 自动侦测设置获取语言选择
303
        $langSet = '';
304
305
        if ($request->get($this->config['detect_var'])) {
306
            // url中设置了语言变量
307
            $langSet = strtolower($request->get($this->config['detect_var']));
308
        } elseif ($request->header($this->config['header_var'])) {
309
            // Header中设置了语言变量
310
            $langSet = strtolower($request->header($this->config['header_var']));
0 ignored issues
show
Bug introduced by
It seems like $request->header($this->config['header_var']) can also be of type array; however, parameter $string of strtolower() does only seem to accept string, 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

310
            $langSet = strtolower(/** @scrutinizer ignore-type */ $request->header($this->config['header_var']));
Loading history...
311
        } elseif ($request->cookie($this->config['cookie_var'])) {
312
            // Cookie中设置了语言变量
313
            $langSet = strtolower($request->cookie($this->config['cookie_var']));
314
        } elseif ($request->server('HTTP_ACCEPT_LANGUAGE')) {
315
            // 自动侦测浏览器语言
316
            $match = preg_match('/^([a-z\d\-]+)/i', $request->server('HTTP_ACCEPT_LANGUAGE'), $matches);
317
            if ($match) {
318
                $langSet = strtolower($matches[1]);
319
                if (isset($this->config['accept_language'][$langSet])) {
320
                    $langSet = $this->config['accept_language'][$langSet];
321
                }
322
            }
323
        }
324
325
        if (empty($this->config['allow_lang_list']) || in_array($langSet, $this->config['allow_lang_list'])) {
326
            // 合法的语言
327
            $this->range = $langSet;
328
        }
329
330
        return $this->range;
331
    }
332
333
    /**
334
     * 保存当前语言到Cookie
335
     * @deprecated
336
     * @access public
337
     * @param Cookie $cookie Cookie对象
338
     * @return void
339
     */
340
    public function saveToCookie(Cookie $cookie)
341
    {
342
        if ($this->config['use_cookie']) {
343
            $cookie->set($this->config['cookie_var'], $this->range);
344
        }
345
    }
346
347
}
348