locale.install

  1. drupal
    1. 5 modules/locale/locale.install
    2. 6 modules/locale/locale.install
    3. 7 modules/locale/locale.install
    4. 8 core/modules/locale/locale.install

Install, update and uninstall functions for the locale module.

Functions & methods

NameDescription
locale_schemaImplements hook_schema().
locale_uninstallImplements hook_uninstall().
locale_update_8000Drop textgroup support.
locale_update_8001Language type 'language' renamed to 'language_interface'.
locale_update_8002Removes duplicates in {locales_source}.
locale_update_8003Converts language domains to new format.
locale_update_8004Rename language providers to language negotiation methods.
locale_update_8005Update plural interface translations to new format.
locale_update_8006Add column to track customized string status to locales_target.
locale_update_8007Convert language_negotiation_* variables to use the new callbacks.
locale_update_8008Rename the option variables of the locale language negotiation.
locale_update_8009Convert locale blocks to language blocks.

File

core/modules/locale/locale.install
View source
  1. <?php
  2. /**
  3. * @file
  4. * Install, update and uninstall functions for the locale module.
  5. */
  6. /**
  7. * Implements hook_uninstall().
  8. */
  9. function locale_uninstall() {
  10. // Delete all JavaScript translation files.
  11. $locale_js_directory = 'public://' . variable_get('locale_js_directory', 'languages');
  12. if (is_dir($locale_js_directory)) {
  13. $locale_javascripts = variable_get('locale_translation_javascript', array());
  14. foreach ($locale_javascripts as $langcode => $file_suffix) {
  15. if (!empty($file_suffix)) {
  16. file_unmanaged_delete($locale_js_directory . '/' . $langcode . '_' . $file_suffix . '.js');
  17. }
  18. }
  19. // Delete the JavaScript translations directory if empty.
  20. if (!file_scan_directory($locale_js_directory, '/.*/')) {
  21. drupal_rmdir($locale_js_directory);
  22. }
  23. }
  24. // Clear variables.
  25. variable_del('locale_cache_strings');
  26. variable_del('locale_js_directory');
  27. variable_del('javascript_parsed');
  28. variable_del('locale_field_language_fallback');
  29. variable_del('locale_cache_length');
  30. variable_del('locale_translation_plurals');
  31. variable_del('locale_translation_javascript');
  32. // Remove all node type language variables. Node module might have been
  33. // enabled, but may be disabled, so use a wildcard delete.
  34. db_delete('variable')
  35. ->condition('name', db_like('language_content_type_') . '%', 'LIKE')
  36. ->execute();
  37. }
  38. /**
  39. * Implements hook_schema().
  40. */
  41. function locale_schema() {
  42. $schema['locales_source'] = array(
  43. 'description' => 'List of English source strings.',
  44. 'fields' => array(
  45. 'lid' => array(
  46. 'type' => 'serial',
  47. 'not null' => TRUE,
  48. 'description' => 'Unique identifier of this string.',
  49. ),
  50. 'location' => array(
  51. 'type' => 'text',
  52. 'not null' => FALSE,
  53. 'size' => 'big',
  54. 'description' => 'Drupal path in case of online discovered translations or file path in case of imported strings.',
  55. ),
  56. 'source' => array(
  57. 'type' => 'text',
  58. 'mysql_type' => 'blob',
  59. 'not null' => TRUE,
  60. 'description' => 'The original string in English.',
  61. ),
  62. 'context' => array(
  63. 'type' => 'varchar',
  64. 'length' => 255,
  65. 'not null' => TRUE,
  66. 'default' => '',
  67. 'description' => 'The context this string applies to.',
  68. ),
  69. 'version' => array(
  70. 'type' => 'varchar',
  71. 'length' => 20,
  72. 'not null' => TRUE,
  73. 'default' => 'none',
  74. 'description' => 'Version of Drupal, where the string was last used (for locales optimization).',
  75. ),
  76. ),
  77. 'primary key' => array('lid'),
  78. 'indexes' => array(
  79. 'source_context' => array(array('source', 30), 'context'),
  80. ),
  81. );
  82. $schema['locales_target'] = array(
  83. 'description' => 'Stores translated versions of strings.',
  84. 'fields' => array(
  85. 'lid' => array(
  86. 'type' => 'int',
  87. 'not null' => TRUE,
  88. 'default' => 0,
  89. 'description' => 'Source string ID. References {locales_source}.lid.',
  90. ),
  91. 'translation' => array(
  92. 'type' => 'text',
  93. 'mysql_type' => 'blob',
  94. 'not null' => TRUE,
  95. 'description' => 'Translation string value in this language.',
  96. ),
  97. 'language' => array(
  98. 'type' => 'varchar',
  99. 'length' => 12,
  100. 'not null' => TRUE,
  101. 'default' => '',
  102. 'description' => 'Language code. References {language}.langcode.',
  103. ),
  104. 'customized' => array(
  105. 'type' => 'int',
  106. 'not null' => TRUE,
  107. 'default' => 0, // LOCALE_NOT_CUSTOMIZED
  108. 'description' => 'Boolean indicating whether the translation is custom to this site.',
  109. ),
  110. ),
  111. 'primary key' => array('language', 'lid'),
  112. 'foreign keys' => array(
  113. 'locales_source' => array(
  114. 'table' => 'locales_source',
  115. 'columns' => array('lid' => 'lid'),
  116. ),
  117. ),
  118. 'indexes' => array(
  119. 'lid' => array('lid'),
  120. ),
  121. );
  122. return $schema;
  123. }
  124. /**
  125. * @addtogroup updates-7.x-to-8.x
  126. * @{
  127. */
  128. /**
  129. * Drop textgroup support.
  130. *
  131. * Update assumes i18n migrated this data before the update happened. Core
  132. * never used textgroups for anything, so it is not our job to find place
  133. * for the data elsewhere.
  134. */
  135. function locale_update_8000() {
  136. $subquery = db_select('locales_source', 'ls')
  137. ->fields('ls', array('lid'))
  138. ->condition('ls.textgroup', 'default', '<>');
  139. db_delete('locales_target')
  140. ->condition('lid', $subquery, 'IN')
  141. ->execute();
  142. db_delete('locales_source')
  143. ->condition('textgroup', 'default', '<>')
  144. ->execute();
  145. db_drop_field('locales_source', 'textgroup');
  146. }
  147. /**
  148. * Language type 'language' renamed to 'language_interface'.
  149. */
  150. function locale_update_8001() {
  151. // Only change language_types if we had this setting saved. Keep order
  152. // of types because that is significant for value dependency.
  153. $types = variable_get('language_types', NULL);
  154. if (!empty($types) && isset($types['language'])) {
  155. $new_types = array();
  156. foreach ($types as $key => $type) {
  157. $new_types[$key == 'language' ? 'language_interface' : $key] = $type;
  158. }
  159. variable_set('language_types', $new_types);
  160. }
  161. // Rename language_negotiation_language setting if exists.
  162. $setting = variable_get('language_negotiation_language', NULL);
  163. if ($setting !== NULL) {
  164. variable_set('language_negotiation_language_interface', $setting);
  165. variable_del('language_negotiation_language');
  166. }
  167. // Rename locale_language_providers_weight_language setting if exists.
  168. $weight = variable_get('locale_language_providers_weight_language', NULL);
  169. if ($weight !== NULL) {
  170. variable_set('locale_language_providers_weight_language_interface', $weight);
  171. variable_del('locale_language_providers_weight_language');
  172. }
  173. // Update block data in all core block related tables. Contributed modules
  174. // storing data for blocks will need to update for themselves.
  175. $block_tables = array('block', 'block_node_type', 'block_role');
  176. foreach ($block_tables as $table) {
  177. // Perform the update only if the language switcher block data is available.
  178. $block_data = db_query_range('SELECT 1 FROM {' . $table . '} WHERE delta = :delta AND module = :module', 0, 1, array(':delta' => 'language', ':module' => 'locale'))
  179. ->fetchField();
  180. if ($block_data) {
  181. // If block information is rebuilt before performing the update, we might
  182. // already have data for the new delta. In this case we need to remove it
  183. // to avoid integrity constraint violation errors.
  184. db_delete($table)
  185. ->condition('delta', 'language_interface')
  186. ->condition('module', 'locale')
  187. ->execute();
  188. db_update($table)
  189. ->fields(array(
  190. 'delta' => 'language_interface',
  191. ))
  192. ->condition('delta', 'language')
  193. ->condition('module', 'locale')
  194. ->execute();
  195. }
  196. }
  197. }
  198. /**
  199. * Removes duplicates in {locales_source}.
  200. *
  201. * Aggressively removes duplicates that has not already been removed by
  202. * locale_update_7004() in Drupal 7.x.
  203. */
  204. function locale_update_8002() {
  205. // Look up all duplicates.
  206. $results = db_query("SELECT source, context FROM {locales_source} GROUP BY source, context HAVING COUNT(*) > 1");
  207. // For each set of duplicates, select one row that should survive, preferably
  208. // one that has been translated, and delete the rest.
  209. foreach ($results as $row) {
  210. $lid = db_query("SELECT s.lid FROM {locales_source} s LEFT JOIN {locales_target} t ON s.lid = t.lid WHERE s.source = :source AND s.context = :context ORDER BY translation IS NULL", array(
  211. ':source' => $row->source,
  212. ':context' => $row->context,
  213. ))->fetchField();
  214. db_delete('locales_source')
  215. ->condition('source', $row->source)
  216. ->condition('context', $row->context)
  217. ->condition('lid', $lid, '<>')
  218. ->execute();
  219. }
  220. // Finally remove any rows from {locales_target} that refer to non-existing
  221. // lids.
  222. $subquery = db_select('locales_source', 't')->fields('t', array('lid'));
  223. db_delete('locales_target')->condition('lid', $subquery, 'NOT IN')->execute();
  224. }
  225. /**
  226. * Converts language domains to new format.
  227. */
  228. function locale_update_8003() {
  229. $message = '';
  230. $domains = variable_get('locale_language_negotiation_url_domains', array());
  231. // $used_domains keeps track of the domain names in use.
  232. $used_domains = array();
  233. foreach ($domains as $langcode => $domain) {
  234. // Domain names can not contain protocol and/or ports.
  235. if (!empty($domain)) {
  236. $host = 'http://' . str_replace(array('http://', 'https://'), '', $domain);
  237. if (parse_url($host, PHP_URL_HOST) != $domain) {
  238. $domains[$langcode] = parse_url($host, PHP_URL_HOST);
  239. }
  240. if (array_key_exists($domain, $used_domains)) {
  241. if (empty($message)) {
  242. $message = 'Some languages are using the same domain name, you should change these domain names at ' . l('URL language detection configuration', 'admin/config/regional/language/configure/url' . '.');
  243. }
  244. }
  245. else {
  246. $used_domains[$domain] = $domain;
  247. }
  248. }
  249. }
  250. variable_set('locale_language_negotiation_url_domains', $domains);
  251. if (!empty($message)) {
  252. return $message;
  253. }
  254. }
  255. /**
  256. * Rename language providers to language negotiation methods.
  257. */
  258. function locale_update_8004() {
  259. $types = variable_get('language_types', NULL);
  260. if (!empty($types)) {
  261. foreach ($types as $type => $configurable) {
  262. // Rename the negotiation and language switch callback keys.
  263. $negotiation = variable_get('language_negotiation_' . $type, NULL);
  264. if (!empty($negotiation)) {
  265. foreach ($negotiation as $method_id => &$method) {
  266. $method['callbacks']['negotiation'] = $method['callbacks']['language'];
  267. unset($method['callbacks']['language']);
  268. if (isset($method['callbacks']['switcher'])) {
  269. $method['callbacks']['language_switch'] = $method['callbacks']['switcher'];
  270. unset($method['callbacks']['switcher']);
  271. }
  272. }
  273. variable_set('language_negotiation_' . $type, $negotiation);
  274. }
  275. // Rename the language negotiation methods weight variable.
  276. $weight = variable_get('locale_language_providers_weight_' . $type , NULL);
  277. if ($weight !== NULL) {
  278. variable_set('language_negotiation_methods_weight_' . $type , $weight);
  279. variable_del('locale_language_providers_weight_' . $type);
  280. }
  281. }
  282. }
  283. }
  284. /**
  285. * Update plural interface translations to new format.
  286. *
  287. * See http://drupal.org/node/532512#comment-5679184 for the details of the
  288. * structures handled in this update.
  289. */
  290. function locale_update_8005() {
  291. // Collect all LIDs that are sources to plural variants.
  292. $results = db_query("SELECT lid, plid FROM {locales_target} WHERE plural <> 0");
  293. $plural_lids = array();
  294. foreach ($results as $row) {
  295. // Need to collect both LID and PLID. The LID for the first (singular)
  296. // string can only be retrieved from the first plural's PLID given no
  297. // other indication. The last plural variant is never referenced, so we
  298. // need to store the LID directly for that. We never know whether we are
  299. // on the last plural though, so we always remember LID too.
  300. $plural_lids[] = $row->lid;
  301. $plural_lids[] = $row->plid;
  302. }
  303. $plural_lids = array_unique($plural_lids);
  304. if (!empty($plural_lids)) {
  305. // Look up all translations for these source strings. Ordering by language
  306. // will group the strings by language, the 'plid' order will get the strings
  307. // in singular/plural order and 'plural' will get them in precise sequential
  308. // order needed.
  309. $results = db_query("SELECT s.lid, s.source, t.translation, t.plid, t.plural, t.language FROM {locales_source} s LEFT JOIN {locales_target} t ON s.lid = t.lid WHERE s.lid IN (:lids) ORDER BY t.language, t.plid, t.plural", array(':lids' => $plural_lids));
  310. // Collect the strings into an array and combine values as we go.
  311. $strings = array();
  312. $parents_to_sources = array();
  313. $remove_lids = array();
  314. foreach ($results as $child) {
  315. $strings[$child->language][$child->lid] = array(
  316. 'source' => array($child->source),
  317. 'translation' => array($child->translation),
  318. );
  319. if (empty($child->plid)) {
  320. // Non-children strings point to themselves as parents. This makes it
  321. // easy to look up the utmost parents for any plurals.
  322. $parents_to_sources[$child->lid] = $child->lid;
  323. }
  324. else {
  325. // Children strings point to their utmost parents. Because we get data
  326. // in PLID order, we can ensure that all previous parents have data now,
  327. // so we can just copy the parent's data about their parent, etc.
  328. $parents_to_sources[$child->lid] = $parents_to_sources[$child->plid];
  329. // Append translation to the utmost parent's translation string.
  330. $utmost_parent = &$strings[$child->language][$parents_to_sources[$child->plid]];
  331. // Drop the Drupal-specific numbering scheme from the end of plural
  332. // formulas.
  333. $utmost_parent['translation'][] = str_replace('@count[' . $child->plural .']', '@count', $child->translation);
  334. if (count($utmost_parent['source']) < 2) {
  335. // Append source to the utmost parent's source string only if it is
  336. // the plural variant. Further Drupal specific plural variants are not
  337. // to be retained for source strings.
  338. $utmost_parent['source'][] = $child->source;
  339. }
  340. // All plural variant LIDs are to be removed with their translations.
  341. // Only the singular LIDs will be kept.
  342. $remove_lids[] = $child->lid;
  343. }
  344. }
  345. // Do updates for all source strings and all translations.
  346. $updated_sources = array();
  347. foreach ($strings as $langcode => $translations) {
  348. foreach($translations as $lid => $translation) {
  349. if (!in_array($lid, $updated_sources)) {
  350. // Only update source string if not yet updated. We merged these
  351. // within the translation lookups because plural information was only
  352. // available with the translation, but we don't need to save it again
  353. // for every language.
  354. db_update('locales_source')
  355. ->fields(array(
  356. 'source' => implode(LOCALE_PLURAL_DELIMITER, $translation['source']),
  357. ))
  358. ->condition('lid', $lid)
  359. ->execute();
  360. $updated_sources[] = $lid;
  361. }
  362. db_update('locales_target')
  363. ->fields(array(
  364. 'translation' => implode(LOCALE_PLURAL_DELIMITER, $translation['translation']),
  365. ))
  366. ->condition('lid', $lid)
  367. ->condition('language', $langcode)
  368. ->execute();
  369. }
  370. }
  371. // Remove all plural LIDs from source and target. only keep those which were
  372. // originally used for the singular strings (now updated to contain the
  373. // serialized version of plurals).
  374. $remove_lids = array_unique($remove_lids);
  375. db_delete('locales_source')
  376. ->condition('lid', $remove_lids, 'IN')
  377. ->execute();
  378. db_delete('locales_target')
  379. ->condition('lid', $remove_lids, 'IN')
  380. ->execute();
  381. }
  382. // Drop the primary key because it contains 'plural'.
  383. db_drop_primary_key('locales_target');
  384. // Remove the 'plid' and 'plural' columns and indexes.
  385. db_drop_index('locales_target', 'plid');
  386. db_drop_field('locales_target', 'plid');
  387. db_drop_index('locales_target', 'plural');
  388. db_drop_field('locales_target', 'plural');
  389. // Add back a primary key without 'plural'.
  390. db_add_primary_key('locales_target', array('language', 'lid'));
  391. }
  392. /**
  393. * Add column to track customized string status to locales_target.
  394. */
  395. function locale_update_8006() {
  396. $spec = array(
  397. 'type' => 'int',
  398. 'not null' => TRUE,
  399. 'default' => 0, // LOCALE_NOT_CUSTOMIZED
  400. 'description' => 'Boolean indicating whether the translation is custom to this site.',
  401. );
  402. db_add_field('locales_target', 'customized', $spec);
  403. }
  404. /**
  405. * Convert language_negotiation_* variables to use the new callbacks.
  406. */
  407. function locale_update_8007() {
  408. $variable_names = array(
  409. 'language_negotiation_language_interface',
  410. 'language_negotiation_language_content',
  411. 'language_negotiation_language_url',
  412. );
  413. // Add all language type weight variables. As the function language_types()
  414. // is not available its functionality is rebuild.
  415. $language_types = variable_get('language_types', array(
  416. LANGUAGE_TYPE_INTERFACE => TRUE,
  417. LANGUAGE_TYPE_CONTENT => FALSE,
  418. LANGUAGE_TYPE_URL => FALSE,
  419. ));
  420. foreach ($language_types as $language_type => $configurable) {
  421. $variable_names[] = 'language_negotiation_methods_weight_' . $language_type;
  422. }
  423. $callback_map = array(
  424. 'locale_language_from_url' => 'language_from_url',
  425. 'locale_language_switcher_url' => 'language_switcher_url',
  426. 'locale_language_url_rewrite_url' => 'language_url_rewrite_url',
  427. 'locale_language_from_session' => 'language_from_session',
  428. 'locale_language_switcher_session' => 'language_switcher_session',
  429. 'locale_language_url_rewrite_session' => 'language_url_rewrite_session',
  430. 'locale_language_from_user' => 'language_from_user',
  431. 'locale_language_from_browser' => 'language_from_browser',
  432. 'locale_language_url_fallback' => 'language_url_fallback',
  433. 'locale_language_from_interface' => 'language_from_interface',
  434. );
  435. $type_map = array(
  436. 'locale-interface' => 'language-interface',
  437. 'locale-url' => 'language-url',
  438. 'locale-url-fallback' => 'language-url-fallback',
  439. 'locale-browser' => 'language-browser',
  440. 'locale-user' => 'language-user',
  441. 'locale-session' => 'language-session',
  442. );
  443. foreach ($variable_names as $variable_name) {
  444. $value = variable_get($variable_name);
  445. // Skip processing if the variable is not stored in the db.
  446. if ($value === NULL) {
  447. continue;
  448. }
  449. $new_value = $value;
  450. foreach ($value as $type => $type_settings) {
  451. // Convert the file.
  452. if (isset($type_settings['file']) && (strpos($type_settings['file'], 'core/includes/locale.inc') !== FALSE)) {
  453. $new_value[$type]['file'] = 'core/modules/language/language.negotiation.inc';
  454. }
  455. // Convert the callbacks.
  456. if (is_array($type_settings) && isset($type_settings['callbacks'])) {
  457. foreach ($type_settings['callbacks'] as $key => $callback) {
  458. if (isset($callback_map[$callback])) {
  459. $new_value[$type]['callbacks'][$key] = $callback_map[$callback];
  460. }
  461. }
  462. }
  463. // Convert the type.
  464. if (isset($type_map[$type])) {
  465. $new_value[$type_map[$type]] = $new_value[$type];
  466. unset($new_value[$type]);
  467. }
  468. }
  469. // If necessary maintain the order of the values / keys of the variable.
  470. if (stristr($variable_name, 'language_negotiation_methods_weight_') !== FALSE) {
  471. asort($new_value);
  472. }
  473. variable_set($variable_name, $new_value);
  474. }
  475. }
  476. /**
  477. * Rename the option variables of the locale language negotiation.
  478. */
  479. function locale_update_8008() {
  480. $variable_name_map = array(
  481. 'locale_language_negotiation_url_part' => 'language_negotiation_url_part',
  482. 'locale_language_negotiation_url_domains' => 'language_negotiation_url_domains',
  483. 'locale_language_negotiation_url_prefixes' => 'language_negotiation_url_prefixes',
  484. 'locale_language_negotiation_session_param' => 'language_negotiation_session_param',
  485. );
  486. foreach ($variable_name_map as $deprecated_variable_name => $new_variable_name) {
  487. // Check if this variable is stored in the db and if so rename it.
  488. $value = variable_get($deprecated_variable_name);
  489. if ($value !== NULL) {
  490. variable_set($new_variable_name, $value);
  491. variable_del($deprecated_variable_name);
  492. }
  493. }
  494. }
  495. /**
  496. * Convert locale blocks to language blocks.
  497. */
  498. function locale_update_8009() {
  499. $block_tables = array('block', 'block_node_type', 'block_role');
  500. foreach ($block_tables as $table) {
  501. db_update($table)
  502. ->fields(array('module' => 'language'))
  503. ->condition('module', 'locale')
  504. ->execute();
  505. }
  506. }
  507. /**
  508. * @} End of "addtogroup updates-7.x-to-8.x"
  509. * The next series of updates should start at 9000.
  510. */
Login or register to post comments