Index: l10n_update.locale.inc =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/l10n_update/l10n_update.locale.inc,v retrieving revision 1.2.2.3 diff -u -p -r1.2.2.3 l10n_update.locale.inc --- l10n_update.locale.inc 19 Sep 2010 15:56:45 -0000 1.2.2.3 +++ l10n_update.locale.inc 25 Oct 2010 16:10:11 -0000 @@ -7,9 +7,9 @@ /** * Parses Gettext Portable Object file information and inserts into database - * + * * This is an improved version of _locale_import_po() to handle translation status - * + * * @param $file * Drupal file object corresponding to the PO file to import * @param $langcode @@ -77,18 +77,68 @@ function _l10n_update_locale_import_po($ * Text group to import PO file into (eg. 'default' for interface translations) */ function _l10n_update_locale_import_read_po($op, $file, $mode = NULL, $lang = NULL, $group = 'default') { - $fd = fopen($file->filepath, "rb"); // File will get closed by PHP on return - if (!$fd) { - _locale_import_message('The translation import failed, because the file %filename could not be read.', $file); + if ($size = filesize($file->filepath)) { + // File will get closed by PHP on return. + $fd = fopen($file->filepath, "rb"); + if (!$fd) { + _locale_import_message('The translation import failed, because the file %filename could not be read.', $file); + return FALSE; + } + + if ($size > variable_get('l10n_update_po_seek_limit', 50000)) { + // If the file size is above our seek limit, we try and seek into the file + // in small chunks. + $chunk_size = variable_get('l10n_update_po_chunk_size', 100); + $seek_position = 0; + while(is_int($seek_position = _l10n_update_locale_import_parse_po($op, $file, $fd, $mode, $lang, $group, $seek_position, $chunk_size))); + } + else { + // Small file, should be imported in one. + _locale_import_parse_po($op, $file, $fd, $mode, $lang, $group); + } + } + else { + _locale_import_message('The translation import failed, because the file %filename could not be found or was empty.', $file); return FALSE; } +} + +/** + * Parses Gettext Portable Object file into an array + * + * @param $op + * Storage operation type: db-store or mem-store + * @param $file + * Drupal file object corresponding to the PO file being imported + * @param $fd + * File system pointer for the same PO file, opened by _l10n_update_locale_import_read_po + * @param $mode + * Should existing translations be replaced LOCALE_IMPORT_KEEP or LOCALE_IMPORT_OVERWRITE + * @param $lang + * Language code + * @param $group + * Text group to import PO file into (eg. 'default' for interface translations) + * @param $seek_position + * Position from which to start/continue parsing (that position returned by + * this function in a previous iteration). + * @param $chunk_size + * Approximate number of lines to parse in one iteration - but continue to + * end of current entry. If not set, or set to zero, continue to end of file. + */ +function _l10n_update_locale_import_parse_po($op, $file, $fd, $mode = NULL, $lang = NULL, $group = 'default', $seek_position = NULL, $chunk_size = NULL) { $context = "COMMENT"; // Parser context: COMMENT, MSGID, MSGID_PLURAL, MSGSTR and MSGSTR_ARR $current = array(); // Current entry being read $plural = 0; // Current plural form $lineno = 0; // Current line + // Set file position indicator to where previous iteration left off. + if ($seek_position !== NULL) { + fseek($fd, $seek_position); + } + while (!feof($fd)) { + $seek_position_before_line = ftell($fd); $line = fgets($fd, 10*1024); // A line should not be this long if ($lineno == 0) { // The first line might come with a UTF-8 BOM, which should be removed. @@ -103,9 +153,14 @@ function _l10n_update_locale_import_read } elseif (($context == "MSGSTR") || ($context == "MSGSTR_ARR")) { // End current entry, start a new one _l10n_update_locale_import_one_string($op, $current, $mode, $lang, $file, $group); - $current = array(); - $current["#"][] = substr($line, 1); - $context = "COMMENT"; + if ($chunk_size && ($lineno > $chunk_size)) { + return $seek_position_before_line; + } + else { + $current = array(); + $current["#"][] = substr($line, 1); + $context = "COMMENT"; + } } else { // Parse error _locale_import_message('The translation file %filename contains an error: "msgstr" was expected but not found on line %line.', $file, $lineno); @@ -130,6 +185,9 @@ function _l10n_update_locale_import_read if (($context == "MSGSTR") || ($context == "MSGSTR_ARR")) { // End current entry, start a new one _l10n_update_locale_import_one_string($op, $current, $mode, $lang, $file, $group); $current = array(); + if ($chunk_size && ($lineno > $chunk_size)) { + return $seek_position_before_line; + } } elseif ($context == "MSGID") { // Already in this context? Parse error _locale_import_message('The translation file %filename contains an error: "msgid" is unexpected on line %line.', $file, $lineno); @@ -209,6 +267,7 @@ function _l10n_update_locale_import_read return FALSE; } + return TRUE; } /** @@ -364,4 +423,3 @@ function _l10n_update_locale_import_one_ return $lid; } -