comparison core/modules/locale/tests/src/Functional/LocaleUpdateBase.php @ 0:4c8ae668cc8c

Initial import (non-working)
author Chris Cannam
date Wed, 29 Nov 2017 16:09:58 +0000
parents
children 1fec387a4317
comparison
equal deleted inserted replaced
-1:000000000000 0:4c8ae668cc8c
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\Utility\SafeMarkup;
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 ->save();
67 }
68
69 /**
70 * Sets the value of the default translations directory.
71 *
72 * @param string $path
73 * Path of the translations directory relative to the drupal installation
74 * directory.
75 */
76 protected function setTranslationsDirectory($path) {
77 file_prepare_directory($path, FILE_CREATE_DIRECTORY);
78 $this->config('locale.settings')->set('translation.path', $path)->save();
79 }
80
81 /**
82 * Adds a language.
83 *
84 * @param string $langcode
85 * The language code of the language to add.
86 */
87 protected function addLanguage($langcode) {
88 $edit = ['predefined_langcode' => $langcode];
89 $this->drupalPostForm('admin/config/regional/language/add', $edit, t('Add language'));
90 $this->container->get('language_manager')->reset();
91 $this->assertTrue(\Drupal::languageManager()->getLanguage($langcode), SafeMarkup::format('Language %langcode added.', ['%langcode' => $langcode]));
92 }
93
94 /**
95 * Creates a translation file and tests its timestamp.
96 *
97 * @param string $path
98 * Path of the file relative to the public file path.
99 * @param string $filename
100 * Name of the file to create.
101 * @param int $timestamp
102 * (optional) Timestamp to set the file to. Defaults to current time.
103 * @param array $translations
104 * (optional) Array of source/target value translation strings. Only
105 * singular strings are supported, no plurals. No double quotes are allowed
106 * in source and translations strings.
107 */
108 protected function makePoFile($path, $filename, $timestamp = NULL, array $translations = []) {
109 $timestamp = $timestamp ? $timestamp : REQUEST_TIME;
110 $path = 'public://' . $path;
111 $text = '';
112 $po_header = <<<EOF
113 msgid ""
114 msgstr ""
115 "Project-Id-Version: Drupal 8\\n"
116 "MIME-Version: 1.0\\n"
117 "Content-Type: text/plain; charset=UTF-8\\n"
118 "Content-Transfer-Encoding: 8bit\\n"
119 "Plural-Forms: nplurals=2; plural=(n > 1);\\n"
120
121 EOF;
122
123 // Convert array of translations to Gettext source and translation strings.
124 if ($translations) {
125 foreach ($translations as $source => $target) {
126 $text .= 'msgid "' . $source . '"' . "\n";
127 $text .= 'msgstr "' . $target . '"' . "\n";
128 }
129 }
130
131 file_prepare_directory($path, FILE_CREATE_DIRECTORY);
132 $file = File::create([
133 'uid' => 1,
134 'filename' => $filename,
135 'uri' => $path . '/' . $filename,
136 'filemime' => 'text/x-gettext-translation',
137 'timestamp' => $timestamp,
138 'status' => FILE_STATUS_PERMANENT,
139 ]);
140 file_put_contents($file->getFileUri(), $po_header . $text);
141 touch(drupal_realpath($file->getFileUri()), $timestamp);
142 $file->save();
143 }
144
145 /**
146 * Setup the environment containing local and remote translation files.
147 *
148 * Update tests require a simulated environment for local and remote files.
149 * Normally remote files are located at a remote server (e.g. ftp.drupal.org).
150 * For testing we can not rely on this. A directory in the file system of the
151 * test site is designated for remote files and is addressed using an absolute
152 * URL. Because Drupal does not allow files with a po extension to be accessed
153 * (denied in .htaccess) the translation files get a _po extension. Another
154 * directory is designated for local translation files.
155 *
156 * The environment is set up with the following files. File creation times are
157 * set to create different variations in test conditions.
158 * contrib_module_one
159 * - remote file: timestamp new
160 * - local file: timestamp old
161 * contrib_module_two
162 * - remote file: timestamp old
163 * - local file: timestamp new
164 * contrib_module_three
165 * - remote file: timestamp old
166 * - local file: timestamp old
167 * custom_module_one
168 * - local file: timestamp new
169 * Time stamp of current translation set by setCurrentTranslations() is always
170 * timestamp medium. This makes it easy to predict which translation will be
171 * imported.
172 */
173 protected function setTranslationFiles() {
174 $config = $this->config('locale.settings');
175
176 // A flag is set to let the locale_test module replace the project data with
177 // a set of test projects which match the below project files.
178 \Drupal::state()->set('locale.test_projects_alter', TRUE);
179 \Drupal::state()->set('locale.remove_core_project', FALSE);
180
181 // Setup the environment.
182 $public_path = PublicStream::basePath();
183 $this->setTranslationsDirectory($public_path . '/local');
184 $config->set('translation.default_filename', '%project-%version.%language._po')->save();
185
186 // Setting up sets of translations for the translation files.
187 $translations_one = ['January' => 'Januar_1', 'February' => 'Februar_1', 'March' => 'Marz_1'];
188 $translations_two = ['February' => 'Februar_2', 'March' => 'Marz_2', 'April' => 'April_2'];
189 $translations_three = ['April' => 'April_3', 'May' => 'Mai_3', 'June' => 'Juni_3'];
190
191 // Add a number of files to the local file system to serve as remote
192 // translation server and match the project definitions set in
193 // locale_test_locale_translation_projects_alter().
194 $this->makePoFile('remote/8.x/contrib_module_one', 'contrib_module_one-8.x-1.1.de._po', $this->timestampNew, $translations_one);
195 $this->makePoFile('remote/8.x/contrib_module_two', 'contrib_module_two-8.x-2.0-beta4.de._po', $this->timestampOld, $translations_two);
196 $this->makePoFile('remote/8.x/contrib_module_three', 'contrib_module_three-8.x-1.0.de._po', $this->timestampOld, $translations_three);
197
198 // Add a number of files to the local file system to serve as local
199 // translation files and match the project definitions set in
200 // locale_test_locale_translation_projects_alter().
201 $this->makePoFile('local', 'contrib_module_one-8.x-1.1.de._po', $this->timestampOld, $translations_one);
202 $this->makePoFile('local', 'contrib_module_two-8.x-2.0-beta4.de._po', $this->timestampNew, $translations_two);
203 $this->makePoFile('local', 'contrib_module_three-8.x-1.0.de._po', $this->timestampOld, $translations_three);
204 $this->makePoFile('local', 'custom_module_one.de.po', $this->timestampNew);
205 }
206
207 /**
208 * Setup existing translations in the database and set up the status of
209 * existing translations.
210 */
211 protected function setCurrentTranslations() {
212 // Add non customized translations to the database.
213 $langcode = 'de';
214 $context = '';
215 $non_customized_translations = [
216 'March' => 'Marz',
217 'June' => 'Juni',
218 ];
219 foreach ($non_customized_translations as $source => $translation) {
220 $string = $this->container->get('locale.storage')->createString([
221 'source' => $source,
222 'context' => $context,
223 ])
224 ->save();
225 $this->container->get('locale.storage')->createTranslation([
226 'lid' => $string->getId(),
227 'language' => $langcode,
228 'translation' => $translation,
229 'customized' => LOCALE_NOT_CUSTOMIZED,
230 ])->save();
231 }
232
233 // Add customized translations to the database.
234 $customized_translations = [
235 'January' => 'Januar_customized',
236 'February' => 'Februar_customized',
237 'May' => 'Mai_customized',
238 ];
239 foreach ($customized_translations as $source => $translation) {
240 $string = $this->container->get('locale.storage')->createString([
241 'source' => $source,
242 'context' => $context,
243 ])
244 ->save();
245 $this->container->get('locale.storage')->createTranslation([
246 'lid' => $string->getId(),
247 'language' => $langcode,
248 'translation' => $translation,
249 'customized' => LOCALE_CUSTOMIZED,
250 ])->save();
251 }
252
253 // Add a state of current translations in locale_files.
254 $default = [
255 'langcode' => $langcode,
256 'uri' => '',
257 'timestamp' => $this->timestampMedium,
258 'last_checked' => $this->timestampMedium,
259 ];
260 $data[] = [
261 'project' => 'contrib_module_one',
262 'filename' => 'contrib_module_one-8.x-1.1.de._po',
263 'version' => '8.x-1.1',
264 ];
265 $data[] = [
266 'project' => 'contrib_module_two',
267 'filename' => 'contrib_module_two-8.x-2.0-beta4.de._po',
268 'version' => '8.x-2.0-beta4',
269 ];
270 $data[] = [
271 'project' => 'contrib_module_three',
272 'filename' => 'contrib_module_three-8.x-1.0.de._po',
273 'version' => '8.x-1.0',
274 ];
275 $data[] = [
276 'project' => 'custom_module_one',
277 'filename' => 'custom_module_one.de.po',
278 'version' => '',
279 ];
280 foreach ($data as $file) {
281 $file = array_merge($default, $file);
282 db_insert('locale_file')->fields($file)->execute();
283 }
284 }
285
286 /**
287 * Checks the translation of a string.
288 *
289 * @param string $source
290 * Translation source string.
291 * @param string $translation
292 * Translation to check. Use empty string to check for a not existing
293 * translation.
294 * @param string $langcode
295 * Language code of the language to translate to.
296 * @param string $message
297 * (optional) A message to display with the assertion.
298 */
299 protected function assertTranslation($source, $translation, $langcode, $message = '') {
300 $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();
301 $db_translation = $db_translation == FALSE ? '' : $db_translation;
302 $this->assertEqual($translation, $db_translation, $message ? $message : format_string('Correct translation of %source (%language)', ['%source' => $source, '%language' => $langcode]));
303 }
304
305 }