1<?php 2 3/** 4 * @file 5 * Install, update, and uninstall functions for the Locale module. 6 */ 7 8use Drupal\Core\File\Exception\FileException; 9use Drupal\Core\File\FileSystemInterface; 10use Drupal\Core\Link; 11use Drupal\Core\Url; 12 13/** 14 * Implements hook_install(). 15 */ 16function locale_install() { 17 // Create the interface translations directory and ensure it's writable. 18 if (!$directory = \Drupal::config('locale.settings')->get('translation.path')) { 19 $site_path = \Drupal::service('site.path'); 20 $directory = $site_path . '/files/translations'; 21 \Drupal::configFactory()->getEditable('locale.settings')->set('translation.path', $directory)->save(); 22 } 23 \Drupal::service('file_system')->prepareDirectory($directory, FileSystemInterface::CREATE_DIRECTORY | FileSystemInterface::MODIFY_PERMISSIONS); 24} 25 26/** 27 * Implements hook_uninstall(). 28 */ 29function locale_uninstall() { 30 $config = \Drupal::config('locale.settings'); 31 // Delete all JavaScript translation files. 32 $locale_js_directory = 'public://' . $config->get('javascript.directory'); 33 34 if (is_dir($locale_js_directory)) { 35 $locale_javascripts = \Drupal::state()->get('locale.translation.javascript') ?: []; 36 /** @var \Drupal\Core\File\FileSystemInterface $file_system */ 37 $file_system = \Drupal::service('file_system'); 38 foreach ($locale_javascripts as $langcode => $file_suffix) { 39 if (!empty($file_suffix)) { 40 try { 41 $file_system->delete($locale_js_directory . '/' . $langcode . '_' . $file_suffix . '.js'); 42 } 43 catch (FileException $e) { 44 // Ignore and continue. 45 } 46 } 47 } 48 // Delete the JavaScript translations directory if empty. 49 if (is_dir($locale_js_directory)) { 50 if (!$file_system->scanDirectory($locale_js_directory, '/.*/')) { 51 $file_system->rmdir($locale_js_directory); 52 } 53 } 54 } 55 56 // Clear variables. 57 \Drupal::state()->delete('system.javascript_parsed'); 58 \Drupal::state()->delete('locale.translation.plurals'); 59 \Drupal::state()->delete('locale.translation.javascript'); 60} 61 62/** 63 * Implements hook_schema(). 64 */ 65function locale_schema() { 66 $schema['locales_source'] = [ 67 'description' => 'List of English source strings.', 68 'fields' => [ 69 'lid' => [ 70 'type' => 'serial', 71 'not null' => TRUE, 72 'description' => 'Unique identifier of this string.', 73 ], 74 'source' => [ 75 'type' => 'text', 76 'mysql_type' => 'blob', 77 'not null' => TRUE, 78 'description' => 'The original string in English.', 79 ], 80 'context' => [ 81 'type' => 'varchar_ascii', 82 'length' => 255, 83 'not null' => TRUE, 84 'default' => '', 85 'description' => 'The context this string applies to.', 86 ], 87 'version' => [ 88 'type' => 'varchar_ascii', 89 'length' => 20, 90 'not null' => TRUE, 91 'default' => 'none', 92 'description' => 'Version of Drupal where the string was last used (for locales optimization).', 93 ], 94 ], 95 'primary key' => ['lid'], 96 'indexes' => [ 97 'source_context' => [['source', 30], 'context'], 98 ], 99 ]; 100 101 $schema['locales_target'] = [ 102 'description' => 'Stores translated versions of strings.', 103 'fields' => [ 104 'lid' => [ 105 'type' => 'int', 106 'not null' => TRUE, 107 'default' => 0, 108 'description' => 'Source string ID. References {locales_source}.lid.', 109 ], 110 'translation' => [ 111 'type' => 'text', 112 'mysql_type' => 'blob', 113 'not null' => TRUE, 114 'description' => 'Translation string value in this language.', 115 ], 116 'language' => [ 117 'type' => 'varchar_ascii', 118 'length' => 12, 119 'not null' => TRUE, 120 'default' => '', 121 'description' => 'Language code. References {language}.langcode.', 122 ], 123 'customized' => [ 124 'type' => 'int', 125 'not null' => TRUE, 126 // LOCALE_NOT_CUSTOMIZED 127 'default' => 0, 128 'description' => 'Boolean indicating whether the translation is custom to this site.', 129 ], 130 ], 131 'primary key' => ['language', 'lid'], 132 'foreign keys' => [ 133 'locales_source' => [ 134 'table' => 'locales_source', 135 'columns' => ['lid' => 'lid'], 136 ], 137 ], 138 'indexes' => [ 139 'lid' => ['lid'], 140 ], 141 ]; 142 143 $schema['locales_location'] = [ 144 'description' => 'Location information for source strings.', 145 'fields' => [ 146 'lid' => [ 147 'type' => 'serial', 148 'not null' => TRUE, 149 'description' => 'Unique identifier of this location.', 150 ], 151 'sid' => [ 152 'type' => 'int', 153 'not null' => TRUE, 154 'description' => 'Unique identifier of this string.', 155 ], 156 'type' => [ 157 'type' => 'varchar_ascii', 158 'length' => 50, 159 'not null' => TRUE, 160 'default' => '', 161 'description' => 'The location type (file, config, path, etc).', 162 ], 163 'name' => [ 164 'type' => 'varchar', 165 'length' => 255, 166 'not null' => TRUE, 167 'default' => '', 168 'description' => 'Type dependent location information (file name, path, etc).', 169 ], 170 'version' => [ 171 'type' => 'varchar_ascii', 172 'length' => 20, 173 'not null' => TRUE, 174 'default' => 'none', 175 'description' => 'Version of Drupal where the location was found.', 176 ], 177 ], 178 'primary key' => ['lid'], 179 'foreign keys' => [ 180 'locales_source' => [ 181 'table' => 'locales_source', 182 'columns' => ['sid' => 'lid'], 183 ], 184 ], 185 'indexes' => [ 186 'string_id' => ['sid'], 187 'string_type' => ['sid', 'type'], 188 ], 189 ]; 190 191 $schema['locale_file'] = [ 192 'description' => 'File import status information for interface translation files.', 193 'fields' => [ 194 'project' => [ 195 'type' => 'varchar_ascii', 196 'length' => '255', 197 'not null' => TRUE, 198 'default' => '', 199 'description' => 'A unique short name to identify the project the file belongs to.', 200 ], 201 'langcode' => [ 202 'type' => 'varchar_ascii', 203 'length' => '12', 204 'not null' => TRUE, 205 'default' => '', 206 'description' => 'Language code of this translation. References {language}.langcode.', 207 ], 208 'filename' => [ 209 'type' => 'varchar', 210 'length' => 255, 211 'not null' => TRUE, 212 'default' => '', 213 'description' => 'Filename of the imported file.', 214 ], 215 'version' => [ 216 'type' => 'varchar', 217 'length' => '128', 218 'not null' => TRUE, 219 'default' => '', 220 'description' => 'Version tag of the imported file.', 221 ], 222 'uri' => [ 223 'type' => 'varchar', 224 'length' => 255, 225 'not null' => TRUE, 226 'default' => '', 227 'description' => 'URI of the remote file, the resulting local file or the locally imported file.', 228 ], 229 'timestamp' => [ 230 'type' => 'int', 231 'not null' => FALSE, 232 'default' => 0, 233 'description' => 'Unix timestamp of the imported file.', 234 ], 235 'last_checked' => [ 236 'type' => 'int', 237 'not null' => FALSE, 238 'default' => 0, 239 'description' => 'Unix timestamp of the last time this translation was confirmed to be the most recent release available.', 240 ], 241 ], 242 'primary key' => ['project', 'langcode'], 243 ]; 244 return $schema; 245} 246 247/** 248 * Implements hook_requirements(). 249 */ 250function locale_requirements($phase) { 251 $requirements = []; 252 if ($phase == 'runtime') { 253 $available_updates = []; 254 $untranslated = []; 255 $languages = locale_translatable_language_list(); 256 257 if ($languages) { 258 // Determine the status of the translation updates per language. 259 $status = locale_translation_get_status(); 260 if ($status) { 261 foreach ($status as $project) { 262 foreach ($project as $langcode => $project_info) { 263 if (empty($project_info->type)) { 264 $untranslated[$langcode] = $languages[$langcode]->getName(); 265 } 266 elseif ($project_info->type == LOCALE_TRANSLATION_LOCAL || $project_info->type == LOCALE_TRANSLATION_REMOTE) { 267 $available_updates[$langcode] = $languages[$langcode]->getName(); 268 } 269 } 270 } 271 272 if ($available_updates || $untranslated) { 273 if ($available_updates) { 274 $requirements['locale_translation'] = [ 275 'title' => t('Translation update status'), 276 'value' => Link::fromTextAndUrl(t('Updates available'), Url::fromRoute('locale.translate_status'))->toString(), 277 'severity' => REQUIREMENT_WARNING, 278 'description' => t('Updates available for: @languages. See the <a href=":updates">Available translation updates</a> page for more information.', ['@languages' => implode(', ', $available_updates), ':updates' => Url::fromRoute('locale.translate_status')->toString()]), 279 ]; 280 } 281 else { 282 $requirements['locale_translation'] = [ 283 'title' => t('Translation update status'), 284 'value' => t('Missing translations'), 285 'severity' => REQUIREMENT_INFO, 286 'description' => t('Missing translations for: @languages. See the <a href=":updates">Available translation updates</a> page for more information.', ['@languages' => implode(', ', $untranslated), ':updates' => Url::fromRoute('locale.translate_status')->toString()]), 287 ]; 288 } 289 } 290 else { 291 $requirements['locale_translation'] = [ 292 'title' => t('Translation update status'), 293 'value' => t('Up to date'), 294 'severity' => REQUIREMENT_OK, 295 ]; 296 } 297 } 298 else { 299 $requirements['locale_translation'] = [ 300 'title' => t('Translation update status'), 301 'value' => Link::fromTextAndUrl(t('Can not determine status'), Url::fromRoute('locale.translate_status'))->toString(), 302 'severity' => REQUIREMENT_WARNING, 303 'description' => t('No translation status is available. See the <a href=":updates">Available translation updates</a> page for more information.', [':updates' => Url::fromRoute('locale.translate_status')->toString()]), 304 ]; 305 } 306 } 307 } 308 return $requirements; 309} 310 311/** 312 * Delete translation status data in state. 313 */ 314function locale_update_8300() { 315 // Delete the old translation status data, it will be rebuilt and stored in 316 // the new key value collection. 317 \Drupal::state()->delete('locale.translation_status'); 318} 319 320/** 321 * Update default server pattern value to use https. 322 */ 323function locale_update_8500() { 324 $update_url = \Drupal::config('locale.settings')->get('translation.default_server_pattern'); 325 if ($update_url == 'http://ftp.drupal.org/files/translations/%core/%project/%project-%version.%language.po') { 326 \Drupal::configFactory()->getEditable('locale.settings') 327 ->set('translation.default_server_pattern', 'https://ftp.drupal.org/files/translations/%core/%project/%project-%version.%language.po') 328 ->save(); 329 } 330} 331 332/** 333 * Clear Locale project storage to use new 'all' instead of 8.x in URLs. 334 */ 335function locale_update_8800() { 336 \Drupal::service('locale.project')->deleteAll(); 337} 338