sebacruz
2/8/2012 - 10:02 PM

Kohana: i18n strings generator

Kohana: i18n strings generator

<?php
print(Kohana::FILE_SECURITY."\n\n");
print("return array(\n");

foreach ($data as $file)
{
	print("\t// ".$file['filepath_human']."\n");

	foreach ($file['lines'] as $line)
	{
		$line['line_string'] = str_replace('<?php', '', $line['line_string']);
		$line['line_string'] = str_replace('<?', '', $line['line_string']);
		$line['line_string'] = str_replace('?>', '', $line['line_string']);
		$line['line_string'] = trim($line['line_string']);

		foreach ($line['phrases'] as $phrase)
		{
			$phrase_fixed = str_replace('\\\'', '\'', $phrase);
			$phrase_fixed = str_replace('\\"', '"', $phrase_fixed);

			$phrase_translated = I18n::get($phrase_fixed, $language_code);

			$phrase_translated_fixed = str_replace('\'', '\\\'', $phrase_translated);

			$not_translated = '';

			if ($phrase_fixed === $phrase_translated)
			{
				$not_translated = '/// TODO';
				$phrase_translated_fixed = '';
			}

// 			print($not_translated."\t'$phrase' => '".$phrase_translated_fixed."', // ".$line['line_number'].": ".$line['line_string']."\n");
			print($not_translated."\t'$phrase' => '".$phrase_translated_fixed."', // ".$line['line_number']."\n");
		}
	}

	print("\n");
}

// Orphan phrases
print("\t// Orphan phrases\n");

foreach ($orphe_phrases as $phrase)
{
	$phrase_translated = I18n::get($phrase, $language_code);
	$not_translated = '';

	if ($phrase === $phrase_translated)
	{
		$not_translated = '/// TODO';
		$phrase_translated = '';
	}

	print($not_translated."\t'$phrase' => '".$phrase_translated."',\n");
}
print(");\n");
<?php defined('SYSPATH') or die('No direct access allowed.');

return array
(
	'languages' => array(
		'en' => 'English',
		'ca' => 'Català',
		'es' => 'Español',
		'fr' => 'Français',
	),

	// The default language correspond to the language wrote in PHP code
	'default' => 'en',
);

/// NOTE when adding more languages we need to check for the respective JS plugins' translations
<?php defined('SYSPATH') or die('No direct script access.');

class Controller_Cron extends Controller {

	public function before()
	{
		// Set default language
		I18n::$lang = Kohana::$config->load('i18n.default');
	}

	public function action_i18n_generator()
	{
		if ( ! Kohana::$is_cli)
		{
			echo 'Usage: php index.php --uri=/cron/i18n_generator';
			return;
		}

		$this->auto_render = FALSE;

		$path = APPPATH;
		$data = array();
		$unique_phrases_helper = array();

		$scan_files = $this->get_dir_files($path, array('php'));

		foreach ($scan_files as $file)
		{
			$file_path_human = substr($file, strlen($path));
// 			echo Kohana::debug($file_path_human);

			// Get each line of the file
			$file_lines = file($file, FILE_IGNORE_NEW_LINES);

			$data_file = array();

			foreach ($file_lines as $num_line => $file_line)
			{
				$num_line++;
// 				echo Kohana::debug($num_line, $file_line, $file_path_human);

// 				if (preg_match_all('/(?P<key>\w+):(?P<name>[\p{L}+|\D+])/u', $file_line, $matches))
// 				if (preg_match('/^(?P<name>.*?[^(TO|COPYTO)]+)( TO (?P<assignedto>\w[^(COPYTO)]+))?( COPYTO (?P<copyto>\w[^(TO)]+))?$/u', trim($email['Subject']), $matches))
// 				if (preg_match_all('/__\(\'(?P<phrase>.+)\'(, ?array\(.+\))?\)/u', $file_line, $matches))
// 				if (preg_match_all('/__\(\'(?P<phrase>.*)(, ?array\(.+\))?\'\)/u', $file_line, $matches))
// 				if (preg_match_all("/__\('(?P<phrase>.*?[^;])'\)/u", $file_line, $matches))
// 				if (preg_match_all("/__\([^'.+'$]\)/u", $file_line, $matches))
// 				if (preg_match_all("/__\([^_]+\)/u", $file_line, $matches))
// 				if (preg_match_all("/__\([^\b__]+\)/u", $file_line, $matches))
// 				if (preg_match_all("/__\((?P<phrase>((?!__).)+)\)/u", $file_line, $matches)) /// NOTE IT WORKS!!!
// 				if (preg_match_all("/__\((?P<phrase>((?!__)|(?!array).)+)\)/u", $file_line, $matches))
// 				if (preg_match_all("/__\(('|\")(?P<phrase>((?!__)|(?! ?array ?\().)+)('|\")/u", $file_line, $matches)) /// NOTE IT WORKS!!!
				if (preg_match_all("/__\(('|\")(?P<phrase>((?!__)|(?! ?array ?\().)+)('\)|',|\"\)|\",)/u", $file_line, $matches)) /// NOTE IT WORKS!!!
				{
// 					echo Kohana::debug($file_path_human, $num_line, $file_line, $matches);
// 					echo Kohana::debug($file_path_human, $num_line, $file_line, $matches['phrase']);
// 					echo Kohana::debug($matches['phrase']);

					$new_phrases = array_diff(array_unique($matches['phrase']), $unique_phrases_helper);

					if ($new_phrases)
					{
						$data_file[] = array(
							'line_number' => $num_line,
							'line_string' => $file_line,
							'phrases' => $new_phrases,
						);

						$unique_phrases_helper = array_merge($new_phrases, $unique_phrases_helper);
					}
				}
			}

			if ($data_file)
			{
				$data[] = array(
					'filepath' => $file,
					'filepath_human' => $file_path_human,
					'lines' => $data_file,
				);
			}
		}

// 		echo Kohana::debug($data);

		$languages = Kohana::$config->load('i18n.languages');
		$default_language = Kohana::$config->load('i18n.default');
		$orphe_phrases = array();

		// Fix phrases
		foreach ($unique_phrases_helper as $key => $phrase)
		{
			$unique_phrases_helper[$key] = str_replace('\\\'', '\'', $unique_phrases_helper[$key]);
			$unique_phrases_helper[$key] = str_replace('\\"', '"', $unique_phrases_helper[$key]);
		}

		// Add phrases present in current i18n language files but are not present in current code
		foreach ($languages as $language_code => $language)
		{
			$i18n_messages = array_keys(I18n::load($language_code));

			$orphe_phrases = array_merge($orphe_phrases, array_diff($i18n_messages, $unique_phrases_helper));
		}

		$orphe_phrases = array_unique($orphe_phrases);

// 		echo Kohana::debug($orphe_phrases);

		// Generate new i18n files
		foreach ($languages as $language_code => $language)
		{
			if ($default_language !== $language_code)
			{
				$filename = APPPATH.'i18n/'.$language_code.'.php';

				if (file_exists($filename))
				{
					rename($filename, $filename.'.old');
				}

				$content = View::factory('i18n_generator')
					->bind('data', $data)
					->set('orphe_phrases', $orphe_phrases)
					->set('language_code', $language_code);

				if (FALSE === file_put_contents($filename, $content))
				{
					echo 'There\'s an error writing the file: '.$filename."\n";
				}
				else
				{
					echo 'File ok: '.$filename."\n";
				}
			}
		}

		// Fix permissions
// 		system('chown marcalj:marcalj '.APPPATH.'logs/i18n/*');

		echo 'Finish';
	}

	/**
	 * Working tests:
	 *
	 * <?php echo __('tèst1'); ?>
	 * <?php echo __('tést2 :mico', array(':mico' => I18n::$lang)); ?>
	 * <?php echo __('tëst3 :mico', array(':mico' => I18n::$lang)); ?><?php echo __('test4'); ?>
	 * <?php echo __('test5 :mico', array(':mico' => I18n::$lang)).__('test6'); ?>
	 * <?php echo __('test7 :mico', array(':mico' => HTML::anchor(Route::get('website/new-tradu')->uri(array('language' => I18n::$lang)), __('test8')))); ?>
	 * <?php echo __('test9 :mico', array(':mico' => HTML::anchor(Route::get('website/new-tradu')->uri(array('language' => I18n::$lang)), __('test10 :moco', array(':moco' => I18n::$lang))))); ?>
	 * <?php echo __('tést11'); ?><?php echo __('tést12'); ?>
	 * <?php echo __('test13'); ?><?php echo __('tëst14 :mico', array(':mico' => I18n::$lang)); ?>
	 * <?php echo __('tést15'); ?><?php echo __('tést16'); ?><?php echo __('tést17'); ?>
	 * <?php echo __('tést18_jodete'); ?>
	 * <?php echo __('tést19;'); ?>
	 * <?php echo __("tést20;"); ?>
	 * <?php echo __('tést21 you\'re'); ?>
	 * <?php echo __('tést21 "enviar"'); ?>
	 */

	public function get_dir_files($dir, $types = NULL)
	{
		// Remove DIRECTORY_SEPARATOR at the end
		$dir = rtrim($dir, DIRECTORY_SEPARATOR);

		$path = '';

		$stack[] = $dir;

		while ($stack)
		{
			$thisdir = array_pop($stack);

			if ($dircont = scandir($thisdir))
			{
				$i = 0;

				while (isset($dircont[$i]))
				{
					if ($dircont[$i] !== '.' && $dircont[$i] !== '..')
					{
						$current_file = $thisdir.DIRECTORY_SEPARATOR.$dircont[$i];

						if (is_file($current_file))
						{
							if (is_array($types))
							{
								if (in_array(strtolower(pathinfo($thisdir.$dircont[$i], PATHINFO_EXTENSION)), $types, TRUE))
								{
									$path[] = $thisdir.DIRECTORY_SEPARATOR.$dircont[$i];
								}
							}
						}
						elseif (is_dir($current_file))
						{
							$stack[] = $current_file;
						}
					}

					$i++;
				}
			}
		}

		return $path;
	}

	/// FIXME use this function (alert!! it's recursive!)
	/**
	 * Recursively finds all of the files in the specified directory at any
	 * location in the [Cascading Filesystem](kohana/files), and returns an
	 * array of all the files found, sorted alphabetically.
	 *
	 *     // Find all view files.
	 *     $views = Kohana::list_files('views');
	 *
	 * @param   string  directory name
	 * @param   array   list of paths to search
	 * @return  array
	 */
// 	public static function list_files($directory = NULL, array $paths = NULL)

} // End Cron