Gettext utilisera toujours les parameters régionaux par défaut du système

Je dois localiser une application Web PHP sous Windows uniquement et j’évalue l’extension gettext, mais j’ai le plus de mal à le faire fonctionner dans mon environnement de développement Windows 7. J’ai utilisé des essais et des erreurs avec Process Monitor pour surmonter la documentation médiocre et inexacte et j’ai réussi à faire afficher des chaînes _() partir du catalogue * .po correspondant aux parameters régionaux par défaut de l’ordinateur (espagnol moderne dans mon cas) . Toutes mes tentatives pour définir des parameters régionaux différents sont ignorées en silence.

J’ai écrit un script de test avec beaucoup de choses redondantes:

 

Dans mon cas, toujours es_ES@modern .

J’ai PHP / 5.4.5 mais je m’attends à ce qu’il fonctionne dans n’importe quel serveur raisonnablement mis à jour que nos clients possèdent.

J’ai lu beaucoup de références vagues sur la nécessité d’installer des locales, même sous Windows, mais sans détails précis. Quel peut être le problème?

(Je sais que le conseil courant est de vider gettext et d’utiliser une autre bibliothèque.)


D’autres tests:

Mon code s’exécute parfaitement tel quel sur deux autres ordinateurs: Windows Vista 32 bits et Windows 7 32 bits. Il échoue dans mon ordinateur (Windows 7 64 bits) et un autre (Windows Server 2003 32 bits)

  • La version d’Apache ne semble pas pertinente (cela se produit également avec l’interpréteur de ligne de commande).
  • La version de PHP ne semble pas pertinente (a également essayé la dernière version de PHP / 5.5.5 32 bits sur mon PC).
  • Mon arborescence de registre [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Nls] est identique à l’autre.

Edit: Lors du test sur la ligne de commande, j’ai découvert que la définition de la variable d’environnement LANG avant l’exécution du script PHP change finalement le langage:

 C:\>set LANG=en_GB C:\>php C:\test\gettext.php 

Cela prouve définitivement que mon ordinateur possède les ressources correctes, mais je me demande aussi pourquoi PHP prétend que putenv() fonctionne et l’ignore ensuite:

 var_dump( getenv('LANG'), putenv('LANG=en_GB'), getenv('LANG') ); 
 bool(false) bool(true) ssortingng(5) "en_GB" 

Même cela n’a aucun effet:

 $_ENV['LANG'] = 'en_GB'; $_SERVER['LANG'] = 'en_GB'; 

C’est un problème qui a été reconnu et partiellement résolu par l’équipe PHP.

C’est une chose assez technique, apparemment liée à la manière dont les variables d’environnement (sur lesquelles gettext dépend fortement) sont gérées par la plate-forme sous-jacente. En outre, quelque chose a changé dans les bibliothèques Visual C Runtime de VC9 à VC11 qui affecte tout cela.

Pour résumer:

  • Les builds non thread-safe ont été corrigés dans l’arborescence source le 21 novembre 2014.
  • Les versions thread-safe (par exemple le module Apache) ne l’ont pas et il n’y a pas de solution claire en vue.

La clé est d’ utiliser une version PHP non-thread-safe (= NTS) .

Malheureusement, Windows et PHP ne gèrent pas bien les environnements pour les processus threadés, donc le putenv (‘LC_ALL =’. $ Locale); commande ne fonctionne pas.

Enfin, je me retrouve avec Apache 2.4 + FCGID + PHP 7.1 NTS, qui fonctionne bien maintenant sous Windows 7, et il s’agit d’une installation sans fil.

Une instruction étape par étape sur la façon d’installer un tel système est ici: https://www.youtube.com/watch?v=UXrJPrGaPB0

J’ai utilisé la version VC14 et x64 pour tous les composants (VC est l’abréviation de “Microsoft Visual C ++ Redissortingbutable”). Pour cela, j’ai d’abord installé VC14, téléchargé ici: https://www.microsoft.com/en-us/download/details.aspx?id=48145

J’ai eu le même problème avec PHP 5.6.30 VC11 Theard Safe sur Windows 10. Contournement trouvé et résoudre ce problème ici par sirio3mil.

Apparemment, PHP avec TS peut accéder uniquement au dossier de langue Locale. Donc, lorsque la fonction setlocale et putenv est un appel avec une autre langue que celle du système, le dossier avec .mo et .po ne peut pas être lu.

La solution consiste à avoir un seul dossier de langue avec la langue du système et plusieurs paires de fichiers .mo / .po pour chaque langue traduite. Le domaine sera défini avec la langue souhaitée.

Exemple avec le français suisse, l’allemand et l’italien:

Structure de dossier

\ Locale \ fr_CH \ LC_MESSAGES

  • fr_CH.mo + fr_CH.po // langue du système
  • de_CH.mo + de_CH.po
  • it_CH.mo + it_CH.po

Code

 $lang = 'fr_CH' or 'de_CH' or 'it_CH' bindtextdomain($lang, '.\Locale'); textdomain($lang); bind_textdomain_codeset($lang, 'UTF-8'); setlocale (LC_ALL, $lang); putenv('LC_ALL=' . $lang); 

Premier problème: setlocale ()

Pour que cela fonctionne, vous devez définir un paramètre régional valide. Sur Windows, setlocale () ne fonctionnera pas comme prévu. Vous devez définir une variable d’environnement, comme ceci:

 // putenv("LANG=$lang"); <- WRONG! putenv('LC_ALL='.$locale); 

Deuxième problème: noms de parameters régionaux.

Les noms de parameters régionaux Windows sont différents de Linux. Essayez avec 'ita', 'eng', 'deu', 'ger', 'esp'. Vous pouvez obtenir une liste complète ici: http://www.microsoft.com/resources/msdn/goglobal/default.mspx

Exemple:

 //putenv("LANG=esp"); <- WRONG! putenv('LC_ALL=esp'); 

Troisième problème, le plus gros: l'extension gettext sur Windows n'est pas thread-safe. Chaque fois que vous changez de langue, le changement est vaste. Si vous lancez PHP comme fast-cgi vous êtes ok. Si vous exécutez php en tant que module apache (par exemple), c'est un désordre total car la langue change pour chaque instance de php. Le problème est que gettext () repose sur les parameters régionaux. Ce paramètre est étendu à Windows PHP. Vous ne pouvez pas changer les parameters régionaux pour un thread PHP, mais uniquement pour le processus PHP.

Dit ceci, voici un code de travail:

 // $MAINPATH is your document root $locales=array( 'it'=>'ita', 'en'=>'eng', 'de'=>'deu', 'fr'=>'fra', 'es'=>'esp', 'ru'=>'rus' ); $locale = $locales[$lang]; $res=putenv('LC_ALL='.$locale); $rres=bindtextdomain('default', $MAINPATH.'locale'); $dres=textdomain('default'); 

La structure du répertoire local doit être la suivante:

 deu LC_MESSAGES default.mo esp LC_MESSAGES default.mo fra LC_MESSAGES default.mo ita LC_MESSAGES default.mo rus LC_MESSAGES default.mo 

Sur Ubuntu, cela fonctionne si vous définissez votre LC_ALL par défaut et laissez les langues et langues vides, comme ceci:

 LANG= LANGUAGE= LC_ALL= "en_US.utf8" 

Vous devez passer à PHP 5.6.6 pour Windows, ça marche!