Category Archives: javascript

symfony i18n Plugin written in ExtJs

This symfony plugin is a simple rewrite from the excellent mgI18nPlugin written with jQuery.

As i dont think jQuery is the best solution for nifty RIAs, i forked it and rewrote the interface with ExtJs.

Here is the Fork: https://github.com/digitalkaoz/mgI18nPlugin .

A Screenshot will explain nearly everything:

Requirements

  • symfony 1.3
  • Propel or Doctrine
  • pdo_mysql (not tested with others databases)
  • ExtJs

Installation

  • edit your factories.yml
    all:
       # ...
       i18n:
         class: mgI18N
         param:
           source:               mgMySQL
           database:             doctrine  # or propel or any names defined in the databases.yml files
           debug:                false
           learning_mode:        true        # if 'on' all translations are automatically added to the database
           global_application:  'frontend' # Optional ; use the same translations catalogues for all applications
           untranslated_prefix:  "[T]"
           untranslated_suffix:  "[/T]"
           cache:
             class: sfFileCache
             param:
               automatic_cleaning_factor: 0
               cache_dir:                 %SF_I18N_CACHE_DIR%
               lifetime:                  86400
               prefix:                    %SF_APP_DIR%
  • you can change the default doctrine connection’s name by editing your app.yml file
     all:
       # ...
       mgI18nPlugin:
         connection: doctrine
         cultures_available:
           fr: Français
           en: English

    you can use 2 databases : a project database and a translation database. Separating
    databases help you to manage different staging.

  • (optional) edit the databases.yml file to add the mg_i18n_plugin connection.
     mg_i18n_plugin:
       class: sfDoctrineDatabase
       param:
         dsn: 'mysql:host=127.0.0.1;dbname=project_database_i18n;charset=utf-8'
         username: username
         password: password
  • install the table
    symfony i18n:mg-create-table frontend
  • Install ExtJS
    • update the view.yml
      javascripts:
          - ext-all.js
        stylesheets:
          - /js/resources/ext-all.css
      
  • publish plugin asset
    symfony plugin:publish-assets
  • install plugin translation for each application
    symfony i18n:mg-xliff-import frontend plugins/mgI18nPlugin/i18n/*
  • add the filter, edit the filters.yml (the filter add current page translation messages)
    i18n:
       class: mgI18nFilter
     common:    ~ # before the common filter
    
  • clear cache
    symfony cc
  • click the Translations Button in your WebDebug Toolbar

Registering Event

In some edge cases, the plugin might not find the translation. The current fallback
is to register to an event, and add the translation into an array.

  • connect to the event
     class ProjectConfiguration extends sfProjectConfiguration
     {
       public function setup()
       {
         $this->enableAllPluginsExcept(array(
          'sfPropelPlugin',
          'sfCompat10Plugin'
         ));
         // [...]
         $this->dispatcher->connect('mgI18nPlugin.assign_ajax_values', array('mgI18nAjaxTranslation', 'listenToEvent'));
       }
     }
    
  • Create a class mgI18nAjaxTranslation
  • Now these messages will appear on the AJAX tabs

Of course you can connect many different objects to the mgI18nPlugin.assign_ajax_values event, from modules to plugins.

Security

By default the translation panel appears only if the current user is a sfGuard’s super admin. This behavior is controlled by the mgI18nUser class. Copy-and-paste this class into the project|application lib folder and customize the logic depends on the specification.

 class mgI18nAjaxTranslation extends mgI18nMessageHelper
 {
   public static function listenToEvent(sfEvent $event, $i18n_messages)
   {
     $messages = array(
       'your-catalogue' => array(
         array('your_message', array('name_param1', 'name_param2'),
       ),
     );
     return self::appendMessages($i18n_messages, $messages);
   }
 }

Note

You can import xliff catalogue with the command :
symfony i18n:mg-xliff-import frontend YOUR_CATALOGUE

move your Javascripts to Pagebottom with ease in symfony

Currently i am doing some page speed improvements to my site, and wanted to move all my javascripts to the page bottom.

My first approach was simply moving the script helper to the page bottom:

<?php include_javascripts() ?>
</body>

But that wont worked as expected.
Some Widget or Subsites may write some inline scripts, that uses included class from the top of the page.

For example (original):

<script type="text/javascript" src="jquery.js" >

<script type="text/javascript">
  $.somefunction();
</script>

would result in (moved helper to the bottom):

<script type="text/javascript">
  $.somefunction();
</script>

<script type="text/javascript" src="jquery.js" ></script>

that leads to nasty javascript errors!

Here is the solution for that:
Its a simple symfony Filter which greps all script tags and moves them in correct order the bottom of the page!

activate the filter after your rendering filter in your filters.yml

rendering: ~
scripts:
  class: DomScriptFilter

Here is the Filter:

/**
 * this filter moves all script tags to the bottom of the dom
 *
 * @author robert
 * @package lib.filter
 */
class DomScriptFilter extends sfFilter
{
  /**
   * @var EXPRESSION finds all script tags and moves them to the bottom
   */
  const EXPRESSION = "/<script [^>]*>([\d\D\w\W\s\S]*?)<\/script>/";
  /**
   * executes this filter
   *
   * @param sfFilterChain $filterChain
   */
  public function execute($filterChain)
  {
    $filterChain->execute();
    $content = $this->getContext()->getResponse()->getContent();
    preg_match_all(self::EXPRESSION, $content, $scripts);
    preg_replace(self::EXPRESSION, '', $content);
    $content = str_replace('', join('',$scripts[0]).'', $content);
    $this->getContext()->getResponse()->setContent($content);
  }
}

and voila it works as expected (with filter):


<script type="text/javascript" src="jquery.js" >
<script type="text/javascript">
  $.somefunction();
</script>

Now the page feels much faster, since we dont have to wait for javascripts to load to render the page…

setInterval vs. setTimeout in Javascript

Recently i ran into a strange javascript behavior.

I tried to periodically update a certain container on a page.

At first i tried it with:

foobar = function(){
  $('#my_div').load('myurl');
  setTimeout('foobar',10000);
};
setTimeout('foobar',10000);

I found out, its working correctly (it updates the div every 10 seconds), but i detaches the old DOM (the whole site), and adds the new Response-DOM as new Content, thats very strange because if you click another page, and then use the Browser-Back Button, there are no styles, or Javascript. So very very very bad, i didn’t get the clue what went wrong.

Then i refactored it bit, so it looks like this:

foobar = function(){
  $('#my_div').load('myurl');
};
setInterval('foobar',10000);

And voila, its working as expected. It updates the div correctly, and leaves the rest of the DOM untouched.
Dont know whats the difference between those 2 examples?!