t('Translations'), 'default_hook' => 'translations_defaults', 'feature_source' => TRUE, 'default_file' => FEATURES_DEFAULTS_INCLUDED, ); foreach (language_list() as $langcode => $language) { $machine_langcode = strtr($langcode, array('-' => '_')); $translations["translations_{$machine_langcode}"] = array( 'name' => t('Translations: !name', array('!name' => t($language->name))), 'default_hook' => "translations_{$machine_langcode}_defaults", 'feature_source' => TRUE, 'base' => 'translations', 'default_file' => FEATURES_DEFAULTS_INCLUDED, 'supersedes' => 'translations', ); } return $translations; } /** * Implementation of hook_features_export_options(). */ function translations_features_export_options($component) { // Ignore legacy option. if ($component == 'translations') return array(); $options = array(); $textgroups = module_invoke_all('locale', 'groups'); list(,$machine_langcode) = explode('_', $component, 2); $langcode = strtr($machine_langcode, array('_' => '-')); $languages = language_list(); $language = $languages[$langcode]; foreach ($textgroups as $textgroup => $label) { if ($textgroup == 'default' && $langcode == 'en') continue; if ($textgroup != 'default' && $langcode == translations_features_string_source_language()) continue; $options[$machine_langcode . ':' . $textgroup] = t($language->name) . ': ' . $label; } return $options; } /** * Helper to return site's string source language. */ function translations_features_string_source_language() { if (module_exists('i18n_string')) { return i18n_string_source_language(); } return language_default('language'); } /** * Implementation of hook_features_export(). */ function translations_features_export($data, &$export, $module_name) { foreach ($data as $component) { list($machine_langcode,) = explode(':', $component); $export['features']["translations_{$machine_langcode}"][$component] = $component; } $export['dependencies']['features'] = 'features'; $export['dependencies']['features_translations'] = 'features_translations'; return array(); } /** * Implementation of hook_features_export_render(). */ function translations_features_export_render($module_name, $data, $export = NULL) { $languages = language_list(); $code = array( ' $translations = array();', ' $translatables = array();', ); $machine_langcode = ''; // won't change in the loop foreach ($data as $component) { list($machine_langcode, $textgroup) = explode(':', $component); $langcode = strtr($machine_langcode, array('_' => '-')); $strings = _features_translations_locale_export_get_strings($languages[$langcode], $textgroup); foreach ($strings as $md5 => $string) { $code[] = " \$translations['{$machine_langcode}:{$textgroup}']['{$md5}'] = " . features_var_export($string, ' ') . ";"; // potx compatibility $code[] = " \$translatables[] = t('" . str_replace("'", "\'", $string->source) . "', array(), array('context' => '" . str_replace("'", "\'", $string->context) . "'));"; } } $code[] = ' return $translations;'; $code = implode("\n", $code); return array("translations_{$machine_langcode}_defaults" => $code); } /** * Implementation of hook_features_revert(). */ function translations_features_revert($module_name, $component) { include_once('includes/locale.inc'); $translations = features_get_default($component, $module_name); if (!empty($translations)) { $report = array('updates' => 0, 'skips' => 0, 'additions' => 0, 'deletes' => 0); $lids = array(); foreach ($translations as $key => $strings) { list($machine_langcode, $textgroup) = explode(':', $key); $langcode = strtr($machine_langcode, array('_' => '-')); foreach ($strings as $md5 => $string) { if (!empty($string['plid'])) { if (!isset($lids[$string['plid']])) { watchdog('features', 'Translations: importing plid %plid not found for string %source', array( '%plid' => $string['plid'], '%source' => $string['source'], ), WATCHDOG_WARNING); $string['plid'] = 0; } else { $string['plid'] = $lids[$string['plid']]; } } $lids[$md5] = _locale_import_one_string_db( $report, $langcode, $string['context'], $string['source'], $string['translation'], $textgroup, $string['location'], LOCALE_IMPORT_OVERWRITE, $string['plid'], $string['plural'] ); if (module_exists('l10n_update')) { // Set the "string is customized" flag so featured translations can roundtrip. db_update('locales_target') ->fields(array( // Use literal here as the named constant is not available globally in some versions. 'l10n_status' => 1, )) ->condition('language', $langcode) ->condition('lid', $lids[$md5]) ->execute(); } } } watchdog('features', 'Translations: results for importing feature %feature: %report', array( '%feature' => $module_name . ':' . $component, '%report' => var_export($report, TRUE), ), WATCHDOG_INFO); } return TRUE; } /** * Helper to return translated strings in given language and group. */ function _features_translations_locale_export_get_strings($language, $group) { $query = db_select('locales_source', 's'); $query->join('locales_target', 't', 's.lid = t.lid'); $query->fields('s', array('lid', 'source', 'context', 'location')); $query->fields('t', array('translation', 'plid', 'plural')); $query->addExpression('MD5(CONCAT(s.source, s.context))', 'source_md5'); $query->condition('t.language', $language->language); $query->condition('s.textgroup', $group); //exclude unchanged lids if (module_exists('l10n_update')) { // Use literal here as the named constant is not available globally in some versions. $query->condition('t.l10n_status', 0, '<>'); } $query->orderBy('t.plural', 'ASC')->orderBy('source_md5', 'ASC'); $result = $query->execute()->fetchAll(); $strings = array(); $lids = array(); foreach ($result as $string) { $md5 = $string->source_md5; $lids[$string->lid] = $md5; if (!empty($string->plid)) { if (!isset($lids[$string->plid])) { watchdog('features', 'Translations: exporting plid %plid not found for string %source.', array('%plid' => $string->plid, '%source' => $string->source)); $string->plid = 0; } else { $string->plid = $lids[$string->plid]; } } unset($string->lid, $string->source_md5); // don't want those in the export $strings[$md5] = $string; } return $strings; }