_boinctranslate_locale_import_read_po()   F
last analyzed

Complexity

Conditions 40
Paths 114

Size

Total Lines 248
Code Lines 191

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 40
eloc 191
nc 114
nop 5
dl 0
loc 248
rs 3.24
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
// $id$
3
4
/**
5
 * Functions that are shared amongst files and dependent modules go
6
 * here to keep the clutter down in the main module file.
7
 */
8
9
/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *
10
 * Page callbacks from hook_menu()
11
 *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  */
12
13
/**
14
 *
15
 */
16
function boinctranslate_initialize_languages() {
17
18
  require_once(getcwd() . '/includes/locale.inc');
19
20
  $api_base_url = 'https://www.transifex.com/api/2';
21
  $project_name = variable_get(
22
    'boinc_translate_transifex_project_name', ''
23
  );
24
  $operations = array();
25
26
  if ($project_name) {
27
    // Get all languages configured for this project at Transifex
28
    $path = "project/{$project_name}/languages";
29
    $response = boinctranslate_transifex_request($path);
30
31
    if ($response == '404 NOT FOUND') {
32
      drupal_set_message(
33
        t('Unable to get languages for %project.',
34
          array(
35
            '%project' => $project_name,
36
          )
37
        ), 'warning'
38
      );
39
    }
40
    elseif ($response) {
41
      if (is_array($response)) {
42
43
        $installed_languages = language_list();
44
        $available_languages = _locale_get_predefined_list();
45
        $transifex_languages = array();
46
        $disabled_languages = array();
47
        $process_batches = FALSE;
48
49
        // Set up Transifex languages in Drupal
50
        foreach ($response as $language) {
51
          $posix_code = $language['language_code'];
52
          $rfc_code = strtolower(str_replace('_', '-', $posix_code));
53
          $transifex_languages[$rfc_code] = $language;
54
          if (!isset($installed_languages[$rfc_code])) {
55
            // See if this language can be installed from a predefined list
56
            if (isset($available_languages[$rfc_code])) {
57
              locale_add_language(
58
                $rfc_code,
59
                NULL,
60
                NULL,
61
                NULL,
62
                NULL,
63
                NULL,
64
                FALSE
65
              );
66
              drupal_set_message(
67
                'Added predefined language: '.$available_languages[$rfc_code][0]
68
              );
69
              db_query("UPDATE {languages} SET enabled = 1 WHERE language = '%s'", $rfc_code);
70
            }
71
            else {
72
              // Retrieve language details from Transifex
73
              $path = "language/{$posix_code}";
74
              $response = boinctranslate_transifex_request($path);
75
76
              if ($response == '404 NOT FOUND') {
77
                drupal_set_message(
78
                  t('Unable to get details for language %code.',
79
                    array(
80
                      '%code' => $posix_code,
81
                    )
82
                  ), 'warning'
83
                );
84
              }
85
              elseif ($response) {
86
                if (!empty($response['name'])) {
87
                  // Add a custom language to Drupal and enable
88
                  locale_add_language(
89
                    $rfc_code,
90
                    $response['name'],
91
                    $response['name'],
92
                    $response['rtl'],
93
                    NULL,
94
                    NULL,
95
                    TRUE
96
                  );
97
                  drupal_set_message(
98
                    'Added new language: '.$response['name']
99
                  );
100
                }
101
                else {
102
                  $variables = array(
103
                    '%code' => $posix_code,
104
                  );
105
                  drupal_set_message(
106
                    t('Unable to get details for language %code.', $variables),
107
                    'error'
108
                  );
109
                  watchdog(
110
                    'boinctranslate',
111
                    'Unable to get details for language %code.',
112
                    $variables,
113
                    WATCHDOG_ERROR
114
                  );
115
                }
116
              }
117
              else {
118
               $variables = array(
119
                  '%code' => $posix_code,
120
                );
121
                drupal_set_message(
122
                  t('Invalid response while getting details for language %code.', $variables),
123
                  'error'
124
                );
125
                watchdog(
126
                  'boinctranslate',
127
                  'Invalid response while getting details for language %code.',
128
                  $variables,
129
                  WATCHDOG_ERROR
130
                );
131
              }
132
            }
133
            // Import any language files for the newly added language
134
            if ($batch = locale_batch_by_language($rfc_code, '_locale_batch_language_finished')) {
135
              $operations = array_merge($operations, $batch['operations']);
136
              $process_batches = TRUE;
137
            }
138
          }
139
        }
140
        drupal_set_message('Finished installing official BOINC languages.');
141
        // Disable languages that are not in Transifex
142
        foreach ($installed_languages as $langcode => $language) {
143
          if (!isset($transifex_languages[$langcode])) {
144
            $disabled_languages[$langcode] = $langcode;
145
            db_query("UPDATE {languages} SET enabled = 0 WHERE language = '%s'", $langcode);
146
          }
147
        }
148
        if ($disabled_languages) {
149
          drupal_set_message('The following languages were not found in Transifex and were disabled: ' . implode(' ', $disabled_languages));
150
        }
151
        if ($process_batches) {
152
          $batch = array(
153
            'operations' => $operations,
154
          );
155
          batch_set($batch);
156
          batch_process('admin/boinc/translation');
157
        }
158
      }
159
      else {
160
        $variables = array(
161
          '%project' => $project_name,
162
        );
163
        drupal_set_message(
164
          t('No languages found for %project. (Does the configured account have sufficient privileges at Transifex?)', $variables),
165
          'error'
166
        );
167
        watchdog(
168
          'boinctranslate',
169
          'No languages found for %project. (Does the configured account have sufficient privileges at Transifex?)',
170
          $variables,
171
          WATCHDOG_ERROR
172
        );
173
      }
174
    }
175
    else {
176
     $variables = array(
177
        '%project' => $project_name,
178
      );
179
      drupal_set_message(
180
        t('Invalid response while getting languages for %project.', $variables),
181
        'error'
182
      );
183
      watchdog(
184
        'boinctranslate',
185
        'Invalid response while getting languages for %project.',
186
        $variables,
187
        WATCHDOG_ERROR
188
      );
189
    }
190
  }
191
  drupal_goto('admin/boinc/translation');
192
}
193
194
/**
195
 *
196
 */
197
function boinctranslate_export_translations() {
198
  require_once(getcwd() . '/includes/locale.inc');
199
  $project_name = variable_get(
200
    'boinc_translate_transifex_project_name', ''
201
  );
202
  // Get resource names from local config
203
  $resource_config = (variable_get(
204
    'boinc_translate_transifex_project_resources', ''
205
  ));
206
  $resource_names = boinctranslate_parse_resources($resource_config);
207
  $primary_resource = reset($resource_names);
208
209
  if ($project_name AND $primary_resource) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
Coding Style introduced by
As per coding-style, PHP keywords should be in lowercase; expected and, but found AND.
Loading history...
210
    // Create or update the translation source, if needed
211
    $source_exists = FALSE;
212
    $path = "project/{$project_name}/resources";
213
    $resources = boinctranslate_transifex_request($path);
214
    if ($resources AND is_array($resources)) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
Coding Style introduced by
As per coding-style, PHP keywords should be in lowercase; expected and, but found AND.
Loading history...
215
      foreach ($resources as $resource) {
216
        if ($resource['slug'] == $primary_resource) {
217
          $source_exists = TRUE;
218
          break;
219
        }
220
      }
221
      if (!$source_exists) {
222
        // Create the source
223
        $path = "project/{$project_name}/resources";
224
        $post = array(
225
          'slug' => $primary_resource,
226
          'name' => 'Drupal-Project',
227
          'i18n_type' => 'PO',
228
          'category' => 'Drupal',
229
          'content' => boinctranslate_get_po('en', 'project'),
230
        );
231
        $result = boinctranslate_transifex_request($path, $post);
232
      }
233
      else {
234
        // Update the source
235
        $path = "project/{$project_name}/resource/{$primary_resource}/content";
236
        $post = array(
237
          'content' => boinctranslate_get_po('en', 'project')
238
        );
239
        $result = boinctranslate_transifex_request($path, $post, TRUE, TRUE);
240
      }
241
    }
242
243
    if (is_array($result) OR substr($result, 0, 6) != 'ERROR:') {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $result does not seem to be defined for all execution paths leading up to this point.
Loading history...
Comprehensibility Best Practice introduced by
Using logical operators such as or instead of || is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
Coding Style introduced by
As per coding-style, PHP keywords should be in lowercase; expected or, but found OR.
Loading history...
244
      $enabled_languages = locale_language_list();
245
      if ($source_exists) {
246
        drupal_set_message('Updated source translation strings at Transifex');
247
      }
248
      else {
249
        drupal_set_message('Established new translation resource at Transifex');
250
      }
251
      // Try to export translations for all enabled languages
252
      foreach ($enabled_languages as $langcode => $language_name) {
253
        if ($langcode == 'en') {
254
          continue;
255
        }
256
        $po_file = boinctranslate_get_po($langcode, 'project');
257
        if ($po_file) {
258
          $path = "project/{$project_name}/resource/{$primary_resource}/translation/{$langcode}";
259
          $post = array(
260
            'content' => $po_file,
261
          );
262
          $result = boinctranslate_transifex_request($path, $post, TRUE, TRUE);
263
          if (!is_array($result)
264
          AND substr($result, 0, 6) == 'ERROR:') {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
Coding Style introduced by
As per coding-style, PHP keywords should be in lowercase; expected and, but found AND.
Loading history...
Bug introduced by
It seems like $result can also be of type null; however, parameter $string of substr() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

264
          AND substr(/** @scrutinizer ignore-type */ $result, 0, 6) == 'ERROR:') {
Loading history...
265
            drupal_set_message(
266
              "Unable to update {$language_name} translations: {$result}",
267
              'warning'
268
            );
269
          }
270
          else {
271
            drupal_set_message("Updated {$language_name} translations");
272
            //drupal_set_message('DEBUG: <pre>'.print_r($result,1).'</pre>');
273
          }
274
        }
275
        else {
276
          drupal_set_message("No translations to export for {$language_name}");
277
        }
278
      }
279
    }
280
    else {
281
      drupal_set_message(
282
        "Unable to update the translation source: {$result}",
283
        'warning'
284
      );
285
    }
286
  }
287
  else {
288
    drupal_set_message(
289
      'Failed to export translations: Transifex settings are not intiailized.',
290
      'error'
291
    );
292
  }
293
  drupal_goto('admin/boinc/translation');
294
}
295
296
/**
297
 *
298
 */
299
function boinctranslate_update_official_boinc_translations() {
300
  require_once(getcwd() . '/includes/locale.inc');
301
  $project_name = variable_get(
302
    'boinc_translate_transifex_standard_name', ''
303
  );
304
  $drupal_resource = variable_get(
305
    'boinc_translate_transifex_boinc_drupal_resource', ''
306
  );
307
308
  if ($project_name AND $drupal_resource) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
Coding Style introduced by
As per coding-style, PHP keywords should be in lowercase; expected and, but found AND.
Loading history...
309
    // Create or update the translation source, if needed
310
    $source_exists = FALSE;
311
    $path = "project/{$project_name}/resources";
312
    $resources = boinctranslate_transifex_request($path);
313
    if ($resources AND is_array($resources)) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
Coding Style introduced by
As per coding-style, PHP keywords should be in lowercase; expected and, but found AND.
Loading history...
314
      foreach ($resources as $resource) {
315
        if ($resource['slug'] == $drupal_resource) {
316
          $source_exists = TRUE;
317
          break;
318
        }
319
      }
320
    }
321
322
    if ($source_exists) {
323
      $enabled_languages = locale_language_list();
324
      // Try to export translations for all enabled languages
325
      foreach ($enabled_languages as $langcode => $language_name) {
326
        if ($langcode == 'en') {
327
          continue;
328
        }
329
        $po_file = boinctranslate_get_po($langcode, 'boinc');
330
        if ($po_file) {
331
          $path = "project/{$project_name}/resource/{$drupal_resource}/translation/{$langcode}";
332
          $post = array(
333
            'content' => $po_file,
334
          );
335
          $result = boinctranslate_transifex_request($path, $post, TRUE, TRUE);
336
337
          if (!is_array($result)) {
338
            if (substr($result, 0, 6) == 'ERROR:') {
0 ignored issues
show
Bug introduced by
It seems like $result can also be of type null; however, parameter $string of substr() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

338
            if (substr(/** @scrutinizer ignore-type */ $result, 0, 6) == 'ERROR:') {
Loading history...
339
              drupal_set_message(
340
                "Unable to update {$language_name} official BOINC translations: {$result}",
341
                'warning'
342
              );
343
            }
344
            elseif ($result == '401 UNAUTHORIZED') {
345
              drupal_set_message(
346
                'Not authorized to update official BOINC translations',
347
                'warning'
348
              );
349
              break;
350
            }
351
            elseif ($result == 'success') {
352
              drupal_set_message("Updated {$language_name} official BOINC translations");
353
            }
354
            else {
355
              drupal_set_message(
356
                "Unexpected response for {$language_name}: {$result}",
357
                'warning'
358
              );
359
            }
360
          }
361
          else {
362
            drupal_set_message("Updated {$language_name} official BOINC translations");
363
            //drupal_set_message('DEBUG: <pre>'.print_r($result,1).'</pre>');
364
          }
365
        }
366
        else {
367
          drupal_set_message("No official BOINC translations to export for {$language_name}");
368
        }
369
      }
370
    }
371
    else {
372
      drupal_set_message(
373
        "The {$drupal_resource} resource does not exist in the {$project_name} project at Transifex",
374
        'warning'
375
      );
376
    }
377
  }
378
  else {
379
    drupal_set_message(
380
      'Failed to export official BOINC translations: Transifex settings are not intiailized.',
381
      'error'
382
    );
383
  }
384
  drupal_goto('admin/boinc/translation');
385
}
386
387
/**
388
 *
389
 */
390
function boinctranslate_download_pot($type = 'boinc') {
391
  $po = boinctranslate_get_po(NULL, $type);
392
  _locale_export_po(NULL, $po);
393
}
394
395
/**
396
 *
397
 */
398
function boinctranslate_transifex_request($path, $post = NULL, $json = TRUE, $use_put = FALSE, $username = '', $password = '') {
399
  $debug_mode = variable_get('boinc_debug_mode', 0);
400
401
  // Transifex details
402
  $api_base_url = 'https://www.transifex.com/api/2';
403
  if (!$username) $username = variable_get('boinc_translate_transifex_user', '');
404
  if (!$password) $password = variable_get('boinc_translate_transifex_pass', '');
405
406
  $url = "{$api_base_url}/{$path}";
407
  $headers = array(
408
    'Authorization' => 'Basic ' . base64_encode($username . ":" . $password),
409
  );
410
  $data = NULL;
411
412
  if ($post) {
413
    if ($json) {
414
      $headers['Content-Type'] = 'application/json';
415
      $data = json_encode($post);
416
    }
417
    else {
418
      $data = drupal_query_string_encode($post);
419
    }
420
    $method = ($use_put) ? 'PUT' : 'POST';
421
  }
422
  else {
423
    $method = 'GET';
424
  }
425
426
  $response = drupal_http_request($url, $headers, $method, $data, 1, 10);
427
428
  switch ($response->code) {
429
  case 200:
430
  case 304:
431
    if ($json) {
432
      // Process as JSON
433
      return json_decode($response->data, TRUE);
434
    }
435
    else {
436
      return (string) $response->data;
437
    }
438
    break;
439
  case 404:
440
    return '404 NOT FOUND';
441
  case 401:
442
    return '401 UNAUTHORIZED';
443
  case 400:
444
    if ($debug_mode) watchdog('boinctranslate', "The following response was received when trying to communicate with the Transifex system: \n{$response}", array(), WATCHDOG_WARNING);
445
    return "ERROR: {$response->data}";
446
  case 405:
447
    if ($debug_mode) watchdog('boinctranslate', "The following response was received when trying to communicate with the Transifex system: \n{$response}", array(), WATCHDOG_WARNING);
448
    return "ERROR: User not allowed to perform this action";
449
  }
450
451
  return NULL;
452
}
453
454
/**
455
 *
456
 */
457
function boinctranslate_get_po($langcode, $type = 'standard') {
458
459
  require_once(getcwd() . '/includes/locale.inc');
460
461
  $all_languages = language_list();
462
  $language = $langcode ? $all_languages[$langcode] : NULL;
463
  $textgroups = array();
464
  $strings = array();
465
466
  switch ($type) {
467
  case 'standard':
468
    $textgroups = array(
469
      'default',
470
      'taxonomy',
471
      'views',
472
    );
473
    break;
474
  case 'boinc':
475
    $textgroups = array(
476
      'boinc',
477
    );
478
    break;
479
  case 'project':
480
    $textgroups = array(
481
      'blocks',
482
      'menu',
483
      'project',
484
    );
485
    break;
486
  default:
0 ignored issues
show
Coding Style introduced by
DEFAULT keyword must be indented 4 spaces from SWITCH keyword
Loading history...
Coding Style introduced by
DEFAULT case must have a breaking statement
Loading history...
487
  }
488
489
  // Merge textgroup strings together for export as one file
490
  foreach ($textgroups as $textgroup) {
491
    $strings += _locale_export_get_strings($language, $textgroup);
492
  }
493
  ksort($strings);
494
  foreach ($strings as $id => $string) {
495
    // Set the string context
496
    $strings[$id]['context'] = trim($string['comment']);
497
  }
498
  if ($langcode AND $langcode != 'en') {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
Coding Style introduced by
As per coding-style, PHP keywords should be in lowercase; expected and, but found AND.
Loading history...
499
    // If not the source language, remove untranslated strings from the ouput
500
    foreach ($strings as $i => $string) {
501
      if (!$string['translation']) {
502
        unset($strings[$i]);
503
      }
504
    }
505
  }
506
  if ($strings) {
507
    return boinctranslate_export_po_generate($language, $strings, NULL, $type);
508
  }
509
510
  return NULL;
511
}
512
513
/**
514
 *
515
 */
516
function boinctranslate_export_po_generate($language = NULL, $strings = array(), $header = NULL, $type = NULL) {
517
518
  require_once(getcwd() . '/includes/locale.inc');
519
  global $user;
520
521
  // unset $language to indicate template creation
522
  if (isset($language) && $language->language == "en") {
523
    $language = NULL;
524
  }
525
526
  if (!isset($header)) {
527
    if (isset($type) && $type == "project") {
528
      $header = "# ".variable_get('site_name', 'Drupal-BOINC')." drupal localization template\n";
529
      $header .= "# Copyright (C) ".date("Y")." ".variable_get('site_name', 'Drupal-BOINC')."\n";
530
    } else {
531
      $header = "# BOINC drupal localization template\n";
532
      $header .= "# Copyright (C) ".date("Y")." University of California\n";
533
    }
534
    $header .= '# Generated by ' . $user->name . ' <' . $user->mail . ">\n";
535
    $header .= "#\n";
536
    $header .= "# This file is distributed under the same license as BOINC.\n";
537
    $header .= "#\n";
538
    $header .= "msgid \"\"\n";
539
    $header .= "msgstr \"\"\n";
540
    if (isset($type) && $type == "project") {
541
      $header .= "\"Project-Id-Version: ".variable_get('site_name', 'Drupal-BOINC')." ".date("Y-m-d-H:iO")."\\n\"\n";
542
    } else {
543
      $header .= "\"Project-Id-Version: BOINC unknown\\n\"\n"; // TODO: add SHA1 of source checkout here
0 ignored issues
show
Coding Style Best Practice introduced by
Comments for TODO tasks are often forgotten in the code; it might be better to use a dedicated issue tracker.
Loading history...
544
    }
545
    $header .= "\"Report-Msgid-Bugs-To: BOINC translation team <[email protected]>\\n\"\n";
546
    $header .= "\"POT-Creation-Date: " . date("Y-m-d H:iO") . "\\n\"\n";
547
    if (isset($language)) {
548
      $header .= "\"PO-Revision-Date: " . date("Y-m-d H:iO") . "\\n\"\n";
549
    }
550
    $header .= "\"Last-Translator: Generated automatically from Drupal translate interface\\n\"\n";
551
    $header .= "\"MIME-Version: 1.0\\n\"\n";
552
    $header .= "\"Content-Type: text/plain; charset=utf-8\\n\"\n";
553
    $header .= "\"Content-Transfer-Encoding: 8bit\\n\"\n";
554
    if (isset($language)) {
555
      $header .= "\"Language: ".$language->language."\\n\"";
556
      if ($language->formula && $language->plurals) {
557
        $header .= "\"Plural-Forms: nplurals=" . $language->plurals . "; plural=" . strtr($language->formula, array('$' => '')) . ";\\n\"\n";
558
      }
559
    }
560
    $header .= "\"X-Poedit-SourceCharset: utf-8\\n\"\n";
561
  }
562
563
  $output = $header . "\n";
564
565
  foreach ($strings as $lid => $string) {
566
    // Only process non-children, children are output below their parent.
567
    if (!isset($string['child'])) {
568
      if ($string['comment']) {
569
        $output .= '#: ' . $string['comment'] . "\n";
570
      }
571
      if ($string['context']) {
572
        $output .= 'msgctxt "' . $string['context'] . "\"\n";
573
      }
574
      $output .= 'msgid ' . _locale_export_string($string['source']);
575
      if (!empty($string['plural'])) {
576
        $plural = $string['plural'];
577
        $output .= 'msgid_plural ' . _locale_export_string($strings[$plural]['source']);
578
        if (isset($language)) {
579
          $translation = $string['translation'];
580
          for ($i = 0; $i < $language->plurals; $i++) {
581
            $output .= 'msgstr[' . $i . '] ' . _locale_export_string($translation);
582
            if ($plural) {
583
              $translation = _locale_export_remove_plural($strings[$plural]['translation']);
584
              $plural = isset($strings[$plural]['plural']) ? $strings[$plural]['plural'] : 0;
585
            }
586
            else {
587
              $translation = '';
588
            }
589
          }
590
        }
591
        else {
592
          $output .= 'msgstr[0] ""' . "\n";
593
          $output .= 'msgstr[1] ""' . "\n";
594
        }
595
      }
596
      else {
597
        $output .= 'msgstr ' . _locale_export_string($string['translation']);
598
      }
599
      $output .= "\n";
600
    }
601
  }
602
  return $output;
603
}
604
605
/**
606
 *
607
 */
608
function boinctranslate_refresh_translations() {
609
  require_once(getcwd() . '/includes/locale.inc');
610
  $errors = array();
611
  $languages = locale_language_list();
612
  $translation_resources = array();
613
  $operations = array();
614
  $debug_mode = variable_get('boinc_debug_mode', 0);
615
616
  $boinc_name = variable_get(
617
    'boinc_translate_transifex_standard_name', ''
618
  );
619
  $boinc_resources = boinctranslate_parse_resources(
620
    variable_get('boinc_translate_transifex_standard_resources', array())
621
  );
622
  // Add the Official BOINC resource to the list of BOINC resources;
623
  // The official resource overrides any additional resources provided, so it
624
  // should be added to the end so as to be processed last
625
  $drupal_resource = variable_get(
626
    'boinc_translate_transifex_boinc_drupal_resource', ''
627
  );
628
  $boinc_resources[] = $drupal_resource;
629
  if ($boinc_name AND $boinc_resources) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
Coding Style introduced by
As per coding-style, PHP keywords should be in lowercase; expected and, but found AND.
Loading history...
630
    $translation_resources[$boinc_name] = array(
631
      'resources' => $boinc_resources,
632
      'textgroups' => array(
633
        'boinc',
634
        'default',
635
        'taxonomy',
636
        'views',
637
      ),
638
    );
639
  }
640
  $project_name = variable_get(
641
    'boinc_translate_transifex_project_name', ''
642
  );
643
  $project_resources = boinctranslate_parse_resources(
644
    variable_get('boinc_translate_transifex_project_resources', array())
645
  );
646
  if ($project_name AND $project_resources) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
Coding Style introduced by
As per coding-style, PHP keywords should be in lowercase; expected and, but found AND.
Loading history...
647
    $translation_resources[$project_name] = array(
648
      'resources' => $project_resources,
649
      'textgroups' => array(
650
        'blocks',
651
        'menu',
652
        'project',
653
      ),
654
    );
655
    // Be sure any strings from the override file are added to the boinc group
656
    $override_file = './' . drupal_get_path('module', 'boinctranslate') . '/includes/other-boinc-translation-strings.txt';
657
    $other_strings = file($override_file);
658
    if ($other_strings) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $other_strings of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
659
      foreach ($other_strings as $string) {
660
        $string = trim($string);
661
        if ($string) {
662
          // Ignore lines starting with '#' i.e., comments.
663
          if ($string[0] === "#")
664
            continue;
665
666
          // Use '|' as delimiter to split string and context info.
667
          $line = explode("|", $string);
668
          if ($line) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $line of type string[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
669
            if (count($line)==1) {
670
              $tl0 = trim($line[0]);
671
              if ($tl0) {
672
                bts($tl0);
673
              }
674
            }
675
            elseif (count($line)>1) {
676
              $tl0 = trim($line[0]);
677
              $tl1 = trim($line[1]);
678
              if ($tl0 and $tl1) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
679
                bts($tl0, array(), NULL, $tl1);
680
              }
681
            }
682
          }// if ($line)
683
684
        }// if ($string)
685
      }// foreach
686
    }// if ($other_strings)
687
  }
688
689
  foreach ($languages as $langcode => $language) {
690
    if ($langcode == 'en') {
691
      continue;
692
    }
693
694
    $import_stats = array(
695
      'new' => 0,
696
      'updated' => 0,
697
      'deleted' => 0,
698
      'skipped' => 0,
699
    );
700
701
    foreach ($translation_resources as $project => $translation) {
702
      foreach ($translation['resources'] as $resource) {
703
704
        // Add this language to the batch operations
705
        $operations[] = array(
706
          'boinctranslate_refresh_translations_op',
707
          array(
708
            $project, $resource, $langcode, $language, $translation['textgroups'], $debug_mode
0 ignored issues
show
Coding Style introduced by
Each value in a multi-line array must be on a new line
Loading history...
Coding Style introduced by
There should be a trailing comma after the last value of an array declaration.
Loading history...
709
          ),
710
        );
711
      }
712
    }
713
    if ($batch = locale_batch_by_language($langcode)) {
714
      foreach ($batch['operations'] as $op) {
715
        $operations[] = array(
716
          'boinctranslate_refresh_translations_op',
717
          array(
718
            NULL, $op[1][0], $langcode, $language, array('default'), $debug_mode
0 ignored issues
show
Coding Style introduced by
Each value in a multi-line array must be on a new line
Loading history...
Coding Style introduced by
There should be a trailing comma after the last value of an array declaration.
Loading history...
719
          ),
720
        );
721
      }
722
    }
723
  }
724
725
  $batch = array(
726
    'operations' => $operations,
727
    'finished' => 'boinctranslate_refresh_translations_finished',
728
    'title' => t('Importing translations'),
729
    'init_message' => t('Beginning translation import...'),
730
    'progress_message' => t('Applied @current out of @total translation updates.'),
731
    'error_message' => t('Translation import has encountered an error.'),
732
  );
733
734
  batch_set($batch);
735
  batch_process();
736
}
737
738
739
/**
740
 * Batch operation for importing translations
741
 */
742
function boinctranslate_refresh_translations_op($project, $resource, $langcode, $language, $textgroups, $debug_mode, &$context) {
743
744
  require_once(getcwd() . '/includes/locale.inc');
745
746
  if ($debug_mode) {
747
    watchdog(
748
      'boinctranslate',
749
      'Checking for @language updates in @project:@resource',
750
      array('@language' => $language, '@project' => $project, '@resource' => $resource),
751
      WATCHDOG_INFO
752
    );
753
  }
754
755
  if ($project) {
756
    // Import the configured resources
757
    $success = FALSE;
758
    $message = '';
759
    $path = "project/{$project}/resource/{$resource}/translation/{$langcode}";
760
    $response = boinctranslate_transifex_request($path);
761
762
    if ($response == '404 NOT FOUND') {
763
      $message = "Project resource {$project}:{$resource} not found in {$language}.";
764
    }
765
    elseif ($response) {
766
      if (!empty($response['content'])) {
767
        $po_text = $response['content'];
768
769
        // Write the translation file to a temporary location
770
        $file = new stdClass();
771
        $file->filepath = file_save_data($po_text, NULL);
772
        $file->filename = basename($file->filepath);
773
        if (!$file->filepath) {
774
          $message = 'Unable to create temporary file in '
775
            . file_directory_temp() . " for {$language} translation "
776
            . "resource {$project}:{$resource}";
777
        }
778
779
        foreach ($textgroups as $textgroup) {
780
          // Import the translations from the file to each related textgroup
781
          if (!$results = _boinctranslate_locale_import_po($file, $langcode, LOCALE_IMPORT_OVERWRITE, $textgroup)) {
782
            $message = "The {$language} translation import of"
783
              . " {$project}:{$resource} failed.";
784
            $success = FALSE;
785
            break;
786
          }
787
          else {
788
            $success = TRUE;
789
          }
790
        }
791
      }
792
      else {
793
        $message = "Unable to read response for {$language} translation import"
794
          . " of {$project}:{$resource}.";
795
      }
796
    }
797
    else {
798
      $message = "Translation data not found in response for {$language}"
799
        . " translation import of {$project}:{$resource}.";
800
    }
801
  }
802
  else {
803
    // If project isn't specified, import as a local Drupal resource
804
    $project = 'drupal.local';
805
    $file = new stdClass();
806
    $file->filepath = $resource;
807
    $file->filename = basename($file->filepath);
808
    if (!$results = _boinctranslate_locale_import_po($file, $langcode, LOCALE_IMPORT_OVERWRITE, $textgroup)) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $textgroup does not exist. Did you maybe mean $textgroups?
Loading history...
809
      $message = "The {$language} translation import of"
810
        . " local file {$resource} failed.";
811
      $success = FALSE;
812
    }
813
    else {
814
      $success = TRUE;
815
    }
816
  }
817
818
  if ($success) {
819
    // Store some result for post-processing in the finished callback.
820
    $context['results']['success'][] = "{$langcode}:{$textgroup}";
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $textgroup does not seem to be defined for all execution paths leading up to this point.
Loading history...
821
    $message = "Imported {$language} translations in {$project}:{$resource} ({$results['new']} added, {$results['updated']} refreshed, {$results['deleted']} removed)";
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $results does not seem to be defined for all execution paths leading up to this point.
Loading history...
822
823
    if ($debug_mode) {
824
      watchdog(
825
        'boinctranslate',
826
        $message,
827
        array(),
828
        WATCHDOG_INFO
829
      );
830
    }
831
  }
832
  else {
833
    $context['results']['failure'][] = "{$langcode}:{$textgroup}";
834
    watchdog(
835
      'boinctranslate',
836
      $message,
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $message does not seem to be defined for all execution paths leading up to this point.
Loading history...
837
      array(),
838
      WATCHDOG_WARNING
839
    );
840
  }
841
842
  // Update our progress information.
843
  $context['sandbox']['progress']++;
844
  $context['sandbox']['language'] = $langcode;
845
  $context['message'] = $message;
846
847
  // Update the progress for the batch engine
848
  if ($context['sandbox']['progress'] >= $context['sandbox']['max']) {
849
    $context['finished'] = 1;
850
  }
851
  else {
852
    $context['finished'] = $context['sandbox']['progress'] / $context['sandbox']['max'];
853
  }
854
}
855
856
/**
857
 * Batch 'finished' callback
858
 */
859
function boinctranslate_refresh_translations_finished($success, $results, $operations) {
860
  if ($success) {
861
    // Let's count our successes
862
    $count = count($results['success']);
863
    $message = "Successfully completed {$count} import operations";
864
    watchdog(
865
      'boinctranslate',
866
      'Successfully completed @count import operations.',
867
      array('@count' => $count),
868
      WATCHDOG_INFO
869
    );
870
  }
871
  else {
872
    // An error occurred.
873
    // $operations contains the operations that remained unprocessed.
874
    $error_operation = reset($operations);
875
    $message = 'An error occurred while processing ' . $error_operation[0] . ' with arguments :' . print_r($error_operation[0], TRUE);
0 ignored issues
show
Bug introduced by
Are you sure print_r($error_operation[0], TRUE) of type string|true can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

875
    $message = 'An error occurred while processing ' . $error_operation[0] . ' with arguments :' . /** @scrutinizer ignore-type */ print_r($error_operation[0], TRUE);
Loading history...
876
    watchdog(
877
      'boinctranslate',
878
      $message,
879
      array(),
880
      WATCHDOG_WARNING
881
    );
882
  }
883
  drupal_set_message($message);
884
  drupal_goto('admin/boinc/translation');
885
}
886
887
/**
888
 *
889
 */
890
function _boinctranslate_locale_import_po($file, $langcode, $mode, $group = NULL) {
891
  // Try to allocate enough time to parse and import the data.
892
  if (function_exists('set_time_limit')) {
893
    @set_time_limit(240);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for set_time_limit(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

893
    /** @scrutinizer ignore-unhandled */ @set_time_limit(240);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
894
  }
895
896
  require_once(getcwd() . '/includes/locale.inc');
897
898
  // Check if we have the language already in the database.
899
  if (!db_fetch_object(db_query("SELECT language FROM {languages} WHERE language = '%s'", $langcode))) {
900
    drupal_set_message(t('The language selected for import is not supported.'), 'error');
901
    return FALSE;
902
  }
903
904
  // Get strings from file (returns on failure after a partial import, or on success)
905
  $status = _boinctranslate_locale_import_read_po('db-store', $file, $mode, $langcode, $group);
906
  if ($status === FALSE) {
0 ignored issues
show
introduced by
The condition $status === FALSE is always true.
Loading history...
907
    // Error messages are set in _locale_import_read_po().
908
    return FALSE;
909
  }
910
911
  // Get status information on import process.
912
  list($headerdone, $additions, $updates, $deletes, $skips) = _boinctranslate_locale_import_one_string('db-report');
913
914
  if (!$headerdone) {
915
    drupal_set_message(t('The translation file %filename appears to have a missing or malformed header.', array('%filename' => $file->filename)), 'error');
916
  }
917
918
  // Clear cache and force refresh of JavaScript translations.
919
  _locale_invalidate_js($langcode);
920
  cache_clear_all('locale:', 'cache', TRUE);
921
922
  // Rebuild the menu, strings may have changed.
923
  menu_rebuild();
924
925
  return array(
926
    'new' => $additions,
927
    'updated' => $updates,
928
    'deleted' => $deletes,
929
    'skipped' => $skips,
930
  );
931
}
932
933
/**
934
 *
935
 */
936
function _boinctranslate_locale_import_read_po($op, $file, $mode = NULL, $lang = NULL, $group = 'default') {
937
938
  require_once(getcwd() . '/includes/locale.inc');
939
940
  $fd = fopen($file->filepath, "rb"); // File will get closed by PHP on return
941
  if (!$fd) {
0 ignored issues
show
introduced by
$fd is of type resource, thus it always evaluated to false.
Loading history...
942
    watchdog(
943
      'boinctranslate',
944
      'The translation import for %lang failed, because %filename could not be read.',
945
      array('%lang' => $lang, '%filename' => $file->filename),
946
      WATCHDOG_WARNING
947
    );
948
    _locale_import_message('The translation import failed, because the file %filename could not be read.', $file);
949
    return FALSE;
950
  }
951
952
  $context = "COMMENT"; // Parser context: COMMENT, MSGID, MSGID_PLURAL, MSGSTR and MSGSTR_ARR
953
  $current = array(); // Current entry being read
954
  $plural = 0; // Current plural form
955
  $lineno = 0; // Current line
956
957
  while (!feof($fd)) {
958
    $line = fgets($fd, 10 * 1024); // A line should not be this long
959
    if ($lineno == 0) {
960
      // The first line might come with a UTF-8 BOM, which should be removed.
961
      $line = str_replace("\xEF\xBB\xBF", '', $line);
962
    }
963
    $lineno++;
964
    $line = trim(strtr($line, array("\\\n" => "")));
965
966
    if (!strncmp("#", $line, 1)) { // A comment
967
      if ($context == "COMMENT") { // Already in comment context: add
968
        $current["#"][] = substr($line, 1);
969
      }
970
      elseif (($context == "MSGSTR") || ($context == "MSGSTR_ARR")) { // End current entry, start a new one
971
        _boinctranslate_locale_import_one_string($op, $current, $mode, $lang, $file, $group);
972
        $current = array();
973
        $current["#"][] = substr($line, 1);
974
        $context = "COMMENT";
975
      }
976
      else { // Parse error
977
        watchdog(
978
          'boinctranslate',
979
          'The translation file %filename for %lang contains an error: "msgstr" was expected but not found on line %line.',
980
          array('%filename' => $file->filename, '%lang' => $lang, '%line' => $lineno),
981
          WATCHDOG_WARNING
982
        );
983
        _locale_import_message('The translation file %filename contains an error: "msgstr" was expected but not found on line %line.', $file, $lineno);
984
        return FALSE;
985
      }
986
    }
987
    elseif (!strncmp("msgctxt", $line, 7)) {
988
      if (($context == "MSGSTR") || ($context == "MSGSTR_ARR")) { // End current entry, start a new one
989
        _boinctranslate_locale_import_one_string($op, $current, $mode, $lang, $file, $group);
990
        $current = array();
991
      }
992
      elseif (($context == "MSGID") || ($context == "MSGCTXT")) { // Already in this context? Parse error
993
        watchdog(
994
          'boinctranslate',
995
          'The translation file %filename for %lang contains an error: "msgctxt" is unexpected on line %line.',
996
          array('%filename' => $file->filename, '%lang' => $lang, '%line' => $lineno),
997
          WATCHDOG_WARNING
998
        );
999
        _locale_import_message('The translation file %filename contains an error: "msgid" is unexpected on line %line.', $file, $lineno);
1000
        return FALSE;
1001
      }
1002
      $line = trim(substr($line, 7));
1003
      $quoted = _locale_import_parse_quoted($line);
1004
      if ($quoted === FALSE) {
1005
        watchdog(
1006
          'boinctranslate',
1007
          'The translation file %filename for language %lang contains a syntax error on line %line.',
1008
          array('%filename' => $file->filename, '%lang' => $lang, '%line' => $lineno),
1009
          WATCHDOG_WARNING
1010
        );
1011
        _locale_import_message('The translation file %filename contains a syntax error on line %line.', $file, $lineno);
1012
        return FALSE;
1013
      }
1014
      $current["msgctxt"] = $quoted;
1015
      $context = "MSGCTXT";
1016
    }
1017
    elseif (!strncmp("msgid_plural", $line, 12)) {
1018
      if ($context != "MSGID") { // Must be plural form for current entry
1019
        watchdog(
1020
          'boinctranslate',
1021
          'The translation file %filename for %lang contains an error: "msgid_plural" was expected but not found on line %line.',
1022
          array('%filename' => $file->filename, '%lang' => $lang, '%line' => $lineno),
1023
          WATCHDOG_WARNING
1024
        );
1025
        _locale_import_message('The translation file %filename contains an error: "msgid_plural" was expected but not found on line %line.', $file, $lineno);
1026
        return FALSE;
1027
      }
1028
      $line = trim(substr($line, 12));
1029
      $quoted = _locale_import_parse_quoted($line);
1030
      if ($quoted === FALSE) {
1031
        watchdog(
1032
          'boinctranslate',
1033
          'The translation file %filename for language %lang contains a syntax error on line %line.',
1034
          array('%filename' => $file->filename, '%lang' => $lang, '%line' => $lineno),
1035
          WATCHDOG_WARNING
1036
        );
1037
        _locale_import_message('The translation file %filename contains a syntax error on line %line.', $file, $lineno);
1038
        return FALSE;
1039
      }
1040
      $current["msgid"] = $current["msgid"] . "\0" . $quoted;
1041
      $context = "MSGID_PLURAL";
1042
    }
1043
    elseif (!strncmp("msgid", $line, 5)) {
1044
      if (($context == "MSGSTR") || ($context == "MSGSTR_ARR")) { // End current entry, start a new one
1045
        _boinctranslate_locale_import_one_string($op, $current, $mode, $lang, $file, $group);
1046
        $current = array();
1047
      }
1048
      elseif ($context == "MSGID") { // Already in this context? Parse error
1049
        watchdog(
1050
          'boinctranslate',
1051
          'The translation file %filename for %lang contains an error: "msgid" is unexpected on line %line.',
1052
          array('%filename' => $file->filename, '%lang' => $lang, '%line' => $lineno),
1053
          WATCHDOG_WARNING
1054
        );
1055
        _locale_import_message('The translation file %filename contains an error: "msgid" is unexpected on line %line.', $file, $lineno);
1056
        return FALSE;
1057
      }
1058
      $line = trim(substr($line, 5));
1059
      $quoted = _locale_import_parse_quoted($line);
1060
      if ($quoted === FALSE) {
1061
        watchdog(
1062
          'boinctranslate',
1063
          'The translation file %filename for language %lang contains a syntax error on line %line.',
1064
          array('%filename' => $file->filename, '%lang' => $lang, '%line' => $lineno),
1065
          WATCHDOG_WARNING
1066
        );
1067
        _locale_import_message('The translation file %filename contains a syntax error on line %line.', $file, $lineno);
1068
        return FALSE;
1069
      }
1070
      $current["msgid"] = $quoted;
1071
      $context = "MSGID";
1072
    }
1073
    elseif (!strncmp("msgstr[", $line, 7)) {
1074
      if (($context != "MSGID") && ($context != "MSGID_PLURAL") && ($context != "MSGSTR_ARR")) { // Must come after msgid, msgid_plural, or msgstr[]
1075
        watchdog(
1076
          'boinctranslate',
1077
          'The translation file %filename for %lang contains an error: "msgstr[]" is unexpected on line %line.',
1078
          array('%filename' => $file->filename, '%lang' => $lang, '%line' => $lineno),
1079
          WATCHDOG_WARNING
1080
        );
1081
        _locale_import_message('The translation file %filename contains an error: "msgstr[]" is unexpected on line %line.', $file, $lineno);
1082
        return FALSE;
1083
      }
1084
      if (strpos($line, "]") === FALSE) {
1085
        watchdog(
1086
          'boinctranslate',
1087
          'The translation file %filename for language %lang contains a syntax error on line %line.',
1088
          array('%filename' => $file->filename, '%lang' => $lang, '%line' => $lineno),
1089
          WATCHDOG_WARNING
1090
        );
1091
        _locale_import_message('The translation file %filename contains a syntax error on line %line.', $file, $lineno);
1092
        return FALSE;
1093
      }
1094
      $frombracket = strstr($line, "[");
1095
      $plural = substr($frombracket, 1, strpos($frombracket, "]") - 1);
1096
      $line = trim(strstr($line, " "));
1097
      $quoted = _locale_import_parse_quoted($line);
1098
      if ($quoted === FALSE) {
1099
        watchdog(
1100
          'boinctranslate',
1101
          'The translation file %filename for language %lang contains a syntax error on line %line.',
1102
          array('%filename' => $file->filename, '%lang' => $lang, '%line' => $lineno),
1103
          WATCHDOG_WARNING
1104
        );
1105
        _locale_import_message('The translation file %filename contains a syntax error on line %line.', $file, $lineno);
1106
        return FALSE;
1107
      }
1108
      $current["msgstr"][$plural] = $quoted;
1109
      $context = "MSGSTR_ARR";
1110
    }
1111
    elseif (!strncmp("msgstr", $line, 6)) {
1112
      if ($context != "MSGID") { // Should come just after a msgid block
1113
        watchdog(
1114
          'boinctranslate',
1115
          'The translation file %filename for %lang contains an error: "msgstr" is unexpected on line %line.',
1116
          array('%filename' => $file->filename, '%lang' => $lang, '%line' => $lineno),
1117
          WATCHDOG_WARNING
1118
        );
1119
        _locale_import_message('The translation file %filename contains an error: "msgstr" is unexpected on line %line.', $file, $lineno);
1120
        return FALSE;
1121
      }
1122
      $line = trim(substr($line, 6));
1123
      $quoted = _locale_import_parse_quoted($line);
1124
      if ($quoted === FALSE) {
1125
        watchdog(
1126
          'boinctranslate',
1127
          'The translation file %filename for language %lang contains a syntax error on line %line.',
1128
          array('%filename' => $file->filename, '%lang' => $lang, '%line' => $lineno),
1129
          WATCHDOG_WARNING
1130
        );
1131
        _locale_import_message('The translation file %filename contains a syntax error on line %line.', $file, $lineno);
1132
        return FALSE;
1133
      }
1134
      $current["msgstr"] = $quoted;
1135
      $context = "MSGSTR";
1136
    }
1137
    elseif ($line != "") {
1138
      $quoted = _locale_import_parse_quoted($line);
1139
      if ($quoted === FALSE) {
1140
        watchdog(
1141
          'boinctranslate',
1142
          'The translation file %filename for language %lang contains a syntax error on line %line.',
1143
          array('%filename' => $file->filename, '%lang' => $lang, '%line' => $lineno),
1144
          WATCHDOG_WARNING
1145
        );
1146
        _locale_import_message('The translation file %filename contains a syntax error on line %line.', $file, $lineno);
1147
        return FALSE;
1148
      }
1149
      if (($context == "MSGID") || ($context == "MSGID_PLURAL")) {
1150
        $current["msgid"] .= $quoted;
1151
      }
1152
      elseif ($context == "MSGSTR") {
1153
        $current["msgstr"] .= $quoted;
1154
      }
1155
      elseif ($context == "MSGSTR_ARR") {
1156
        $current["msgstr"][$plural] .= $quoted;
1157
      }
1158
      else {
1159
        watchdog(
1160
          'boinctranslate',
1161
          'The translation file %filename for %lang contains an error: there is an unexpected string on line %line.',
1162
          array('%filename' => $file->filename, '%lang' => $lang, '%line' => $lineno),
1163
          WATCHDOG_WARNING
1164
        );
1165
        _locale_import_message('The translation file %filename contains an error: there is an unexpected string on line %line.', $file, $lineno);
1166
        return FALSE;
1167
      }
1168
    }
1169
  }
1170
1171
  // End of PO file, flush last entry
1172
  if (($context == "MSGSTR") || ($context == "MSGSTR_ARR")) {
1173
    _boinctranslate_locale_import_one_string($op, $current, $mode, $lang, $file, $group);
1174
  }
1175
  elseif ($context != "COMMENT") {
1176
    watchdog(
1177
      'boinctranslate',
1178
      'The translation file %filename for %lang ended unexpectedly at line %line.',
1179
      array('%filename' => $file->filename, '%lang' => $lang, '%line' => $lineno),
1180
      WATCHDOG_WARNING
1181
    );
1182
    _locale_import_message('The translation file %filename ended unexpectedly at line %line.', $file, $lineno);
1183
    return FALSE;
1184
  }
1185
1186
}
1187
1188
/**
1189
 *
1190
 */
1191
function _boinctranslate_locale_import_one_string($op, $value = NULL, $mode = NULL, $lang = NULL, $file = NULL, $group = 'default') {
1192
1193
  require_once(getcwd() . '/includes/locale.inc');
1194
1195
  static $report = array(
1196
    'additions' => 0,
1197
    'updates' => 0,
1198
    'deletes' => 0,
1199
    'skips' => 0,
1200
  );
1201
  static $headerdone = FALSE;
1202
  static $strings = array();
1203
1204
  switch ($op) {
1205
    // Return stored strings
1206
    case 'mem-report':
1207
      return $strings;
1208
1209
      // Store string in memory (only supports single strings)
1210
    case 'mem-store':
1211
      $strings[$value['msgid']] = $value['msgstr'];
1212
      return;
1213
1214
      // Called at end of import to inform the user
1215
    case 'db-report':
1216
      return array(
1217
        $headerdone,
1218
        $report['additions'],
1219
        $report['updates'],
1220
        $report['deletes'],
1221
        $report['skips'],
1222
      );
1223
1224
      // Store the string we got in the database.
1225
    case 'db-store':
1226
      // We got header information.
1227
      if ($value['msgid'] == '') {
1228
        $languages = language_list();
1229
        if (($mode != LOCALE_IMPORT_KEEP) || empty($languages[$lang]->plurals)) {
1230
          // Since we only need to parse the header if we ought to update the
1231
          // plural formula, only run this if we don't need to keep existing
1232
          // data untouched or if we don't have an existing plural formula.
1233
          $header = _locale_import_parse_header($value['msgstr']);
1234
1235
          // Get and store the plural formula if available.
1236
          if (isset($header["Plural-Forms"]) && $p = _locale_import_parse_plural_forms($header["Plural-Forms"], $file->filename)) {
1237
            list($nplurals, $plural) = $p;
1238
            db_query("UPDATE {languages} SET plurals = %d, formula = '%s' WHERE language = '%s'", $nplurals, $plural, $lang);
1239
          }
1240
        }
1241
        $headerdone = TRUE;
1242
      }
1243
1244
      else {
1245
        // Some real string to import.
1246
        $comments = _locale_import_shorten_comments(empty($value['#']) ? array() : $value['#']);
1247
1248
        if (strpos($value['msgid'], "\0")) {
1249
          // This string has plural versions.
1250
          $english = explode("\0", $value['msgid'], 2);
1251
          $entries = array_keys($value['msgstr']);
1252
          for ($i = 3; $i <= count($entries); $i++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
Coding Style Performance introduced by
The use of count() inside a loop condition is not allowed; assign the return value to a variable and use the variable in the loop condition instead
Loading history...
1253
            $english[] = $english[1];
1254
          }
1255
          $translation = array_map('_locale_import_append_plural', $value['msgstr'], $entries);
1256
          $english = array_map('_locale_import_append_plural', $english, $entries);
1257
          foreach ($translation as $key => $trans) {
1258
            if ($key == 0) {
1259
              $plid = 0;
1260
            }
1261
            $plid = _boinctranslate_locale_import_one_string_db($report, $lang, $english[$key], $trans, $group, $comments, $mode, $plid, $key);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $plid seems to be defined later in this foreach loop on line 1259. Are you sure it is defined here?
Loading history...
1262
          }
1263
        }
1264
1265
        else {
1266
          // A simple string to import.
1267
          $english = $value['msgid'];
1268
          $translation = $value['msgstr'];
1269
          _boinctranslate_locale_import_one_string_db($report, $lang, $english, $translation, $group, $comments, $mode);
1270
        }
1271
      }
1272
  } // end of db-store operation
1273
}
1274
1275
/**
1276
 * Modify the _locale_import_one_string_db() function so that it does not add
1277
 * translation strings that do not exist on the site.
1278
 *
1279
 * Function will attempt t overwrite strings in textgroups other than
1280
 * 'boinc' or 'project', without using the location field as a search
1281
 * parameter. All found rows in locales_source are overwritten by the
1282
 * translations.
1283
 *
1284
 * Textgroups 'boinc' and 'project' use the location string to
1285
 * uniquely identify rows in the locales_source database.
1286
 */
1287
function _boinctranslate_locale_import_one_string_db(&$report, $langcode, $source, $translation, $textgroup, $location, $mode, $plid = NULL, $plural = NULL) {
1288
1289
  $ignoreoverwrite = FALSE;
1290
  $lid = 0;
1291
1292
  // Use different DB query depending on the textgroup.
1293
  $uselocation = array("boinc", "project");
1294
  if (in_array($textgroup, $uselocation)) {
1295
    $resource = db_query("SELECT lid FROM {locales_source} WHERE location = '%s' AND source = '%s' AND textgroup = '%s'", $location, $source, $textgroup);
1296
  }
1297
  else {
1298
    $resource = db_query("SELECT lid FROM {locales_source} WHERE source = '%s' AND textgroup = '%s'", $source, $textgroup);
1299
1300
    // Parse the location string for the string ignoreoverwrite, which
1301
    // ignores the LOCAL_IMPORT_OVERWRITE directive below. $parts[2]
1302
    // is hardcoded, it is the third field, separated by ':' in the
1303
    // location string.
1304
    $parts = explode(':', $location);
1305
    if (!empty($parts[2])) {
1306
      if (preg_match('/(ignoreoverwrite)/', $parts[2])) {
1307
        $ignoreoverwrite = TRUE;
1308
      }
1309
    }
1310
  }// if (in_array($textgroup, $uselocation))
1311
1312
  if (!empty($translation)) {
1313
    // Skip this string unless it passes a check for dangerous code.
1314
    // Text groups other than default still can contain HTML tags
1315
    // (i.e. translatable blocks).
1316
    if ($textgroup == "default" && !locale_string_is_safe($translation)) {
1317
      $report['skips']++;
1318
      $lid = 0;
1319
    }
1320
    elseif ($resource) {
1321
      // We have this source string saved already. Loop over the db results from locales_source table.
1322
      while ($row = db_fetch_array($resource)) {
1323
1324
        $lid = $row['lid'];
1325
        // Check of if one or more translations exist for this lid in locales_target table.
1326
        $exists = (bool) db_result(db_query("SELECT lid FROM {locales_target} WHERE lid = %d AND language = '%s'", $lid, $langcode));
1327
        if (!$exists) {
1328
          // No translation in this language, insert translation into locales_target table.
1329
          db_query("INSERT INTO {locales_target} (lid, language, translation, plid, plural) VALUES (%d, '%s', '%s', %d, %d)", $lid, $langcode, $translation, $plid, $plural);
1330
          $report['additions']++;
1331
        }
1332
        else if ( ($mode == LOCALE_IMPORT_OVERWRITE) and (!$ignoreoverwrite) ) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
1333
          // Translation exists, only overwrite if instructed.
1334
          db_query("UPDATE {locales_target} SET translation = '%s', plid = %d, plural = %d WHERE language = '%s' AND lid = %d", $translation, $plid, $plural, $langcode, $lid);
1335
          $report['updates']++;
1336
        }
1337
        else {
1338
          $report['skips']++;
1339
        }// end if !$exists
1340
1341
      }// while
1342
    }
1343
  }
1344
  elseif ($mode == LOCALE_IMPORT_OVERWRITE AND $resource) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
Coding Style introduced by
As per coding-style, PHP keywords should be in lowercase; expected and, but found AND.
Loading history...
1345
    // Loop over db results from locales_source table.
1346
    while ($row = db_fetch_array($resource)) {
1347
      $lid = $row['lid'];
1348
      $exists = (bool) db_result(db_query("SELECT lid FROM {locales_target} WHERE lid = %d AND language = '%s'", $lid, $langcode));
1349
      if ($exists) {
1350
        // Empty translation, remove existing if instructed.
1351
        db_query("DELETE FROM {locales_target} WHERE language = '%s' AND lid = %d AND plid = %d AND plural = %d", $langcode, $lid, $plid, $plural);
1352
        $report['deletes']++;
1353
      }// if $exists
1354
    }// while
1355
  }
1356
  else {
1357
    $report['skips']++;
1358
  }
1359
1360
  return $lid;
1361
}
1362
1363
1364
1365
/**
1366
 * Parse valid resources out of configuration
1367
 */
1368
function boinctranslate_parse_resources($resource_text) {
1369
  $resources = array();
1370
  $resource_array = explode(
1371
    "\n", $resource_text
1372
  );
1373
  foreach ($resource_array as $resource) {
1374
    $resource = trim($resource);
1375
    if ($resource AND $resource[0] != '#') {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
Coding Style introduced by
As per coding-style, PHP keywords should be in lowercase; expected and, but found AND.
Loading history...
1376
      $resources[] = $resource;
1377
    }
1378
  }
1379
  return $resources;
1380
}
1381
1382
/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *
1383
 * Helper Functions for boinctranslate_filter
1384
 *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  */
1385
function _boinctranslate_filter_tips_long() {
1386
    return t("<a id=\"filter-boinctranslate\"></a>
1387
<h2>BOINC Translate Filter Help Information</h2>
1388
1389
<p>Use this filter to split the body of a node into chunks to make translations easier. Add the token '#SPLIT_TOKEN#', without the quotes in the editor when creating or editing a Web page. The filter will then split the text chunks using these tokens as delimiters. Each chunk is translated separately. Example: if a long page as five paragraphs, and each is a chunk, and paragraphs 2 and 3 are edited, chunks 1, 4, and 5 will not require re-translation.</p>
1390
1391
<p>The editor/admin may add as many of these tokens as you wish. You may add and remove them at your discretion. It is permitted for a page as no tokens, as the entire content will be a single chunk- such as for a shorter page.</p>
1392
");
1393
}
1394
1395
/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *
1396
 * Misc utility/helper functions
1397
 *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  */
1398
1399
/**
1400
 * Split a string by newline, and trim each line, implode back into a
1401
 * string. Used for cleaning whitespace title & description elements
1402
 * from project preferences XML upload before adding to translation
1403
 * database.
1404
 */
1405
function _boinctranslate_supertrim($instr) {
1406
  return implode("\n", array_map('trim', preg_split('/\r\n|\r|\n/', $instr) ) );
1407
}
1408