As part of the l10n_update integration in core this issue adds the function 'Get status of local and remote translation source'. See the UML in #1191488: META: Integrate l10n_update functionality in core for the big picture where this fits in. This patch includes the following parts of the UML:

  • Get available translation sources
  • Get status of local translation source
  • Get status of remote translation source
  • Batch get remote translation status
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

Status: Needs review » Needs work

The last submitted patch, locale-remote-status-0.patch, failed testing.

Sutharsan’s picture

Issue tags: +D8MI, +sprint

Tagging for D8MI

Sutharsan’s picture

Status: Needs work » Needs review
Issue tags: -D8MI, -sprint

locale-remote-status-0.patch queued for re-testing.

Status: Needs review » Needs work
Issue tags: +D8MI, +sprint

The last submitted patch, locale-remote-status-0.patch, failed testing.

webflo’s picture

Status: Needs work » Needs review
FileSize
15.53 KB

Rerolled.

pp’s picture

Status: Needs review » Needs work
+++ b/core/modules/locale/locale.compare.inc
@@ -0,0 +1,135 @@
+  $languages = $languages ? $languages : array_keys(locale_translatable_language_list());
...
+    foreach ($languages as $lang) {
+      $project_clone = clone $project;
+      $source = locale_translation_source_build($project_clone, $lang);
+      $source->url = locale_translation_build_string($source, $source->server_pattern);

Use $language or $langcode instead of $lang

Sutharsan’s picture

Status: Needs work » Needs review
FileSize
19.42 KB
20.73 KB

In this patch:

  • pp's comment in #6 included.
  • Added: Local translations status collected
  • Added: Translation status of local and remote are being compared
  • Removed functions: locale_reset_translation_server(), locale_translation_server(). No longer required by dropping server name, server_url.

Still todo:

  • Test scripts
  • Review the batch proces and make possible to run two batch processes in a row. Needed when we are going to download the translations after checking the remote status.
  • Some todo's, mainly documetation
Sutharsan’s picture

Title: Get status of remote translation file » Get status of local and remote translation files

Changing title to match the increased scope of the patch.

attiks’s picture

Status: Needs review » Needs work

Amazing work, some small comments

+++ b/core/modules/locale/locale.batch.incundefined
@@ -0,0 +1,116 @@
+    $context['results'] ++;

is the space needed in front of ++

+++ b/core/modules/locale/locale.compare.incundefined
@@ -0,0 +1,338 @@
+ *
+ * Eliminates a difference between the download time
+ * (Database: locale_file.timestamp) and the actual .po file timestamp.
+ */

what is the unit: seconds, minutes, ...

+++ b/core/modules/locale/locale.compare.incundefined
@@ -0,0 +1,338 @@
+  }
+  if ($check_local) {

add a blank line to improve reading.

+++ b/core/modules/locale/locale.compare.incundefined
@@ -0,0 +1,338 @@
+  else {
+    return $result_remote;

if $check_local is FALSE, does this mean that $check_remote is TRUE? If not add an elseif ($check_remote)

+++ b/core/modules/locale/locale.compare.incundefined
@@ -0,0 +1,338 @@
+ * - translations

is this a root folder?

+++ b/core/modules/locale/locale.compare.incundefined
@@ -0,0 +1,338 @@
+  $directory = $source->directory;

this will need to be changed to translations:// once #1658842: Introduce a translations:// stream wrapper to access the .po file directory is committed

webflo’s picture

The patch looks good. But still a lot of @todos. Here are some minors.

+++ b/core/modules/locale/locale.compare.incundefined
@@ -0,0 +1,338 @@
+ *   String containing place holders. Available place holders:
...
+ *   String with replaced place holders.

Typo: placeholders.

+++ b/core/modules/locale/locale.moduleundefined
@@ -65,6 +66,43 @@ const LOCALE_NOT_CUSTOMIZED = 0;
+ * The file name containing replacement patterns which are also used by the
+ * server pattern. See locale_translation_build_string() for supported patterns.

for supported placeholders. I think its better to standardize the wording.

Gábor Hojtsy’s picture

@Sutharsan: can you work on this going forward or should we try and find others to help out?

Gábor Hojtsy’s picture

Issue tags: +language-ui

Add tag.

Gábor Hojtsy’s picture

Priority: Normal » Major

Elevating to major as it should have been.

Sutharsan’s picture

At the last day of the code sprint in München started to realize that the way the batch is coded is wrong (a lot of processing occurs after the batch function is called). This may or may not work now, but certainly will not work if the batch is followed by the second batch process of downloading and importing the translation. Therefore I will need to rewrite the code to properly build the batch.

Thanks webflow and attiks for your reviews. I will include your remarks, but not make a separate patch from it. You probably won't recognise the code once I'm done ;)

Sutharsan’s picture

Ok, that wasn't too hard (once I understood the batch API).
Done:

  • Comments included.
  • Rewritten the batch process and the calling function. locale_translation_check_projects() is the starting point and will be called in a form submit handler.

Todo:

  • Test scripts
  • Todo's
  • Convert variables to CMI
Gábor Hojtsy’s picture

Status: Needs work » Needs review
Gábor Hojtsy’s picture

Just a quick review. I this this looks good, minus some of the @todo items. I do not agree with this TODO though:

+++ b/core/modules/locale/locale.batch.incundefined
@@ -0,0 +1,181 @@
+// @todo Replace this with a stream wrapper? May use ReadOnlyStreamWrapper:
+//       http://drupal.org/node/1308054

I think this is fine as-is, its a one off check and therefore would have too much of an overhead to get a stream wrapper.

+++ b/core/modules/locale/locale.compare.incundefined
@@ -269,3 +282,220 @@ function locale_translation_build_server_pattern($project, $template) {
+  // If the server_pattern contains a remote file path we check for a
+  // corresponding local po file in the local translation directory. If the server_pattern
+  // is a local po file path we chekc for a po file using this pattern.

+++ b/core/modules/locale/locale.moduleundefined
@@ -66,6 +66,43 @@ const LOCALE_NOT_CUSTOMIZED = 0;
+ * The file name containing placeholders which are also used by the server
+ * pattern. See locale_translation_build_server_pattern() for supported placeholders.

Over 80 chars.

+++ b/core/modules/locale/locale.moduleundefined
@@ -230,6 +267,26 @@ function locale_language_delete($language) {
+// ---------------------------------------------------------------------------------
+// Locale translation core functionality
+
+/**
+ * Returns list of translatable languages.
+ *
+ * @return array
+ *   Array of installed languages keyed by language name. English is omitted
+ *   unless its marked as translatable.
+ */
+function locale_translatable_language_list() {
+//drupal_static_reset('language_list');
+  $languages = language_list();
+//debug($languages);
+//debug(db_query('SELECT * FROM {language} ORDER BY weight ASC, name ASC')->fetchAllAssoc('langcode', PDO::FETCH_ASSOC));
+  if (!locale_translate_english()) {
+    unset($languages['en']);
+  }
+  return $languages;

I think this new function looks like a good wrapper. I'm not sure if you need the debug stuff around for future working patches, it looks pretty straightforward :)

I've also asked webflo and attiks to take a look, don't wait for them with any updates though IMHO.

Gábor Hojtsy’s picture

@Sutharsan: Do you need any help with this? What kind of help is needed?

Sutharsan’s picture

@Gábor, thanks for the offer, but I'm fine. Writing the test took more time because I had to climb a lot of hills to get it to work.
This is a working version with still some work todo, but good enough for a review.

Done:

  • Test scripts
  • Variables converted to CMI

Todo:

  • Todo's (both documentation and code)
  • Admin page for config variables
Sutharsan’s picture

The Localization Update module has three update modes: "Local files and remote server", "Local files only" and "Remote server only". I consider removing the the "Remote server only" option and thus reducing it to one choice (checkbox): "Local files only". I'm looking for some feedback on this.

Option "Local files only" not selected
This is the default. Both remote and local translation files will be investigated and the most recent translation will be used to import. Local files can be either downloaded files stored in the local file system, files included in custom modules or files included in profiles as part of a distribution. Downloaded files (e.g. from l.d.o) will only be saved in the local file system if a Translation directory has been set in the configuration. This option has no name because it is difficult to catch it in a few words. If no Translation directory has been defined it will import remote files from the translation server and will import local po files from (custom) modules or distributions which include their own translation files and have defined this in the .info file or with hook_locale_translation_projects_alter().

Option "Local files only" selected
With this option selected only local po files will be considered for import. This option is typically used for multi site installations which share a common directory for po files. One of these sites downloads the po files (Option "Local files only" not selected) from a translation server and stores the in the shared Translation directory. An other use of this option is in cases where a staging system is used to feed the site with new interface translation and no remote translation sources are used.

What do we loose with this change?
We loose the option where only remote sources are used. But since we now allow custom modules to define a local file as their translation source, we need to make exceptions on this rule any way. Because with a strict use of a "Remote server only" option, custom modules would never impor their local po file. I can't think of a use case where there is a need for only remote translation sources and all local sources should be ignored. Both code and interface simplicity will improve by dropping this option.

Sutharsan’s picture

Done:

  • Documentation
  • The "translations://" stream wrapper can be used now.
  • Changed the data structure of the "source" object to make it easier to identify the local and the remote translation file data. See locale_translation_source_build().

I think we can postpone the admin page until a later issue.

Gábor Hojtsy’s picture

Reflecting on #21, I think its fine to drop the remote only option. Otherwise trying to get you more reviewers :)

Gábor Hojtsy’s picture

Oh and for the user interface I assume that would come somewhere between #1804688: Download and import interface translations and #1804702: Display interface translation status.

Sutharsan’s picture

Once #1804688: Download and import interface translations is brought to a decent state, all the variables and settings will be on the radar and a configuration page can be added. #1804702: Display interface translation status is the issue for the update interface and integrating everything into other processes (module enable/disable, add/remove language, etc.)

attiks’s picture

Status: Needs review » Needs work

Nice patch, some typos and minor remarks

+++ b/core/modules/locale/lib/Drupal/locale/Tests/LocaleCompareTest.phpundefined
@@ -29,6 +36,67 @@ public static function getInfo() {
+    $this->drupalPost('admin/config/regional/language/add', array('predefined_langcode' => 'de'), t('Add language'));

Maybe add a comment that we enable German by default.

+++ b/core/modules/locale/lib/Drupal/locale/Tests/LocaleCompareTest.phpundefined
@@ -29,6 +36,67 @@ public static function getInfo() {
+"Project-Id-Version: Drupal 7\\n"

I know it doesn't really matter, but Drupal 7?

+++ b/core/modules/locale/lib/Drupal/locale/Tests/LocaleCompareTest.phpundefined
@@ -69,12 +137,103 @@ function testLocaleCompare() {
+   * URL. Because drupal does not allow file with a po extension to be accessed

file --> files

+++ b/core/modules/locale/lib/Drupal/locale/Tests/LocaleCompareTest.phpundefined
@@ -69,12 +137,103 @@ function testLocaleCompare() {
+   * (denied in .htaccess) the translation files  get a txt extension. An other

two spaces between files get

+++ b/core/modules/locale/lib/Drupal/locale/Tests/LocaleCompareTest.phpundefined
@@ -69,12 +137,103 @@ function testLocaleCompare() {
+    // translation files and match the projct definitions set in

projct --> project

+++ b/core/modules/locale/lib/Drupal/locale/Tests/LocaleCompareTest.phpundefined
@@ -69,12 +137,103 @@ function testLocaleCompare() {
+    //debug(file_scan_directory(variable_get('file_public_path', conf_path() . '/files') . '/local', '/.*\.*/', array('recurse' => TRUE)));
+    //debug(file_scan_directory(variable_get('file_public_path', conf_path() . '/files') . '/remote', '/.*\.*/', array('recurse' => TRUE)));

may be removed

+++ b/core/modules/locale/lib/Drupal/locale/Tests/LocaleCompareTest.phpundefined
@@ -69,12 +137,103 @@ function testLocaleCompare() {
+    $this->assertEqual($result['custom_module_one']['de']->type, 'local', 'Translation of custom_module_one. found');
+  }

dot after custom_module_one may be removed.

+++ b/core/modules/locale/locale.api.phpundefined
@@ -28,7 +28,18 @@
+ * interface translation server pattern = sites/all/modules/custom/example_module/%project-%version.%language.po

No idea how we should right this, since modules is now in the root folder?

+++ b/core/modules/locale/locale.batch.incundefined
@@ -0,0 +1,195 @@
+ *   Batch proces to check the availability of remote Gettext .po files.

proces --> process

should this be remote or local files?

+++ b/core/modules/locale/locale.batch.incundefined
@@ -0,0 +1,195 @@
+ * per project and per language. This data is stored a state variable

... stored *in* a state ...

+++ b/core/modules/locale/locale.batch.incundefined
@@ -0,0 +1,195 @@
+    // Update the file object with the result data. In case of a redirect we
+    // we store the resulting url.

one we too many

+++ b/core/modules/locale/locale.batch.incundefined
@@ -0,0 +1,195 @@
+ * and remote files. But also we also check local sources if no remote file is

... But we also ...

+++ b/core/modules/locale/locale.batch.incundefined
@@ -0,0 +1,195 @@
+ * In the preceding batch processes data of remote and local translation sources

Maybe add a @see that references the 'preceding'.

+++ b/core/modules/locale/locale.compare.incundefined
@@ -265,7 +266,270 @@ function locale_translation_build_server_pattern($project, $template) {
+      $project_clone = clone $project;

Why is this cloned? If it's needed (and I assume it is), add a comment.

+++ b/core/modules/locale/locale.compare.incundefined
@@ -265,7 +266,270 @@ function locale_translation_build_server_pattern($project, $template) {
+ * Only po files in the local file system and checked. Any remote translation

and --> are

+++ b/core/modules/locale/locale.compare.incundefined
@@ -265,7 +266,270 @@ function locale_translation_build_server_pattern($project, $template) {
+    // If the directory contains a streamwrapper, it is converted to a real
+    // path.

Maybe explain why this is needed

+++ b/core/modules/locale/locale.compare.incundefined
@@ -265,7 +266,270 @@ function locale_translation_build_server_pattern($project, $template) {
+  $source = clone $project;

another clone

+++ b/core/modules/locale/locale.compare.incundefined
@@ -265,7 +266,270 @@ function locale_translation_build_server_pattern($project, $template) {
+ * Determine if the source file is a remote or a local file.

remove 'or a local ', because the function name says that.

+++ b/core/modules/locale/locale.compare.incundefined
@@ -265,7 +266,270 @@ function locale_translation_build_server_pattern($project, $template) {
+ *   TRUE if the $url is a remote file location.

remove location

+++ b/core/modules/locale/locale.compare.incundefined
@@ -265,7 +266,270 @@ function locale_translation_build_server_pattern($project, $template) {
+// @todo Move to locale.inc?

is the @todo still needed?

+++ b/core/modules/locale/locale.pages.incundefined
@@ -441,6 +441,43 @@ function locale_translate_edit_form_submit($form, &$form_state) {
+/**
+ * Page callback: Display the current translation status.
+ */

i think you have to add @see locale_menu()

+++ b/core/modules/locale/locale.pages.incundefined
@@ -441,6 +441,43 @@ function locale_translate_edit_form_submit($form, &$form_state) {
+    drupal_set_message(t('No translatable languages available. <a href="@add_lanuage">Add a language</a> first.', array('@add_lanuage' => url('admin/config/regional/language'))), 'warning');

Try to remove the link out of the message, so it's easier to translate.

+++ b/core/modules/locale/locale.pages.incundefined
@@ -441,6 +441,43 @@ function locale_translate_edit_form_submit($form, &$form_state) {
+//debug(state()->get('locale_translation_status'));
+//debug(format_date(state()->get('locale_translation_status_last_update'), 'long'));

debug

+++ b/core/modules/locale/locale.pages.incundefined
@@ -441,6 +441,43 @@ function locale_translate_edit_form_submit($form, &$form_state) {
+  // @todo Calculate and display the translation status here.
+  return 'TODO: Show the transaltion status here';

i assume this is for a follow up issue, if it exists link to it in a comment.

Type: transaltion --> translation

+++ b/core/modules/locale/locale.pages.incundefined
@@ -441,6 +441,43 @@ function locale_translate_edit_form_submit($form, &$form_state) {
+/**
  * Default theme function for translatione edit form.
  */

I know, not part of the patch, but there's a typo translatione --> translation

+++ b/core/modules/locale/tests/modules/locale_test/locale_test.moduleundefined
@@ -16,12 +16,130 @@ function locale_test_system_info_alter(&$info, $file, $type) {
+      // Make the module appear as unhidden.

This sounds strange: "Don't hide the module' or something like that?

Sutharsan’s picture

As proposed in #21, the 'remote check' option is now dropped.

Sutharsan’s picture

Status: Needs work » Needs review
FileSize
12.5 KB
43.67 KB
+++ b/core/modules/locale/locale.api.phpundefined
@@ -28,7 +28,18 @@
+ * interface translation server pattern = sites/all/modules/custom/example_module/%project-%version.%language.po

No idea how we should right this, since modules is now in the root folder?

We can just change it to 'modules/custom/example_module ...' It does not matter where the directory is as long as the file is readable.

Why is this cloned? If it's needed (and I assume it is), add a comment.
...
another clone

One clone removed (I thought I did before). But to the why? I thought it was obvious, but perhaps I am missing something. $project is an object and is therefore by reference. Added one line of comment.

Other comments included.

attiks’s picture

Status: Needs review » Reviewed & tested by the community

I think this looks good, maybe add the notes from #24 into the issue summary.

webchick’s picture

Status: Reviewed & tested by the community » Needs work

Most of these are nit-pickish but this patch introduces some spelling/grammar errors which we need to fix before commit. Also, some work on the naming to make it more obvious what's happening here.

Nice work on the batch API stuff, and the tests! Really exciting to see l10n_update in core pushing forward! :D

+++ b/core/modules/locale/config/locale.settings.ymlundefined
@@ -1,3 +1,5 @@
+  check_mode: 'all'

+++ b/core/modules/locale/locale.compare.incundefined
@@ -265,7 +266,272 @@ function locale_translation_build_server_pattern($project, $template) {
+  if (config('locale.settings')->get('translation.check_mode') == LOCALE_TRANSLATION_CHECK_ALL) {

I don't think this variable is descriptive enough; I had to grep around for context in the rest of the patch to understand. From reading the docs at LOCALE_TRANSLATION_CHECK_ALL and friends, I think it should rather be "update_check_mode" or something (and then those constants named LOCALE_TRANSLATION_UPDATE_CHECK_X)

I would also suggest ALL should be BOTH or REMOTE_AND_LOCAL or something like that. "All" makes it sound like there are multiple choices here, but there are really only two, and REMOTE on its own is not one of them.

+++ b/core/modules/locale/lib/Drupal/locale/Tests/LocaleCompareTest.phpundefined
@@ -30,6 +37,73 @@ public static function getInfo() {
+    variable_set('locale_translate_file_directory', $path);

I was going to whine here about adding a new variable and not using CMI, but I noticed this variable already exists in 8.x. :) So ignore me. :D

+++ b/core/modules/locale/lib/Drupal/locale/Tests/LocaleCompareTest.phpundefined
@@ -30,6 +37,73 @@ public static function getInfo() {
+   * Creates a translation file and test its timestamp.

"tests" its timestamp.

+++ b/core/modules/locale/lib/Drupal/locale/Tests/LocaleCompareTest.phpundefined
@@ -30,6 +37,73 @@ public static function getInfo() {
+   * @param string $timestamp
+   *   Timestamp to set the file to. Defaults to current time.

String? Not an integer?

+++ b/core/modules/locale/lib/Drupal/locale/Tests/LocaleCompareTest.phpundefined
@@ -69,12 +143,89 @@ function testLocaleCompare() {
+   * URL. Because drupal does not allow files with a po extension to be accessed
+   * (denied in .htaccess) the translation files get a txt extension. An other

"Drupal" should be capitalized.

", another" rather than ". An other"

Great job with these comments, btw. Very clearly describe what's going on.

+++ b/core/modules/locale/lib/Drupal/locale/Tests/LocaleCompareTest.phpundefined
@@ -69,12 +143,89 @@ function testLocaleCompare() {
+   * respective local and remote translation directory. The test check whether

The test "checks" whether

+++ b/core/modules/locale/lib/Drupal/locale/Tests/LocaleCompareTest.phpundefined
@@ -69,12 +143,89 @@ function testLocaleCompare() {
+   * the most recent files are selected in the different check scenario's: check

No ' in scenarios.

+++ b/core/modules/locale/lib/Drupal/locale/Tests/LocaleCompareTest.phpundefined
@@ -69,12 +143,89 @@ function testLocaleCompare() {
+    // Setup timestamps to identify old and new translation sources.
...
+    // Setup the environment.

"Set up"

+++ b/core/modules/locale/locale.compare.incundefined
@@ -265,7 +266,272 @@ function locale_translation_build_server_pattern($project, $template) {
+ * @return integer
+ *   - "-1": $source1 < $source2 OR $source1 is missing.
+ *   - "0":  $source1 == $source2 OR both $source1 and $source2 are missing.
+ *   - "1":  $source1 > $source2 OR $source2 is missing.

It probably makes sense to create constants for these so they are self-documenting.

+++ b/core/modules/locale/locale.moduleundefined
@@ -227,7 +275,20 @@ function locale_language_delete($language) {
+ *   unless its marked as translatable.

"it's"

+++ b/core/modules/locale/locale.moduleundefined
@@ -644,6 +705,21 @@ function locale_form_system_file_system_settings_alter(&$form, $form_state) {
+/**
+ * Submit handler for the file system settings form.
+ *
+ * Clears the translation status when the Interface translations directory
+ * changes. Without a translations directory local po files in the directory
+ * should be ignored. The old translation status is no longer valid.
+ */
+function locale_system_file_system_settings_submit(&$form, $form_state) {
+  if ($form['locale_translate_file_directory']['#default_value'] != $form_state['values']['locale_translate_file_directory']) {
+  state()->delete('locale_translation_status');
+  state()->delete('locale_translation_status_last_update');
+  }

Can we pull those two state()->delete() lines into an API function and call it from this form submit handler, rather than embedding the logic in here?

+++ b/core/modules/locale/locale.pages.incundefined
@@ -441,7 +441,44 @@ function locale_translate_edit_form_submit($form, &$form_state) {
+    drupal_set_message(t('No translatable languages available.') . ' ' . l(t('Add language'), 'admin/config/regional/language'), 'warning');

Is this legit? I thought you needed to do t('blah blah <a href="@something">blah</a>')?

Sutharsan’s picture

Status: Needs work » Needs review
FileSize
11.08 KB
45.32 KB

All comments processed.

attiks’s picture

Status: Needs review » Reviewed & tested by the community

This looks good to me, great job!

webchick’s picture

Status: Reviewed & tested by the community » Fixed

Awesome, thanks a lot! Committed and pushed to 8.x. Not sure if this needs a change notice?

Gábor Hojtsy’s picture

Gábor Hojtsy’s picture

It did not take the sprint tag removal for some reason.

Automatically closed -- issue fixed for 2 weeks with no activity.

Anonymous’s picture

Issue summary: View changes

Adding UML details.