Completed
Pull Request — 6.0 (#2115)
by nhzex
06:13
created

Lang::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 4
ccs 3
cts 3
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
 * @package think
0 ignored issues
show
Coding Style introduced by
Package name "think" is not valid; consider "Think" instead
Loading history...
18
 */
19
class Lang
20
{
21
    /**
22
     * 配置参数
23
     * @var array
24
     */
25
    protected $config = [
26
        // 默认语言
27
        'default_lang'    => 'zh-cn',
28
        // 允许的语言列表
29
        'allow_lang_list' => [],
30
        // 是否使用Cookie记录
31
        'use_cookie'      => true,
32
        // 扩展语言包
33
        'extend_list'     => [],
34
        // 多语言cookie变量
35
        'cookie_var'      => 'think_lang',
36
        // 多语言自动侦测变量名
37
        'detect_var'      => 'lang',
38
        // Accept-Language转义为对应语言包名称
39
        'accept_language' => [
40
            'zh-hans-cn' => 'zh-cn',
41
        ],
42
        // 是否支持语言分组
43
        'allow_group'     => false,
44
    ];
45
46
    /**
47
     * 多语言信息
48
     * @var array
49
     */
50
    private $lang = [];
0 ignored issues
show
Coding Style introduced by
Private member variable "lang" must be prefixed with an underscore
Loading history...
51
52
    /**
53
     * 当前语言
54
     * @var string
55
     */
56
    private $range = 'zh-cn';
0 ignored issues
show
Coding Style introduced by
Private member variable "range" must be prefixed with an underscore
Loading history...
57
58
    /**
59
     * 构造方法
60
     * @access public
61
     * @param array $config
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
62
     */
63 1
    public function __construct(array $config = [])
64
    {
65 1
        $this->config = array_merge($this->config, array_change_key_case($config));
66 1
        $this->range  = $this->config['default_lang'];
67 1
    }
68
69 1
    public static function __make(Config $config)
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function __make()
Loading history...
70
    {
71 1
        return new static($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

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