Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
58.33% covered (warning)
58.33%
28 / 48
37.50% covered (danger)
37.50%
3 / 8
CRAP
0.00% covered (danger)
0.00%
0 / 1
language_file_loader
58.33% covered (warning)
58.33%
28 / 48
37.50% covered (danger)
37.50%
3 / 8
52.90
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 set_extension_manager
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 load
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 load_extension
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
6
 load_file
33.33% covered (danger)
33.33%
4 / 12
0.00% covered (danger)
0.00%
0 / 1
5.67
 get_language_file_path
60.00% covered (warning)
60.00%
6 / 10
0.00% covered (danger)
0.00%
0 / 1
6.60
 get_composer_lang_values
81.82% covered (warning)
81.82%
9 / 11
0.00% covered (danger)
0.00%
0 / 1
6.22
 load_language_file
66.67% covered (warning)
66.67%
2 / 3
0.00% covered (danger)
0.00%
0 / 1
2.15
1<?php
2/**
3 *
4 * This file is part of the phpBB Forum Software package.
5 *
6 * @copyright (c) phpBB Limited <https://www.phpbb.com>
7 * @license GNU General Public License, version 2 (GPL-2.0)
8 *
9 * For full copyright and license information, please see
10 * the docs/CREDITS.txt file.
11 *
12 */
13
14namespace phpbb\language;
15
16use phpbb\language\exception\language_file_not_found;
17
18/**
19 * Language file loader
20 */
21class language_file_loader
22{
23    /**
24     * @var string    Path to phpBB's root
25     */
26    protected $phpbb_root_path;
27
28    /**
29     * @var string    Extension of PHP files
30     */
31    protected $php_ext;
32
33    /**
34     * @var \phpbb\extension\manager|null    Extension manager
35     */
36    protected $extension_manager;
37
38    /**
39     * Constructor
40     *
41     * @param string    $phpbb_root_path    Path to phpBB's root
42     * @param string    $php_ext            Extension of PHP files
43     */
44    public function __construct($phpbb_root_path, $php_ext)
45    {
46        $this->phpbb_root_path    = $phpbb_root_path;
47        $this->php_ext            = $php_ext;
48
49        $this->extension_manager = null;
50    }
51
52    /**
53     * Extension manager setter
54     *
55     * @param \phpbb\extension\manager    $extension_manager    Extension manager
56     */
57    public function set_extension_manager(\phpbb\extension\manager $extension_manager)
58    {
59        $this->extension_manager = $extension_manager;
60    }
61
62    /**
63     * Loads language array for the given component
64     *
65     * @param string        $component    Name of the language component
66     * @param string|array    $locale        ISO code of the language to load, or array of ISO codes if you want to
67     *                                     specify additional language fallback steps
68     * @param array            $lang        Array reference containing language strings
69     */
70    public function load($component, $locale, &$lang)
71    {
72        $locale = (array) $locale;
73
74        // Determine path to language directory
75        $path = $this->phpbb_root_path . 'language/';
76
77        $this->load_file($path, $component, $locale, $lang);
78    }
79
80    /**
81     * Loads language array for the given extension component
82     *
83     * @param string        $extension    Name of the extension
84     * @param string        $component    Name of the language component
85     * @param string|array    $locale        ISO code of the language to load, or array of ISO codes if you want to
86     *                                     specify additional language fallback steps
87     * @param array            $lang        Array reference containing language strings
88     */
89    public function load_extension($extension, $component, $locale, &$lang)
90    {
91        // Check if extension manager was loaded
92        if ($this->extension_manager === null)
93        {
94            // If not, let's return
95            return;
96        }
97
98        $locale = (array) $locale;
99
100        // Determine path to language directory
101        $path = $this->extension_manager->get_extension_path($extension, true) . 'language/';
102
103        $this->load_file($path, $component, $locale, $lang);
104    }
105
106    /**
107     * Prepares language file loading
108     *
109     * @param string    $path        Path to search for file in
110     * @param string    $component    Name of the language component
111     * @param array        $locale        Array containing language fallback options
112     * @param array        $lang        Array reference of language strings
113     */
114    protected function load_file($path, $component, $locale, &$lang)
115    {
116        // This is BC stuff and not the best idea as it makes language fallback
117        // implementation quite hard like below.
118        if (strpos($this->phpbb_root_path . $component, $path) === 0)
119        {
120            // Filter out the path
121            $path_diff = str_replace($path, '', dirname($this->phpbb_root_path . $component));
122            $language_file = basename($component, '.' . $this->php_ext);
123            $component = '';
124
125            // This step is needed to resolve language/en/subdir style $component
126            // $path already points to the language base directory so we need to eliminate
127            // the first directory from the path (that should be the language directory)
128            $path_diff_parts = explode('/', $path_diff);
129
130            if (count($path_diff_parts) > 1)
131            {
132                array_shift($path_diff_parts);
133                $component = implode('/', $path_diff_parts) . '/';
134            }
135
136            $component .= $language_file;
137        }
138
139        // Determine filename
140        $filename = $component . '.' . $this->php_ext;
141
142        // Determine path to file
143        $file_path = $this->get_language_file_path($path, $filename, $locale);
144
145        // Load language array
146        $this->load_language_file($file_path, $lang);
147    }
148
149    /**
150     * This function implements language fallback logic
151     *
152     * @param string    $path        Path to language directory
153     * @param string    $filename    Filename to load language strings from
154     * @param array        $locales    Array containing language fallback options
155     *
156     * @return string    Relative path to language file
157     *
158     * @throws language_file_not_found    When the path to the file cannot be resolved
159     */
160    protected function get_language_file_path($path, $filename, $locales)
161    {
162        $language_file_path = $filename;
163
164        // Language fallback logic
165        foreach ($locales as $locale)
166        {
167            $language_file_path = $path . $locale . '/' . $filename;
168
169            // If we are in install, try to use the updated version, when available
170            if (defined('IN_INSTALL'))
171            {
172                $install_language_path = str_replace('language/', 'install/update/new/language/', $language_file_path);
173                if (file_exists($install_language_path))
174                {
175                    return $install_language_path;
176                }
177            }
178
179            if (file_exists($language_file_path))
180            {
181                return $language_file_path;
182            }
183        }
184
185        // The language file is not exist
186        throw new language_file_not_found('Language file ' . $language_file_path . ' couldn\'t be opened.');
187    }
188
189    /**
190     * Get language values from composer.json files
191     *
192     * @param array|string $locales
193     * @return array
194     */
195    public function get_composer_lang_values(array|string $locales): array
196    {
197        if (!is_array($locales))
198        {
199            $locales = [$locales];
200        }
201
202        $file_helper = new language_file_helper($this->phpbb_root_path);
203        $composer_lang_vars = $file_helper->get_available_languages();
204
205        foreach ($composer_lang_vars as $key => $value)
206        {
207            $composer_lang_vars[$value['iso']] = $value;
208            unset($composer_lang_vars[$key]);
209        }
210
211        foreach ($locales as $locale)
212        {
213            if (isset($composer_lang_vars[$locale]))
214            {
215                return $composer_lang_vars[$locale];
216            }
217        }
218
219        return count($composer_lang_vars) ? array_shift($composer_lang_vars) : [];
220    }
221
222    /**
223     * Loads language file
224     *
225     * @param string    $path    Path to language file to load
226     * @param array        $lang    Reference of the array of language strings
227     */
228    protected function load_language_file($path, &$lang)
229    {
230        // Do not suppress error if in DEBUG mode
231        if (defined('DEBUG'))
232        {
233            include $path;
234        }
235        else
236        {
237            @include $path;
238        }
239    }
240}