How to clear php's gettext cache without restart Apache nor change domain?
Asked Answered
I

6

24

This is a little code snippet from php manual:

putenv('LC_ALL=zh_CN');
setlocale(LC_ALL, 'zh_CN');

bindtextdomain('domain', './locale');
textdomain('domain');

echo gettext('Hello');

Which will output 你好 as defined in domain.mo file, but the problem is as long as the Apache is running, gettext() always return the cached result.

If I change the translation of Hello to 您好 in domain.mo, it will still output 你好.

However there is a fix for this by changing the domain argument of bindtextdomain() and textdomain() to a new name. Like from "domain" to "domain2". But this is really painful to edit the php file every time I updated the .mo file.

Is there a better way for doing this, like remove some folders or calling some php functions to do the job? So that I can write a little script for this purpose.

Insignificance answered 29/11, 2012 at 12:17 Comment(0)
I
17

Every solution (1, 2, 3) suggests changing the domain to get rid of the cache problem, but this will create lots of out-of-date cache in memory.

So I dug into the gnu-gettext source for details on the cache strategy (bindtextdom.c:78.)

When bindtextdomain(domain, dirname) is called, it will check whether domain exists in the cache; if so, it will then check if dirname is the same with the one in the cache. If this fails, it will force a cache flush for the same domain, instead of creating a new one in memory.

The fix is incredibly simple, first create a dummy link to the locale folder where your .mo file is stored:

cd locale
ln -s . nocache

Then add one single line before bindtextdomain()

bindtextdomain('domain', './locale/nocache');
bindtextdomain('domain', './locale');

Now the cache is forced to flush every time.


Updates:

This hack may not works in some cases (Can't figure out the exact conditions.) This solution is NOT something you should use in production environment, but only for those who need to fix something while keeping httpd running!

Whenever you can, please avoid using gettext from very beginning, this is really something ancient and should be deprecated for good.

Insignificance answered 29/11, 2012 at 15:25 Comment(6)
And dont' forget to add some if (debug) { ... nocache} to minimize stats load on disk.Refluent
"Whenever you can, please avoid using gettext from very beginning, this is really something ancient and should be deprecated for good." Why should I avoid it? And could you name some alternatives?Salt
@Salt check out the answer belowInsignificance
@Insignificance what do you recommend to using besides gettext?Zig
The gettext libs are used by Wordpress for its native i18n... I think it's going to be in use for a very long time.Hynes
Ran in to some segfaults using this :DPsychomotor
D
14

I called clearstatcache(); function after translating from messages.po to messages.mo and its working fine without restarting apache. Loading each change what I am making in any language file.

Dixson answered 23/9, 2013 at 6:46 Comment(1)
doesn't work here on docker + php:apache + PHP 7 :(Luteal
D
8

ok, in my case I needed to restart phpfpm by doing service php5.6-fpm-sp restart.

If you are using php-fpm you MUST restart phpfpm in order to clear gettext's cache, restarting apache2 doesn't work.

Hope is useful to someone else.

Doggone answered 7/2, 2015 at 13:36 Comment(0)
I
1

There is IMHO no direct way to do that (besides domain workaround you've mentioned), that's reason why we're using php-gettext.

Update: Which we've started to maintain as motranslator, installable by Composer and compatible with all PHP versions.

Inspire answered 29/11, 2012 at 14:57 Comment(2)
Thanks. The code I have is hard coded gettext() everywhere, really can't make this switch.Insignificance
Well the switch is simple replacing gettext by _gettext, what can be done by simple text replacing.Uyekawa
P
1

The solution for me was to save the files with a different name, using the date for example, and then changing the domain:

#the path for a domain, the .mo files must match the domain
#the trick to avoid permanent caching, is to use different names for the domain,             like the date messages_180320151250
$domain = 'messages_180320151300';

#sets the path for a domain, the .mo files must match the domain
bindtextdomain($domain, $_SERVER['DOCUMENT_ROOT']."/apps/cp/locale");

textdomain($domain);
Postal answered 18/3, 2015 at 14:16 Comment(0)
K
0

Use apachectl graceful command to ask the process to re-read the config. It will end the request AFTER the request finished serving. So it looks safe.

According to Apache HTTP Server 2.2 Documentation

The USR1 or graceful signal causes the parent process to advise the children to exit after their current request (or to exit immediately if they're not serving anything). The parent re-reads its configuration files and re-opens its log files. As each child dies off the parent replaces it with a child from the new generation of the configuration, which begins serving new requests immediately.

It worked for me.

Kynthia answered 3/4, 2018 at 2:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.