Skip to content

Commit e863ecc

Browse files
committed
v0.3.0 update
1 parent f42961f commit e863ecc

1 file changed

Lines changed: 350 additions & 0 deletions

File tree

Lines changed: 350 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,350 @@
1+
====== PHP RFC: Add Locale::getDisplayKeyword() and Locale::getDisplayKeywordValue() ======
2+
* Version: 0.9
3+
* Date: 2026-05-22
4+
* Author: Your Name, your_email_address@example.com
5+
* Status: Draft
6+
* Implementation: https://github.com/...
7+
* Discussion thread:
8+
9+
===== Introduction =====
10+
11+
This RFC proposes adding ``Locale::getDisplayKeyword()`` and
12+
``Locale::getDisplayKeywordValue()`` to ``ext/intl``, together with their
13+
procedural aliases. These APIs expose ICU's
14+
``uloc_getDisplayKeyword()`` and ``uloc_getDisplayKeywordValue()`` to PHP
15+
userland.
16+
17+
PHP already exposes a family of locale display helpers such as
18+
``Locale::getDisplayLanguage()``, ``Locale::getDisplayRegion()``,
19+
``Locale::getDisplayVariant()``, and ``Locale::getDisplayName()``. PHP also
20+
exposes ``Locale::getKeywords()``, which allows code to extract locale keyword
21+
pairs. What is currently missing is a way to localize the keyword names
22+
themselves and the display labels for their values. This proposal fills that
23+
gap in a way that is consistent with the existing ``Locale`` API surface.
24+
25+
<PHP>
26+
<?php
27+
28+
$locale = 'de_DE@collation=phonebook';
29+
$keyword = 'collation';
30+
31+
echo Locale::getDisplayKeyword($keyword, 'en'), PHP_EOL;
32+
echo Locale::getDisplayKeywordValue($locale, $keyword, 'en'), PHP_EOL;
33+
34+
?>
35+
</PHP>
36+
37+
===== Proposal =====
38+
39+
Add two new procedural functions and two new ``Locale`` static methods:
40+
41+
<PHP>
42+
<?php
43+
44+
function locale_get_display_keyword(
45+
string $keyword,
46+
?string $displayLocale = null
47+
): string|false {}
48+
49+
function locale_get_display_keyword_value(
50+
string $locale,
51+
string $keyword,
52+
?string $displayLocale = null
53+
): string|false {}
54+
55+
class Locale
56+
{
57+
public static function getDisplayKeyword(
58+
string $keyword,
59+
?string $displayLocale = null
60+
): string|false {}
61+
62+
public static function getDisplayKeywordValue(
63+
string $locale,
64+
string $keyword,
65+
?string $displayLocale = null
66+
): string|false {}
67+
}
68+
69+
?>
70+
</PHP>
71+
72+
The proposed methods intentionally follow the existing ``Locale::getDisplay*()``
73+
naming pattern.
74+
75+
==== Semantics ====
76+
77+
``Locale::getDisplayKeyword()`` returns a localized display label for a locale
78+
keyword, such as ``collation`` or ``calendar``.
79+
80+
``Locale::getDisplayKeywordValue()`` returns a localized display label for the
81+
value of a given keyword inside a locale identifier.
82+
83+
The new APIs should follow the behavior of the existing display-oriented
84+
``Locale`` methods:
85+
86+
* If ``$displayLocale`` is ``null``, the current default locale is used.
87+
* On ICU failure, the function returns ``false`` and reports the error through
88+
the existing intl error mechanism.
89+
* Embedded NUL bytes in string parameters should continue to throw
90+
``ValueError``, consistent with current locale input handling.
91+
* Invalid locale strings should continue to follow existing ICU-backed
92+
``ext/intl`` behavior.
93+
94+
==== Motivation ====
95+
96+
This proposal brings practical value because it completes an already existing
97+
workflow in ``ext/intl``:
98+
99+
* Parse or receive a locale identifier.
100+
* Extract keyword/value pairs via ``Locale::getKeywords()``.
101+
* Render those keywords and values for humans in a chosen display locale.
102+
103+
Without these APIs, userland code must maintain its own mapping layer for
104+
keyword labels and keyword values, even though ICU already contains the data and
105+
PHP already exposes adjacent display APIs.
106+
107+
This is a pragmatic addition for applications that render locale settings in:
108+
109+
* admin interfaces
110+
* user profile settings
111+
* CMS configuration screens
112+
* diagnostics and developer tooling
113+
* internationalization dashboards
114+
115+
==== API Details ====
116+
117+
=== locale_get_display_keyword() / Locale::getDisplayKeyword() ===
118+
119+
Returns a localized display label for a locale keyword.
120+
121+
Example intent:
122+
123+
* ``Locale::getDisplayKeyword('collation', 'en')`` should return the English
124+
display label for the ``collation`` keyword.
125+
* ``Locale::getDisplayKeyword('calendar', 'fr')`` should return the French
126+
display label for the ``calendar`` keyword.
127+
128+
=== locale_get_display_keyword_value() / Locale::getDisplayKeywordValue() ===
129+
130+
Returns a localized display label for the value of a given locale keyword.
131+
132+
The first parameter is the locale string that carries the keyword value. The
133+
second parameter identifies which keyword should be resolved from that locale.
134+
135+
Example intent:
136+
137+
* ``Locale::getDisplayKeywordValue('de_DE@collation=phonebook', 'collation', 'en')``
138+
should return the English display label for the ``phonebook`` collation
139+
value.
140+
* ``Locale::getDisplayKeywordValue('en_US@calendar=gregorian', 'calendar', 'en')``
141+
should return the English display label for the ``gregorian`` calendar
142+
value.
143+
144+
==== Interaction with Existing Functionality ====
145+
146+
This RFC complements, rather than replaces, the following existing APIs:
147+
148+
* ``Locale::getKeywords()``
149+
* ``Locale::getDisplayLanguage()``
150+
* ``Locale::getDisplayScript()``
151+
* ``Locale::getDisplayRegion()``
152+
* ``Locale::getDisplayVariant()``
153+
* ``Locale::getDisplayName()``
154+
155+
The new methods are specifically intended to cover the missing "display the
156+
keyword and its value" step.
157+
158+
==== Edge Cases ====
159+
160+
The following edge cases should be covered by tests and documented:
161+
162+
* ``$displayLocale === null`` uses the default locale.
163+
* Locale identifiers with multiple keyword/value pairs.
164+
* A requested keyword not present in the locale identifier.
165+
* Invalid locale strings.
166+
* Invalid or unsupported keywords.
167+
* Embedded NUL bytes in any string argument.
168+
169+
If a keyword is not present in the locale identifier, the implementation should
170+
follow ICU behavior and existing ``ext/intl`` failure conventions rather than
171+
inventing PHP-specific fallback semantics.
172+
173+
==== Examples ====
174+
175+
Simple example:
176+
177+
<PHP>
178+
<?php
179+
180+
$locale = 'de_DE@collation=phonebook';
181+
182+
echo Locale::getDisplayKeyword('collation', 'en'), PHP_EOL;
183+
echo Locale::getDisplayKeywordValue($locale, 'collation', 'en'), PHP_EOL;
184+
185+
?>
186+
</PHP>
187+
188+
Example showing composition with ``Locale::getKeywords()``:
189+
190+
<PHP>
191+
<?php
192+
193+
$locale = 'en_US@calendar=gregorian;collation=phonebook';
194+
$displayLocale = 'en';
195+
196+
foreach (Locale::getKeywords($locale) as $keyword => $value) {
197+
$label = Locale::getDisplayKeyword($keyword, $displayLocale);
198+
$displayValue = Locale::getDisplayKeywordValue($locale, $keyword, $displayLocale);
199+
200+
printf("%s: %s\n", $label, $displayValue);
201+
}
202+
203+
?>
204+
</PHP>
205+
206+
Example showing an edge case:
207+
208+
<PHP>
209+
<?php
210+
211+
var_dump(Locale::getDisplayKeywordValue('en_US@calendar=gregorian', 'currency', 'en'));
212+
213+
?>
214+
</PHP>
215+
216+
The exact return value in the edge case above should match ICU-backed failure
217+
behavior as implemented in the patch and documented in the manual.
218+
219+
===== Backward Incompatible Changes =====
220+
221+
There are no intentional backward incompatible changes to existing behavior.
222+
223+
However, the following low-risk compatibility concerns exist and should be noted:
224+
225+
* New global functions ``locale_get_display_keyword()`` and
226+
``locale_get_display_keyword_value()`` may conflict with userland polyfills
227+
in codebases that defined those names conditionally.
228+
* New ``Locale`` methods may conflict with userland subclasses of ``Locale``
229+
that already define methods with the same names but incompatible signatures.
230+
231+
These risks are typical for additions of new internal functions and methods.
232+
233+
Before voting, it would be reasonable to do a lightweight ecosystem scan using:
234+
235+
* GitHub code search
236+
* grep.app
237+
* Sourcegraph
238+
239+
to estimate whether these exact names are already used in polyfills or
240+
``Locale`` subclasses.
241+
242+
===== Proposed PHP Version(s) =====
243+
244+
Next PHP 8.x.
245+
246+
===== RFC Impact =====
247+
248+
==== To the Ecosystem ====
249+
250+
This is a straightforward API addition. IDEs, LSPs, static analyzers, and
251+
documentation generators would need updated stubs so the new functions and
252+
methods are recognized.
253+
254+
Userland internationalization libraries and admin UIs may simplify their own
255+
locale metadata mapping code if they choose to adopt these APIs.
256+
257+
==== To Existing Extensions ====
258+
259+
No existing extension behavior should change.
260+
261+
The implementation is limited to ``ext/intl`` and its stubs, arginfo, tests,
262+
and manual documentation.
263+
264+
==== To SAPIs ====
265+
266+
No SAPI-specific impact is expected.
267+
268+
Behavior should be identical across CLI, FPM, Apache module, the development
269+
server, and embedded use, subject only to the availability and behavior of the
270+
linked ICU version as already applies to ``ext/intl``.
271+
272+
===== Open Issues =====
273+
274+
The following details should be confirmed during discussion and resolved before
275+
the RFC enters voting:
276+
277+
* Exact failure behavior when the requested keyword is absent from the locale.
278+
* Exact failure behavior for invalid or unsupported keyword names.
279+
* Whether the implementation should share an internal helper with the existing
280+
``Locale::getDisplay*()`` functions for consistency.
281+
* Whether an implementation PR will be prepared before the RFC enters voting.
282+
283+
===== Future Scope =====
284+
285+
This RFC does not propose a general policy that all ICU locale helper functions
286+
must be exposed automatically.
287+
288+
It is intentionally limited to two methods that fit naturally into the existing
289+
``Locale::getDisplay*()`` family and directly complement
290+
``Locale::getKeywords()``.
291+
292+
Future RFCs may evaluate other ICU-backed locale helpers independently on their
293+
own merits.
294+
295+
===== Voting Choices =====
296+
297+
Primary Vote requiring a 2/3 majority to accept the RFC:
298+
299+
<doodle title="Add Locale::getDisplayKeyword() and Locale::getDisplayKeywordValue() as outlined in the RFC?" voteType="single" closed="true" closeon="2026-05-29T15:30:00Z">
300+
* Yes
301+
* No
302+
* Abstain
303+
</doodle>
304+
305+
===== Patches and Tests =====
306+
307+
No implementation PR exists yet.
308+
309+
The expected implementation work is:
310+
311+
* wrappers around ICU's ``uloc_getDisplayKeyword()`` and
312+
``uloc_getDisplayKeywordValue()``
313+
* ``ext/intl/php_intl.stub.php`` updates
314+
* ``ext/intl/locale/locale.stub.php`` updates
315+
* arginfo regeneration
316+
* phpt coverage for success and failure cases
317+
318+
If there is no patch by the time discussion begins, the RFC should clearly state
319+
who plans to implement it.
320+
321+
===== Implementation =====
322+
323+
After the RFC is implemented, this section should contain:
324+
325+
* the version(s) it was merged into
326+
* a link to the git commit(s)
327+
* a link to the PHP manual entry for the feature
328+
329+
===== References =====
330+
331+
* GH-22097: https://github.com/php/php-src/issues/22097
332+
* ICU ``uloc_getDisplayKeyword()`` and ``uloc_getDisplayKeywordValue()``:
333+
https://unicode-org.github.io/icu-docs/apidoc/released/icu4c/uloc_8h.html
334+
* PHP RFC howto: https://wiki.php.net/rfc/howto
335+
336+
===== Rejected Features =====
337+
338+
The earlier idea of exposing locale orientation APIs
339+
(``Locale::getCharacterOrientation()`` and ``Locale::getLineOrientation()``)
340+
was discussed first, but this RFC intentionally does not pursue that direction.
341+
342+
The reason is that ``Locale::getDisplayKeyword()`` and
343+
``Locale::getDisplayKeywordValue()`` fill a clearer gap in the existing
344+
``Locale`` API and are more naturally aligned with common PHP application needs.
345+
346+
===== Changelog =====
347+
348+
* 2026-05-22: Initial wiki-format draft created. Scope focused on
349+
``Locale::getDisplayKeyword()`` and
350+
``Locale::getDisplayKeywordValue()`` instead of locale orientation APIs.

0 commit comments

Comments
 (0)