AbstractLocale::numerals()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
1
<?php namespace Fisharebest\Localization\Locale;
2
3
use Fisharebest\Localization\Language\LanguageInterface;
4
use Fisharebest\Localization\PluralRule\PluralRuleInterface;
5
use Fisharebest\Localization\Script\ScriptInterface;
6
use Fisharebest\Localization\Territory\TerritoryInterface;
7
use Fisharebest\Localization\Variant\VariantInterface;
8
9
/**
10
 * Class AbstractLocale - The “root” locale, from which all others are derived.
11
 *
12
 * @author    Greg Roach <[email protected]>
13
 * @copyright (c) 2018 Greg Roach
14
 * @license   GPLv3+
15
 */
16
abstract class AbstractLocale
17
{
18
    // "Source" strings, when translating numbers
19
    const DECIMAL  = '.'; // The default decimal mark
20
    const GROUP    = ','; // The digit group separator
21
    const NEGATIVE = '-'; // Negative numbers
22
23
    // "Target" strings, when translating numbers
24
    const ALM          = "\xD8\x9C"; // Arabic Letter Mark
25
    const APOSTROPHE   = '’';
26
    const ARAB_DECIMAL = "\xD9\xAB";
27
    const ARAB_GROUP   = "\xD9\xAC";
28
    const ARAB_MINUS   = "\xE2\x88\x92";
29
    const ARAB_PERCENT = "\xD9\xAA";
30
    const COMMA        = ',';
31
    const DOT          = '.';
32
    const HYPHEN       = '-';
33
    const LTR_MARK     = "\xE2\x80\x8E"; // Left-to-right marker
34
    const MINUS_SIGN   = "\xE2\x88\x92";
35
    const NBSP         = "\xC2\xA0"; // A non-breaking space
36
    const PRIME        = '\'';
37
    const RTL_MARK     = "\xE2\x80\x8F"; // Right-to-left marker
38
39
    // For formatting percentages
40
    const PERCENT     = '%%';
41
    const PLACEHOLDER = '%s';
42
43
    /**
44
     * Generate a linux locale code for this locale.  Examples include
45
     * "fr", “en_GB”, “ca_ES@valencia” and “sr@latin”.
46
     *
47
     * @return string
48
     */
49
    public function code()
50
    {
51
        $code = $this->language()->code() . '_' . $this->territory()->code();
52
53
        if ($this->script() != $this->language()->defaultScript()) {
54
            $code .= '@' . strtolower($this->script()->unicodeName());
55
        }
56
57
        if ($this->variant() !== null) {
58
            if ($this->variant()->code() === 'posix') {
59
                $code = 'POSIX';
60
            } else {
61
                $code .= '@' . $this->variant()->code();
62
            }
63
        }
64
65
        return $code;
66
    }
67
68
    /**
69
     * Which collation sequence should be used for this locale?
70
     * “unicode_ci” would mean use “utf8_unicode_ci”, “utf8mb4_unicode_ci”, etc.
71
     *
72
     * @link http://dev.mysql.com/doc/refman/5.7/en/charset-unicode-sets.html
73
     * @return string
74
     */
75
    public function collation()
76
    {
77
        return 'unicode_ci';
78
    }
79
80
    /**
81
     * Convert (Hindu-Arabic) digits into a localized form
82
     *
83
     * @param string $string e.g. "123.45"
84
     *
85
     * @return string
86
     */
87
    public function digits($string)
88
    {
89
        return strtr($string, $this->numberSymbols() + $this->numerals());
90
    }
91
92
    /**
93
     * When writing large numbers place a separator after this number of digits.
94
     *
95
     * @return int
96
     */
97
    protected function digitsFirstGroup()
98
    {
99
        return 3;
100
    }
101
102
    /**
103
     * When writing large numbers place a separator after this number of digits.
104
     *
105
     * @return int
106
     */
107
    protected function digitsGroup()
108
    {
109
        return 3;
110
    }
111
112
    /**
113
     * Is text written left-to-right “ltr” or right-to-left “rtl”.
114
     * Most scripts are only written in one direction, but there are a few that
115
     * can be written in either direction.
116
     *
117
     * @return string “ltr” or “rtl”
118
     */
119
    public function direction()
120
    {
121
        return $this->script()->direction();
122
    }
123
124
    /**
125
     * A sortable version of the locale name.  For example, “British English”
126
     * might sort as “ENGLISH, BRITISH” to keep all the variants of English together.
127
     *
128
     * All-capitals makes sorting easier, as we can use a simple strcmp().
129
     *
130
     * @return string
131
     */
132
    public function endonymSortable()
133
    {
134
        return $this->endonym();
135
    }
136
137
    /**
138
     * Markup for an HTML element
139
     *
140
     * @return string e.g. lang="ar" dir="rtl"
141
     */
142
    public function htmlAttributes()
143
    {
144
        if ($this->direction() === 'rtl' || $this->direction() !== $this->script()->direction()) {
145
            return 'lang="' . $this->languageTag() . '" dir="' . $this->direction() . '"';
146
        } else {
147
            return 'lang="' . $this->languageTag() . '"';
148
        }
149
    }
150
151
    /**
152
     * The IETF language tag for the locale.  Examples include
153
     * “fr, “en-GB”, “ca-ES-valencia” and “sr-Latn”.
154
     *
155
     * @return string
156
     */
157
    public function languageTag()
158
    {
159
        $language_tag = $this->language()->code();
160
        if ($this->script() != $this->language()->defaultScript()) {
161
            $language_tag .= '-' . $this->script()->code();
162
        }
163
        if ($this->territory() != $this->language()->defaultTerritory()) {
164
            $language_tag .= '-' . $this->territory()->code();
165
        }
166
        if ($this->variant()) {
167
            $language_tag .= '-' . $this->variant()->code();
168
        }
169
170
        return $language_tag;
171
    }
172
173
    /**
174
     * When using grouping digits in numbers, keep this many of digits together.
175
     *
176
     * @return int
177
     */
178
    protected function minimumGroupingDigits()
179
    {
180
        return 1;
181
    }
182
183
    /**
184
     * Convert (Hindu-Arabic) digits into a localized form
185
     *
186
     * @param float $number The number to be localized
187
     *
188
     * @return string
189
     */
190
    public function number($number)
191
    {
192
        if ($number < 0) {
193
            $number   = -$number;
194
            $negative = self::NEGATIVE;
195
        } else {
196
            $negative = '';
197
        }
198
        $parts    = explode(self::DECIMAL, (string) $number, 2);
199
        $integers = $parts[0];
200
        if (strlen($integers) >= $this->digitsFirstGroup() + $this->minimumGroupingDigits()) {
201
            $todo     = substr($integers, 0, -$this->digitsFirstGroup());
202
            $integers = self::GROUP . substr($integers, -$this->digitsFirstGroup());
203
            while (strlen($todo) >= $this->digitsGroup() + $this->minimumGroupingDigits()) {
204
                $integers = self::GROUP . substr($todo, -$this->digitsGroup()) . $integers;
205
                $todo     = substr($todo, 0, -$this->digitsGroup());
206
            }
207
            $integers = $todo . $integers;
208
        }
209
        if (count($parts) > 1) {
210
            $decimals = self::DECIMAL . $parts[1];
211
        } else {
212
            $decimals = '';
213
        }
214
215
        return $this->digits($negative . $integers . $decimals);
216
    }
217
218
    /**
219
     * The symbols used to format numbers.
220
     *
221
     * @return string[]
222
     */
223
    protected function numberSymbols()
224
    {
225
        return array();
226
    }
227
228
    /**
229
     * The numerals (0123456789) used by this locale.
230
     *
231
     * @return string[]
232
     */
233
    protected function numerals()
234
    {
235
        return $this->script()->numerals();
236
    }
237
238
    /**
239
     * Convert (Hindu-Arabic) digits into a localized form
240
     *
241
     * @param float $number The number to be localized
242
     *
243
     * @return string
244
     */
245
    public function percent($number)
246
    {
247
        return sprintf($this->percentFormat(), $this->number($number * 100.0));
248
    }
249
250
    /**
251
     * How to format a floating point number (%s) as a percentage.
252
     *
253
     * @return string
254
     */
255
    protected function percentFormat()
256
    {
257
        return self::PLACEHOLDER . self::PERCENT;
258
    }
259
260
    /**
261
     * Which plural rule is used in this locale
262
     *
263
     * @return PluralRuleInterface
264
     */
265
    public function pluralRule()
266
    {
267
        return $this->language()->pluralRule();
268
    }
269
270
    /**
271
     * The script used by this locale.
272
     *
273
     * @return ScriptInterface
274
     */
275
    public function script()
276
    {
277
        return $this->language()->defaultScript();
278
    }
279
280
    /**
281
     * The territory used by this locale.
282
     *
283
     * @return TerritoryInterface
284
     */
285
    public function territory()
286
    {
287
        return $this->language()->defaultTerritory();
288
    }
289
290
    /**
291
     * The variant, if any of this locale.
292
     *
293
     * @return VariantInterface|null
294
     */
295
    public function variant()
296
    {
297
        return null;
298
    }
299
}
300