features_translations.module 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. <?php
  2. /**
  3. * Implementation of hook_features_api().
  4. */
  5. function features_translations_features_api() {
  6. $translations = array();
  7. // Legacy option - we don't write to it anymore.
  8. $translations['translations'] = array(
  9. 'name' => t('Translations'),
  10. 'default_hook' => 'translations_defaults',
  11. 'feature_source' => TRUE,
  12. 'default_file' => FEATURES_DEFAULTS_INCLUDED,
  13. );
  14. foreach (language_list() as $langcode => $language) {
  15. $machine_langcode = strtr($langcode, array('-' => '_'));
  16. $translations["translations_{$machine_langcode}"] = array(
  17. 'name' => t('Translations: !name', array('!name' => t($language->name))),
  18. 'default_hook' => "translations_{$machine_langcode}_defaults",
  19. 'feature_source' => TRUE,
  20. 'base' => 'translations',
  21. 'default_file' => FEATURES_DEFAULTS_INCLUDED,
  22. 'supersedes' => 'translations',
  23. );
  24. }
  25. return $translations;
  26. }
  27. /**
  28. * Implementation of hook_features_export_options().
  29. */
  30. function translations_features_export_options($component) {
  31. // Ignore legacy option.
  32. if ($component == 'translations') return array();
  33. $options = array();
  34. $textgroups = module_invoke_all('locale', 'groups');
  35. list(,$machine_langcode) = explode('_', $component, 2);
  36. $langcode = strtr($machine_langcode, array('_' => '-'));
  37. $languages = language_list();
  38. $language = $languages[$langcode];
  39. foreach ($textgroups as $textgroup => $label) {
  40. if ($textgroup == 'default' && $langcode == 'en') continue;
  41. if ($textgroup != 'default' && $langcode == translations_features_string_source_language()) continue;
  42. $options[$machine_langcode . ':' . $textgroup] = t($language->name) . ': ' . $label;
  43. }
  44. return $options;
  45. }
  46. /**
  47. * Helper to return site's string source language.
  48. */
  49. function translations_features_string_source_language() {
  50. if (module_exists('i18n_string')) {
  51. return i18n_string_source_language();
  52. }
  53. return language_default('language');
  54. }
  55. /**
  56. * Implementation of hook_features_export().
  57. */
  58. function translations_features_export($data, &$export, $module_name) {
  59. foreach ($data as $component) {
  60. list($machine_langcode,) = explode(':', $component);
  61. $export['features']["translations_{$machine_langcode}"][$component] = $component;
  62. }
  63. $export['dependencies']['features'] = 'features';
  64. $export['dependencies']['features_translations'] = 'features_translations';
  65. return array();
  66. }
  67. /**
  68. * Implementation of hook_features_export_render().
  69. */
  70. function translations_features_export_render($module_name, $data, $export = NULL) {
  71. $languages = language_list();
  72. $code = array(
  73. ' $translations = array();',
  74. ' $translatables = array();',
  75. );
  76. $machine_langcode = ''; // won't change in the loop
  77. foreach ($data as $component) {
  78. list($machine_langcode, $textgroup) = explode(':', $component);
  79. $langcode = strtr($machine_langcode, array('_' => '-'));
  80. $strings = _features_translations_locale_export_get_strings($languages[$langcode], $textgroup);
  81. foreach ($strings as $md5 => $string) {
  82. $code[] = " \$translations['{$machine_langcode}:{$textgroup}']['{$md5}'] = " . features_var_export($string, ' ') . ";";
  83. // potx compatibility
  84. $code[] = " \$translatables[] = t('" .
  85. str_replace("'", "\'", $string->source) .
  86. "', array(), array('context' => '" .
  87. str_replace("'", "\'", $string->context) .
  88. "'));";
  89. }
  90. }
  91. $code[] = ' return $translations;';
  92. $code = implode("\n", $code);
  93. return array("translations_{$machine_langcode}_defaults" => $code);
  94. }
  95. /**
  96. * Implementation of hook_features_revert().
  97. */
  98. function translations_features_revert($module_name, $component) {
  99. include_once('includes/locale.inc');
  100. $translations = features_get_default($component, $module_name);
  101. if (!empty($translations)) {
  102. $report = array('updates' => 0, 'skips' => 0, 'additions' => 0, 'deletes' => 0);
  103. $lids = array();
  104. foreach ($translations as $key => $strings) {
  105. list($machine_langcode, $textgroup) = explode(':', $key);
  106. $langcode = strtr($machine_langcode, array('_' => '-'));
  107. foreach ($strings as $md5 => $string) {
  108. if (!empty($string['plid'])) {
  109. if (!isset($lids[$string['plid']])) {
  110. watchdog('features', 'Translations: importing plid %plid not found for string %source', array(
  111. '%plid' => $string['plid'],
  112. '%source' => $string['source'],
  113. ), WATCHDOG_WARNING);
  114. $string['plid'] = 0;
  115. }
  116. else {
  117. $string['plid'] = $lids[$string['plid']];
  118. }
  119. }
  120. $lids[$md5] = _locale_import_one_string_db(
  121. $report,
  122. $langcode,
  123. $string['context'],
  124. $string['source'],
  125. $string['translation'],
  126. $textgroup,
  127. $string['location'],
  128. LOCALE_IMPORT_OVERWRITE,
  129. $string['plid'],
  130. $string['plural']
  131. );
  132. if (module_exists('l10n_update')) {
  133. // Set the "string is customized" flag so featured translations can roundtrip.
  134. db_update('locales_target')
  135. ->fields(array(
  136. // Use literal here as the named constant is not available globally in some versions.
  137. 'l10n_status' => 1,
  138. ))
  139. ->condition('language', $langcode)
  140. ->condition('lid', $lids[$md5])
  141. ->execute();
  142. }
  143. }
  144. }
  145. watchdog('features', 'Translations: results for importing feature %feature: %report', array(
  146. '%feature' => $module_name . ':' . $component,
  147. '%report' => var_export($report, TRUE),
  148. ), WATCHDOG_INFO);
  149. }
  150. return TRUE;
  151. }
  152. /**
  153. * Helper to return translated strings in given language and group.
  154. */
  155. function _features_translations_locale_export_get_strings($language, $group) {
  156. $query = db_select('locales_source', 's');
  157. $query->join('locales_target', 't', 's.lid = t.lid');
  158. $query->fields('s', array('lid', 'source', 'context', 'location'));
  159. $query->fields('t', array('translation', 'plid', 'plural'));
  160. $query->addExpression('MD5(CONCAT(s.source, s.context))', 'source_md5');
  161. $query->condition('t.language', $language->language);
  162. $query->condition('s.textgroup', $group);
  163. //exclude unchanged lids
  164. if (module_exists('l10n_update')) {
  165. // Use literal here as the named constant is not available globally in some versions.
  166. $query->condition('t.l10n_status', 0, '<>');
  167. }
  168. $query->orderBy('t.plural', 'ASC')->orderBy('source_md5', 'ASC');
  169. $result = $query->execute()->fetchAll();
  170. $strings = array();
  171. $lids = array();
  172. foreach ($result as $string) {
  173. $md5 = $string->source_md5;
  174. $lids[$string->lid] = $md5;
  175. if (!empty($string->plid)) {
  176. if (!isset($lids[$string->plid])) {
  177. watchdog('features', 'Translations: exporting plid %plid not found for string %source.', array('%plid' => $string->plid, '%source' => $string->source));
  178. $string->plid = 0;
  179. }
  180. else {
  181. $string->plid = $lids[$string->plid];
  182. }
  183. }
  184. unset($string->lid, $string->source_md5); // don't want those in the export
  185. $strings[$md5] = $string;
  186. }
  187. return $strings;
  188. }