Skip to content

Commit cb244e3

Browse files
committed
Add Locale::getDisplayKeyword() and Locale::getDisplayKeywordValue()
1 parent 78d394e commit cb244e3

9 files changed

Lines changed: 260 additions & 0 deletions

ext/intl/locale/locale.stub.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,18 @@ public static function getDisplayLanguage(string $locale, ?string $displayLocale
9292
*/
9393
public static function getDisplayVariant(string $locale, ?string $displayLocale = null): string|false {}
9494

95+
/**
96+
* @tentative-return-type
97+
* @alias locale_get_display_keyword
98+
*/
99+
public static function getDisplayKeyword(string $keyword, ?string $displayLocale = null): string|false {}
100+
101+
/**
102+
* @tentative-return-type
103+
* @alias locale_get_display_keyword_value
104+
*/
105+
public static function getDisplayKeywordValue(string $locale, string $keyword, ?string $displayLocale = null): string|false {}
106+
95107
/**
96108
* @tentative-return-type
97109
* @alias locale_compose

ext/intl/locale/locale_arginfo.h

Lines changed: 15 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ext/intl/locale/locale_methods.cpp

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ ZEND_EXTERN_MODULE_GLOBALS( intl )
4444
#define EXTLANG_PREFIX "a"
4545
#define PRIVATE_PREFIX "x"
4646
#define DISP_NAME "name"
47+
#define DISP_KEYWORD "keyword"
48+
#define DISP_KEYWORD_VALUE "keyword_value"
4749

4850
#define MAX_NO_VARIANT 15
4951
#define MAX_NO_EXTLANG 3
@@ -671,6 +673,107 @@ static void get_icu_disp_value_src_php( const char* tag_name, INTERNAL_FUNCTION_
671673
}
672674
/* }}} */
673675

676+
/* {{{
677+
* common code shared by display keyword functions to get the value from ICU
678+
}}} */
679+
static void get_icu_disp_keyword_value_src_php(const char* tag_name, INTERNAL_FUNCTION_PARAMETERS)
680+
{
681+
char* loc_name = NULL;
682+
size_t loc_name_len = 0;
683+
char* keyword_name = NULL;
684+
size_t keyword_name_len = 0;
685+
char* disp_loc_name = NULL;
686+
size_t disp_loc_name_len = 0;
687+
int free_loc_name = 0;
688+
689+
UChar* disp_name = NULL;
690+
int32_t disp_name_len = 0;
691+
int32_t buflen = 512;
692+
UErrorCode status = U_ZERO_ERROR;
693+
694+
zend_string* u8str;
695+
char* msg = NULL;
696+
697+
intl_error_reset( NULL );
698+
699+
if (strcmp(tag_name, DISP_KEYWORD) == 0) {
700+
ZEND_PARSE_PARAMETERS_START(1, 2)
701+
Z_PARAM_PATH(keyword_name, keyword_name_len)
702+
Z_PARAM_OPTIONAL
703+
Z_PARAM_PATH_OR_NULL(disp_loc_name, disp_loc_name_len)
704+
ZEND_PARSE_PARAMETERS_END();
705+
} else {
706+
ZEND_PARSE_PARAMETERS_START(2, 3)
707+
Z_PARAM_PATH(loc_name, loc_name_len)
708+
Z_PARAM_PATH(keyword_name, keyword_name_len)
709+
Z_PARAM_OPTIONAL
710+
Z_PARAM_PATH_OR_NULL(disp_loc_name, disp_loc_name_len)
711+
ZEND_PARSE_PARAMETERS_END();
712+
713+
if (loc_name_len > ULOC_FULLNAME_CAPACITY) {
714+
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR, "name too long");
715+
RETURN_FALSE;
716+
}
717+
718+
if (loc_name_len == 0) {
719+
loc_name = (char *)intl_locale_get_default();
720+
}
721+
}
722+
723+
if (!disp_loc_name) {
724+
disp_loc_name = estrdup(intl_locale_get_default());
725+
free_loc_name = 1;
726+
}
727+
728+
do {
729+
disp_name = reinterpret_cast<UChar *>(erealloc(disp_name, buflen * sizeof(UChar)));
730+
disp_name_len = buflen;
731+
732+
if (strcmp(tag_name, DISP_KEYWORD) == 0) {
733+
buflen = uloc_getDisplayKeyword(keyword_name, disp_loc_name, disp_name, disp_name_len, &status);
734+
} else {
735+
buflen = uloc_getDisplayKeywordValue(loc_name, keyword_name, disp_loc_name, disp_name, disp_name_len, &status);
736+
}
737+
738+
/* U_STRING_NOT_TERMINATED_WARNING is admissible here; don't look for it */
739+
if (U_FAILURE(status)) {
740+
if (status == U_BUFFER_OVERFLOW_ERROR) {
741+
status = U_ZERO_ERROR;
742+
continue;
743+
}
744+
745+
spprintf(&msg, 0, "unable to get locale %s", tag_name);
746+
intl_error_set( NULL, status, msg);
747+
efree(msg);
748+
if (disp_name) {
749+
efree(disp_name);
750+
}
751+
if (free_loc_name) {
752+
efree((void *)disp_loc_name);
753+
disp_loc_name = NULL;
754+
}
755+
RETURN_FALSE;
756+
}
757+
} while (buflen > disp_name_len);
758+
759+
if (free_loc_name) {
760+
efree((void *)disp_loc_name);
761+
disp_loc_name = NULL;
762+
}
763+
764+
u8str = intl_convert_utf16_to_utf8(disp_name, buflen, &status);
765+
efree(disp_name);
766+
if (!u8str) {
767+
spprintf(&msg, 0, "error converting display name for %s to UTF-8", tag_name);
768+
intl_error_set( NULL, status, msg);
769+
efree(msg);
770+
RETURN_FALSE;
771+
}
772+
773+
RETVAL_NEW_STR(u8str);
774+
}
775+
/* }}} */
776+
674777
/* {{{ gets the name for the $locale in $in_locale or default_locale */
675778
U_CFUNC PHP_FUNCTION(locale_get_display_name)
676779
{
@@ -711,6 +814,20 @@ U_CFUNC PHP_FUNCTION(locale_get_display_variant)
711814
{
712815
get_icu_disp_value_src_php( LOC_VARIANT_TAG , INTERNAL_FUNCTION_PARAM_PASSTHRU );
713816
}
817+
/* }}} */
818+
819+
/* {{{ gets the keyword display label in $in_locale or default_locale */
820+
U_CFUNC PHP_FUNCTION(locale_get_display_keyword)
821+
{
822+
get_icu_disp_keyword_value_src_php(DISP_KEYWORD, INTERNAL_FUNCTION_PARAM_PASSTHRU);
823+
}
824+
/* }}} */
825+
826+
/* {{{ gets the keyword value display label in $in_locale or default_locale */
827+
U_CFUNC PHP_FUNCTION(locale_get_display_keyword_value)
828+
{
829+
get_icu_disp_keyword_value_src_php(DISP_KEYWORD_VALUE, INTERNAL_FUNCTION_PARAM_PASSTHRU);
830+
}
714831
/* }}} */
715832

716833
/* {{{ return an associative array containing keyword-value

ext/intl/php_intl.stub.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -487,6 +487,10 @@ function locale_get_display_language(string $locale, ?string $displayLocale = nu
487487

488488
function locale_get_display_variant(string $locale, ?string $displayLocale = null): string|false {}
489489

490+
function locale_get_display_keyword(string $keyword, ?string $displayLocale = null): string|false {}
491+
492+
function locale_get_display_keyword_value(string $locale, string $keyword, ?string $displayLocale = null): string|false {}
493+
490494
function locale_compose(array $subtags): string|false {}
491495

492496
function locale_parse(string $locale): ?array {}

ext/intl/php_intl_arginfo.h

Lines changed: 15 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ext/intl/tests/locale/bug74993.phpt

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ intl
55
--FILE--
66
<?php
77
$funcs = [
8+
'locale_get_display_keyword',
9+
'locale_get_display_keyword_value',
810
'locale_get_display_language',
911
'locale_get_display_name',
1012
'locale_get_display_region',
@@ -19,6 +21,23 @@ foreach ($funcs as $func) {
1921
}
2022
?>
2123
--EXPECT--
24+
Function [ <internal:intl> function locale_get_display_keyword ] {
25+
26+
- Parameters [2] {
27+
Parameter #0 [ <required> string $keyword ]
28+
Parameter #1 [ <optional> ?string $displayLocale = null ]
29+
}
30+
- Return [ string|false ]
31+
}
32+
Function [ <internal:intl> function locale_get_display_keyword_value ] {
33+
34+
- Parameters [3] {
35+
Parameter #0 [ <required> string $locale ]
36+
Parameter #1 [ <required> string $keyword ]
37+
Parameter #2 [ <optional> ?string $displayLocale = null ]
38+
}
39+
- Return [ string|false ]
40+
}
2241
Function [ <internal:intl> function locale_get_display_language ] {
2342

2443
- Parameters [2] {
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
--TEST--
2+
locale_get_display_keyword() basic
3+
--EXTENSIONS--
4+
intl
5+
--FILE--
6+
<?php
7+
8+
function ut_main()
9+
{
10+
$default = ut_loc_get_default();
11+
ut_loc_set_default('en');
12+
13+
var_dump(ut_loc_get_display_keyword('calendar', 'en'));
14+
var_dump(ut_loc_get_display_keyword('calendar', null));
15+
var_dump(ut_loc_get_display_keyword_value('de_DE@calendar=gregorian', 'calendar', 'en'));
16+
var_dump(ut_loc_get_display_keyword_value('de_DE@calendar=gregorian', 'calendar', null));
17+
var_dump(ut_loc_get_display_keyword_value('de_DE@collation=phonebook', 'collation', 'en'));
18+
19+
ut_loc_set_default($default);
20+
}
21+
22+
include_once 'ut_common.inc';
23+
ut_run();
24+
?>
25+
--EXPECT--
26+
string(8) "Calendar"
27+
string(8) "Calendar"
28+
string(18) "Gregorian Calendar"
29+
string(18) "Gregorian Calendar"
30+
string(20) "Phonebook Sort Order"
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
--TEST--
2+
locale_get_display_keyword() throwing null bytes exceptions.
3+
--EXTENSIONS--
4+
intl
5+
--FILE--
6+
<?php
7+
8+
function ut_main()
9+
{
10+
$calls = [
11+
fn() => ut_loc_get_display_keyword("cur\0rency", "fr"),
12+
fn() => ut_loc_get_display_keyword("currency", "f\0r"),
13+
fn() => ut_loc_get_display_keyword_value("de_DE@calendar=gregorian\0", "calendar", "en"),
14+
fn() => ut_loc_get_display_keyword_value("de_DE@calendar=gregorian", "cal\0endar", "en"),
15+
fn() => ut_loc_get_display_keyword_value("de_DE@calendar=gregorian", "calendar", "e\0n"),
16+
];
17+
18+
foreach ($calls as $call) {
19+
try {
20+
$call();
21+
} catch (\ValueError $e) {
22+
echo $e->getMessage(), PHP_EOL;
23+
}
24+
}
25+
}
26+
27+
include_once 'ut_common.inc';
28+
ut_run();
29+
?>
30+
--EXPECT--
31+
Locale::getDisplayKeyword(): Argument #1 ($keyword) must not contain any null bytes
32+
Locale::getDisplayKeyword(): Argument #2 ($displayLocale) must not contain any null bytes
33+
Locale::getDisplayKeywordValue(): Argument #1 ($locale) must not contain any null bytes
34+
Locale::getDisplayKeywordValue(): Argument #2 ($keyword) must not contain any null bytes
35+
Locale::getDisplayKeywordValue(): Argument #3 ($displayLocale) must not contain any null bytes
36+
locale_get_display_keyword(): Argument #1 ($keyword) must not contain any null bytes
37+
locale_get_display_keyword(): Argument #2 ($displayLocale) must not contain any null bytes
38+
locale_get_display_keyword_value(): Argument #1 ($locale) must not contain any null bytes
39+
locale_get_display_keyword_value(): Argument #2 ($keyword) must not contain any null bytes
40+
locale_get_display_keyword_value(): Argument #3 ($displayLocale) must not contain any null bytes

ext/intl/tests/ut_common.inc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,14 @@ function ut_loc_get_display_variant( $locale , $dispLocale )
272272
{
273273
return $GLOBALS['oo-mode'] ? Locale::getDisplayVariant( $locale , $dispLocale ) : locale_get_display_variant( $locale, $dispLocale );
274274
}
275+
function ut_loc_get_display_keyword( $keyword , $dispLocale )
276+
{
277+
return $GLOBALS['oo-mode'] ? Locale::getDisplayKeyword( $keyword , $dispLocale ) : locale_get_display_keyword( $keyword, $dispLocale );
278+
}
279+
function ut_loc_get_display_keyword_value( $locale , $keyword , $dispLocale )
280+
{
281+
return $GLOBALS['oo-mode'] ? Locale::getDisplayKeywordValue( $locale , $keyword , $dispLocale ) : locale_get_display_keyword_value( $locale, $keyword, $dispLocale );
282+
}
275283
function ut_loc_locale_compose( $loc_parts_arr )
276284
{
277285
return $GLOBALS['oo-mode'] ? Locale::composeLocale( $loc_parts_arr ) : locale_compose( $loc_parts_arr );

0 commit comments

Comments
 (0)