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

问题描述 投票:0回答:2

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

我正在尝试构建一个非常常见的简单多语言应用程序,我已经google了很多包括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_GBen_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文件

Q.1)有什么我错过了最佳实践吗?

更新:我修复了gettext不工作问题,将.utf8放在locale字符串后重新启动服务器并删除我的头痛;)

在这里我的phpinfo(INFO_ENVIRONMENT)结果enter image description here

php internationalization gettext multilingual poedit
2个回答
1
投票

难道你没有忘记指定你将使用哪个域作为默认域名?

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

textdomain($domain);

?>

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' );?>

我希望这个对你有用!

© www.soinside.com 2019 - 2024. All rights reserved.