Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
22 / 22
100.00% covered (success)
100.00%
13 / 13
CRAP
100.00% covered (success)
100.00%
1 / 1
Verba
100.00% covered (success)
100.00%
22 / 22
100.00% covered (success)
100.00%
13 / 13
17
100.00% covered (success)
100.00%
1 / 1
 activate
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 deactivate
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 translator
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 translate
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 translateContext
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 translatePlural
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 translateContextPlural
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 translateDomain
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 translateDomainContext
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 translateDomainPlural
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 translateDomainContextPlural
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 args
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
5
 current
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3declare(strict_types=1);
4
5namespace Celema\Verba;
6
7use InvalidArgumentException;
8
9/**
10 * Process-wide holder and facade for the active translator.
11 *
12 * The eight global translation functions delegate here. With no translator
13 * active, lookups return the message id (with interpolation), which
14 * keeps translation calls safe in tests, CLI, and early boot.
15 *
16 * @api
17 */
18final class Verba
19{
20    private static ?Translator $translator = null;
21
22    private static ?Translator $fallback = null;
23
24    public static function activate(Translator $translator): void
25    {
26        self::$translator = $translator;
27    }
28
29    public static function deactivate(): void
30    {
31        self::$translator = null;
32    }
33
34    public static function translator(): ?Translator
35    {
36        return self::$translator;
37    }
38
39    /**
40     * @param array<array-key, string|int|float> $args
41     */
42    public static function translate(string $id, array $args = []): string
43    {
44        return self::current()->translate($id, $args);
45    }
46
47    /**
48     * @param array<array-key, string|int|float> $args
49     */
50    public static function translateContext(string $context, string $id, array $args = []): string
51    {
52        return self::current()->translateContext($context, $id, $args);
53    }
54
55    /**
56     * @param array<array-key, string|int|float> $args
57     */
58    public static function translatePlural(string $one, string $many, int $n, array $args = []): string
59    {
60        return self::current()->translatePlural($one, $many, $n, $args);
61    }
62
63    /**
64     * @param array<array-key, string|int|float> $args
65     */
66    public static function translateContextPlural(
67        string $context,
68        string $one,
69        string $many,
70        int $n,
71        array $args = [],
72    ): string {
73        return self::current()->translateContextPlural($context, $one, $many, $n, $args);
74    }
75
76    /**
77     * @param array<array-key, string|int|float> $args
78     */
79    public static function translateDomain(string $domain, string $id, array $args = []): string
80    {
81        return self::current()->translateDomain($domain, $id, $args);
82    }
83
84    /**
85     * @param array<array-key, string|int|float> $args
86     */
87    public static function translateDomainContext(
88        string $domain,
89        string $context,
90        string $id,
91        array $args = [],
92    ): string {
93        return self::current()->translateDomainContext($domain, $context, $id, $args);
94    }
95
96    /**
97     * @param array<array-key, string|int|float> $args
98     */
99    public static function translateDomainPlural(
100        string $domain,
101        string $one,
102        string $many,
103        int $n,
104        array $args = [],
105    ): string {
106        return self::current()->translateDomainPlural($domain, $one, $many, $n, $args);
107    }
108
109    /**
110     * @param array<array-key, string|int|float> $args
111     */
112    // @mago-expect lint:excessive-parameter-list The API mirrors the translator method.
113    public static function translateDomainContextPlural(
114        string $domain,
115        string $context,
116        string $one,
117        string $many,
118        int $n,
119        array $args = [],
120    ): string {
121        return self::current()->translateDomainContextPlural($domain, $context, $one, $many, $n, $args);
122    }
123
124    /**
125     * Normalizes variadic message arguments into a single args array. A lone
126     * array argument is a named-placeholder map; anything else is a positional
127     * (sprintf) list of scalars, so an array among several arguments is rejected.
128     *
129     * @param array<array-key, string|int|float|array<array-key, string|int|float>> $args
130     * @return array<array-key, string|int|float>
131     */
132    public static function args(array $args): array
133    {
134        if (count($args) === 1) {
135            $first = reset($args);
136
137            if (is_array($first)) {
138                return $first;
139            }
140        }
141
142        $positional = [];
143
144        foreach ($args as $key => $arg) {
145            if (is_array($arg)) {
146                throw new InvalidArgumentException('A named-placeholder array must be the only message argument');
147            }
148
149            $positional[$key] = $arg;
150        }
151
152        return $positional;
153    }
154
155    private static function current(): Translator
156    {
157        return self::$translator ?? (self::$fallback ??= new Translator('en', []));
158    }
159}