There are several javascript files that contain hardcoded language strings.

This is the list:

  • autocomplete.js
    • line 254: return alert('An HTTP error '+ xmlhttp.status +' occured.\n'+ acdb.uri);
  • drupal.js
    • line 36: throw new Error("No XML component installed!");
    • line 317: return { status: 0, data: data.length ? data : 'Unspecified error' };
  • progress.js
    • line 85: return alert('An HTTP error '+ xmlhttp.status +' occured.\n'+ pb.uri);
    • Additional note: This script doesn't have CVS $Id$ tag.
  • update.js
    • line 16: progress.setProgress(-1, 'Starting updates');
  • upload.js
    • line 42: this.progress.setProgress(-1, 'Uploading file');
    • line 68: alert('An error occurred:\n\n'+ error);

A possible way to fix this would be to create a named array in drupal.js and fill this array from PHP generated code. Said array could be accessed directly by those scripts in need for a language string.

  • Step 1 would look like:
    // somewhere in drupal.js
    lang = new Array();
    
  • Step 2, filling the lang array:

    Use PHP code (where functions such as t() can be used) to generate something like this in page.tpl.php

    «script type="text/javascript"»<!--//--><![CDATA[//><!--
    lang['no_xml_component'] = 'No XML component installed!';
    lang['unspecified_error'] = 'Unspecified error';
    // ...and so on...
    //--><!]]>«/script»
    
  • Step 3, using the lang array:

    In drupal.js, you could then do this:

    • line 36: throw new Error(lang['no_xml_component']);
    • line 317: return { status: 0, data: data.length ? data : lang['unspecified_error'] };

For step 2, rather than generating inline code in page.tpl.php, that piece of javascript used to create the lang array items could be a PHP script. ie. including something like this in page.tpl.php:

«script type="text/javascript" src="/misc/drupal_js_lang.php"»«/script»

and then, misc/drupal_js_lang.php could look like:

$lang = array(
  'no_xml_component' => 'No XML component installed!',
  'unspecified_error' => 'Unspecified error',
  // ...and so on...
);

foreach ($lang as $key => $text) {
  print "lang['$key'] = ". drupal_to_js($text) .";\n";
}
CommentFileSizeAuthor
#10 upload-progress-message.patch1.17 KBnedjo

Comments

markus_petrux’s picture

Oops, I made a mistake in the last code snippet. I forgot to use the t() function.

Now fixed.

$lang = array(
  'no_xml_component' => t('No XML component installed!'),
  'unspecified_error' => t('Unspecified error'),
  // ...and so on...
);
foreach ($lang as $key => $text) {
  print "lang['$key'] = ". drupal_to_js($text) .";\n";
}
markus_petrux’s picture

I have marked this issue as a dup:
http://drupal.org/node/60208

nedjo’s picture

Thanks for your work on this issue Markus.

The suggested approach is straightforward and has the advantage of integrating with our current localization--i.e, we don't have to write additional files.

I've implemented something comparable in the Javascript Tools package, i.e., dynamic generation of js configuration files to accompany behaviours. We would I suppose add a menu item for each configuration file:


    $items[] = array(
      'path' => 'upload/settings.js',
      'title' => t('uploaddefaults'),
      'access' => user_access('access content'),
      'type' => MENU_CALLBACK,
      'callback' => 'upload_settings'
     );

When adding the file, we would have to test for clean urls:


  drupal_add_js((variable_get('clean_url', '0') ? '' : '?q=') . 'upload/settings.js');

And in the callback, we would include a text/javascript header:


function upload_settings() {
  drupal_set_header('Content-Type: text/javascript');
  // I've left out the new lines at the ends of lines because the filter didn't like them.
  print "lang['upload_progress_message'] = '" . t('Uploading file') . '";'";
  print "lang['upload_error_message'] = '" . t('An error occurred:') . '";'";
  exit();
}

markus_petrux’s picture

This method would need to do a full Drupal bootstrap et al.

Maybe a simple php file, doing a lighter bootstrap, just to get access to t(), would suffice?

nedjo’s picture

Title: Hardcoded language in javascript files » Hardcoded language in javascript files breaks localization
Priority: Normal » Critical

This method would need to do a full Drupal bootstrap et al.

True. Elsewhere (e.g., autocomplete) we encode data needed by js into form elements on the page.Should we think of doing the same here? Or could we have a routine to generate the needed localization files, e.g., upload_lang_es.js for the Spanish localization, saving them as new (static) files?

Upgrading to critical, because this breaks localization. If we do nothing else, we should eliminate the 'Uploading file' string from upload.js for 4.7. That's the one that will be seen by regular users even if there are no errors.

nedjo’s picture

Or we could support static localization files, e.g., upload_fr.js.

* we declare the lang array in drupal.js
* in each js file, all user messages are added to this array
* in drupal_add_js, for each file added we test for the existance of a file matching the current $locale,
adding it after the requested file so that it overrides the declared array items.


global $locale;

$localized_file =  substr($file, 0, strpos($file, '.js')) . $locale . '.js';
if (file_exists($localized_file)) {
  drupal_set_html_head(' ..... ');
}

* optionally, we implement an equivalent to the t() function so we can use, e.g., %error.

dries’s picture

Category: bug » feature
Priority: Critical » Normal

Going to make this a normal feature request. It's certainly not a showstopping bug.

markus_petrux’s picture

nedjo, I believe your initial idea (to use a drupal menu handler) would be easier to implement. ie. doing a full Drupal bootstrap give us the tools to deal with t() and unicode. We could also cache these localized .js files, or even send them compressed with gzip.

On the other hand, there could be simple xx.js files, maybe like TinyMCE, so Drupal would only need to do a drupal_add_js() when preparing drupal.js. But that introduces a different method for translations...

nedjo’s picture

Okay, agreed, localization is a feature request and not critical at this point

Still, the upload message is going to be a bit glaring and we should probably deal with it for 4.7.

Here's a minimal patch that makes the message argument to the progress object's setMessage method optional, and removes the message from upload.js. This would remove the only untranslatable string that most users are likely to see, arguably a sufficient 4.7 fix.

nedjo’s picture

Status: Active » Needs review
StatusFileSize
new1.17 KB

Forgot the patch.

nedjo’s picture

Status: Needs review » Active

Scratch that. I was overlooking the fact that anyone who wants to control display of progress messages can do so through css.

For an upload message, the following should do it:


#uploadprogressbar div.message {
  display: none;
}

Or even, I suppose (for browsers supporting the :before pseudo element):


#uploadprogressbar div.message {
  display: none;
}

#uploadprogressbar div.bar:before {
  content: "[translation of 'uploading file']";
}

So, no, we don't need to patch 4.7 and can focus on putting in place a good 4.8 solution.

bdragon’s picture

Version: x.y.z » 6.x-dev
Status: Active » Fixed

We finally have a t() for javascript, in Drupal 6. Huzzah!

Anonymous’s picture

Status: Fixed » Closed (fixed)