<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>2 tablespoons</title>
  <link rel="alternate" type="text/html" href="http://2tbsp.com"/>
  <link rel="self" type="application/atom+xml" href="http://2tbsp.com/atom/feed"/>
  <id>http://2tbsp.com/atom/feed</id>
  <updated>2011-01-24T21:07:12-05:00</updated>
  <entry>
    <title>Restore individual MySQL records with SELECT INTO OUTFILE and LOAD DATA INFILE</title>
    <link rel="alternate" type="text/html" href="http://2tbsp.com/content/restore-individual-mysql-records-select-outfile-and-load-data-infile" />
    <id>http://2tbsp.com/content/restore-individual-mysql-records-select-outfile-and-load-data-infile</id>
    <published>2012-06-24T23:24:38-04:00</published>
    <updated>2012-06-25T21:14:28-04:00</updated>
    <author>
      <name>chad</name>
    </author>
    <category term="How to" />
    <category term="MySQL" />
    <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>Every now and then, a single CMS post may vanish or a forum user's posts are accidentally deleted. No worries, right? That's why we make backups. If you have an active site with lots of users posting content, loading a backup is probably not practical. So, load up the latest incremental backup and select the records you need, and do it easily with MySQL's SELECT INTO OUTFILE and LOAD DATA INFILE.</p>
<p>    </div></summary>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>Every now and then, a single CMS post may vanish or a forum user's posts are accidentally deleted. No worries, right? That's why we make backups. If you have an active site with lots of users posting content, loading a backup is probably not practical. So, load up the latest incremental backup and select the records you need, and do it easily with MySQL's SELECT INTO OUTFILE and LOAD DATA INFILE.</p>
<p><!--break-->As the MySQL documentation says, these commands are meant to work in pairs. Here's a simple example of restoring all fields for a specific collection of records.</p>
<pre class="brush: sql;gutter: false; fontsize: 100; first-line: 1; ">SELECT * INTO OUTFILE '/tmp/data-out.csv'
  FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"'
  LINES TERMINATED BY '\n'
  FROM my_table
  WHERE id = N;
</pre>
<p>Move the CSV file to your production server and load it. Be sure to specify which fields you selected.</p>
<pre class="brush: sql;gutter: false; fontsize: 100; first-line: 1; ">LOAD DATA INFILE '/tmp/data-out.csv' INTO TABLE my_table 
  FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"'
  LINES TERMINATED BY '\n'
  (field1, field2, field3, field4);
</pre>
<p>
﻿﻿Each of these commands is capable of more. See the MySQL docs for complete details.﻿﻿﻿</p>    </div></content>
  </entry>
  <entry>
    <title>Connect to MS SQL Server and Sybase ASE from Mac OS X and Linux with unixODBC and FreeTDS </title>
    <link rel="alternate" type="text/html" href="http://2tbsp.com/content/connect-ms-sql-server-and-sybase-ase-mac-os-x-and-linux-unixodbc-and-freetds" />
    <id>http://2tbsp.com/content/connect-ms-sql-server-and-sybase-ase-mac-os-x-and-linux-unixodbc-and-freetds</id>
    <published>2012-06-08T15:12:13-04:00</published>
    <updated>2012-06-08T15:30:02-04:00</updated>
    <author>
      <name>chad</name>
    </author>
    <category term="Databases" />
    <category term="How to" />
    <category term="Open Source" />
    <category term="OS X" />
    <category term="PHP" />
    <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>Although I haven't had need to do so for freelance jobs, I do administer several Windows-based <a href="http://en.wikipedia.org/wiki/Sybase" target="_blank" title="Sybase" class="zem_slink" rel="wikipedia">Sybase</a> and MS SQL Servers at my day job.    </div></summary>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>Although I haven't had need to do so for freelance jobs, I do administer several Windows-based <a href="http://en.wikipedia.org/wiki/Sybase" target="_blank" title="Sybase" class="zem_slink" rel="wikipedia">Sybase</a> and MS SQL Servers at my day job. It's helpful to be able to connect directly to these servers from my Mac desktop in addition to using Apple RDC to manage and work against them directly via <a href="http://en.wikipedia.org/wiki/Microsoft_SQL_Server" target="_blank" title="Microsoft SQL Server" class="zem_slink" rel="wikipedia">MS SQL Server</a> Management Studio and Sybase Central.
 
I had previously installed <a href="http://www.unixodbc.org/">unixODBC</a> and <a href="http://www.freetds.org/">FreeTDS</a> on an OS X 10.4 desktop. This old Tiger was replaced by a new machine running Lion recently. I tried installing unixODBC and FreeTDS using <a href="http://www.macports.org/" target="_blank" title="MacPorts" class="zem_slink" rel="homepage">MacPorts</a> on the new machine, but was unable to connect to Sybase servers. I found <a href="http://blog.nguyenvq.com/2010/05/16/freetds-unixodbc-rodbc-r/">Vinh Nguyen's blog post</a> which refreshed my memory on the installation steps. Vinh notes problems with MacPorts, too. With a refreshed memory and some trial and error, I was able to get everything up and running again. For future reference, here are the steps from the latest installation and configuration of unixODBC and FreeTDS on OS X Lion.
 
</p>
<h2>Installation Requirements</h2>
<p>
 
You'll need Apple's developer tools, so be sure you have XCode installed. A commenter on Vinh's post noted errors experienced before installing gawk, which I had already installed via MacPorts. I downloaded all packages with wget from the command line.
 
</p>
<h2>Configure and Build unixODBC and FreeTDS from Source</h2>
<p>
 
FreeTDS will work with either iODBC or unixODBC, but I've not had luck with iODBC. Build and install unixODBC first and then FreeTDS. I built and installed everything in the standard location, /usr/local, feel free to change the path to suite your needs.
 
</p>
<pre class="brush: plain;gutter: false; fontsize: 100; first-line: 1; ">cd /usr/local/src </pre>
<h3>unixODBC</h3>
<p>Nothing special here.</p>
<pre class="brush: plain;gutter: false; fontsize: 100; first-line: 1; ">wget ftp://ftp.unixodbc.org/pub/unixODBC/unixODBC-2.3.1.tar.gz
tar xvfz unixODBC-2.3.1.tar.gz cd unixODBC-2.3.1
./configure
make
sudo make install </pre>
<h3>FreeTDS</h3>
<p>
 
I followed Vinh's recommendation of installing the latest development version, so I grabbed the latest FreeTDS nightly snapshot.
 
</p>
<pre class="brush: plain;gutter: false; fontsize: 100; first-line: 1; ">wget ftp://ftp.ibiblio.org/pub/Linux/ALPHA/freetds/current/freetds-current.tgz </pre>
<p>Configure the installer with the proper <a href="http://en.wikipedia.org/wiki/Tabular_Data_Stream" target="_blank" title="Tabular Data Stream" class="zem_slink" rel="wikipedia">TDS</a> version and path to unixODBC.
 
</p>
<pre class="brush: plain;gutter: false; fontsize: 100; first-line: 1; ">./configure --with-tdsver=8.0 --with-unixodbc=/usr/local
make
sudo make install
</pre>
<p>Check the FreeTDS install with tsql.
 
</p>
<pre class="brush: plain;gutter: false; fontsize: 100; first-line: 1; ">tsql -C
Compile-time settings (established with the "configure" script)
                            Version: freetds v0.92.dev.20120312
             freetds.conf directory: /usr/local/etc
     MS db-lib source compatibility: no
        Sybase binary compatibility: no
                      Thread safety: yes
                      iconv library: yes
                        TDS version: 5.0
                              iODBC: no
                           unixodbc: yes
              SSPI "trusted" logins: no
                           Kerberos: no</pre>
<p>If you have Sybase or MS db-lib installed locally, check out the FreeTDS documentation for instructions on further configuration options.
</p>
<h2>Configuration</h2>
<p>
 
To get up and running for basic usage, you'll need to define your servers and DSNs in the freetds.conf and odbc.ini files, respectively. Either create and edit these at the system-level in /usr/local/etc or just for you in your home directory. For more advanced language and connection needs, you'll also want to configure locales.conf and pool.conf.
</p>
<p> 
Vinh states that he needed to use TDS version 8.0 for MS SQL Server connections. I found that I needed to use TDS version 5.0 for Sybase connections.
</p>
<p> 
Here's a basic Sybase server DSN defined in ~/.odbc.ini. The default section contains default (surprise) values to be used by servers. Each host's DSN may override or extend the default values.
 
</p>
<pre class="brush: plain;gutter: false; fontsize: 100; first-line: 1; ">[default]
Driver=/usr/local/lib/libtdsodbc.so
TDS_Version=5.0
Port=5000
;UseCursor=1
;Trace=Yes
;Tracefile=/tmp/odbc.log
 
[SybaseDSN]
Description=Sybase ASE 12.5 or 15 Server
ServerName=HOSTNAME
Database=DATABASE
</pre>
<p>And here's the corresponding Sybase server entry in ~/.freetds.conf. The ServerName in the odbc.ini's DSN needs to match a HOSTNAME defined in the freetds.conf file! As with the odbc.ini file's default section, the global definitions in freetds.conf apply to all servers defined, unless the server section defines the value. Uncomment the dump and debug values to log connection output if have problems connecting.
 
</p>
<pre class="brush: plain;gutter: false; fontsize: 100; first-line: 1; ">[global]
  tds version = 5.0
  client charset = UTF-8
 
  # Whether to write a TDSDUMP file for diagnostic purposes
  # (setting this to /tmp is insecure on a multi-user system)
  #dump file = /tmp/freetds.log
  #debug flags = 0xffff
  #debug level = 10
 
  # Command and connection timeouts
  #timeout = 10
  connect timeout = 10
 
  # If you get out-of-memory errors, it may mean that your client
  # is trying to allocate a huge buffer for a TEXT field. 
  # Try setting 'text size' to a more reasonable limit
  text size = 64512
 
  # Default TDS version for Sybase 12.5 and 15
  tds version = 5.0
 
  # Default Sybase ASE port on Windows
  port = 5000
 
[HOSTNAME]      
  host = IP.ADDRESS.HERE
</pre>
<p>Check out the default odbc.ini and freetds.conf configuration files for MS SQL Server connection examples.
 
</p>
<h2>unixODBC and FreeTDS Usage</h2>
<p>
 
unixODBC provides an isql client, comparable to those which ship with MS SQL Server and Sybase. After configuring your ODBC DSN entries and FreeTDS servers, isql use is straightforward.
 
</p>
<pre class="brush: plain;gutter: false; fontsize: 100; first-line: 1; ">isql DSN USERNAME PASSWORD </pre>
<p>Note that isql does not require that you enter "go" after each SQL query or command.
 
</p>
<p>FreeTDS provides the following utilities, among <a href="http://www.freetds.org/userguide/usefreetds.htm#UTILITIES">several others</a>.
</p>
<p> 
From the FreeTDS manual:
 
</p>
<blockquote>
<p>bsqldb - A non-interactive equivalent of the isql utility programs distributed by Sybase and Microsoft. Like them, bsqldb uses the command "go" on a line by itself as a separator between batches. The last batch need not be followed by "go".
</p>
</blockquote>
<blockquote>
<p> 
fisql - A complete replacement of the isql utility programs distributed by Sybase and Microsoft. Like them, fisql uses the command "go" on a line by itself as a separator between batches.
 
 
</p>
<pre class="brush: plain;gutter: false; fontsize: 100; first-line: 1; ">fisql -H HOST -S SERVER -U USERNAME -P PASSWORD -D DATABASE -s COLUMNSEPERATOR -i INPUTFILE -o OUTPUTFILE </pre>
</blockquote>
<p>After confirming that you can indeed connect to and work against targeted database servers, install your preferred programming languages TDS bindings (Ruby, Python, Perl, C). Java users should check our jTDS. </p>
<p>For PHP users, build PHP with
 
--with-mssql=/usr/local/bin/freetds
 
Sybase users should use PHP's MS SQL functions, which are essentially the same as PHP's Sybase functions.</p>
<p>Good luck!</p>
<div class="zemanta-pixie" style="margin-top: 10px; height: 15px;"><a href="http://www.zemanta.com/?px" title="Enhanced by Zemanta" class="zemanta-pixie-a"><img src="http://img.zemanta.com/zemified_e.png?x-id=463e6665-acc6-408c-8946-db47f0f4b54e" alt="Enhanced by Zemanta" style="border: medium none; float: right;" class="zemanta-pixie-img"></a></div>    </div></content>
  </entry>
  <entry>
    <title>Tutorial: Getting started with localization and translation in Drupal 7, by example</title>
    <link rel="alternate" type="text/html" href="http://2tbsp.com/content/tutorial-getting-started-localization-and-translation-drupal-7" />
    <id>http://2tbsp.com/content/tutorial-getting-started-localization-and-translation-drupal-7</id>
    <published>2011-11-23T15:23:58-05:00</published>
    <updated>2012-06-04T00:33:37-04:00</updated>
    <author>
      <name>chad</name>
    </author>
    <category term="Drupal" />
    <category term="How to" />
    <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>I'm beginning to build a Drupal-powered web site for a customer. A goal for this project is to provide translation of pages, events, and announcements for Spanish-speaking site visitors. Although <a href="http://www.nytimes.com/2010/03/09/technology/09translate.html">Google's Translation service is great</a>, automated translation tools remain <a href="http://wikitranslation.org/blog/funny-translation-errors/">less than perfect</a>. Fortunately, the customer has several dedicated bilingual volunteers who will translate as much of the site's content as possible.</p>    </div></summary>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>I'm beginning to build a Drupal-powered web site for a customer. A goal for this project is to provide translation of pages, events, and announcements for Spanish-speaking site visitors. Although <a href="http://www.nytimes.com/2010/03/09/technology/09translate.html">Google's Translation service is great</a>, automated translation tools remain <a href="http://wikitranslation.org/blog/funny-translation-errors/">less than perfect</a>. Fortunately, the customer has several dedicated bilingual volunteers who will translate as much of the site's content as possible.</p>
<p>In this post, I'll walk you through the steps to configure a Drupal 7 site so that it may be translated to other languages.</p>
<h2>It's Not Just Translation</h2>
<p><img src="http://2tbsp.com/system/files/not-butter-300x216.jpg" alt="not-butter-300x216.jpg" style="float: right; margin-top: 10px; margin-bottom: 10px; margin-left: 10px; border: 1px #000000 solid;" height="216" width="300"> If you're new to building multilingual web sites, I recommend reading the Wikipedia entries on <a href="http://en.wikipedia.org/wiki/Internationalization_and_localization">internationalization</a> and <a href="http://en.wikipedia.org/wiki/Localization">localization</a>. Building a multilingual web site involves much more than translating content from one language to another. Translation must be done with an awareness of a language's idioms as spoken within a geographic region. If you're a native English speaker in the United States you probably know that "a lift" means something quite different to the English. Idiomatic differences also exist in Spanish spoken in Mexico, Latin America, South America, and, of course, Spain. Localizing translations is one of <a href="http://blog.sakhr.com/2011/03/machine-translation-and-why-it-is_14.html">the biggest challenges for machine translation</a> and the primary reason we chose to manually translate our content rather than slapping the Google Translation Widget on our pages.</p>
<h2>Localization, Translation, and Drupal</h2>
<p>Localizing and translating a web site is a complicated task, but Drupal does a remarkably good job of simplifying the process. If you're interested in the technical details and decisions that went into how Drupal supports internationalization, have a look at Gabor Hojtsy's series, "<a href="http://hojtsy.hu/multilingual-drupal7">Drupal 7's new multilingual systems compilation</a>."</p>
<p><a href="http://www.google.com/url?sa=t&amp;rct=j&amp;q=&amp;esrc=s&amp;source=web&amp;cd=1&amp;ved=0CEUQFjAA&amp;url=http%3A%2F%2Fwww.lullabot.com%2Fabout%2Fteam%2Fkaren-stevenson&amp;ei=NazsTuzONceqiQLnkvTRBA&amp;usg=AFQjCNHDWqmm93zUSNVj1rgeH7PZXbPykw&amp;sig2=Byp7UjMDrCAFZg9ZgREmSw" target="_blank">Karen Stevenson</a> wrote a wonderful article, "<a href="http://www.lullabot.com/articles/localized-and-multi-lingual-content-drupal-7">Localized and Multi-Lingual Content in Drupal 7</a>", which summarizes Gabor's series. In her article, Karen discusses the two site components requiring translation, the interface and the site's content. Text in Drupal's interface, including the login form and navigation menu, has already been translated into many of the world's languages which saves you, I, and the rest of the Drupal community a ton of time.</p>
<p>Karen also breaks down the two content translation options available in Drupal 7, full-node translation and entity translation, which is new in Drupal 7. After some consideration, I decided that entity translation was the best choice for the site I'm building. So, with this introductory information in mind, here are the steps I used to configure multilingual support in a Drupal 7 site.</p>
<h2>1.0 Define Languages and Translate the Interface</h2>
<p>The foundation for multilingual support in Drupal 7 is the Locale module which ships with the default distribution. Enable locale, then define the languages your site will support. In this article, I'll be using Drush to install and enable modules. If you're new to Drush, have a look at my <a href="http://2tbsp.com/content/introduction-drupals-command-line-shell-interface-drush">introductory article</a>, or download and enable modules through Drupal's administration interface.</p>
<h3>1.1 Enable the Locale Module, Add Languages, Configure Language Switching</h3>
<pre>drush @my-site pm-enable locale
</pre>
<p>With locale enabled, you can now add the languages your site will support.</p>
<ol>
<li>Go to Administration &gt; Configuration &gt; Languages (under "Regional and Language")</li>
<li>Click "Add language"</li>
<li>Select a predefined language, in my case, Spanish (Español)</li>
<li>Click "Add Language"</li>
</ol>
<p>Add as many languages as you need. You can also add custom language translations here.&nbsp;&nbsp;</p>
<p>&nbsp;&nbsp;<img src="http://2tbsp.com/system/files/Screen%20shot%202011-11-23%20at%2011_13_45%20PM.png" alt="Screen shot 2011-11-23 at 11.13.45 PM.png" style="border: 1px solid #000000;" name="Screen%20shot%202011-11-23%20at%2011_13_45%20PM.png" height="203" width="480"></p>
<p>After adding languages, you'll need to configure how users' language preference are detected and how they'll switch between languages.</p>
<ol>
<li>Select the "Detection and Selection" tab (Administration &gt; Configuration &gt; Languages)</li>
<li>Check one or more methods to detect the language to display (I enabled all, although I won't use all initially)</li>
<li>Save the settings</li>
</ol>
<p><img src="http://2tbsp.com/system/files/Screen%20shot%202011-11-23%20at%2011_14_44%20PM.png" alt="Screen shot 2011-11-23 at 11.14.44 PM.png" style="border: 1px solid #000000;" name="Screen%20shot%202011-11-23%20at%2011_14_44%20PM.png" height="191" width="480"></p>
<p>You can rearrange the priority of detection methods, set which part of the URL to use in detection (es.mysite.com vs. mysite.com/es/), and set a request/session variable name to use to switch languages.</p>
<h3>1.2 Load an Interface Language Translation</h3>
<p>If you're localizing for one of the predefined languages listed on the Add Language form, most, if not all, interface translation work has already been done for you. Most of the core Drupal interface, including default menus and blocks, has already been translated by the Drupal community. All you need to do is download a translation file and load it.</p>
<p><img src="http://2tbsp.com/system/files/Screen%20shot%202011-11-23%20at%2011_04_16%20PM.png" alt="Screen shot 2011-11-23 at 11.04.16 PM.png" style="border: 1px solid #000000;" name="Screen%20shot%202011-11-23%20at%2011_04_16%20PM.png" height="150" width="480"></p>
<ol>
<li>Visit <a href="http://localize.drupal.org/">localize.drupal.org</a> and download an <a href="http://localize.drupal.org/translate/downloads">available interface translation</a> for Drupal 7.</li>
<li>Go to Administration &gt; Configuration &gt; Translate Interface.</li>
<li>Select the "Import" tab.</li>
<li>Choose the language file you downloaded (in my case, drupal-7.9.es.po).</li>
<li>Be sure the "Import into" menu selection corresponds to the imported file.</li>
<li>Choose whether to replace existing string translations, or just import new ones. Yes, this means that if a translated string isn't appropriate for your site, you can override imported values. Just be careful not to overwrite your changes when updating translations.</li>
<li>Click Import.</li>
</ol>
<p>Once complete, you'll be shown an import results showing how many strings were updated and added. You'll also see the percentage of the translation complete for that language. Since it's one of the most spoken languages on the planet, Spanish is a well maintained Drupal interface translation which is typically at 100% complete.</p>
<p>You may now visit your site and append the language code (http://mysite.com/es) to the URL to see the fruits of your labor, so far. Next, let's enable content translation.</p>
<p><img src="http://2tbsp.com/system/files/Screen%20shot%202011-11-23%20at%2011_34_25%20PM.png" alt="Screen shot 2011-11-23 at 11.34.25 PM.png" style="border: 1px #000000 solid;"></p>
<h2>2.0 Enable Content Translation</h2>
<p>As Karen points out in her article, content translation in Drupal 7 can now be configured at the node or field levels. She notes the <a href="http://groups.drupal.org/node/165194" target="_blank">debate among Drupal developers</a> about the merits of each method. For this site, since I'm new to developing multilingual sites, I've decided to follow Karen's recommendation and use the newer field translation model.</p>
<p>Since the translation debate was not settled before Drupal 7 shipped, field translation is not part of core. I'll need to install several contributed modules to enable field translation.</p>
<ul>
<li><a href="http://drupal.org/project/entity_translation" target="_blank">Entity Translation</a> - Enables translation of node fields, with the exception of titles.</li>
<li><a href="http://drupal.org/project/title" target="_blank">Title</a> - Enables translation of node titles.</li>
<li><a href="http://drupal.org/project/entity">Entity</a> - Title module dependency.</li>
</ul>
<p>Here are the Drush commands used to download and install these.</p>
<pre>drush @my-site dl entity_translation title entity 
</pre>
<p><span style="font-family: monospace; white-space: pre;">drush @my-site en entity_translation title entity</span></p>
<p>After installation, define which content types (Blog posts, Basic Pages, Articles, etc.) can be translated.</p>
<ol>
<li>Go to Administration &gt; Structure &gt; Content Types</li>
<li>Edit an existing content type, i.e. "Basic page"</li>
<li>Select the "Publishing options" tab</li>
<li>Choose "Enabled, with entity translation"</li>
<li>Save the changes</li>
</ol>
<p>Next, convert the Title field to a regular field using the Title module, and set which fields are translatable.</p>
<ol>
<li>Go to Administration &gt; Structure &gt; Content types</li>
<li>Select "manage fields" for the content type you enabled translation for, i.e. "Basic page"</li>
<li>Click "replace" for the Title field</li>
<li>Check "Replace title with a field instance" and save</li>
<li>Select the "Manage Display" tab</li>
<li>Change the Title field's Label and Format to &lt;Hidden&gt; and Save</li>
<li>Select the "Manage Fields" tab</li>
<li>Edit the Body field</li>
<li>Select the "Field Settings" tab</li>
<li>Check "Users may translate this field" and save the field settings</li>
<li>Repeat steps 8 through 10 for other translatable fields</li>
</ol>
<p>Now give it a try. You'll now see a Translation tab next to the standard View and Edit node tabs.</p>
<p><img src="http://2tbsp.com/system/files/Screen%20shot%202011-11-23%20at%2011_59_44%20PM.png" alt="Screen shot 2011-11-23 at 11.59.44 PM.png" style="border: 1px #000000 solid;" height="118" width="480"></p>
<p>On this tab you'll now see an "add translation" link next to each language you've enabled. Clicking this will display a slightly altered add/edit node form to create a translated version of the original. The translation form will contain the original languages values for reference during translation.</p>
<p>The translation form provides controls to set published state, whether the translation requires an update, and a translated URL alias.</p>
<p><img src="http://2tbsp.com/system/files/Screen%20shot%202011-11-27%20at%2011_34_04%20PM.png" alt="Screen shot 2011-11-27 at 11.34.04 PM.png" style="border: 1px #000000 solid;" height="341" width="480"></p>
<p>After saving the translation, click on it's title in the translation list to view it. We're almost there. We still need to translate the site's title, slogan, and main menu. We also need to provide a way for visitors to switch languages.</p>
<p><img src="http://2tbsp.com/system/files/Screen%20shot%202011-11-27%20at%2011_47_20%20PM.png" alt="Screen shot 2011-11-27 at 11.47.20 PM.png" style="border: 1px #000000 dotted;" height="331" width="480"></p>
<h2>3.0 Switching Between Languages</h2>
<p>Next, let's provide a language switcher for users. The Locale module provides a simple block with enabled languages listed. If your site's translated to several languages, this list will take up a lot of real estate. The Language Dropdown module converts the language switcher list to an attractive dropdown menu.</p>
<p><span style="font-family: monospace; white-space: pre;">drush @my-site dl lang_dropdown</span></p>
<p><span style="font-family: monospace; white-space: pre;">drush @my-site en lang_dropdown</span></p>
<p>Next, enable the language switcher block.</p>
<ol>
<li>Visit Administration &gt; Structure &gt; Blocks</li>
<li>Enable and place Language switcher dropdown (user interface text)</li>
</ol>
<p>You should now see a fully-functional language switcher menu like this. If you'd like, you can also download and install the <a href="http://drupal.org/project/languageicons" target="_blank">Language Icons</a> module which will add flags for each language in the menu.</p>
<p><img src="http://2tbsp.com/system/files/Screen%20shot%202011-11-24%20at%2012_33_23%20PM.png" alt="Screen shot 2011-11-24 at 12.33.23 PM.png" style="border: 1px #000000 solid;" height="137" width="215"></p>
<p><span style="font-size: 21px; font-weight: bold;">4.0 Menu Item, Block, Variable, and Contact Form Translation</span></p>
<p>What about translating menu items and blocks? Let's not forget about the site's name, slogan, and contact form. To tackle these tasks, you'll need the i18n module and the slew of module's it, and it's sub-modules, depend upon.</p>
<h3>Install i18n, Translate Menu Items</h3>
<ol>
<li>Download i18n<br>
<pre>drush @my-site dl i18n
</pre>
</li>
<li>Enable i18n_menu, which will also enable several additional required modules.<br>
<pre>drush @my-site en i18n_menu

</pre>
<pre>The following extensions will be enabled: i18n_menu, i18n_translation, i18n_string, i18n_block, variable, i18n
Do you really want to continue? (y/n): y
i18n_translation was enabled successfully.            [ok]
i18n_menu was enabled successfully.                   [ok]
i18n_string was enabled successfully.                 [ok]
i18n_block was enabled successfully.                  [ok]
variable was enabled successfully.                    [ok]
i18n was enabled successfully.                        [ok]
Refreshed 16 strings for the enabled modules.         [status]
</pre>
</li>
<li>Go to Administration &gt; Structure &gt; Menus</li>
<li>Click "edit menu" for the Main menu</li>
<li>Under "Multilingual options", set the Translation mode to "Translate and Localize"</li>
<li>Save the menu</li>
<li>Edit a menu item from the "List Links" tab</li>
<li>Select the "Translate" tab</li>
<li>Translate the item and save</li>
</ol>
<p><img src="http://2tbsp.com/system/files/Screen%20shot%202011-11-28%20at%2012_16_49%20AM.png" alt="Screen shot 2011-11-28 at 12.16.49 AM.png" style="border: 1px #000000 solid;" height="70" width="480"></p>
<p>Repeat for each menu item.</p>
<p><img src="http://2tbsp.com/system/files/Screen%20shot%202011-11-28%20at%209_30_08%20PM.png" alt="Screen shot 2011-11-28 at 9.30.08 PM.png" style="border: 1px #000000 solid;" height="106" width="355"></p>
<p>Note that translation of the Home tab requires that it's default language be changed to English. Once this is done, a translation for the Home tab may be added. You'll see both "Home" and the translated version of Home on menu lists, but only the tab appropriate for a selected language will be displayed to end-users.</p>
<h3>Translate Site Variables</h3>
<p>The Internationalization module, along with the Variables module, provide support for translating site variable values. These include, but are not limited to, site name, slogan</p>
<ol>
<li>Enable the i18n Variable Translation module and it's required modules, Variable store and Variable realm</li>
<li>Visit Administration &gt; Configuration &gt; Multilingual Settings</li>
<li>Click on the "Variables" tab</li>
<li>Select variable to be translated</li>
<li>Save</li>
</ol>
<p><img src="http://2tbsp.com/system/files/Screen%20shot%202011-11-28%20at%2010_46_39%20PM.png" alt="Screen shot 2011-11-28 at 10.46.39 PM.png" style="border: 1px #000000 solid;" height="74" width="480"></p>
<p>This list also includes the RSS feed description, user-related email messages (welcome, password reset, etc.).</p>
<p>Now, to translate the site's name and slogan.</p>
<ol>
<li>Go to Administration &gt; Configuration &gt; Site Information</li>
<li>Select the language to translate variable values to</li>
<li>Translate variables</li>
<li>Save</li>
</ol>
<p><img src="http://2tbsp.com/system/files/Screen%20shot%202011-11-28%20at%2010_52_32%20PM.png" alt="Screen shot 2011-11-28 at 10.52.32 PM.png" style="border: 1px #000000 solid;" height="226" width="480"></p>
<p>Now you'll see the translated site name and slogan in your banner!</p>
<p><br>
<img src="http://2tbsp.com/system/files/Screen%20shot%202011-11-28%20at%2010_54_34%20PM.png" alt="Screen shot 2011-11-28 at 10.54.34 PM.png" height="115" width="480"></p>
<h3>Enable Block Translation</h3>
<p>When i18n_menu was enabled above, i18n_block was automatically enabled which, as the name suggests, provides support for block translation. Just create or edit a block and set which languages it can translated to.</p>
<p><img src="http://2tbsp.com/system/files/Screen%20shot%202011-11-28%20at%2012_33_27%20AM.png" alt="Screen shot 2011-11-28 at 12.33.27 AM.png" style="border: 1px #000000 solid;" height="213" width="480"></p>
<p><img src="http://2tbsp.com/system/files/Screen%20shot%202011-11-28%20at%2012.37.34%20AM.png" alt="Screen shot 2011-11-28 at 10.25.15 PM.png" height="221" width="491"></p>
<p>You may receive the following error when attempting to translate blocks:</p>
<p>"The string blocks:block:1:body for textgroup blocks is not allowed for translation because of its text format."</p>
<p>No worries, you just need to set which text formats are translatable.</p>
<ol>
<li>Visit Administration &gt; Multilingual settings</li>
<li>Select the "Strings" tab</li>
<li>Select the Translatable text formats to allow, i.e. Filtered HTML, Full HTML, Plain text</li>
</ol>
<h3>Translate Contact Form Categories and Auto-Reply Messages</h3>
<p>This is another relatively straight forward process. Enabling the Contact Translation module allows for the translation of Contact form categories and auto-response messages.
</p>
<ol>
<li>Enable the Contact and Contact Translation modules</li>
<li>Go to Administration &gt; Structure &gt; Contact Form</li>
<li>Edit or Add a category</li>
<li>Click the "Translate" tab</li>
<li>Translate the Category and Auto-reply values</li>
</ol>
<p><img src="http://2tbsp.com/system/files/Screen%20shot%202011-11-28%20at%2011_29_37%20PM.png" alt="Screen shot 2011-11-28 at 11.29.37 PM.png" height="104" width="480"></p>
<p>After adding a few categories and translating them, your contact form should look something like this.</p>
<p><img src="http://2tbsp.com/system/files/Screen%20shot%202011-11-29%20at%203_57_29%20PM.png" alt="Screen shot 2011-11-29 at 3.57.29 PM.png" style="border: 1px solid #000000;" name="Screen%20shot%202011-11-29%20at%203_57_29%20PM.png" height="380" width="478"></p>
<p>You'll probably want to create a language-specific URL path for special pages, like the contact page (Administration &gt; Configuration &gt; URL aliases).</p>
<p><img src="http://2tbsp.com/system/files/Screen%20shot%202011-11-29%20at%203_50_29%20PM.png" alt="Screen shot 2011-11-29 at 3.50.29 PM.png" style="border: 1px solid #000000;" name="Screen%20shot%202011-11-29%20at%203_50_29%20PM.png" height="166" width="480"></p>
<p><span style="font-size: 21px; font-weight: bold;">6.0 Set Date Formats</span></p>
<p>Don't forget to set locale-appropriate date formats. IBM provides a nice <a href="http://publib.boulder.ibm.com/infocenter/wf/v2r7m0/index.jsp?topic=/com.ibm.help.wf.doc/locale_spec/i_xfdl_r_locale_quick_reference.html" target="_blank">locale quick reference</a> which includes various locales' date formats.</p>
<p>I'll set the following date formats for es-MX at Administration &gt; Configuration &gt; Date and Time.</p>
<ul>
<li>Short: 28/11/2011</li>
<li>Medium: 28 de noviembre de 2011</li>
<li>Long: lunes 28 de noviembre de 2011</li>
</ul>
<p><img src="http://2tbsp.com/system/files/Screen%20shot%202011-11-28%20at%209.59.12%20PM.png" alt="Screen shot 2011-11-28 at 9.59.12 PM.png" style="border: 1px #000000 solid;"></p>
<p>And here's how the date displays for articles and blog posts.</p>
<p><a href="http://2tbsp.com/system/files/Screen%20shot%202011-11-28%20at%2010_01_37%20PM.png"><img src="http://2tbsp.com/system/files/Screen%20shot%202011-11-28%20at%2010_01_37%20PM_0.png" alt="Screen shot 2011-11-28 at 10.01.37 PM.png" style="border: 1px solid #000000;" name="Screen%20shot%202011-11-28%20at%2010_01_37%20PM_0.png" height="102" width="480"></a></p>
<h2>Additional Considerations</h2>
<p>There are a few things I haven't touched upon, at least not yet. The Internationalization module makes it relatively easy to tackle these additional translation tasks.</p>
<ul>
<li>If you set a node as your site's <strong>homepage</strong>, you'll need to <a href="http://drupal.org/node/1216132" target="_blank">provide translated nodes for each languages homepage</a>.</li>
<li>If you've enabled node <strong>comments</strong>, you'll need to consider how you want to display comments made in various languages. Have a look at the Filter comments per language section of the Comment settings tab.</li>
<li>Taxonomy</li>
<li>Views, <a href="http://drupal.org/project/i18nviews" target="_blank">Internationalization Views</a></li>
<li>URLs without accents, <a href="http://drupal.org/project/transliteration" target="_blank">Transliteration</a></li>
<li>Tracking and managing your site's translation is a lot easier is you can get a bird's eye view.</li>
<li>i18n update</li>
<li>l10n_install</li>
</ul>
<p>The Drupal article on <a href="http://drupal.org/node/1268692" target="_blank">Basic Internationalization Setup</a> provides additional detail and I highly recommend that everyone review it. You may want to also review the <a href="http://drupal.org/node/133977">i18n module's documentation</a>.</p>    </div></content>
  </entry>
  <entry>
    <title>An Introduction to Drupal&#039;s Command Line Interface, Drush</title>
    <link rel="alternate" type="text/html" href="http://2tbsp.com/content/introduction-drupals-command-line-shell-interface-drush" />
    <id>http://2tbsp.com/content/introduction-drupals-command-line-shell-interface-drush</id>
    <published>2011-07-04T00:31:55-04:00</published>
    <updated>2012-04-28T15:44:54-04:00</updated>
    <author>
      <name>chad</name>
    </author>
    <category term="Bash" />
    <category term="Drupal" />
    <category term="Unix" />
    <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>I previously wrote about a couple of <a href="http://2tbsp.com/content/streamline-drupal-update-process">bash scripts</a> I wrote to manage Drupal core and module updates via SVN. While those scripts handle the basics pretty well, I realized that I needed to get to know <a href="http://drush.ws/" target="_blank">Drush</a>. I have a few Drupal upgrade project's coming up, so I spent the past few days getting familiar with Drush. 
Here's what I've learned so far.</p>    </div></summary>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>I previously wrote about a couple of <a href="http://2tbsp.com/content/streamline-drupal-update-process">bash scripts</a> I wrote to manage Drupal core and module updates via SVN. While those scripts handle the basics pretty well, I realized that I needed to get to know <a href="http://drush.ws/" target="_blank">Drush</a>. I have a few Drupal upgrade project's coming up, so I spent the past few days getting familiar with Drush. 
Here's what I've learned so far.</p>
<h2>Drush, What is it? What does it do?</h2>
<p>
Drush is a command line interface to Drupal. At it's core, it's a shell script (Unix/Linux), or a bat script (Windows), and a collection of PHP scripts which handle most Drupal maintenance tasks. Here are some of the things you can do with the current Drush release, version 4.4. </p>
<ul>
<li>View info: version, install location, status, module info, site activity (watchdog)</li>
<li>Manage modules: enable, disable, download, install, uninstall</li>
<li>Update: update core (Drupal 6 to 7), modules, and the database (update.php)</li>
<li>Deploy: install via profiles or update remote instances via rsync</li>
<li>Maintain: dump the database, run cron, clear caches, build the search index, get and set core and module variables</li>
<li>Extend: Several modules add Drush features and you can create your own.
</li>
</ul>
<h2>Install Drush</h2>
<p>
Install Drush by either downloading it from its drupal.org <a href="http://drupal.org/project/drush">project page</a> or through a package manager on Debian or Ubuntu. MacPorts has an older version of Drush which requires PHP 5.2, so I downloaded and installed manually. 
</p>
<pre class="brush: bash;gutter: false; fontsize: 100; first-line: 1; ">% cd /usr/local
% wget http://ftp.drupal.org/files/projects/drush-7.x-4.4.tar.gz
% tar xvf drush-7.x-4.4.tar.gz</pre>
<p>Then add Drush to your path in your profile.
</p>
<p>export PATH=/usr/local/drush:$PATH
</p>
<h2>Basic Drush Commands</h2>
<p>
Now you're ready to give it a try. Here are a few basic commands to get you started.
</p>
<p>View Drush and Drupal information. You can either change to your root Drupal installation directory, or use the --root/-r flag and provide the path to Drupal regardless of where you happen to be in the file system.
</p>
<pre class="brush: bash;gutter: false; fontsize: 100; first-line: 1; ">% cd /var/www/drupal
% drush status
Drupal version         :  6.22                                       
Site URI               :  http://default                             
Database driver        :  mysqli                                     
Database hostname      :  localhost                                  
Database username      :  root                                       
Database name          :  drupal6                                    
Default theme          :  garland                                    
Administration theme   :  garland                                    
PHP configuration      :                                             
Drush version          :  4.4                                        
Drush configuration    :                                             
Drush alias files      :   
Drupal root            :  /home/chad/drupal-6               
Site path              :  sites/default                              
</pre>
<p>Run cron for the site.
</p>
<pre class="brush: bash;gutter: false; fontsize: 100; first-line: 1; ">% drush cron
Cron run successfully. [success] </pre>
<p>Clear site caches, which comes in handy while developing themes and modules.
</p>
<pre class="brush: bash;gutter: false; fontsize: 100; first-line: 1; ">% drush cc
Enter a number to choose which cache to clear.
 [0]  :  Cancel         
 [1]  :  all            
 [2]  :  theme registry 
 [3]  :  menu           
 [4]  :  css+js         
 [5]  :  block          
 [6]  :  module list    
 [7]  :  theme list     
1
'all' cache was cleared                      [success]
</pre>
<p>List all available modules and themes, including version, description, and status.
</p>
<pre class="brush: bash;gutter: false; fontsize: 100; first-line: 1; ">% drush pm-list
Package          Name                 Type    Status         Version       
&lt;snip&gt;
Core - optional  PHP filter (php)     Module  Not installed  6.22          
Core - optional  Ping (ping)          Module  Not installed  6.22          
Core - optional  Poll (poll)          Module  Not installed  6.22          
Core - optional  Profile (profile)    Module  Not installed  6.22          
Core - optional  Search (search)      Module  Not installed  6.22          
&lt;/snip&gt;</pre>
<p>Enable an existing module.
</p>
<pre class="brush: bash;gutter: false; fontsize: 100; first-line: 1; ">% drush pm-enable poll
The following extensions will be enabled: poll
Do you really want to continue? (y/n): y
poll was enabled successfully.                                               [ok]
</pre>
<p>Download, install, and enable a new contributed module in sites/all/modules/.
</p>
<pre class="brush: bash;gutter: false; fontsize: 100; first-line: 1; ">% drush dl vertical_tabs
Project vertical_tabs (6.x-1.0-rc1) downloaded to           [success]
/home/chad/drupal-6/sites/all/modules/vertical_tabs.
% drush en vertical_tabs
The following extensions will be enabled: vertical_tabs
Do you really want to continue? (y/n): y
vertical_tabs was enabled successfully.                                 [ok]
</pre>
<p>Update an existing module(s).</p>
<pre class="brush: bash;gutter: false; fontsize: 100; first-line: 1; ">% drush pm-updatecode vertical_tabs-1.0-rc2
Update information last refreshed: Wed, 07/06/2011 - 22:14
Update status information on all installed and enabled Drupal projects:
 Name                 Installed version  Proposed version  Status                                   
 Administration menu  6.x-3.0-alpha4     6.x-3.0-alpha4    Up to date                               
 Drupal core          6.22               6.22              Up to date                               
 Vertical Tabs        6.x-1.0-rc1        6.x-1.0-rc2       Specified version available              
 Views                6.x-2.12           6.x-2.12          Up to date                               
Code updates will be made to the following projects: Vertical Tabs [vertical_tabs-6.x-1.0-rc2]
Note: A backup of your project will be stored to backups directory if it is not managed by a supported version control system.
Note: If you have made any modifications to any file that belongs to one of these projects, you will have to migrate those modifications after updating.
Do you really want to continue with the update process? (y/n): y
Project vertical_tabs was updated successfully. Installed version is now 6.x-1.0-rc2.
Backups were saved into the directory                                                    [ok]
/usr/local/drush-backups/drupal6/20110707052105/modules/vertical_tabs.
'all' cache was cleared                                                                  [success]
You have pending database updates. Run `drush updatedb` or visit update.php in your      [warning]
browser.
</pre>
<p>Run update.php after installing updates.</p>
<pre class="brush: bash;gutter: false; fontsize: 100; first-line: 1; ">% drush updatedb
The following updates are pending:
 color module                                                                        
 6001 - Warn site administrator if unsafe CSS color codes are found in the database. 
Do you wish to run all pending updates? (y/n): y
Executing color_update_6001                                                              [success]
'all' cache was cleared                                                                  [success]
Finished performing updates.                                                             [ok]
</pre>
<p>Pretty cool, isn't it? And this is just the tip of the Drush iceberg. </p>
<p>
If you have trouble running commands, try the verbose (-v) and debug (-d) flags to show more output.  There are known issues with Drush failing to make database connections when mysql.sock doesn't exist in the standard location. I found this <a href="http://drupal.org/node/1011932" target="_blank"> Drush issue thread</a> very helpful and in my case, changing my development server's database host name from localhost to 127.0.0.1 in settings.php allowed me to run module-related commands.
</p>
<p>Try 'drush help', download a <a href="http://www.google.com/search?q=drush+cheatsheet" target="_blank">cheatsheet</a>, or checkout the <a href="http://drush.ws/" target="_blank">Drush homepage</a> for a complete list of commands. There are shorter aliases for most Drush commands.</p>
<h2>Configure Drush for Multisite and Remote Operations</h2>
<p>
It doesn't take long to get up and running with a single site, but if you're running multisite, multiple instances (development, staging, live), or remote instances, there's a bit more configuration you'll want to do. 
</p>
<p>Drush will look for configuration files in several places, including your drush install folder, root drupal install directories, and your home directory. I chose to use my home directory and created a dot drush folder there.  
</p>
<pre class="brush: bash;gutter: false; fontsize: 100; first-line: 1; ">% mkdir ~/.drush </pre>
<p>Now create your Drush configuration file. I have both Drupal 6 and 7 development instances installed locally. Since most of my sites are still running on Drupal 6, I set my default root and URI flags to my Drupal 6 instance.
</p>
<p>~/.drush/drushrc.php
</p>
<pre class="brush: php;fontsize: 100; first-line: 1; ">&lt;?php
// Increase PHP's memory limit, -1 for no limit
ini_set('memory_limit', '256M');
// Local root Drupal directory
$options['r'] = '/home/chad/drupal-6';
// URI of my local Drupal instance
$options['l'] = 'http://d6.local';
?&gt;</pre>
<!--?php
// Increase PHP's memory limit, -1 for no limit
ini_set('memory_limit', '256M');
// Local root Drupal directory
$options['r'] = '/var/www/drupal-6';
// URI of my local Drupal instance
$options['l'] = 'http://d6.local';
?-->
<p>In multisite environments, set up an alias configuration file to avoid the need to specify a --uri for each site you maintain. I defined shortcuts for my each of my local development and remote production Drupal instances.
</p>
<p>~/.drush/aliases.drushrc.php
</p>
<pre class="brush: php;fontsize: 100; first-line: 1; ">&lt;?php
$aliases['dev-d7'] = array(
  'uri' =&gt; 'd7.local',
  'root' =&gt; '/home/chad/drupal-7',
  );
$aliases['live-mysite'] = array(
  'uri' =&gt; 'mysite.com',
  'root' =&gt; '/var/www/mysite.com/htdocs',
  'remote-host' =&gt; 'ssh.server.com',
  'remote-user' =&gt; 'ssh-login',
  );
$aliases['dev-mysite'] = array(
  'uri' =&gt; 'mysite.local',
  'root' =&gt; '/home/chad/Sites/drupal',
  );
$aliases['live-mysite'] = array(
  'uri' =&gt; 'mysite.com',
  'root' =&gt; '/var/www/mysite.com/htdocs',
  'remote-host' =&gt; 'ssh.server.com',
  'remote-user' =&gt; 'ssh-login',
  );
?&gt;</pre>
<p>Now, instead of specifying --uri for a Drupal multisite instance, specify the alias instead. The following lists just active modules for a site.
</p>
<pre class="brush: bash;gutter: false; fontsize: 100; first-line: 1; ">% drush @dev-mysite pm-list</pre>
<h2>Simplify Drupal Maintenance with Drush</h2>
<p>
Think of all the possibilities Drush opens up for maintaining existing sites and deploying new ones. You can write command line scripts to build workflows which combine Drush with your existing version control workflow, perform smart database backups which omit unneeded cache tables, and much more. Write a script which deploys site and module updates via Git, Subversion, or rsync! </p>
<p>What will you do or have you done with Drush?</p>
<p>2012-04-28 - Updated drush.rc.php to drushrc.php, thanks anonymous commenter!</p>    </div></content>
  </entry>
  <entry>
    <title>Twitter Module for Gallery 3: Share Your Photos, Movies, and Albums with your Followers</title>
    <link rel="alternate" type="text/html" href="http://2tbsp.com/content/twitter-module-gallery-3" />
    <id>http://2tbsp.com/content/twitter-module-gallery-3</id>
    <published>2011-05-19T11:59:05-04:00</published>
    <updated>2013-07-09T02:19:56-04:00</updated>
    <author>
      <name>chad</name>
    </author>
    <category term="Community/Social Networks" />
    <category term="Gallery" />
    <category term="jquery" />
    <category term="Open Source" />
    <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>I've just packaged and posted the final 1.0 release of a Twitter module for Gallery 3. Share photos, movies, and albums with your Twitter followers, directly from Gallery. Give it a try!</p>
    </div></summary>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>I've just packaged and posted the final 1.0 release of a Twitter module for Gallery 3. Share photos, movies, and albums with your Twitter followers, directly from Gallery. Give it a try!</p>
<h2> <span class="mw-headline"> Features </span></h2>
<ul>
<li> Send Tweets directly from Gallery
</li>
<li> Failed Tweets saved for subsequent attempts
</li>
<li> Integrates with <a href="http://2tbsp.com/content/bitly-module-gallery-3" target="_blank" title="bitly">bit.ly</a> module to shorten item URLs
</li>
</ul>
<h2> <span class="mw-headline"> Support, Bug Reports </span></h2>
<p>Please post problems, questions, and comments to <a href="http://gallery.menalto.com/node/100791" target="_blank" class="external free" rel="nofollow">http://gallery.menalto.com/node/100791</a>
</p>
<h2> <span class="mw-headline"> Installation </span></h2>
<ol>
<li> <a href="https://github.com/downloads/ckieffer/gallery3-contrib/twitter-1.tar.gz" target="_blank" title="Download Twitter version 1">Download the module</a> and unpack the module to your Gallery 3 modules directory
</li>
<li> Enable the module via Admin &gt; Modules
</li>
<li> Register your Gallery with <a href="http://dev.twitter.com/" target="_blank" class="external text" rel="nofollow">Twitter</a>
<ol>
<li> Application Name: My Awesome Gallery (cannot contain 'Twitter')
</li>
<li> Description: Short summary of your Gallery (optional)
</li>
<li> Application Website: <span class="external free">http://yourgallery.com</span>
</li>
<li> Organization: Your name or company
</li>
<li> Application Type: Browser
</li>
<li> Callback URL: <span class="external free">http://yourgallery.com/path</span>
</li>
<li> Default Access Type: Read &amp; Write
</li>
<li> Application Icon: Use the Gallery or your site logo
</li>
</ol>
</li>
<li> Configure the module at Admin &gt; Settings &gt; Twitter
<ol>
<li> Enter the Twitter Consumer Key and Secret provided by Twitter
</li>
<li> Edit the Default Tweet. The following replacement tokens are available:
<ol>
<li>&nbsp;%type: photo, movie, album
</li>
<li>&nbsp;%title: The item's title
</li>
<li>&nbsp;%description The item's description
</li>
<li> The full item link or bit.ly shortened URL is then appended to this.
</li>
</ol>
</li>
</ol>
</li>
</ol>
<h2> <span class="mw-headline"> User OAuth Verification Process </span></h2>
<p>Registered Gallery users will be prompted to allow Gallery to send<br />
Tweets on their behalf the first time they select "Share on Twitter."<br />
This is a one-time verification valid until the user revokes access for<br />
Gallery.
</p>
<p>Also available via Git in <a href="http://github.com/gallery/gallery3-contrib/tree/master/3.1/modules/twitter" target="_blank" class="external text" rel="nofollow">gallery3-contrib</a>
</p>
<h2> <span class="mw-headline"> Roadmap </span></h2>
<p>version 2
</p>
<ul>
<li> Display Twitter profile/follow links on Gallery user profile pages.
</li>
<li> Provide "Share on Twitter" for anonymous users.
</li>
<li> Display item (re)tweets.
</li>
</ul>
<h2> <span class="mw-headline"> History </span></h2>
<p>2011-05-19 - 1</p>
<ul>
<li>No change from 1 beta2.</li>
</ul>
<p>2011-03-15 - 1 beta2
</p>
<ul>
<li> Allow users to change from one Twitter account to another from their profile page.
</li>
<li> Compose Tweet JavaScript widget fixes to read default options, accept custom widget options.
</li>
<li> Disable the "Tweet" button if the message is over 140 characters.
</li>
<li> Truncate default tweet values longer than 140.
</li>
</ul>
<p>2011-02-15 - 1 beta1
</p>
<h2> <span class="mw-headline"> Credits </span></h2>
<p>Twitter OAuth support courtesy of <a href="http://abrah.am/" class="external text" rel="nofollow">Abraham Williams'</a> awesome <a href="https://github.com/abraham/twitteroauth" class="external text" rel="nofollow">TwitterOAuth PHP library</a>.
</p>
    </div></content>
  </entry>
  <entry>
    <title>Bash scripts to streamline the Drupal core and module update process via Subversion</title>
    <link rel="alternate" type="text/html" href="http://2tbsp.com/content/streamline-drupal-update-process" />
    <id>http://2tbsp.com/content/streamline-drupal-update-process</id>
    <published>2011-02-21T10:21:55-05:00</published>
    <updated>2011-02-21T19:32:40-05:00</updated>
    <author>
      <name>chad</name>
    </author>
    <category term="Bash" />
    <category term="Drupal" />
    <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>Drupal is a great foundation for so many types of web sites. The <a href="http://drupal.org/home" target="_blank">Drupal community </a>continuously improves <a href="http://drupal.org/download" target="_blank">its core</a> and the growing list of <a href="http://drupal.org/project/modules" target="_blank">add-on modules</a> to extend functionality and improve security. If you manage several Drupal sites, all of this extending and improving can make keeping Drupal up-to-date a time-consuming task. Here are a few notes about how I maintain my Drupal and a few shell scripts I've created to streamline the process.    </div></summary>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>Drupal is a great foundation for so many types of web sites. The <a href="http://drupal.org/home" target="_blank">Drupal community </a>continuously improves <a href="http://drupal.org/download" target="_blank">its core</a> and the growing list of <a href="http://drupal.org/project/modules" target="_blank">add-on modules</a> to extend functionality and improve security. If you manage several Drupal sites, all of this extending and improving can make keeping Drupal up-to-date a time-consuming task. Here are a few notes about how I maintain my Drupal and a few shell scripts I've created to streamline the process.<!--break--></p>
<h2>Drupal Multisite and Subversion</h2>
<p>I use Drupal's <a href="http://drupal.org/getting-started/6/install/multi-site" target="_blank">multisite feature</a> and <a href="http://subversion.tigris.org/" target="_blank">Subversion</a> to create and manage almost every site I develop. </p>
<p>Here's the basic process:</p>
<ol>
<li>Download core and module updates tarballs </li>
<li>Unpack the update over a local SVN working copy </li>
<li>Test and commit the updates locally </li>
<li>Run SVN update for the remote production copy </li>
</ol>
<p>About a year ago, I wrote a few shell scripts to streamline this process for Drupal 6 and recently added support for Drupal 7. </p>
<h2>Drupal Core and Module Update Scripts</h2>
<p>Before using the update Drupal core script, be sure that you've set your Subversion repository to ignore 
local files that you don't want to add (i.e. settings.php, symlinks, etc.). If you don't, the script may add and commit files you don't want in your repo. With that out of the way, here are the scripts and a what they do.</p>
<p>drupal_update.sh does the following:</p>
<ol>
<li>Moves the core update package to tmp and unpacks it.</li>
<li>Removes the .htaccess and sites/example.sites.php files.</li>
<li>Zips the modified core package and unpacks over the local install.</li>
<li>SVN adds any new files.</li>
<li>Pauses and prompts you to run update.php locally and test.</li>
<li>Checks in the modified and new files upon confirmation.</li>
<li>Prompts to run SVN update against the remote installation.</li>
</ol>
<p>drupal_module_update.sh does the following:</p>
<ol>
<li>Moves the module update package to either sites/all/modules or sites/yourdomain.com/modules and unpacks it.</li>
<li>SVN adds any new files.</li>
<li>Pauses and prompts you to run update.php locally and test.</li>
<li>Checks in modified and new files upon confirmation.&nbsp;</li>
<li>Prompts to run SVN update against the remote installation.</li>
</ol>
<p>I still have several features I'll be adding, including the use of <a href="http://drupal.org/project/drush" target="_blank">drush</a> to run database updates (update.php) and the removal of deprecated files. See the Roadmap for a full to do list.</p>
<h2>Get the scripts, Configure 'em, and Use</h2>
<ol>
<li>Clone the <a href="https://github.com/ckieffer/drupal-tools" target="_blank" title="drupal-tools">Git repo</a> or Download (<a href="https://github.com/ckieffer/drupal-tools/tarball/master">tar.gz</a> or <a href="https://github.com/ckieffer/drupal-tools/zipball/master">zip</a>)</li>
<li>Remove the .default extension froma drupal_info.sh</li>
<li>Edit drupal_info.sh, add local and remote path information for your Drupal 6 and 7 instance. Add SSH server and username for remote server.</li>
<li>Download Drupal core/module updates to $DownloadsPath, the following to update a Drupal core:<br>
<pre class="brush: bash;gutter: false; fontsize: 100; first-line: 1; ">% drupal_update.sh</pre>
or, update a shared or site-specific module with:<br>
<pre class="brush: bash;gutter: false; fontsize: 100; first-line: 1; ">% drupal_module_update.sh
</pre></li>
</ol>
<h2>Roadmap</h2>
<ul>
<li>Delete deprecated package files from SVN via svn remove.</li>
<li>Provide <a href="http://drupal.org/project/drush" target="_blank">drush</a> integration to initiate update.php, etc.</li>
<li>Cleanup and release a "create new multisite instance" script.</li>
<li>Add theme update/install support.</li>
</ul>
<h2>Change Log</h2>
<p>2011-02-11 version 0.8</p>
<ul>
<li>Added support for Drupal 7.</li>
<li>Auto-detect version.</li>
<li>Automatically add new files for Drupal core updates.</li>
<li>Fix include of drupal_info.sh to allow aliased script execution to work.</li>
</ul>    </div></content>
  </entry>
  <entry>
    <title>bit.ly module for Gallery 3</title>
    <link rel="alternate" type="text/html" href="http://2tbsp.com/content/bitly-module-gallery-3" />
    <id>http://2tbsp.com/content/bitly-module-gallery-3</id>
    <published>2011-01-15T01:09:41-05:00</published>
    <updated>2013-07-09T02:24:45-04:00</updated>
    <author>
      <name>chad</name>
    </author>
    <category term="Gallery" />
    <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>I finally made some time to get back to work on Gallery. Step one, create a simple module to shorten Gallery 3 album, photo, and movie links with bit.ly. Step two is to create a Twitter module which will make use of the bit.ly module. </p>
    </div></summary>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>I finally made some time to get back to work on Gallery. Step one, create a simple module to shorten Gallery 3 album, photo, and movie links with bit.ly. Step two is to create a Twitter module which will make use of the bit.ly module. </p>
<h2>Installation</h2>
<ol>
<li>Sign up for a <a href="http://bit.ly/" class="external text" rel="nofollow">bit.ly account</a>, if you don't have one.
</li>
<li><a href="https://github.com/downloads/ckieffer/gallery3-contrib/bitly.tar.gz">Download the module</a>, unpack to your Gallery 3 modules directory.</li>
<li> Enable the module via Admin &gt; Modules
</li>
<li> Configure the module at Admin &gt; Settings &gt; bit.ly
<ol>
<li> Enter your bit.ly <a href="http://bit.ly/a/your_api_key" class="external text" rel="nofollow">Username and API Key</a>
</li>
<li> Select a preferred domain, bit.ly or j.mp</li>
</ol>
</li>
</ol>
<h2><span class="mw-headline">Features </span></h2>
<ul>
<li> Provides "Shorten link with bit.ly" site and contextual menu links
</li>
<li> Displays shortened links in the info module's sidebar block
</li>
<li> Choose bit.ly or j.mp as a base URL
</li>
<li> Provides static methods to shorten and retrieve item links for other Gallery modules</li>
</ul>
<h2><span class="mw-headline">Notes </span></h2>
<ul>
<li> The preferred domain setting may be changed at anytime without<br />
breaking existing shortened links. The Gallery item's bit.ly hash can be<br />
 used with either domain.
</li>
<li> Your bit.ly account will provide some nice extras, including<br />
click counts, QR codes, and social network sharing stats for your<br />
shortened Gallery links.
</li>
</ul>
    </div></content>
  </entry>
  <entry>
    <title>Del.icio.us evacuation procedure for your bookmarks</title>
    <link rel="alternate" type="text/html" href="http://2tbsp.com/content/delicious-evacuation-procedure-your-bookmarks" />
    <id>http://2tbsp.com/content/delicious-evacuation-procedure-your-bookmarks</id>
    <published>2011-01-02T21:05:05-05:00</published>
    <updated>2011-01-03T20:47:08-05:00</updated>
    <author>
      <name>chad</name>
    </author>
    <category term="Bash" />
    <category term="Community/Social Networks" />
    <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>Thanks to @andrew_k for posting an awesomely simple curl command to dump bookmarks for a del.icio.us account.</p>
<p><a href="http://twitter.com/#%21/andrew_k/status/15524488837865472" title="del.icio.us evacuation procedure"><img src="http://2tbsp.com/system/files/delicious_tweet_0.png" alt="@andrew_k's del.icio.us evacuation procedure" width="526" height="240"></a></p>    </div></summary>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>Thanks to @andrew_k for posting an awesomely simple curl command to dump bookmarks for a del.icio.us account.</p>
<p><a href="http://twitter.com/#%21/andrew_k/status/15524488837865472" title="del.icio.us evacuation procedure"><img src="http://2tbsp.com/system/files/delicious_tweet_0.png" alt="@andrew_k's del.icio.us evacuation procedure" width="526" height="240"></a></p>
<p>My wife and I both use del.icio.us. The following is a simple shell 
script I'm running periodically during the day to keep a backup of our 
bookmarks. I'll keep running this up until Yahoo! pulls the plug or 
until I find a suitable alternative.</p>
<p>If you need to dump a single account, just hardcode your login and 
password into the curl URL and run the command as crontab entry 
directly.</p>
<p>&nbsp;</p>
<p>
<pre class="brush: bash;fontsize: 100; first-line: 1; ">#!/bin/bash
#
# Script: backup_delicious.sh
# Description: Backup delicious bookmarks to an XML file
# Location: /usr/local/bin
# Author: Chad Kieffer, ckieffer at gmail dot com
#
# Sample cron entry:
# 0 9,12,15,18,21 * * * '/usr/local/bin/backup_delicious.sh'
USER=(
  'user1'
  'user2'
)
PASSWORD=(
  'user1password'
  'user2password'
)
for (( i = 0 ; i &lt; ${#USER[@]} ; i++ ))
  do
    /usr/bin/curl https://${USER[$i]}:${PASSWORD[$i]}@api.del.icio.us/v1/posts/all &gt; /path/to/backup/directory/bookmarks_${USER[$i]}.xml
done
exit 0
</pre></p>    </div></content>
  </entry>
  <entry>
    <title>Speed up HTML markup in Netbeans with Zen Coding</title>
    <link rel="alternate" type="text/html" href="http://2tbsp.com/node/116" />
    <id>http://2tbsp.com/node/116</id>
    <published>2010-02-27T11:39:09-05:00</published>
    <updated>2011-01-19T20:36:16-05:00</updated>
    <author>
      <name>chad</name>
    </author>
    <category term="How to" />
    <category term="HTML/CSS" />
    <category term="NetBeans" />
    <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>My friend Derek shared a link about Zen Coding a month ago which I finally made time to look at this morning. <a href="http://code.google.com/p/zen-coding/">Zen Coding</a> is a plugin designed to supercharge your HTML markup and CSS coding and it's available for several IDEs and text editors. I watched the available screencasts and gave it a try this morning. It's remarkable what you can do with it.</p>    </div></summary>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>My friend Derek shared a link about Zen Coding a month ago which I finally made time to look at this morning. <a href="http://code.google.com/p/zen-coding/">Zen Coding</a> is a plugin designed to supercharge your HTML markup and CSS coding and it's available for several IDEs and text editors. I watched the available screencasts and gave it a try this morning. It's remarkable what you can do with it.</p>
<p>Although the NetBeans version of Zen Coding doesn't provide CSS support and is missing many of the HTML features available in other versions of the plugin, it's still worth an install. <a href="http://rmcreative.ru/">Alexander Makarov</a> created the NetBeans version of the plugin and provides basic instructions in Russian. After translating the instructions and a bit of trial and error, I was able to get the basics workings. Here's how to install and use it for NetBeans for OS X.</p>
<h2>Install</h2>
<ol>
<li><a href="http://code.google.com/p/zen-coding/downloads/list" target="_blank" title="Download NetBeans Zen HTML">Download NetBeans Zen HTML</a>, version 1.2 at the writing of this post.</li>
<li>Move the downloaded package to your .netbeans directory and unpack. Replace the 6.8 directories in the commands below to match your NetBeans version.</li>
</ol>
<p><pre class="brush: bash;gutter: false; fontsize: 100; first-line: 1; ">% mv NetBeans.Zen.HTML.1.2.zip ~/.netbeans/6.8 
% cd ~/.netbeans/6.8 
% unzip NetBeans.Zen.HTML.1.2.zip</pre></p>
<h2>Use</h2>
<p>NetBeans already provides HTML tag completion for individual opening and closing tags.</p>
<p><img src="/system/files/01zen-coding.png" alt="Native NetBeans HTML tag autocomplete" height="98" width="450"></p>
<p>Zen Coding inserts both the opening and closing tags with a keystroke. The tab key triggers Zen Coding's HTML autocomplete magic by inserting both the opening and closing tags. Note the standard NetBeans red box targets to enter text or attribute values. Use the tab key to move between the boxes and hit enter when you're done with an entry.</p>
<p><img src="/system/files/02zen-coding.png" alt="Basic zen-coding NetBeans example" height="50" width="450"></p>
<p>Inserting anchors and their URLs is a breeze.</p>
<p><img src="/system/files/03zen-coding.png" alt="Insert anchor zen-coding NetBeans example" height="41" width="450"></p>
<p>Markup existing text quickly, just select and hit ctrl+Enter or Return.</p>
<p><img src="/system/files/04zen-coding.png" alt="Markup existing text blocks with zen-coding for Netbeans" height="305" width="450"></p>
<p>You can also insert class, id, and style attributes with the 
following keystrokes:</p>
<ul>
<li>ctrl+2 = class</li>
<li>ctrl+3 = id</li>
<li>ctrl+4
 = style</li>
</ul>
<p><img src="/system/files/05zen-coding.png" alt="Insert attributes with zen-coding for Netbeans" height="18" width="450"></p>
<p>Note that attribute insertion is a bit quirky. I found it easier to insert a tag, hit the tab key, position my cursor in 
the opening tag (i.e. &lt;tag|&gt;), and then insert the attribute.</p>
<p>I highly recommend this plugin. The Netbeans version only implements a portion of what the plugin is capable of in other editors. I'm going to give it a whirl with Textmate next!</p>    </div></content>
  </entry>
  <entry>
    <title>Add RTL support to Superfish jQuery menu plugin</title>
    <link rel="alternate" type="text/html" href="http://2tbsp.com/node/114" />
    <id>http://2tbsp.com/node/114</id>
    <published>2009-11-20T22:17:03-05:00</published>
    <updated>2011-01-31T12:34:42-05:00</updated>
    <author>
      <name>chad</name>
    </author>
    <category term="Gallery" />
    <category term="HTML/CSS" />
    <category term="JavaScript" />
    <category term="jquery" />
    <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p><a href="http://github.com/gallery/gallery3">Gallery 3's</a> core themes use the <a href="http://users.tpg.com.au/j_birch/plugins/superfish/">Superfish</a> menu plugin for jQuery. Superfish provides very nice multi-level dropdown menus, but it does not include support for RTL languages.

</p>    </div></summary>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p><a href="http://github.com/gallery/gallery3">Gallery 3's</a> core themes use the <a href="http://users.tpg.com.au/j_birch/plugins/superfish/">Superfish</a> menu plugin for jQuery. Superfish provides very nice multi-level dropdown menus, but it does not include support for RTL languages.

</p><p>So along with other <a href="/node/113">recent work</a> to provide better RTL support for Gallery 3 themes, I also wrote the following RTL overrides for Superfish. 

Just drop the following in somewhere after the inclusion of the Superfish style sheet when your site's in RTL mode! Oh, you'll also need the submenu/arrows sprite file, <a href="/system/files/arrows-ffffff-rtl.png">arrows-ffffff-rtl.png</a> flipped too.

</p><p>&nbsp;</p><p><pre class="brush: css;fontsize: 100; first-line: 1; ">/* RTL Superfish ~~~~~~~~~~~~~~~~~~~~~~~~~ */

.rtl .sf-menu a { 
  border-left: none;
  border-right:1px solid #fff;
} 

.rtl .sf-menu a.sf-with-ul { 
  padding-left: 2.25em;
  padding-right: 1em;
} 

.rtl .sf-sub-indicator { 
  left: .75em !important;
  right: auto;
  background: url('superfish/images/arrows-ffffff-rtl.png') no-repeat -10px -100px;
  /* 8-bit indexed alpha png. IE6 gets solid image only */
}

.rtl a &gt; .sf-sub-indicator {
  /* give all except IE6 the correct values */
  top: .8em;
  background-position: -10px -100px;
  /* use translucent arrow for modern browsers */
}

/* apply hovers to modern browsers */

.rtl a:focus &gt; .sf-sub-indicator, 
.rtl a:hover &gt; .sf-sub-indicator, 
.rtl a:active &gt; .sf-sub-indicator, 
.rtl li:hover &gt; a &gt; .sf-sub-indicator, 
.rtl li.sfHover &gt; a &gt; .sf-sub-indicator {
  background-position: 0 -100px;
  /* arrow hovers for modern browsers*/
}

/* point right for anchors in subs */

.rtl .sf-menu ul .sf-sub-indicator {
  background-position: 0 0;
}

.rtl .sf-menu ul a &gt; .sf-sub-indicator {
  background-position: -10px 0;
} 

/* apply hovers to modern browsers */

.rtl .sf-menu ul a:focus &gt; .sf-sub-indicator,
.rtl .sf-menu ul a:hover &gt; .sf-sub-indicator,
.rtl .sf-menu ul a:active &gt; .sf-sub-indicator,
.rtl .sf-menu ul li:hover &gt; a &gt; .sf-sub-indicator,
.rtl .sf-menu ul li.sfHover &gt; a &gt; .sf-sub-indicator {
  background-position: 0 0;
  /* arrow hovers for modern browsers*/
}

.rtl .sf-menu li:hover ul,
.rtl .sf-menu li.sfHover ul {
  right: 0;
}

.rtl ul.sf-menu li li:hover ul,
.rtl ul.sf-menu li li.sfHover ul {
  right: 10em;
  /* match ul width */
}

.rtl ul.sf-menu li li li:hover ul,
.rtl ul.sf-menu li li li.sfHover ul {
  right: 10em;
  /* match ul width */
}

/*** shadows for all but IE6 ***/

.rtl .sf-shadow ul {
  background: url('superfish/images/shadow.png') no-repeat bottom left;
  padding: 0 0 9px 8px;
  -moz-border-radius-bottomright: 17px;
  -moz-border-radius-topleft: 17px;
  -webkit-border-top-left-radius: 17px;
  -webkit-border-bottom-right-radius: 17px;
}
</pre></p>    </div></content>
  </entry>
  <entry>
    <title>Flip it, flip it good: Quick tips for supporting RTL languages in your web application</title>
    <link rel="alternate" type="text/html" href="http://2tbsp.com/node/113" />
    <id>http://2tbsp.com/node/113</id>
    <published>2009-11-20T02:54:14-05:00</published>
    <updated>2011-02-10T22:42:45-05:00</updated>
    <author>
      <name>chad</name>
    </author>
    <category term="Gallery" />
    <category term="HTML/CSS" />
    <category term="Open Source" />
    <category term="Web Applications" />
    <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>I've been working with themes in <a href="http://gallery.menalto.com">Gallery</a> for 6 years and it wasn't until recently that I started to give due consideration to a significant portion of Gallery's users, those whose native language is written from <a href="http://wiki.answers.com/Q/What_languages_are_read_from_right_to_left">right to left</a>. Shame on me, because it's really not that difficult to add proper RTL text and layout support to web applications. I hope the following helps out those who need to do the same.</p>
<p>
    </div></summary>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>I've been working with themes in <a href="http://gallery.menalto.com">Gallery</a> for 6 years and it wasn't until recently that I started to give due consideration to a significant portion of Gallery's users, those whose native language is written from <a href="http://wiki.answers.com/Q/What_languages_are_read_from_right_to_left">right to left</a>. Shame on me, because it's really not that difficult to add proper RTL text and layout support to web applications. I hope the following helps out those who need to do the same.</p>
<p>
<!--break--></p>
<p>Here are the primary things you'll need to consider when styling your web application for RTL languages.</p>
<h2>Text direction and alignment</h2>
<p>At the core of everything RTL is the <a href="http://wiki.answers.com/Q/What_languages_are_read_from_right_to_left">CSS direction property</a>. This property defaults to ltr and in Gallery direction is switched to rtl by applying a CSS class to our core template's body element.</p>
<p><pre class="brush: plain;gutter: false; fontsize: 100; first-line: 1; ">&lt;body class="rtl"&gt;</pre></p>
<p>The class is defined simply as:</p>
<p>&nbsp;</p>
<p><pre class="brush: css;gutter: false; fontsize: 100; first-line: 1; ">.rtl { direction: rtl; }</pre></p>
<p>Every CSS adjustment made for RTL will be defined through a <a href="http://css.maxdesign.com.au/selectutorial/selectors_descendant.htm">descendent selector</a> starting with this class. In addition to setting text direction we also set text alignment. Gallery use a couple of generic classes for this.</p>
<p><pre class="brush: css;gutter: false; fontsize: 100; first-line: 1; ">.g-text-left  { text-align: left; }
.g-text-right { text-align: right; } </pre></p>
<p>These classes can easily be redefined when they become the descendant of our RTL class.</p>
<p><pre class="brush: css;gutter: false; fontsize: 100; first-line: 1; ">.rtl .g-text-left  { text-align: right; } 
.rtl .g-text-right { text-align: left; }</pre></p>
<p>The 'g-' prefix on the class names act sort of like namespaces and keep Gallery's CSS from stepping on and/or getting stepped on by CSS when it's integrated with other web applications.</p>
<h2>Layout and block element alignment</h2>
<p>Left floated elements should be floated to the right and vica versa. Gallery uses something like the following to float block elements.</p>
<p><pre class="brush: css;gutter: false; fontsize: 100; first-line: 1; ">.g-left  { float: left; }
.g-right { float: right; }</pre></p>
<p>And here are the RTL equivalents. By now you get the picture.</p>
<p>&nbsp;</p>
<p><pre class="brush: css;gutter: false; fontsize: 100; first-line: 1; ">.rtl .g-left  { float: right; }
.rtl .g-right { float: left; }</pre></p>
<p>You'll also need to flip padding and margin values from left to the right. The following LTR blocks align nicely and use a bit of right margin to add white space between them.</p>
<p><img src="/system/files/rtl-margin1.png" width="425" height="160"></p>
<p>You won't be able to simply float these to the right and maintain alignment.</p>
<p><img src="/system/files/rtl-margin2.png" width="425" height="160"></p>
<p>Swap those margin values from the right to the left!</p>
<p><img src="/system/files/rtl-margin3.png" width="425" height="160"></p>
<p>Much better.</p>
<h2>Icon orientation</h2>
<p>Directional arrows in buttons, dropdown indicators, etc. also need to be flipped. Make sure have a second version or the flipped version's included in your image sprite files.</p>
<p><img src="/system/files/rtl-icons_0.png" alt="Gallery icons" width="499" height="229"></p>
<p>Flipping the arrows on tabs and and the pager button was simply a matter of updating float values. The breadcrumb separator and the play slideshow button icons each required the creation of a mirrored copy.</p>
<h2>Helpul tips</h2>
<p>The following helped me out tremendously while testing RTL styles.</p>
<ul>
<li>Install RTL fonts to use while testing. All I needed to do was pop in my Snow Leopard disk and install Arabic and Hebrew with the extras installer. It was pretty quick and easy.</li>
<li>Enlist the help of users who speak Arabic, Hebrew, etc. to review your work. I was fortunate to have the help of a few Gallery community members who cared enough to provide feedback and submit tickets with annotated screenshots which illustrated problems and defined solutions. Some RTL issues would never have been fixed without their help.</li>
</ul>
<h2>The Final (almost) Product</h2>
<p>We're getting closer to the first Gallery 3 release candidate. Download it and give it a try. In the meantime, check out the <a href="/system/files/rtl-english.png">English display</a> for G3's default theme, Wind, and the <a href="/system/files/rtl-arabic.png">Arabic display</a>.</p>    </div></content>
  </entry>
  <entry>
    <title>The First Ignite Santa Fe!</title>
    <link rel="alternate" type="text/html" href="http://2tbsp.com/first_ignite_santa_fe" />
    <id>http://2tbsp.com/first_ignite_santa_fe</id>
    <published>2009-04-30T23:39:57-04:00</published>
    <updated>2009-05-01T00:45:53-04:00</updated>
    <author>
      <name>chad</name>
    </author>
    <category term="Fun" />
    <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p><img src="http://ignite.oreilly.com/images/ignite-main-logo.gif" style="float: right; margin-left: 20px;" alt="Ignite Santa Fe" /> The past few weeks of rounding up speakers and prepping my talk for the first <a href="http://ignitesantafe.com">Ignite Santa Fe</a> are now a wonderful blur. My nerves and fear of public speaking were quickly washed away last night by an awesome gathering of people, ideas, and perspectives.</p>    </div></summary>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p><img src="http://ignite.oreilly.com/images/ignite-main-logo.gif" style="float: right; margin-left: 20px;" alt="Ignite Santa Fe" /> The past few weeks of rounding up speakers and prepping my talk for the first <a href="http://ignitesantafe.com">Ignite Santa Fe</a> are now a wonderful blur. My nerves and fear of public speaking were quickly washed away last night by an awesome gathering of people, ideas, and perspectives.</p><!--break--><p>What is <a href="http://ignite.oreilly.com">Ignite</a>? It's an event, a vibe, a brainstorm, and a heck of a lot of fun. Speakers are given 5 minutes and 20 slides to share an idea, experience, or passion. Yep, just 20 slides and they advance automatically every 15 seconds. The pace certainly keeps things interesting.</p>

<p>A great group of people from Santa Fe, Los Alamos, Albuquerque, and points between convened at the perfect venue, <a href="http://sfcomplex.org">the Santa Fe Complex</a>. At first I was struck at the diversity of topics but by the end of the night some common threads emerged. Focusing on what's important stuck with me, the simple display of crystals in a museum exhibit to the preservation of the core traditions of a Nepalese village.</p>

<p>I have a few new localized ideas to chew on too. The possibility of increased civic-awareness through live web streaming of local government proceedings and visualizing data local in more meaningful ways. I now know what makes a dinosaur a dinosaur, the steps to setup a non-profit organization, and the dimensions of sound. I got a glimpses back at 60s counterculuture and forward to the inter-reality my kids may likely know. We even had two last minute talks put together as everyone else was speaking. Everyone did a great job!</p>

<p>Thanks to <a href="http://davidmichaelthompson.com/">Mick</a> for grabbing the matches and <a href="http://www.lava3d.com/SteveSmith.html">Steve</a> for providing the kindling. I had great time meeting and seeing everyone and can't wait until we do it again!</p>    </div></content>
  </entry>
  <entry>
    <title>UI and Theme Development Simplified in Gallery 3!</title>
    <link rel="alternate" type="text/html" href="http://2tbsp.com/node/111" />
    <id>http://2tbsp.com/node/111</id>
    <published>2009-02-18T21:18:42-05:00</published>
    <updated>2011-01-22T14:26:12-05:00</updated>
    <author>
      <name>chad</name>
    </author>
    <category term="Gallery" />
    <category term="jquery" />
    <category term="YUI" />
    <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p><img src="/system/files/g3jQuery.png" alt="Gallery 3 and jQuery" align="right" height="122" width="107">The next version of Gallery 3 is a complete rewrite from the ground up. It's coming along nicely thanks, in part, to jQuery and jQuery UI. Here's a bit of background on the project's decision to use jQuery and highlights of Gallery 3's theme system changes.</p>
    </div></summary>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p><img src="/system/files/g3jQuery.png" alt="Gallery 3 and jQuery" align="right" height="122" width="107">The next version of Gallery 3 is a complete rewrite from the ground up. It's coming along nicely thanks, in part, to jQuery and jQuery UI. Here's a bit of background on the project's decision to use jQuery and highlights of Gallery 3's theme system changes.
</p>
<h2>Why rewrite Gallery 2?</h2>
<p>
Despite Gallery 2's success, there are some big issues in the core product. These issues cannot easily be addressed within the current code base. So last October, <a href="http://gallery.menalto.com/gx_sprint" title="Gallery Code Sprint">the development team got together</a> and decided to rewrite the product from the ground up. The <a href="http://gallery.menalto.com/gallery_3_begins" title="Gallery 3 Begins">primary goals of Gallery 3</a> are to make it easier for the Project's core developers to maintain the product while lowering the bar for users to build their own modules and themes.
</p>
<h2>Theming in Gallery 3</h2>
<p>
Gallery 2 themes each have a PHP class file which "hooked" the theme and it's settings into the Gallery 2 framework. To create a new theme you either have to create this class file from scratch or copy and edit another theme's class file. If you want to alter or extend a Gallery 2 theme template you also need to know Smarty PHP template syntax. These requirements are gone in Gallery 3. Just copy and rename an existing theme folder, enable it through the administration interface, and you're set to go. If you've worked with Wordpress, Drupal, or Joomla themes, Gallery 3's theme system will look very familiar.
</p>
<h2>jQuery and jQuery UI in Gallery 3</h2>
<p>
Gallery 2 currently ships with several YUI 2.x components which provide Ajax, dialogs, drag and drop, and autocomplete features. Integrating YUI widgets into Gallery 2's core has been relatively easy but there are few, if any, third-party modules or themes which implement additional YUI-based features.
</p>
<p>
After research and comparison of the YUI (2 and 3PR), Dojo, and jQuery the team decided that Gallery 3 would be built with jQuery. Of the three, jQuery took less time to learn and implement. While each framework has it's strengths, the following points summarize why jQuery was selected.
</p>
<ul>
<li>jQuery's selectors make basic DOM manipulation and effect building quick and easy with minimal code.</li>
<li>jQuery has proven itself easily accessible to a wide range of web developers and designers.</li>
<li>jQuery is light and performs comparatively well.</li>
<li>jQuery UI is providing a stable and growing selection of widgets and effects.</li>
</ul>
<p>
Gallery 3 is currently using the following jQuery plugins and jQuery UI components:
</p>
<ul>
<li><a href="http://jqueryui.com/">jQuery UI 1.6rc6</a>
<ul>
<li>Interactions: Draggable, Droppable, Resizable, Sortable</li>
<li>Widgets: Accordion, Dialog, Datepicker, Progressbar, Tabs</li>
</ul>
<ul>
<li>Effects: Highlight</li>
<li><a href="http://docs.jquery.com/UI/Theming/API">CSS framework</a> - buttons and bars</li>
<li><a href="http://jqueryui.com/themeroller/">Redmond ThemeRoller theme</a></li>
</ul>
</li>
<li><a href="http://users.tpg.com.au/j_birch/plugins/superfish/">Superfish</a> - we expect to replace Superfish with jQuery UI Menu when it's released</li>
<li><a href="http://flesler.blogspot.com/2007/10/jquerylocalscroll-10.html">jQuery.LocalScroll</a></li>
<li><a href="http://malsup.com/jquery/form/">jQuery.form</a></li>
<li><a href="http://plugins.jquery.com/project/Cookie">jQuery.cookie</a></li>
<li><a href="http://www.appelsiini.net/projects/jeditable">jQuery.jeditable</a></li>
</ul>
<p>
Gallery 3's default theme also uses the YUI's Reset, Font, and Grid CSS collections for foundational type styles and page layout. The YUI CSS collection coupled with jQuery UI ThemeRoller themes should allow Gallery 3 users to easily alter page layout and widget appearance in their themes.
</p>
<h2>More to come</h2>
<p>
Take a look at the first <a href="http://gallery.menalto.com/gallery_3.0_alpha_1_released">Gallery 3.0 preview release</a>. Documentation's thin right now, but it shouldn't be too difficult to create a copy of the default theme. Would love to get feedback on the default theme and the current state of our jQuery implementation.
</p>
    </div></content>
  </entry>
  <entry>
    <title>EventBox: Keep up with Twitter and Facebook status updates, and much more</title>
    <link rel="alternate" type="text/html" href="http://2tbsp.com/node/110" />
    <id>http://2tbsp.com/node/110</id>
    <published>2009-02-16T20:31:15-05:00</published>
    <updated>2011-01-18T22:12:12-05:00</updated>
    <author>
      <name>chad</name>
    </author>
    <category term="Applications" />
    <category term="Review" />
    <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>
<img src="/system/files/eb_appicon.png" alt="EventBox Logo" align="right" height="146" width="150">Ever since giving up last year and jumping into the social network fray I've been looking for a good status update viewer and aggregator. I'm trying to keep up with updates from a growing list of family, friends, and peers on Twitter, Facebook, and occasionally Flickr. I'm using Ping.fm to cross post status updates. I've tried the dedicated clients and plugins, but none worked for me quite as well as EventBox.</p>
    </div></summary>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>
<img src="/system/files/eb_appicon.png" alt="EventBox Logo" align="right" height="146" width="150">Ever since giving up last year and jumping into the social network fray I've been looking for a good status update viewer and aggregator. I'm trying to keep up with updates from a growing list of family, friends, and peers on Twitter, Facebook, and occasionally Flickr. I'm using Ping.fm to cross post status updates. I've tried the dedicated clients and plugins, but none worked for me quite as well as EventBox.</p>
<p>The <a href="https://addons.mozilla.org/en-US/firefox/addon/5081">Twitterfox</a>  and <a href="https://addons.mozilla.org/en-US/firefox/addon/3794">Facebook</a>  Firefox plugins work well enough but I'd like a more unified interface. Twitterfox can only show a limited number of updates after not checking updates for a day.</p>
<p>I tried the Adobe Air applications, including <a href="http://www.twhirl.org/">Twhirl</a>  and <a href="http://www.tweetdeck.com/">Tweetdeck</a> . These are both great dedicated Twitter clients. The multipane approach of Tweetdeck and ability to group those you follow into panes is powerful. Both provide Growl-like notification panes. My biggest beefs with these clients are their inability to up font size and Air application's use of the system's default HTML editor to view posted URLs rather than the system's default browser. When I click on posted links, they open in Textmate rather than Firefox. </p>
<p>AlertThingy is another Adobe Air client with a multipane UI similar to Tweetdeck. AlertThingy is a bit more appealing because in addition to Twitter updates, it can also display your Facebook, Flickr, and updates from several other services. Currently, however, AlertThingy doesn't clearly show read vs. unread items and it doesn't seem to reliably retain changes in settings from session to session.</p>
<p>I finally decided to purchase <a href="http://thecosmicmachine.com/">EventBox</a>  after giving it a try. EventBox is an OS X-only client that supports display of Facebook, Twitter, Flickr, and Reddit status, comment, and photo updates. It also includes a generic RSS reader plus support for Google Reader. All of this plus the promise of additional service support convinced me to shell out $15 for a license. </p>
<p>EventBox isn't perfect, but it provides more of what I'm looking for with many of the benefits that come with an OS X native application. The interface is clean and intuitive and provides service-specific views as well as an aggregated unread and recent item&nbsp; views. Unread updates are faded and appear clearly different from unread items. I can control update intervals for each service and turn off new item alerts when I need to tune out distractions and get things done.
</p>
<p>
<a href="/system/files/eventbox.png"><img src="/system/files/eventbox-sm.png"></a> </p>
<p><img src="/system/files/eventbox-applemenu.png" align="right">EventBox also provides an Apple Menu item with an unread count and a summary list of recent updates. Photo viewing for Facebook and Flickr is nice and you can even upload images and edit image metadata directly in EventBox.</p>
<p>EventBox doesn't provide font size controls but overall, this is the only real issue I have with it. I hope that they add support for Ping.fm, LinkedIn, and Delicious. I also hope that thet add support for the Newsgator feed reader, although I might decide to switch to Google Reader. Sync of unread items between multiple installs would be nice to have too. Oh, and they'd really create a stir with an iPhone app! </p>
<p>I'm looking forward to seeing where The Cosmic Machine takes EventBox next. Download the free two week trial and see what you think.
</p>
    </div></content>
  </entry>
  <entry>
    <title>Why I Switched from Eclipse PDT to NetBeans IDE</title>
    <link rel="alternate" type="text/html" href="http://2tbsp.com/node/109" />
    <id>http://2tbsp.com/node/109</id>
    <published>2009-01-28T14:06:18-05:00</published>
    <updated>2011-01-24T21:07:12-05:00</updated>
    <author>
      <name>chad</name>
    </author>
    <category term="JavaScript" />
    <category term="NetBeans" />
    <category term="PHP" />
    <category term="Review" />
    <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>
I had started a post highlighting the recent Eclipse PDT 2.0 release but now find myself dropping the post and the Eclipse IDE altogether. Instead, I'll share why I've switched from Eclipse PDT to NetBeans.
</p>    </div></summary>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>
I had started a post highlighting the recent Eclipse PDT 2.0 release but now find myself dropping the post and the Eclipse IDE altogether. Instead, I'll share why I've switched from Eclipse PDT to NetBeans.
</p>
<p>
First, it should be said that Eclipse 3.4 and PDT 2.0 are huge improvements over previous versions. They're smaller with fewer dependencies. Eclipse 3.4 launches and closes much faster than previous versions thanks to greater use of application and project data caching. PDT 2.0 sports new object-oriented programming features that make navigating and viewing class method relationships really easy. So, with all of these improvements, why change?
</p>
<p>
Regardless of the server-side languages an IDE supports, it must also provide robust support for writing JavaScript. It must also provide support for today's popular JavaScript frameworks, including dojo, jQuery, and YUI. Currently, Eclipse's JSDT plugin does not support these libraries. I've been writing a lot of jQuery lately and JSDT riddled my scripts with error highlights. There is a JSDT patch available to add jQuery and YUI code assist support to <a href="/node/107">JSDT but I was only able to apply it to Eclipse 3.3 and PDT 1.3</a>.
</p>
<p>
I'd read good things about the NetBeans 6.5 release which added PHP editor support. My frustration with JSDT's lack of jQuery support pushed me to download NetBeans and give it a try. I must say that I'm impressed, particularly since this is the first NetBeans release to support PHP editing.
</p>
<p>
I didn't need a tutorial to install and configure NetBeans to <a href="/content/getting_started_eclipse_php_development_tools_%28pdt%29">match my Eclipse environment</a>. NetBeans came with everything I needed out of the box. Here are the hightlights.
</p>
<ul>
<li>The Basics: Project support, code navigation, syntax highlighting, code folding, refactoring, code templates, etc.</li>
<li>CVS and Subversion support.</li>
<li>PHP function completion, documentation popups, and phpDoc autocomplete.</li>
<li>Debugging with xDebug.</li>
<li>Basic project deployment tools.</li>
<li>Complete JavaScript code assist and completion.</li>
<li>Support for jQuery and YUI code completion.</li>
<li>HTML/CSS code completion and validaiton. The CSS preview pane is very cool.</li>
</ul>
<p>
Nice! No need to install plugins to get version control and debugging support. The <a href="http://www.netbeans.org/features/php/">NetBeans site</a> provides good documentation and a number of getting started tutorials.
</p>
<p>
I did have a few issues that are worth mentioning.
</p>
<ul>
<li>Watch out during commits as, unlike Subclipse, NetBeans will automatically svn add new files to your repository for you. I committed a few files before they were ready during my first commits from NetBeans. You can easily add files to an ignore list or deselect files when performing commits.</li>
<li>It took me a while to become accustomed to NetBeans UI. There's more flexibility in how navigation panes can be dislayed in the workspace. I didn't like this at first, but it's grown on me.</li>
</ul>
<p>
I've used Komodo IDE and Zend Studio and am amazed at how close NetBean's feature set is to these commercially licensed packages. If you're looking for a new IDE, give NetBeans a try.
</p>    </div></content>
  </entry>
</feed>
