The 'Views' module is one of the mainstays of Drupal site building. It allows non-programmers to build highly customized listings of data that match certain criteria, then present that data in a variety of ways. A thumbnail gallery of photos, an alphabetized listing of site contributors, and a calendar display of upcoming events are all common applications of Views.
In this series of articles, we'll be taking a quick look at the architecture of the Views module and how its pieces work together; touring the different plug-in points that Views offers developers; and building a simple 'argument handler' for Views that demonstrates how the approach looks in the real world. A bit of knowledge about SQL will be useful for the article, as well as some understanding of object-oriented programming concepts like 'inheritance', but the code samples should be simple enough to tweak even if you're not a pro.
Under the hood, the pieces of a View can be divided into two different groups: the 'data' (stuff that affects the underlying database query that Drupal uses to retrieve the information for the View) and the 'presentation' (stuff that affects how that data is displayed to a user of the web site).
Buildin' SQLThe 'data' portions of the View are more numerous: they correspond roughly to the different pieces of a SQL 'SELECT' statement. That should come as no surprise -- at Views heart is a SQL query builder that turns all of your settings into a query against Drupal's database tables.
The one required file in any Drupal 6 theme is the .info file. It was a great addition to the theme layer and makes defining functionality almost dead simple. Documented features of the .info file allow for adding descriptive information, features, stylesheets and javascript files to the theme. This has made constructing a custom theme much easier compared to Drupal 5 since there is no mucking about in PHP necessary.
The system is not perfect and there are limitations to this set of supported definitions. For instance, all stylesheets added via the theme are always ordered after all the system and module stylesheets. This is less than optimal for reset CSS files and CSS frameworks like 960 grid system. Another common practice is conditional stylesheets for Internet Explorer browsers. The only option to use this method is to hard code the stylesheets into the page.tpl.php or install a module. It would be so nice to define these files in the theme's .info file and keep the themes flexible.
Thankfully, this is fully possible with the help of a couple variables. As a warning for those not versed in PHP, implementing any of this functionality requires it's use.
A little exampleAnything that is added to the .info file is available for use. This is not restricted to the supported features. As an example, let's construct a simple theme called "jim".
Since this is purely an example, our theme is only going to consist of 3 files: jim.info, reset.css and ie6.css. It will not be necessary to add anything to the CSS files since this is only an example, but it will be necessary to add something to the .info file to get it recognized by Drupal.
name = JimThis is only the required information for a Drupal theme. It will not win any beauty contests, but now we can now select the theme as our default in themes administration. Since that is done, let's add our stylesheets in an unconventional way by adding the following lines to our jim.info.
top stylesheets[all][] = reset.cssThe standard practice is to clear the theme registry cache when adding to a theme's .info file, but there will not be any noticeable effect. To get access to this information we will need to delve into some PHP. The proper place for that would be the template.php, so add one to the theme's folder.
Dig into $theme_infoWe will be adding our extra styles to the $styles variable in page.tpl.php. This will be done via hook_preprocess_page() in template.php. In order to use this preprocess function, a page.tpl.php will needed in our theme. I simply copied the core Drupal version at modules -> system -> page.tpl.php to our theme.
To get at our new stylesheets in jim.info, we will need access to the $theme_info variable in the hook_preprocess_page() function. Since it is not immediately available, we will have to load it as a global variable. With all of this in mind, you should have something like this in your template.php:
<?phpIf you have the Devel module installed, you can place to a dpm($theme_info); in that function to display the contents of the variable. If you look in $theme_info->info, you will see your new stylesheet definitions. Now to put them to work for us.
Put stylesheets at the top of the stackOur first task will be to add the top styles to the top of the stylesheet stack. To take advantage of CSS compression in Drupal, we will want to put it in with the rest of the accounted for stylesheets and then run them through drupal_get_css(). There will be a bit of sorting needed to accommodate for the media types. In the end you will have something that looks like the following.
<?php // Get the path to the theme to make the code more
// efficient and simple.
$path = drupal_get_path('theme', $theme_info->info['name']);
// Check if there are stylesheets to be placed at the
// top of the stack.
if (isset($theme_info->info['top stylesheets'])) {
$top_css = array();
// Format the stylesheets to work with
// drupal_get_css().
foreach ($theme_info->info['top stylesheets'] as $media => $styles) {
foreach ($styles as $style){
$top_css[$media][$path . '/' . $style] = TRUE;
}
// Add the stylesheets to the top of the proper
// media type.
array_unshift($vars['css'][$media], $top_css[$media]);
}
// Replace $styles with the new string.
$vars['styles'] = drupal_get_css($vars['css']);
}
}
?>
With this code in place, you can now add new stylesheets at will to the jim.info file. Nice, neat and flexible.
Adding conditions for Internet ExplorerFor something a little more complicated, we will now add the support for the conditional stylesheets that only Internet Explorer will see. It will be good to pass these through the drupal_get_css() to take advantage of CSS compression, but the final output can be tacked onto the end of the existing $styles variable.
With only the conditional stylesheets, your function will look like this:
<?php // Get the path to the theme to make the code more
// efficient and simple.
$path = drupal_get_path('theme', $theme_info->info['name']);
// Check for IE conditional stylesheets.
if (isset($theme_info->info['ie stylesheets'])) {
$ie_css = array();
// Format the array to be compatible with
// drupal_get_css().
foreach ($theme_info->info['ie stylesheets'] as $version => $media) {
foreach ($media as $type => $styles) {
foreach ($styles as $style) {
$ie_css[$version][$type]['theme'][$path . '/' . $style] = TRUE;
}
}
}
// Append the stylesheets to $styles, grouping by IE
// version and applying the proper wrapper.
foreach ($ie_css as $version => $styles) {
$vars['styles'] .= '<!--[if ' . $version . ']>' . "\n" . drupal_get_css($styles) . '<![endif]-->' . "\n";
}
}
}
?>
As with the top stylesheets, you can now add new IE conditional stylesheets via the jim.info file. Each line for a CSS file to add would need to be formatted like so: ie stylesheets[conditional logic][media type][] = filename.
Bringing it all together and base themesBy now, your template.php should look like the following:
<?php // Get the path to the theme to make the code more
// efficient and simple.
$path = drupal_get_path('theme', $theme_info->info['name']);
// Check if there are stylesheets to be placed at the
// top of the stack.
if (isset($theme_info->info['top stylesheets'])) {
$top_css = array();
// Format the stylesheets to work with
// drupal_get_css().
foreach ($theme_info->info['top stylesheets'] as $media => $styles) {
foreach ($styles as $style){
$top_css[$media][$path . '/' . $style] = TRUE;
}
// Add the stylesheets to the top of the proper
// media type.
array_unshift($vars['css'][$media], $top_css[$media]);
}
// Replace $styles with the new string.
$vars['styles'] = drupal_get_css($vars['css']);
}
// Check for IE conditional stylesheets.
if (isset($theme_info->info['ie stylesheets'])) {
$ie_css = array();
// Format the array to be compatible with
// drupal_get_css().
foreach ($theme_info->info['ie stylesheets'] as $version => $media) {
foreach ($media as $type => $styles) {
foreach ($styles as $style) {
$ie_css[$version][$type]['theme'][$path . '/' . $style] = TRUE;
}
}
}
// Append the stylesheets to $styles, grouping by IE
// version and applying the proper wrapper.
foreach ($ie_css as $version => $styles) {
$vars['styles'] .= '<!--[if ' . $version . ']>' . "\n" . drupal_get_css($styles) . '<![endif]-->' . "\n";
}
}
}
?>
This bit of code will work great for a standalone theme. Problems will arise when used in a base theme as stylesheet inheritance will be broken. Thankfully, there is a second variable to help with that: $base_theme_info.
This variable has all information on the current theme's base theme, and all base themes of those base themes. Instead of going through all of the explanation, I will simply post the code that takes advantage of it.
<?php // If there is a base theme, collect the names of all
// themes that may have data files to load.
if(isset($theme_info->base_theme)) {
global $base_theme_info;
foreach($base_theme_info as $base){
$themes_active[] = $base->name;
}
}
// Add the active theme to the list of themes that may
// have data files.
$themes_active[] = $theme_info->name;
// Check for stylesheets to be placed at the top of the
// stack or conditional Internet Explorer styles in the
// .info file and add them to the $styles variable.
$top_styles = array();
$ie_styles = array();
// If there is more than one active theme, check all
// base themes for stylesheets.
if (count($themes_active) > 1) {
foreach ($base_theme_info as $name => $info) {
if (isset($info->info['top stylesheets'])) {
$top_styles[$name] = $info->info['top stylesheets'];
}
if (isset($info->info['ie stylesheets'])) {
$ie_styles[$name] = $info->info['ie stylesheets'];
}
}
}
// Check the current theme for stylesheets.
if (isset($theme_info->info['top stylesheets'])) {
$top_styles[$theme_info->name] = $theme_info->info['top stylesheets'];
}
if (isset($theme_info->info['ie stylesheets'])) {
$ie_styles[$theme_info->name] = $theme_info->info['ie stylesheets'];
}
// If there is at least one entry in the $top_styles
// array, process it.
if (count($top_styles) >= 1) {
// Format the array into a format readable by
// drupal_get_css().
$vars['top_css'] = array();
foreach ($top_styles as $name => $theme_styles) {
$path = drupal_get_path('theme', $name);
foreach ($theme_styles as $media => $styles) {
foreach ($styles as $style){
$vars['top_css'][$media]['featured'][$path . '/' . $style] = TRUE;
}
// Add the new styles to the top of the
// $vars['css'] array.
array_unshift($vars['css'][$media], $vars['top_css'][$media]['featured']);
}
}
// Run $vars['css'] through drupal_get_css and
// replace the $styles variable.
$vars['styles'] = drupal_get_css($vars['css']);
}
// If there is at least one entry in the $ie_styles array,
// process it.
if (count($ie_styles) >= 1) {
// Format the array into a format readable by
// drupal_get_css().
$vars['ie_css'] = array();
foreach ($ie_styles as $name => $theme_styles) {
$path = drupal_get_path('theme', $name);
foreach ($theme_styles as $version => $media) {
foreach ($media as $type => $styles) {
foreach ($styles as $style) {
$vars['ie_css'][$version][$type]['theme'][$path . '/' . $style] = TRUE;
}
}
}
}
// Append the stylesheets to $styles, grouped by IE
// conditional.
foreach ($vars['ie_css'] as $version => $styles) {
$vars['styles'] .= '<!--[if ' . $version . ']>' . "\n" . drupal_get_css($styles) . '<![endif]-->' . "\n";
}
}
}
?>
As expected, this ends up being more complicated. The gist of what is going on here is that we have to add an extra level to check what theme is associated with which content. From that point a lot of the process is the same.
ConclusionFor reference, the above themes are attached to this post.
There is a lot of untapped power available in the .info files. I focused on stylesheets in this instance, but there is certainly more that can be accomplished. Placing javascript files in the footer is just one example. I am sure more imaginative people than I can come up with even more.
For those of you wondering, this functionality will be in an upcoming 2.0 version of the Studio theme pack. This will be one of a few changes and others will most like be highlighted at a later date.
PHP, Social Media, and iPhone Development This Week in Washington, DC
It’s hard to believe it’s the last week in July already. Well, until you walk outside into the humid weather we had been lucky to avoid for most of the summer so far. Things are starting to slow down in the city, but there are some interesting technology events happening in Washington, DC this week. Below are a few that caught our eye, and you can find a full list of the week’s events at DC Tech Events.
Also, while it’s not happening in DC, there’s a great event for Drupal developers this week. DrupalCamp is going to Philadelphia on Friday – just a two hour train ride away!
Tuesday, July 28
6:00 – 8:00 pm
DCPHP Beverage Subgroup: If you’re a PHP developer, this one is for you. Come out for this meetup to get to know other PHP developers and talk about code over a couple cold beers.
So you've got a website using another CMS and you want to switch to Drupal? Well with the new Migrate and Table Wizard modules the whole migration process is now relatively painless!
Recently I created a patch for the migrate module so you can export content sets, paste them into your module and have them automatically imported. This works in much the same way as Views handles default views in code, with the version in the database overriding the version in code. Using the Chaos Tools (ctools) module it was, relatively, easy to add this functionality. Here are the steps involved if you want to add it to your own module.
I don't know how I survived long-distance travel before mp3s. You can only carry around so many cassettes or CDs. When I leave the house for a trip my earbuds are pretty much a permanent fixture until I am home again. At home, if I'm at my computer, I'm probably listening to something all the time. I listen to lots of different genres of music, but overall my standard, fall back is something within the electronic realm. Don't get me wrong, I can also listen to Bettie Serveert anytime of the day or night, but by and large electronica is my default if I'm just not sure what I want to listen to. I love listening but I'm not so good with the ten million terms used to slice and dice the music into the most subtle categories, nor do I really care that much. I'm not even going to bet that everything I lump in "electronica" would technically fall there for others. I have my own little system for identifying my mood/music match and the other day I was thinking of it in more concrete terms. So, here is how I tend to think of the electronic music in my collection with some tracks that I could find out on the internets. Lots of stuff falls all over the place and in between, but these tend to be my "moods:"
Comatose: This is the stuff that makes me drool from inactivity. I typically don't listen to this except when trying to sleep (great for red-eye flights) or making myself take a serious energy timeout.
Some examples: Isan - Cinnabar, Dave and Ardai - Recovery Room EP
Groovin: I spend a lot of time in this mix. A lot of stuff I lump here tends to be called downtempo, ambient, blah, blah, blah, by the cool kids. It has more going on than Comatose but isn't frenetic and can keep me moving along for hours at a time. Lots of stuff I love, love, love here.
Some examples: Cassettes Won't Listen - MPC, Sternklang - The Herb
Dance: Yeah, OK, this is a range of music that just makes me wanna shake my booty or jump around. If I could stay up past 11 pm anymore, I'd love to still go out dancing, but since I'm old and lame I often only dance in my office or hotel room.
Some examples: Le Tompé - Tell Me, Tiësto - Traffic, Astral Projection - Kabalah
Soundtrack: For the badass mofo hero(ine) in all of us. Lots of flying fighter jets in space, blowing up 10-story robots, running through jungles, and all the ladies want to get with me. If you don't have a world like this, I am sorry for you, though you may still like the music.
Some examples: Ugress - Zombie Eagles, Fluke - Another Kind of Blues, Astrix - Techno Widows
I've also got my standard stable of music resources. I tend to only have a handful of resources because my head would explode otherwise, so I'm sure there are a ton of awesome things out there. If there is something more awesome that what I'm using, I'm more likely to drop one and move to the other than try to keep track of more and more awesomeness. (I can only handle so much awesomeness in one lifetime, ya know?)
Spending moneyYeah, I actually buy music. I used to mess with all the peer stuff and grabbed a ton of stuff for free back in the day but I'm not as into that anymore. Lots of the music I listen to is from smaller artists and labels and I'd like to support them.
My main service is eMusic. They have great stuff and reasonably priced subscription set up. They were doing DRM-free mp3s since the start so I've always loved supporting them. If I can't find what I want there, my next stop is Amazon, which again, is DRM-free mp3s. iTunes store is my last stop. Both eMusic and Amazon downloaders will automatically add my new music to my iTunes library so there is no extra hassle involved with regards to that. Lots of the remix, dance stuff I want isn't in the main stores so I also use Traxsource to get DJ cuts.
RadioNow here's the free stuff. I don't subscribe to satellite radio, like Sirius. I'm a net radio kind of gal. While free, I do financially support free radio that I love. I donate to Soma.fm and am a subscriber at Last.fm. Soma has a bunch of stations, though I only regularly tune in to about three of them (Secret Agent, Beat Blender and Groove Salad). Great selection of tunes and no commercials. They rock. That is all.
Last.fm lets the social, friend thing get to work in addition to having stations based on an artist (similar to Pandora) or playing my favorites. One of my favorite things to do is listen to a high match friend's station in explore mode. That will only play songs that I don't have in my collection, so I get only new stuff. They also sometimes have good free tracks for download, like a bunch from the excellent Ugress. You'll notice that a lot of my links up above to artists or tracks use Last.fm because it is a great, centralized place for me to keep track of and share the stuff I like.
The only other net radio that I tune into regularly is Radio Frequence Metz Woippy Clubbing and Dance. This is my typical dance-club-in-a-hotel-room mix.
I should also mention briefly that I will often grab my radio using Audio Hijack Pro so I can have a good mix while offline without having to work hard at making one up myself. It is for the Mac, I love it and it is cheaper than some other options out there. Take that for whatever you want.
The wordI am not big into my RSS feeds or wandering the internets these days for info and honestly my radio sources turn me on to more music than I can keep up with already. I do follow one music blog though that often points to very small netlabel stuff, often free tracks, that I'd otherwise never see. I've found some really nice stuff through Disquiet, like Rich Vom Dorf. If you have any other killer blogs that track the cool, little stuff, let me know in the comments.
I wanted to do automatic scheduled backups with the awesomely amazing SuperDuper!. The computer to be backed up was a Mac Mini running Mac OS X 10.5 Leopard. But the problem was that Parallels Desktop was running all the time. And everyone knows that when you try to back up open files that may be changing, Bad Things Happen.
"No problem," I thought. Since SuperDuper! allows you to run a script before and after a scheduled backup (have I mentioned how brilliant SuperDuper! is?) I'll use a script to suspend the virtual machine before the backup, and resume it afterward.
So I fired up Script Editor and went to open up Parallels Desktop's AppleScript Dictionary.
Uh.
Apparently Parallels Desktop does not implement AppleScript.
I was stymied until I remembered something that the indefatigable Matt Neuburg had written in AppleScript: The Definitive Guide, Second Edition in a chapter titled Unscriptable Applications. The approach is to cheat by using the Accessibility API built into Mac OS X. From there you can direct mouse clicks, radio button selection...in short, all sorts of mayhem. "Aha!" I thought. "I'll just direct Parallels from the Accessibility API! Sort of like the puppeteer in Being John Malkovich."
First I made sure that accessibility was enabled by going to the Universal Access preference pane in System Preferences.
Then I made a shell script for SuperDuper! to run before backup. Here's the script:
#!/bin/sh
osascript /Users/john/suspendparallels.txt
sleep 35
osascript /Users/john/quitparallels.txt
sleep 10
The shell script first executes the suspendparallels.txt AppleScript to suspend the virtual machine:
-- Suspend a Parallels virtual machine.
-- Assumptions:
-- - only one virtual machine is running
-- - the "Enable access for assistive devices" checkbox is checked in the Universal Access control panel
-- Tested on Mac OS X 10.5.7 with Parallels Desktop 4.0.
-- John VanDyk 7/22/2009
tell application "Parallels Desktop" to activate
tell application "System Events"
tell application process "Parallels Desktop"
tell menu "Virtual Machine" of menu bar 1
click menu item "Suspend"
end tell
end tell
end tell
Then the shell script waits for 35 seconds (enough time for the virtual machine to be written to disk), and executes the quitparallels.txt AppleScript:
-- Quit Parallels.
-- Assumptions:
-- - only one virtual machine is running
-- - the "Enable access for assistive devices" checkbox is checked in the Universal Access control panel
-- Tested on Mac OS X 10.5.7 with Parallels Desktop 4.0.
-- John VanDyk 7/22/2009
tell application "Parallels Desktop" to activate
tell application "System Events"
tell application process "Parallels Desktop"
tell menu "Parallels Desktop" of menu bar 1
click menu item "Quit Parallels Desktop"
end tell
end tell
end tell
"But John," I can hear you asking, "why not put these together into one simple AppleScript and just use 'delay 35' to create the pause?" I'll tell you why. Because when you do it that way it doesn't work. Plus I got a scary error about "class released with no pool in place - just leaking". Seriously. So I figured, since AppleScript is always, well, flaky for me, I'd just put as much as I could in the shell script and call out to AppleScript only when necessary.
All right. So now SuperDuper! can clone the drive since the Parallels Desktop Windows XP virtual machine has been suspended and the program has been closed. But what about afterwards, when we want to bring Parallels Desktop up just like it was? Turns out, that's even easier. Here's the shell script that SuperDuper! runs after it completes the copy:
#!/bin/sh
osascript -e 'tell app "Parallels Desktop" to activate'
sleep 10
osascript /Users/john/resumeparallels.txt
That first osascript call is actually launching Parallels Desktop. We give it 10 seconds to launch, which is plenty.
Fortunately it launches with the suspended virtual machine. All we have to do is tell it to resume. Here's resumeparallels.txt:
-- Resume a Parallels virtual machine.
-- Assumptions:
-- - only one virtual machine is running
-- - the "Enable access for assistive devices" checkbox is checked in the Universal Access control panel
-- Tested on Mac OS X 10.5.7 with Parallels Desktop 4.0.
-- John VanDyk 7/22/2009
tell application "Parallels Desktop" to activate
tell application "System Events"
tell application process "Parallels Desktop"
tell menu "Virtual Machine" of menu bar 1
click menu item "Resume"
end tell
end tell
end tell
Presto! It works.
Recently I had to do a migration of an old Drupal site with 4.6 million rows in the history table. The history table records when a user has viewed a node. A record looks like this:
nid uid timestampBecause old versions of Drupal didn't enforce a unique index on the nid-uid combination, sometimes race conditions let two records in with the same nid-uid combo but different timestamps. I got rid of duplicate records with the following process.
1. Find out how many duplicates we have:
SELECT nid, uid, count( * ) AS n
FROM history
GROUP BY nid, uid
HAVING n > 1;
In this case I had 276 records.
2. Since I didn't really care which of the two duplicate records was kept, I could use this approach to quickly throw out duplicates:
ALTER IGNORE TABLE history ADD UNIQUE INDEX unique_index ( uid, nid );
3. Now I discarded the unique index, since I was only using it as a tool to remove duplicates. When I import the data into a modern Drupal, uniques will be enforced anyway.
ALTER TABLE history DROP INDEX unique_index;
4. Repeat step 1, with 0 records in the result set.
I should probably go start some LiveJournal to whine about personal crap, but I don't have one, and I really need to get some stuff off my chest, so this'll have to do. :)
On Saturday, Marci and I are embarking on what could be a life-changing trip for a week to Vancouver, BC. I'll be sans-laptop, so if you need something from me, please let me know before then.
If you care about the long, rambling back-story, feel free to read more.
Online Videos, Mapping DC, and the Agile Development This Week in Washington, DC
We’re beyond the midway point in July already, which is pretty hard to believe. Things continue to jam here in Washington, DC, with unseasonably nice weather (but with some more humidity rolling in this week, unfortunately) and a lot of tech events taking place. This week there are meetups from two brand new groups – MappingDC and Agile DC-MD-VA – as well as some other interesting ones. Below are the events that caught our attention, and you can find a full listing of the week’s tech events here. Have a great week!
Tuesday, July 21
7:00 pm
NetSquared Summer Video Night: It’s movie night at NetSquared this month with a showing of great online advocacy videos, followed by a discussion on what makes them great. Popcorn, beer, and the entertainment will be provided (and you can add your favorite videos to the mix too).
Wednesday, July 22
6:30 – 8:00 pm
DC Media Makers: Allyson Kapin – the founder of WomenWhoTech and a tech blogger – will talk about online media at this month’s Media Makers meetup. Come out to hear some of her tricks and to share your own with the group.
Last week we learned that our video What is Drupal? (in 57 seconds) won six Telly Awards.
It's a little embarrassing, winning six awards for one video. When we submitted our entry, we weren't quite sure what category to put it under. So we just threw it into a few different categories, hoping that it might win in one or two. We didn't expect to win an award in all categories entered. (We hoped, though!)
I wish we had more videos already posted. Soon! Meanwhile, our thanks to the Telly Awards committees who gave us the props!
Related: What is Drupal? ... in 57 secondsMoshe Weitzman recently started the D7CX movement to rally people to get Drupal 7 contributed modules upgraded and released on time for the Drupal 7 release. This would be a great boon to the Drupal 7 release, which shapes up to be a huge improvement over Drupal 6 already. He also suggests a contributed module release manager who can help with (among other things) ensuring that tools are available to help people upgrade.
Me being the guy, who maintains modules important for the translation of Drupal interfaces, such as l10n_client, potx and l10n_server, I looked at this movement from my angle. While my modules are not among the highly popular top 40 modules Moshe highlights, these tools are used to translate them and reach many parts of the globe. So in part on Acquia sponsored time and my free time, I went ahead and ported both the Localization client and Translation template extractor to Drupal 7. Both had their own challenges. The client port is just a direct functionality port, so does not include real string context support yet (a feature new to Drupal 7). The template extractor however got full context support to match what Drupal 7 supports currently. It also got its coder_review integration updated. Both modules now have their 7.x-1.x development snapshots downloadable.
Thanks to these updates, I hope people working on the D7CX movement will not be in the dark about localization API changes and usage limitations of the new API. You can run the template extractor on your code or run the code review from Coder review to get error reports when the localization API was not properly used. While Coder review includes some rules on its own to test for some common errors, only using the actual tool translators use can tell you all the errors you can make while writing your code.
Future plans include backporting the Drupal 7 parsing support from the template extractor to Drupal 6 (which would be easy except a little API change required), so when integrated with the localization server, contexts would be properly stored. Which would require an update to the localization server too. The goal is to have a Localization server system which can be used to translate Drupal 7 core and modules, so translators can work on their part before the release too. Also, the localization client would pass on the context information too to the server, so people can keep using that to translate and share their work right away.
People keen on magic names can just refer to this effort as D7TX, the translator experience ;) Have fun using these tools, and as always report bugs and provide patches please!
Those not following the implementation of concepts from http://d7ux.org/ here is a quick summary of the three main areas:
There are lots of things going on improving user experience even in relatively large scales additionally to these three, but given how close the code freeze is, I am trying to get attention to these three, and especially the overlay and the admin theme, so we can get them in sooner then later.
We launched translate.openatrium.com earlier this week to support translating Open Atrium into more than a dozen languages. It currently ships out of the box in English, Spanish, and Arabic, but we want to grow this. To do this we built a localization server that provides downloadable, up-to-date translations that are automatically repackaged every few hours and that allows people to post their own translations and fixes to the server while they’re doing them on their own sites.
The tools that make this possible have been in the works for some time now. The localization client allows for on page translations of UI strings, and the localization server lets you keep a centralized translations repository for all modules, versions, and languages. We’ve had the tools for awhile, however, in order to realize just how hard it is to actually do and maintain translations in Drupal, you need to try it.
In the case of Open Atrium, we’re not talking about a Drupal module or a single site. Open Atrium is a full featured Drupal intranet distribution that uses Drupal core, some contributed modules, and some custom specific ones, and all of this this is deployed to many sites. This is one of those times when it feels like you have all the pieces to do what you want to do, but it’s still hard to figure out how to make everything work together in a human friendly way to get the job done.
So for Open Atrium, we want to:
Improving Maps for the Federal Education Budget Project
We just overhauled the maps for the Federal Education Budget Project with new custom slippy maps, using TIGER Census data along with OpenStreetMap data. The new mapping stack lets users browse all the nation’s school districts much faster, with dots sized to indicate reading achievement and other variables.
Here’s a look at the new maps:
This is a big change from the first version of the site that utilized static maps, since the map can be panned across the entire country. To make this possible, district information is only loaded when it comes into view – a feature of the OpenLayers Javascript library.
Why custom maps?For the Federal Education Budget Project, custom maps were essential because, rather than mapping points relative to transportation or town boundaries commonly found on maps, the site’s maps portray school district boundaries. As tools like Mapnik and TileCache have approached maturity, it has become possible to make maps that are both custom and rich in interaction. So now on the site you’ll see beautiful maps of school districts, with specific highways and county boundaries added for context.
Do you want your Drupal front page to render in less than a second? Do you want your site to be fast for logged in as well as for anonymous users? Do you want to have total confidence in your ability to weather the storms of internet fortune (e.g. links from Digg, Drudge, Slashdot or MSN.com)? If so, then we hope the Mercury project will be of interest to you.
The goal of this project is to make Drupal as fast as possible for as many people as possible. To that end, we are developing a pre-built Amazon Machine Image (AMI) which will allow anyone with an Amazon Web Services account to spin up an EC2 instance and see how all this works in real-time. The ultimate goal is a production-ready release that can be used for deploying real websites.
Today, thanks to this inspiring post from Eric Hammond at Alestic and some excellent feedback from the Drupal community, I'm proud to announce the public availability of an initial Alpha release. Don't use this for production, but if you want to see how these techniques work in action, you can get a working copy with root access for just a little scratch; ten cents an hour to be precise.
For those hungry to get started, the public AMI id is ami-0722c36e. It's a 32-bit instance, and I've run all my tests on the "small" instance type. You can find it pretty easily by searching for "chapter3" in the AMI list:
This ready-to-run machine image contains the following high-performance options, all configured to work for a harmonious liquid-metal fast WIN:
Since the install comes pre-configured and I didn't have time to do this as a profile, you'll need to use the user #1 credentials I set up. Login: root. Pass: drupal. Change this immediately.
Now, if you want to know more about how this works, see links to the giants who's shoulders we're standing on here, or if you've got a minute to kill while your instance spins up, read on for a full explanation of what we've done in this initial Alpha release.
You can create custom CCK fields, widgets, and formatters for any situation, but it can be hard to see how to do it. I finally found time to create an 'Example' module that creates a simple field, formatter, and widget, with lots of embedded documentation about what belongs where. You need to create three files, an .info file, an .install file, and the module itself. The code below creates a very simple textfield, but it can be used as a starting point for any custom module. I'm also attaching a .zip file with the contents of this custom module.
The .info File; $Id$
name = Example field
description = Defines an example field type.
dependencies[] = content
package = CCK
core = 6.x
<?php
// $Id$
// Notify CCK when this module is enabled, disabled, installed,
// and uninstalled so CCK can do any necessary preparation or cleanup.
/**
* @file
* Implementation of hook_install().
*/
function example_install() {
drupal_load('module', 'content');
content_notify('install', 'example');
}
/**
* Implementation of hook_uninstall().
*/
function example_uninstall() {
drupal_load('module', 'content');
content_notify('uninstall', 'example');
}
/**
* Implementation of hook_enable().
*
* Notify content module when this module is enabled.
*/
function example_enable() {
drupal_load('module', 'content');
content_notify('enable', 'example');
}
/**
* Implementation of hook_disable().
*
* Notify content module when this module is disabled.
*/
This Thursday, July 16th, the DC Geo group will hold it’s first meetup from 6:00 to 9:00 pm at Fortius One’s offices in Arlington.
It’s shaping up to be a great event. Our friend Dmitry Kachaev will be there representing the DC Government’s OCTO Labs and will talk about the Circulator API, which releases real time data for the city’s public transit system. Tom MacWright will give a presentation on some of the work we’ve been doing with Drupal, OpenLayers, and Amazon S3 services. We’ll also hear from a new group called MappingDC that’s working on open data initiatives in the DC area.
This will be a great opportunity to get involved with an exciting new group that brings together the people who are doing some of the best mapping work in Washington, DC, and to share knowledge with them, brainstorm, and network. The Fortius One offices are located at 2200 Wilson Blvd, Suite 307 in Arlington, a short walk from the Court House metro stop. You can RSVP and get more information here, and follow DC Geo on Twitter for news and updates.
Beta Release of Open Source Intranet in a Box
Open Atrium’s code is now in open beta! You can download the code from www.openatrium.com, learn more about its features, read why we open sourced it, and the check out the roadmap for the next release. What we’re most excited about now is getting feedback from you all and growing the developer base over on github.
Open Atrium is a light package that’s extensible, both in terms of features and look. We’ve posted documentation on how to build new features for it and how to change the skin, and and we’re currently documenting other commonly asked questions. As of now, out of the box Open Atrium is available in English, Spanish, and Arabic, with good progress made on German and Hungarian, and it’s being translated into a dozen other languages. We’ll blog more about the translation service and how you can get involved soon.
To follow up on Jeff’s post from last night I want to thank all of the alpha testers who have helped make this release possible. We look forward to working together on github to keep making Open Atrium better.
This week's podcast brings Andrew, Ryan, and Mike back together to discuss Drupal news from the past few weeks. From Panels 3 to $18 million web sites, we'll get you up-to-speed on the latest happenings in the Drupal Community. We also picked 4 winners for our recent book giveaways, so be sure to listen in to see if you've got a free book coming.