PHP - 如何使用带有.po文件的gettext()创建一个简单的多语言应用程序

时间:2018-02-19 08:10:48

标签: php internationalization gettext multilingual poedit

我的服务器已安装:PHP版本5.6.33-3+ubuntu16.04.1+deb.sury.org+1 启用gettext扩展名。

我正在尝试构建一个非常常见的简单多语言应用程序,我搜索了很多,包括SO,但没有找到任何可行的解决方案。

这是我的步骤:

1.)检查安装的gettext扩展程序。

2.)设置演示项目

目录结构:

/demo
-- test.php 
-- /locale/
----/en_GB/
------/LC_MESSAGES/
-------- test.po
-------- test.mo
----/en_IN/
------/LC_MESSAGES/
-------- test.po
-------- test.mo

3.。检查我的系统中的本地可用

C
C.UTF-8
en_AG
en_AG.utf8
en_AU.utf8
en_BW.utf8
en_CA.utf8
en_DK.utf8
en_GB.utf8
en_HK.utf8
en_IE.utf8
en_IN
en_IN.utf8
en_NG
en_NG.utf8
en_NZ.utf8
en_PH.utf8
en_SG.utf8
en_US.utf8
en_ZA.utf8
en_ZM
en_ZM.utf8
en_ZW.utf8
POSIX

4。)使用两种不同的语言en_GB& en_IN

5.。)创建应用程序文件test.php

<?php

// select default locale
$locale = 'en_GB.utf8';   // or 'en_GB'

// set locale from url string
$locale = (isset($_GET['locale'])) ? $_GET['locale'] : $locale; 

// set lang env
putenv("LANGUAGE=$locale");

//set locale:
setlocale( LC_MESSAGES, $locale);

// my understanding for this, is name of my translation files for application ?
$domain = 'test';

// Sets the path for a domain
bindtextdomain($domain, dirname(__FILE__).'/locale'); // where translation files are

//or this:
//bindtextdomain("*", dirname(__FILE__).'/locale');

// Not sure i need to set codeset or not ?
bind_textdomain_codeset($domain, 'UTF-8');

textdomain($domain);
?>

<html>
<head>
  <meta http-equiv="content-type" content="text/html; charset=utf-8">
</head>

<body>

<?php

echo _("hello");

?>

</body>
</html>

6。)为locale/en_GB/LC_MESSAGES/test.po

创建翻译文件
msgid ""
msgstr ""
"Project-Id-Version: \n"
"POT-Creation-Date: 2018-02-19 12:16+0530\n"
"PO-Revision-Date: 2018-02-19 12:16+0530\n"
"Last-Translator: \n"
"Language-Team: \n"
"Language: en_GB\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Poedit 1.8.7.1\n"
"X-Poedit-Basepath: ..\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Poedit-SearchPath-0: test.php\n"

#: test.php:38
msgid "hello"
msgstr "Hello"

7.。)为locale/en_IN/LC_MESSAGES/test.po

创建翻译文件
msgid ""
msgstr ""
"Project-Id-Version: \n"
"POT-Creation-Date: 2018-02-19 12:16+0530\n"
"PO-Revision-Date: 2018-02-19 13:01+0530\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Poedit 1.8.7.1\n"
"X-Poedit-Basepath: ..\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"Last-Translator: \n"
"Language: en_IN\n"
"X-Poedit-SearchPath-0: test.php\n"

#: test.php:38
msgid "hello"
msgstr "Namaste"

我使用poedit编译.mo文件

问题1)我有什么想念的最佳做法吗?

更新:通过将.utf8置于语言环境字符串之后并重新启动服务器和放大器,我修复了gettext无法解决问题的问题。它消除了我的头痛;)

此处我的phpinfo(INFO_ENVIRONMENT)结果 enter image description here

2 个答案:

答案 0 :(得分:1)

您是否忘记了将要使用哪个域作为默认域名?

// Not sure i need to set codeset or not ?
bind_textdomain_codeset($domain, 'UTF-8');

textdomain($domain);

?>

答案 1 :(得分:0)

我的问题是服务器缓存了.mo文件,因此在首次处理时它可以正常工作,但是当mo文件将被更改时,这些更改在应用程序上不可见。 您可以尝试一下

<?php
namespace utils;
class simple_i18n
{
  const DIR_LANG   =  '/LC_MESSAGES/';
  const CODESET    =  'UTF-8';
  private static $domain     =   null;
  private static $locale     =   'en_US';

  public static function init( $locale, $domain )
  {
    self::$locale  =  $locale;
    self::$domain  =  $domain;
    self::preparePOMO( self::$domain, self::$locale, self::CODESET, I18N_DIR );
    self::activateLocaleSettings();
    self::generateNewTextdomain();
  }
  private static function activateLocaleSettings()
  {
    putenv( 'LC_ALL=' . self::$locale );
    setlocale( LC_ALL, self::$locale );
  }
  private static function generateNewTextdomain()
  {
    $textDomain  =  sprintf( '%s_%s', self::$domain, self::$locale );
    // Set base directory for all locales
    bindtextdomain( $textDomain, I18N_DIR );
    // Set domain codeset (optional)
    bind_textdomain_codeset( $textDomain, self::CODESET );
    // File: ./locale/de_DE/LC_MESSAGES/domain_de_DE.mo
    textdomain( $textDomain );
  }
  private static function preparePOMO( &$domain, $locale, $codeset, $directory )
  {
    if ( !is_dir( $directory . '/' . $locale . self::DIR_LANG ) ){
      self::$locale  =  'en_EN';
      return;
    }
    if ( !( $gestor  =  opendir( $directory . '/' . $locale . self::DIR_LANG  ) ) ) return;
    while( false !== ( $entrada = readdir( $gestor ) ) ) :
      preg_match( '/\d{14,25}/',$entrada, $matches );
      if ( $matches ) :
        unlink( $directory . '/' . $locale . self::DIR_LANG . $entrada );          
      endif;
    endwhile;    
    $auxDom  =  $domain;
    $domain  =  $domain . date( 'Ymdhisu' );
    copy( $directory . '/' . $locale . self::DIR_LANG . $auxDom . '_' . $locale . '.mo', $directory . '/' . $locale . self::DIR_LANG . $domain . '_' . $locale . '.mo'  );     
  }
}

此代码为.mo文件创建一个副本,并防止从服务器缓存(否则必须重新启动服务器)。 使用方法:

include_once '[PATH TO simple_i18n.php file]/simple_i18n.php';

现在,您必须为.po和.mo文件定义目录:

defined( 'I18N_DIR' ) || define( 'I18N_DIR', '[PATH TO LOCALE]/locale' );
$locale     =  'en_GB'; //or 'en_IN'
$domain     =  'your_domain_name'; //in your case test but you must add 'en_GB' and 'en_IN' as sufix in every directory
\utils\simple_i18n::init( $locale, $domain );

现在您可以使用它了!

<?php echo _( 'hello' );?>

我希望它对您有用!