Skip to content

Conversation

@Starfox64
Copy link

@Starfox64 Starfox64 commented Oct 24, 2025

gettext is not thread safe and can only load a single locale per process, this causes a mix and match of languages to be returned from translations.

https://stackoverflow.com/a/1646343

@henderkes
Copy link
Contributor

henderkes commented Oct 24, 2025

This should be added to the php documentation as well. And maybe php should even fail to compile gettext extension in a ZTS build?
Does it also affect the intl extension, considering that libintl is part of the gettext package?

@Starfox64
Copy link
Author

After further research, it seems this isn't strictly gettext specific but in fact related to setlocale having a process-wide effect on Linux.
I should probably change the reason then.

This probably also affects libintl in general whenever changes to the locale occur but I'm not 100% sure either. How should we go about documenting it ?

@henderkes
Copy link
Contributor

I wonder if this couldn't be changed in php-src. uselocale() does the same as setlocale(), but it's mt-safe and only affects the current thread.

Copy link
Contributor

@henderkes henderkes left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Placeholder so we don't accidentally merge. Asking php maintainers first.

@henderkes
Copy link
Contributor

I will create a php RFC to rework setlocale() to use uselocale() on Posix too.

@henderkes
Copy link
Contributor

I have a POC working, but it's more complicated than I'd hoped, because uselocale doesn't support setting individual locales. I need to createlocale with the intended masks and free old locales, if no longer required. To convert them to locale strings individually, we need to track one per available LC_ constant,, which is 5 in general and then another 5 gnu extensions.

Tl;dr: working, but messy.

@henderkes
Copy link
Contributor

henderkes commented Oct 28, 2025

Given the following PHP code to simulate different FrankenPHP requests:

<?php
use parallel\Runtime;

setlocale(LC_ALL,'C');
echo "main@start   : ".setlocale(LC_ALL,0)." | dp=".localeconv()['decimal_point']."\n";

$f = (new Runtime())->run(function () {
    setlocale(LC_ALL,'de_DE.UTF-8');
    echo "worker@set   : ".setlocale(LC_ALL,0)." | dp=".localeconv()['decimal_point']."\n";
});

echo "main@after   : ".setlocale(LC_ALL,0)." | dp=".localeconv()['decimal_point']."\n";

$f->value();

Currently:

[m@M bin]$ php -d "extension=/home/m/static-php-cli/buildroot/modules/parallel.so" localetest.php 
main@start   : C.UTF-8 | dp=.
worker@set   : de_DE.UTF-8 | dp=,
main@after   : de_DE.UTF-8 | dp=,

Expected, after proposed implementation:

[m@M bin]$ ./php -d "extension=/home/m/static-php-cli/buildroot/modules/parallel.so" localetest.php 
main@start   : C.UTF-8 | dp=.
worker@set   : de_DE.UTF-8 | dp=,
main@after   : C.UTF-8 | dp=.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants