Passed
Push — main ( c702a3...9b65d9 )
by Sammy
01:42
created

Lezer.php (6 issues)

1
<?php
2
3
/*
4
 * i18n class called Lezer, shorthand L
5
 * honnors Ludwik *Lejzer* Zamenhof (Polish: Ludwik Łazarz Zamenhof; 15 December [O.S. 3 December] 1859 – 14 April [O.S. 1 April] 1917),
6
 * a medical doctor, inventor, and writer; most widely known for creating Esperanto.
7
 *
8
 * also Lezer is dutch for Reader, and it sounds like LASER, which is kinda cool.
9
 */
10
namespace HexMakina\Lezer;
11
12
use HexMakina\LocalFS\FileSystem;
13
use HexMakina\Tempus\{Dato,DatoTempo,Tempo};
14
15
class Lezer extends \i18n
16
{
17
18
    private $detected_language_files = [];
19
    private $detected_language_env = [];
20
21
  // protected $basePath = 'locale';
22
  // protected $filePath = 'locale/{LANGUAGE}/user_interface.ini'; // uses gettext hierarchy
23
  // protected $cachePath = 'locale/cache/';
24
  // protected $fallbackLang = 'fra';  // uses ISO-639-3
25
    protected $currentLang = null;
26
27
    public function one_language()
28
    {
29
        $this->detect_language_files();
30
        $this->detect_language_env();
31
        $the_one_language = current(array_intersect($this->detect_language_files(), $this->detect_language_env()));
32
33
        if ($the_one_language) {
34
            $this->setForcedLang($the_one_language);
35
        }
36
37
        return $the_one_language;
38
    }
39
40
    public function detect_language_files()
41
    {
42
        $files = FileSystem::preg_scandir(dirname($this->filePath), '/.json$/');
43
        if (empty($files)) {
44
            return [];
45
        }
46
47
        $files = implode('', $files);
48
        $res = preg_match_all('/([a-z]{3})\.json/', $files, $m);
49
        if ($res) { // false or 0 is none found
50
            $this->detected_language_files = $m[1];
51
        }
52
        return $this->detected_language_files;
53
    }
54
55
  /**
56
   * getUserLangs()
57
   * Returns the user languages
58
   * Normally it returns an array like this:
59
   * 1. Forced language
60
   * 2. Language in $_GET['lang']
61
   * 3. Language in $_SESSION['lang']
62
   * 4. COOKIE
63
   * 5. Fallback language
64
   * Note: duplicate values are deleted.
65
   *
66
   * @return array with the user languages sorted by priority.
67
   */
68
    public function detect_language_env()
69
    {
70
        $userLangs = array();
71
72
        // 1. forced language
73
        if ($this->forcedLang != null) {
74
            $userLangs['forced'] = $this->forcedLang;
75
        }
76
77
        // 2. GET parameter 'lang'
78
        if (isset($_GET['lang']) && is_string($_GET['lang'])) {
79
            $userLangs['get'] = $_GET['lang'];
80
        }
81
82
        // 3. SESSION parameter 'lang'
83
        if (isset($_SESSION['lang']) && is_string($_SESSION['lang'])) {
84
            $userLangs['session'] = $_SESSION['lang'];
85
        }
86
87
        // 4. COOKIES
88
        if (isset($_COOKIE['lang']) && is_string($_COOKIE['lang'])) {
89
            $userLangs['cookie'] = $_COOKIE['lang'];
90
        }
91
92
        // Lowest priority: fallback
93
        $userLangs['fallback'] = $this->fallbackLang;
94
        // remove duplicate elements
95
        $userLangs = array_unique($userLangs);
96
97
        // remove illegal userLangs
98
        foreach ($userLangs as $key => $value) {
99
            // only allow a-z, A-Z and 0-9 and _ and -
100
            if (preg_match('/^[a-zA-Z0-9_-]*$/', $value) === 1) {
101
                $this->detected_language_env[$key] = $value;
102
            }
103
        }
104
105
        return $this->detected_language_env;
106
    }
107
108
109
    public function compileFunction()
110
    {
111
        return ''
112
        . "function " . $this->prefix . '($string, $args=NULL) {' . "\n"
113
        . '    if (!defined("' . $this->prefix . '::".$string))'
114
        . '       return $string;'
115
        . '    $return = constant("' . $this->prefix . '::".$string);' . "\n"
116
        . '    return $args ? vsprintf($return,$args) : $return;'
117
        . "\n}";
118
    }
119
120
    public function l($message, $context=[]) : string
121
    {
122
        return call_user_func($this->prefix, $message, $context);
123
    }
124
125
126
  // options['decimals'] = int
127
  // options['abbrev'] = mixed: key needs to be set
128
    public static function when($event, $options = [])
129
    {
130
        try {
131
            $amount_of_days = DatoTempo::days_diff(new \DateTime($event), new \DateTime());
132
        } catch (\Exception $e) {
133
            return __FUNCTION__ . ': error';
134
        }
135
136
        if ($amount_of_days === -1) {
137
            return $this->l('DATETIME_RANGE_YESTERDAY');
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using $this inside a static method is generally not recommended and can lead to errors in newer PHP versions.
Loading history...
138
        } elseif ($amount_of_days === 0) {
139
            return $this->l('DATETIME_RANGE_TODAY');
140
        } elseif ($amount_of_days === 1) {
141
            return $this->l('DATETIME_RANGE_TOMORROW');
142
        }
143
144
145
        $datetime_parts = [
146
        'y' => 'DATETIME_UNIT_YEAR',
147
        'm' => 'DATETIME_UNIT_MONTH',
148
        'w' => 'DATETIME_UNIT_WEEK',
149
        'd' => 'DATETIME_UNIT_DAY',
150
        'h' => 'DATETIME_UNIT_HOUR',
151
        'i' => 'DATETIME_UNIT_MINUTE',
152
        's' => 'DATETIME_UNIT_SECOND'
153
        ];
154
155
        $date_diff = DatoTempo::days_diff_in_parts(abs($amount_of_days));
156
        $ordering = [];
157
        foreach ($datetime_parts as $unit => $label) {
158
            if (!isset($date_diff[$unit])) {
159
                continue;
160
            }
161
162
            $qty = (int)$date_diff[$unit];
163
164
            if ($qty === 0) {
165
                continue;
166
            }
167
168
            if (isset($options['abbrev'])) {
169
                $label .= '_ABBREV';
170
            } elseif ($qty > 1) {
171
                $label .= '_PLURAL';
172
            }
173
174
            $ordering[$unit] = $qty . ' ' . L($label) . '.';
0 ignored issues
show
The function L was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

174
            $ordering[$unit] = $qty . ' ' . /** @scrutinizer ignore-call */ L($label) . '.';
Loading history...
175
        }
176
        $ret = (isset($amount_of_days) && $amount_of_days >= 0) ? L('DATETIME_RANGE_PREFIX_FUTURE') : L('DATETIME_RANGE_PREFIX_PAST');
177
        $ret .= ' ' . implode(' & ', array_slice($ordering, 0, 2));
178
179
        return $ret;
180
    }
181
182
    public static function time($time_string, $short = true)
183
    {
184
        if ($short === true) {
185
            $time_string = substr($time_string, 0, 5);
186
        }
187
        return $time_string;
188
    }
189
190
    public static function human_date($date_string, $short = true)
191
    {
192
        if ($date_string === '0000-00-00' || empty($date_string)) {
193
            return $this->l('MODEL_common_VALUE_EMPTY');
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using $this inside a static method is generally not recommended and can lead to errors in newer PHP versions.
Loading history...
194
        }
195
196
        if (preg_match('/^[0-9]{4}$/', $date_string) === 1) {
197
            return intval($date_string);
198
        }
199
200
        list($year, $month, $day) = explode('-', $date_string);
201
202
        $ret = intval($day) . ' ' . L("DATETIME_CALENDAR_MONTH_$month");
0 ignored issues
show
The function L was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

202
        $ret = intval($day) . ' ' . /** @scrutinizer ignore-call */ L("DATETIME_CALENDAR_MONTH_$month");
Loading history...
203
204
        if ($short === true && Dato::format(null, 'Y') === $year) {
205
            return $ret;
206
        } else {
207
            return "$ret $year";
208
        }
209
    }
210
211
    public static function human_month($date_string)
212
    {
213
        return $this->l('DATETIME_CALENDAR_MONTH_' . Dato::format($date_string, 'm'));
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using $this inside a static method is generally not recommended and can lead to errors in newer PHP versions.
Loading history...
214
    }
215
216
    public static function human_day($date_string)
217
    {
218
        return $this->l('DATETIME_CALENDAR_DAY_' . Dato::format($date_string, 'N'));
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using $this inside a static method is generally not recommended and can lead to errors in newer PHP versions.
Loading history...
219
    }
220
221
    public static function human_seconds($seconds)
222
    {
223
        $hours = floor($seconds / 3600);
224
        $mins = floor(($seconds - $hours * 3600) / 60);
225
        $secs = floor($seconds % 60);
226
227
        $hours_format = '%dh %dm %ds';
228
        return sprintf($hours_format, $hours, $mins, $secs);
229
    }
230
}
231