Updated Drupal to 8.6. This goes with the following updates because it's possible...
[yaffs-website] / web / core / modules / locale / tests / src / Functional / LocaleUpdateBase.php
1 <?php
2
3 namespace Drupal\Tests\locale\Functional;
4
5 use Drupal\Core\StreamWrapper\PublicStream;
6 use Drupal\file\Entity\File;
7 use Drupal\Tests\BrowserTestBase;
8 use Drupal\Component\Render\FormattableMarkup;
9
10 /**
11  * Base class for testing updates to string translations.
12  */
13 abstract class LocaleUpdateBase extends BrowserTestBase {
14
15   /**
16    * Timestamp for an old translation.
17    *
18    * @var int
19    */
20   protected $timestampOld;
21
22   /**
23    * Timestamp for a medium aged translation.
24    *
25    * @var int
26    */
27   protected $timestampMedium;
28
29   /**
30    * Timestamp for a new translation.
31    *
32    * @var int
33    */
34   protected $timestampNew;
35
36   /**
37    * Timestamp for current time.
38    *
39    * @var int
40    */
41   protected $timestampNow;
42
43   /**
44    * Modules to enable.
45    *
46    * @var array
47    */
48   public static $modules = ['locale', 'locale_test'];
49
50   /**
51    * {@inheritdoc}
52    */
53   protected function setUp() {
54     parent::setUp();
55
56     // Setup timestamps to identify old and new translation sources.
57     $this->timestampOld = REQUEST_TIME - 300;
58     $this->timestampMedium = REQUEST_TIME - 200;
59     $this->timestampNew = REQUEST_TIME - 100;
60     $this->timestampNow = REQUEST_TIME;
61
62     // Enable import of translations. By default this is disabled for automated
63     // tests.
64     $this->config('locale.settings')
65       ->set('translation.import_enabled', TRUE)
66       ->set('translation.use_source', LOCALE_TRANSLATION_USE_SOURCE_LOCAL)
67       ->save();
68   }
69
70   /**
71    * Sets the value of the default translations directory.
72    *
73    * @param string $path
74    *   Path of the translations directory relative to the drupal installation
75    *   directory.
76    */
77   protected function setTranslationsDirectory($path) {
78     file_prepare_directory($path, FILE_CREATE_DIRECTORY);
79     $this->config('locale.settings')->set('translation.path', $path)->save();
80   }
81
82   /**
83    * Adds a language.
84    *
85    * @param string $langcode
86    *   The language code of the language to add.
87    */
88   protected function addLanguage($langcode) {
89     $edit = ['predefined_langcode' => $langcode];
90     $this->drupalPostForm('admin/config/regional/language/add', $edit, t('Add language'));
91     $this->container->get('language_manager')->reset();
92     $this->assertTrue(\Drupal::languageManager()->getLanguage($langcode), new FormattableMarkup('Language %langcode added.', ['%langcode' => $langcode]));
93   }
94
95   /**
96    * Creates a translation file and tests its timestamp.
97    *
98    * @param string $path
99    *   Path of the file relative to the public file path.
100    * @param string $filename
101    *   Name of the file to create.
102    * @param int $timestamp
103    *   (optional) Timestamp to set the file to. Defaults to current time.
104    * @param array $translations
105    *   (optional) Array of source/target value translation strings. Only
106    *   singular strings are supported, no plurals. No double quotes are allowed
107    *   in source and translations strings.
108    */
109   protected function makePoFile($path, $filename, $timestamp = NULL, array $translations = []) {
110     $timestamp = $timestamp ? $timestamp : REQUEST_TIME;
111     $path = 'public://' . $path;
112     $text = '';
113     $po_header = <<<EOF
114 msgid ""
115 msgstr ""
116 "Project-Id-Version: Drupal 8\\n"
117 "MIME-Version: 1.0\\n"
118 "Content-Type: text/plain; charset=UTF-8\\n"
119 "Content-Transfer-Encoding: 8bit\\n"
120 "Plural-Forms: nplurals=2; plural=(n > 1);\\n"
121
122 EOF;
123
124     // Convert array of translations to Gettext source and translation strings.
125     if ($translations) {
126       foreach ($translations as $source => $target) {
127         $text .= 'msgid "' . $source . '"' . "\n";
128         $text .= 'msgstr "' . $target . '"' . "\n";
129       }
130     }
131
132     file_prepare_directory($path, FILE_CREATE_DIRECTORY);
133     $file = File::create([
134       'uid' => 1,
135       'filename' => $filename,
136       'uri' => $path . '/' . $filename,
137       'filemime' => 'text/x-gettext-translation',
138       'timestamp' => $timestamp,
139       'status' => FILE_STATUS_PERMANENT,
140     ]);
141     file_put_contents($file->getFileUri(), $po_header . $text);
142     touch(\Drupal::service('file_system')->realpath($file->getFileUri()), $timestamp);
143     $file->save();
144   }
145
146   /**
147    * Setup the environment containing local and remote translation files.
148    *
149    * Update tests require a simulated environment for local and remote files.
150    * Normally remote files are located at a remote server (e.g. ftp.drupal.org).
151    * For testing we can not rely on this. A directory in the file system of the
152    * test site is designated for remote files and is addressed using an absolute
153    * URL. Because Drupal does not allow files with a po extension to be accessed
154    * (denied in .htaccess) the translation files get a _po extension. Another
155    * directory is designated for local translation files.
156    *
157    * The environment is set up with the following files. File creation times are
158    * set to create different variations in test conditions.
159    *   contrib_module_one
160    *    - remote file: timestamp new
161    *    - local file:  timestamp old
162    *   contrib_module_two
163    *    - remote file: timestamp old
164    *    - local file:  timestamp new
165    *   contrib_module_three
166    *    - remote file: timestamp old
167    *    - local file:  timestamp old
168    *   custom_module_one
169    *    - local file:  timestamp new
170    * Time stamp of current translation set by setCurrentTranslations() is always
171    * timestamp medium. This makes it easy to predict which translation will be
172    * imported.
173    */
174   protected function setTranslationFiles() {
175     $config = $this->config('locale.settings');
176
177     // A flag is set to let the locale_test module replace the project data with
178     // a set of test projects which match the below project files.
179     \Drupal::state()->set('locale.test_projects_alter', TRUE);
180     \Drupal::state()->set('locale.remove_core_project', FALSE);
181
182     // Setup the environment.
183     $public_path = PublicStream::basePath();
184     $this->setTranslationsDirectory($public_path . '/local');
185     $config->set('translation.default_filename', '%project-%version.%language._po')->save();
186
187     // Setting up sets of translations for the translation files.
188     $translations_one = ['January' => 'Januar_1', 'February' => 'Februar_1', 'March' => 'Marz_1'];
189     $translations_two = ['February' => 'Februar_2', 'March' => 'Marz_2', 'April' => 'April_2'];
190     $translations_three = ['April' => 'April_3', 'May' => 'Mai_3', 'June' => 'Juni_3'];
191
192     // Add a number of files to the local file system to serve as remote
193     // translation server and match the project definitions set in
194     // locale_test_locale_translation_projects_alter().
195     $this->makePoFile('remote/8.x/contrib_module_one', 'contrib_module_one-8.x-1.1.de._po', $this->timestampNew, $translations_one);
196     $this->makePoFile('remote/8.x/contrib_module_two', 'contrib_module_two-8.x-2.0-beta4.de._po', $this->timestampOld, $translations_two);
197     $this->makePoFile('remote/8.x/contrib_module_three', 'contrib_module_three-8.x-1.0.de._po', $this->timestampOld, $translations_three);
198
199     // Add a number of files to the local file system to serve as local
200     // translation files and match the project definitions set in
201     // locale_test_locale_translation_projects_alter().
202     $this->makePoFile('local', 'contrib_module_one-8.x-1.1.de._po', $this->timestampOld, $translations_one);
203     $this->makePoFile('local', 'contrib_module_two-8.x-2.0-beta4.de._po', $this->timestampNew, $translations_two);
204     $this->makePoFile('local', 'contrib_module_three-8.x-1.0.de._po', $this->timestampOld, $translations_three);
205     $this->makePoFile('local', 'custom_module_one.de.po', $this->timestampNew);
206   }
207
208   /**
209    * Setup existing translations in the database and set up the status of
210    * existing translations.
211    */
212   protected function setCurrentTranslations() {
213     // Add non customized translations to the database.
214     $langcode = 'de';
215     $context = '';
216     $non_customized_translations = [
217       'March' => 'Marz',
218       'June' => 'Juni',
219     ];
220     foreach ($non_customized_translations as $source => $translation) {
221       $string = $this->container->get('locale.storage')->createString([
222         'source' => $source,
223         'context' => $context,
224       ])
225         ->save();
226       $this->container->get('locale.storage')->createTranslation([
227         'lid' => $string->getId(),
228         'language' => $langcode,
229         'translation' => $translation,
230         'customized' => LOCALE_NOT_CUSTOMIZED,
231       ])->save();
232     }
233
234     // Add customized translations to the database.
235     $customized_translations = [
236       'January' => 'Januar_customized',
237       'February' => 'Februar_customized',
238       'May' => 'Mai_customized',
239     ];
240     foreach ($customized_translations as $source => $translation) {
241       $string = $this->container->get('locale.storage')->createString([
242         'source' => $source,
243         'context' => $context,
244       ])
245         ->save();
246       $this->container->get('locale.storage')->createTranslation([
247         'lid' => $string->getId(),
248         'language' => $langcode,
249         'translation' => $translation,
250         'customized' => LOCALE_CUSTOMIZED,
251       ])->save();
252     }
253
254     // Add a state of current translations in locale_files.
255     $default = [
256       'langcode' => $langcode,
257       'uri' => '',
258       'timestamp' => $this->timestampMedium,
259       'last_checked' => $this->timestampMedium,
260     ];
261     $data[] = [
262       'project' => 'contrib_module_one',
263       'filename' => 'contrib_module_one-8.x-1.1.de._po',
264       'version' => '8.x-1.1',
265     ];
266     $data[] = [
267       'project' => 'contrib_module_two',
268       'filename' => 'contrib_module_two-8.x-2.0-beta4.de._po',
269       'version' => '8.x-2.0-beta4',
270     ];
271     $data[] = [
272       'project' => 'contrib_module_three',
273       'filename' => 'contrib_module_three-8.x-1.0.de._po',
274       'version' => '8.x-1.0',
275     ];
276     $data[] = [
277       'project' => 'custom_module_one',
278       'filename' => 'custom_module_one.de.po',
279       'version' => '',
280     ];
281     foreach ($data as $file) {
282       $file = array_merge($default, $file);
283       db_insert('locale_file')->fields($file)->execute();
284     }
285   }
286
287   /**
288    * Checks the translation of a string.
289    *
290    * @param string $source
291    *   Translation source string.
292    * @param string $translation
293    *   Translation to check. Use empty string to check for a not existing
294    *   translation.
295    * @param string $langcode
296    *   Language code of the language to translate to.
297    * @param string $message
298    *   (optional) A message to display with the assertion.
299    */
300   protected function assertTranslation($source, $translation, $langcode, $message = '') {
301     $db_translation = db_query('SELECT translation FROM {locales_target} lt INNER JOIN {locales_source} ls ON ls.lid = lt.lid WHERE ls.source = :source AND lt.language = :langcode', [':source' => $source, ':langcode' => $langcode])->fetchField();
302     $db_translation = $db_translation == FALSE ? '' : $db_translation;
303     $this->assertEqual($translation, $db_translation, $message ? $message : format_string('Correct translation of %source (%language)', ['%source' => $source, '%language' => $langcode]));
304   }
305
306 }