Source for file Ethna_Plugin_Generator_I18n.php
Documentation is available at Ethna_Plugin_Generator_I18n.php
// vim: foldmethod=marker
* Ethna_Plugin_Generator_I18n.php
* @author Yoshinari Takaoka <takaoka@beatcraft.com>
* @license http://www.opensource.org/licenses/bsd-license.php The BSD License
// {{{ Ethna_Plugin_Generator_I18n
* i18n 向け、メッセージカタログ生成クラスのスーパークラス
* @author Yoshinari Takaoka <takaoka@beatcraft.com>
/** @var array 解析済みトークン */
/** @var boolean gettext利用フラグ */
/** @var boolean 既存ファイルが存在した場合にtrue */
/** @var string 実行時のUnix Time(ファイル名生成用) */
* @param string $locale 生成するカタログのロケール
* @param int $use_gettext gettext 使用フラグ
* false ならEthna組み込みのカタログ生成
* @param array $ext_dirs 走査する追加のディレクトリの配列
* @return true|Ethna_Error true:成功 Ethna_Error:失敗
function &generate($locale, $use_gettext, $ext_dirs =
array())
// 既存ファイルが存在した場合は、以下の動きをする
// 1. Ethna 組み込みのカタログの場合、既存のiniファイル
// の中身を抽出し、既存の翻訳を可能な限りマージする
// 2. gettext 利用の場合は、新たにファイルを作らせ、
// 既存翻訳とのマージは msgmergeプログラムを使わせる
?
("[NOTICE]: Message catalog file already exists! "
.
"CREATING NEW FILE ...\n"
.
"You can run msgmerge program to merge translation.\n"
:
("[NOTICE]: Message catalog file already exists!\n"
.
"This is overwritten and existing translation is merged automatically.\n");
print
"\n-------------------------------\n"
.
"-------------------------------\n\n";
// app ディレクトリとテンプレートディレクトリを
// 再帰的に走査する。ユーザから指定があればそれも走査
$app_dir =
$this->ctl->getDirectory('app');
$template_dir =
$this->ctl->getDirectory('template');
$app_dir, "${template_dir}/${locale}",
foreach ($scan_dir as $dir) {
// 解析済みトークンを元に、カタログファイルを生成
$locale_dir =
$this->ctl->getDirectory('locale');
$filename =
$this->locale .
".${ext}";
$outfile_path =
"${locale_dir}/"
.
"/LC_MESSAGES/$filename";
$new_filename =
$this->locale .
'_' .
$this->time .
".${ext}";
$outfile_path =
"${locale_dir}/"
.
"/LC_MESSAGES/$new_filename";
* @param string $dir 走査対象ディレクトリ
* @return true|Ethna_Errortrue:成功 Ethna_Error:失敗
$php_ext =
$this->ctl->getExt('php');
$tpl_ext =
$this->ctl->getExt('tpl');
while(($file =
readdir($dh)) !==
false) {
if (strpos($file, '.') !==
0) { // 隠しファイルは対象外
* 指定されたPHPスクリプトを調べ、メッセージ処理関数の呼び出し
* NOTICE: このメソッドは、指定ファイルがPHPスクリプト
* (テンプレートファイル)として正しいものかどう
* @param string $file 走査対象ファイル
* @return true|Ethna_Errortrue:成功 Ethna_Error:失敗
printf("Analyzing file ... %s\n", $file);
$fp =
@fopen($file_path, 'r');
$token_num =
count($file_tokens);
// アクションディレクトリは特別扱いするため、それ
for ($i =
0; $i <
$token_num; $i++
) {
$token =
$file_tokens[$i];
// PHP 5.2.2 以降のみ行番号を取得可能
// @see http://www.php.net/token_get_all
// i18n 呼び出し関数の場合、フラグを立てる
if ($token_idx ==
T_STRING &&
$token_str ==
'_et') {
// i18n 呼び出しの後、定数文字列が来たら、
// それを引数と看做す。PHPの文法的にvalid
if ($in_et_function ==
true
&&
$token_idx ==
T_CONSTANT_ENCAPSED_STRING) {
$token_str =
substr($token_str, 1); // 最初のクォートを除く
$token_str =
substr($token_str, 0, -
1); // 最後のクォートを除く
$this->tokens[$file_path][] =
array(
'token_str' =>
$token_str,
'linenum' =>
$token_linenum,
// ActionForm の $form メンバ解析
$php_ext =
$this->ctl->getExt('php');
$action_dir_regex =
$action_dir;
$action_dir_regex =
str_replace('\\', '\\\\', $action_dir);
$action_dir_regex =
str_replace('/', '\\\\', $action_dir_regex);
&&
!preg_match("#.*Test\.${php_ext}$#", $file_path)) {
// Ethna組み込みのメッセージカタログであれば翻訳をマージする
* 指定されたPHPスクリプトを調べ、メッセージ処理関数の呼び出し
* NOTICE: このメソッドは、指定ファイルがPHPスクリプトとして
* @param string $file_path 走査対象ファイル
* @return true|Ethna_Errortrue:成功 Ethna_Error:失敗
for ($i =
0; $i <
count($tokens); $i++
) {
if ($token_name ==
T_CLASS) { // クラス定義開始
// T_CLASS の直後に来た T_STRING をクラス名と見做す
if ($class_started ===
true &&
$token_name ==
T_STRING) {
$class_names[] =
$token_str;
foreach ($class_names as $name) {
$action_name =
$this->ctl->actionFormToName($name);
if (!empty($action_name)) {
// 特定したクラスをインスタンス化し、フォーム定義を解析する
printf(" Analyzing ActionForm class ... %s\n", $af_classname);
$af =
new $af_classname($this->ctl);
$form_def =
$af->getDef();
$translatable_code =
array('name', 'required_error', 'type_error', 'min_error',
'max_error', 'regexp_error'
foreach ($form_def as $key =>
$def) {
// @see http://ethna.jp/ethna-document-dev_guide-form-message.html
foreach ($translatable_code as $code) {
$token_str =
$def[$code];
$this->tokens[$file_path][] =
array(
'token_str' =>
$token_str,
'linenum' =>
false, // 行番号は取得しない
* 指定されたテンプレートファイルを調べ、メッセージ処理関数
* @param string $file 走査対象ファイル
* @return true|Ethna_Errortrue:成功 Ethna_Error:失敗
// デフォルトはSmartyのテンプレートと看做す
$renderer =
& $this->ctl->getRenderer();
$engine =
& $renderer->getEngine();
"You seems to use template engine other than Smarty ... : $engine_name"
printf("Analyzing Template file ... %s\n", $file);
// use smarty internal function :)
$compile_path =
$engine->_get_compile_path($file);
if ($engine->_is_compiled($file, $compile_path)
||
$engine->_compile_resource($file, $compile_path)) {
if (empty($compile_result)) {
"could not compile template file : $file"
for ($i =
0; $i <
count($tokens); $i++
) {
if ($token_name ==
T_STRING
&&
strcmp($token_str, 'smarty_modifier_i18n') ===
0) {
$i18n_str =
substr($i18n_str, 1); // 最初のクォートを除く
$i18n_str =
substr($i18n_str, 0, -
1); // 最後のクォートを除く
$this->tokens[$file][] =
array(
'token_str' =>
$i18n_str,
* @param $tokens 解析対象トークン
for ($j =
$index; $j >
0; $j--
) {
$tmp_token =
$tokens[$j];
if ($tmp_token_name ==
T_CONSTANT_ENCAPSED_STRING
&&
!preg_match('#^["\']i18n["\']$#', $tmp_token_str)) {
$prev_token =
$tokens[$j -
1];
if (!is_array($prev_token) &&
$prev_token ==
'=') {
* Ethna組み込みのメッセージカタログファイルを、上書き
$i18n =
$this->ctl->getI18N();
$existing_catalog =
$i18n->parseEthnaMsgCatalog($outfile_path);
foreach ($this->tokens as $file_path =>
$tokens) {
for ($i =
0; $i <
count($tokens); $i++
) {
$token_str =
$token['token_str'];
$this->tokens[$file_path][$i]['translation'] =
$existing_catalog[$token_str];
* 解析済みのメッセージ処理関数の情報を元に、カタログファイ
* [appid]/[locale_dir]/[locale_name]/LC_MESSAGES/[locale_name].[ini|po]
* @param string $locale 生成するカタログのロケール
* @param int $use_gettext gettext 使用フラグ
* false ならEthna組み込みのカタログ生成
* @return true|Ethna_Errortrue:成功 Ethna_Error:失敗
$resolved =
$this->_resolveSkelfile($skel);
if ($resolved ===
false) {
$macro['project_id'] =
$this->ctl->getAppId();
$macro['locale_name'] =
$this->locale;
$macro['now_date'] =
strftime('%Y-%m-%d %H:%M%z');
foreach ($macro as $k =>
$v) {
// generate file contents
foreach ($this->tokens as $file_path =>
$tokens) {
foreach ($tokens as $token) {
$token_str =
$token['token_str'];
$token_line =
$token['linenum'];
$token_line =
($token_line !==
false) ?
":${token_line}" :
'';
$translation =
$token['translation'];
"#: ${file_path}${token_line}\n"
.
"msgid \"${token_str}\"\n"
.
"msgstr \"${translation}\"\n\n"
if ($is_first_loop ===
false) {
$contents .=
"\n; ${file_path}\n";
$contents .=
"\"${token_str}\" = \"${translation}\"\n";
$outfile_dir =
dirname($outfile_path);
$wfp =
@fopen($outfile_path, "w");
if (fwrite($wfp, $contents) ===
false) {
printf("Message catalog template successfully created [%s]\n", $outfile_path);
Documentation generated on Fri, 11 Nov 2011 04:00:16 +0900 by phpDocumentor 1.4.3