Recent posts:
The Wordchuck Blog.
Shelly Roche is a Ruby on Rails engineer and founder of Wordchuck. She usually blogs about Ruby, Rails 3, woodchucks, i18n, l10n, startup life or whatever has her fired up on any given day. Yes, she is available for i18n consulting & training. Find her or by . |
» Wordchuck on TechCrunch TV
» New Feature: Custom Locale Details
To change your setting, go to the "Settings" page for your project and select the option you'd like under the "Libraries & Dictionaries" heading:
» Video: Internationalization (i18n) Tips and Tricks
Here's the video:
Part 1:
Part 2:
Part 3:
Check out some of Pivotal's other awesome Tech Talks - they cover a wide variety of topics and services helpful for engineers and startups.
» New Wordchuck Features Released
"Translation Summary" page
- See the status of your translations for each language
- See at a glance which languages still need human translation
- Submit all remaining machine translations for a language to professionals
"Translation Details" page
- Lists all translations for a language, for each status (for example, review all of the translations completed by your invited translators.)
- Click to make changes.
The Wordchuck API
- Our new API allows anyone to use Wordchuck to internationalize their website, mobile app, or software.
- Documentation is underway, but hasn't been posted yet. In the meantime, please if you need instructions, and we'll get you everything you need.
- We'll make a separate announcement with details and documentation as soon as we're ready.
Library of Common Terms
- We've launched our Library of professionally-translated words and phrases that are commonly used on websites and apps -- things like buttons, menu items, labels, etc. We're getting these items professionally translated and making them available to you for free!
- It's all automatic - when you create or update content, we'll check to see if the translations already exist in our library and instantly populate those that do. This feature should save everyone a bunch of money, AND improve the translation quality of your site (especially if you're starting off with only machine translations).
- We're constantly adding to the library, so please if you'd like something added.
Library of Localized Formats
- Similar in concept to our Library of Common Terms, our new Library of locale-specific formats includes things like dates, times, currencies and more. The library is human-translated, and exists for 28 languages so far. Details are posted here.
- And you know the drill: if there's a locale you'd like added to the library, just .
Performance Improvements & Bug Fixes
- We're running faster and better than ever. Of course, in true startup form, there are still a few things in the queue to be fixed.
- If you run into anything, and we'll shift priorities to get on it.
Big, HUGE Thanks
We really, really appreciate all of your feedback, bug reports, patience, encouragement and support. We love all of your feedback, but it especially makes our day when we hear we've been able to save someone a boatload of time and money. That's why we're doing this!
So keep the feedback coming. Our #1 goal is to keep you happy, and to keep saving you time and money in new ways. anytime and let us know how we can make your experience even better.
» Recurly Goes International with Wordchuck
According to founder Isaac Hall, the company is already seeing a payoff:
On their experience using Wordchuck to simplify the internationalization process:
HUGE thanks to Isaac and Recurly for giving us invaluable feedback throughout the process, and for helping us make Wordchuck even better.
Read more about Recurly's internationalization process at their blog.
Stay tuned to the Wordchuck blog for announcements on some of our Recurly-inspired enhancements, and some exciting new features launching very soon!
» Wordchuck Launches Library of Locale-Specific Details
The library is free for Wordchuck projects, and means you automatically get locale-specific data (like date formats, currencies, date/times, numbers, etc.) included when you generate your locale files using our Ruby gem.
The Library includes locale details for:
» Arabic
» British (en-GB)
» Chinese (zh-CN)
» Croatian
» Czech
» Danish
» Dutch
» English
» Estonian
» Finnish
» French
» German
» Greek
» Hindi
» Indonesian
» Italian
» Japanese
» Latvian
» Polish
» Portuguese
» Romanian
» Russian
» Slovak
» Spanish
» Spanish - Latin America (es-AR)
» Swedish
» Turkish
» Vietnamese
To include the new locale data, simply run:
rake wordchuck:generate
We're working on including more, so please let us know if you have specific locales you'd like added.
» I18n Tech Talk at Pivotal Labs
Thanks to all who attended, particularly those who did not throw fruit.
» How to: Localize in Rails 3
What is Localization?
If you want to offer your site in more than one language, you need to go through a process called internationalization (i18n) and localization (l10n).
As I wrote about in my previous post, the internationalization process involves abstracting your site’s content strings, dates and currencies from your application and replacing each abstracted piece of content with a placeholder.
The localization process involves translating your content and providing other locale-specific information, like date and currency formats.
Localization in Rails 3:
In Rails 3, all dependencies for localization (l10n) are automatically included as part of the built-in i18n library, so let’s take a look at the three steps required to localize your site using i18n’s default Simple backend (more on that in another post):
Step 1: Add translations
When we internationalized our site, we created a locale file to store our site's content strings in our default language -- for this example, English. We created our base locale file in config/locales and called it en.rb. If we want to offer our site in French, we need to add a new locale file to config/locales (called fr.rb) to store our French translations. The French locale file will look very similar to our base English locale file, except:
» the descriptive content keys (:page_title, for example) will point to the French translation:
{ :fr => { :welcome => { :page_title => "Bienvenue sur mon site!" } } }
We'll create a new locale file for each language, so if we are translating into French, Spanish and Japanese, we'll end up with four files in our config/locales directory: en.rb, fr.rb, es.rb and ja.rb.
As you can imagine, managing content and translations becomes pretty cumbersome as our site's content grows and changes. Every change requires us to generate new translations, then copy and paste the new translations into each locale file.
Step 2: Define locale-specific formats
Localization involves more than just translating a content string from one language into another. We also need to tell our app how to display locale-specific content like dates and currencies.
{ :'fr' => { :date => { :abbr_day_names => ["dim", "lun", "mar", "mer", "jeu", "ven", "sam"], :abbr_month_names => ["day", "month", "year"], :day_names => ["dimanche", "lundi", "mardi", "mercredi", "jeudi", "vendredi", "samedi"], :month_names => ["~", "janvier", "février", "mars", "avril", "mai", "juin", "juillet", "août", "septembre", "octobre", "novembre", "décembre"], :formats => { :default => "%d/%m/%Y", :long => "%e %B %Y", :long_ordinal => "%e %B %Y", :only_day => "%e", :short => "%e %b" } } } }
Step 3: Use localized formats
To use a localized date format, we simply specify the :format in our view code, like so:
"content">Last updated <%= post.updated_at, :format => :short -%>
> </div>
Additional Resources:
If you'd like to play around with a fully-featured Rails 3 i18n and l10n implementation, check out our demo app here. The source code is available on github, so you can see exactly how everything works.
The official Rails i18n API documentation is excellent, and packed with all sorts of additional details and options for doing more complex implementations of internationalization and localization.
» How to: Internationalize in Rails 3
What is Internationalization?
If you want to offer your site in more than one language, you need to go through a process called internationalization (i18n) and localization (l10n).
The internationalization process involves abstracting your site’s content strings, dates and currencies from your application and replacing each abstracted piece of content with a placeholder.
The localization process involves translating your content and providing other locale-specific information, like date and currency formats.
Internationalization in Rails 3:
In Rails 3, all dependencies for Internationalization (i18n) are already included, so let’s take a look at the three steps required to get up and running using I18n’s default Simple backend (more on that in another post):
Step 1: Abstract your content
Each piece of text we want to translate will need to be copied into a new file, called a locale file. Locale files can be .yml or .rb format, and will be created in our config/locales directory. Our base locale is the default language for our site, in my case, English. My base locale file is therefore called en.rb (config/locales/en.rb).
In this example, I’m copying the “Welcome to my site!” string from my view:
"content">Welcome to my site!</h2>
You are going to like it here.<
/p> </div>
{ :en => { :welcome => { :page_title => "Welcome to my site!" } } }
Step 2: Insert placeholders
As we abstract each piece of content, we need to replace it with a placeholder that will perform the lookup to display the properly translated content to our users. Continuing with the example from above, we're going to replace the “Welcome to my site!” text in our view with our call to I18n’s translate method, passing in the section and key we defined in our locale file to help identify the correct piece of content:
"content"><%= t(:page_title, :scope => :welcome) -%>
>You are going to like it here.
</div>
Step 3: Set the locale
The final step is to set up your application to pass the locale, so the i18n placeholders know which translations to display.
The default locale is updated on every request within a before_filter set in the ApplicationController:
before_filter :set_locale def set_locale I18n.locale = params[:locale] if params.include?('locale') end
The idea here is to set the locale on every route automatically, based on what locale is set for the current request:
def default_url_options(options = {}) options.merge!({ :locale => I18n.locale }) end
In order for this to work, we need to wrap every applicable route within a :locale scope to ensure that the locale is included within any named routes.
Your routes file will look something like this:
scope ':locale' do resources :buckets, :only => [ :index ] resources :items, :only => [ :index, :show, :edit, :update ] end
This way, we don’t have to specify the locale manually when we call a named route method. It all happens automatically for us.
Of course, you do not have to store the locale in the URL if you do want to. It can also be stored in browser's session[], or as a data item within the user's database profile. But placing the desired locale in the URL ensures that bookmarks or shared links always point to the content as the user was looking at it.
YAY - we've made it through a simple i18n setup and ready for our next step: localization!
Additional Resources:
If you'd like to play around with a fully-featured Rails 3 i18n implementation, check out our demo app here. The source code is available on github, so you can see exactly how everything works.
The official Rails i18n API documentation is excellent, and packed with all sorts of additional details and options for doing more complex implementations of internationalization.
» Running on Async Rails 3
It was actually quite simple to set up, as I was already running Rails 3 + Ruby 1.9.2. I used 's Async Rails 3.x demo project on github as a reference, as well as some, er, light reading from , and everything pretty much worked as advertised.
Step 1: Use the right gems
Add these gems to your Gemfile:
source 'http://rubygems.org' gem 'rails', '3.0.0' gem 'rake', '0.8.7' gem 'thin', '1.2.7' gem 'rack', '>=1.0.0' gem 'eventmachine', '0.12.10' gem 'rack-fiber_pool', :require => 'rack/fiber_pool' gem 'mysql2', '0.2.4' gem 'builder'
Step 2: Enable threaded mode
In your various environments' configs:
# Enable threaded mode
config.threadsafe!
Step 3: Add FiberPool as Rack middleware
Update config.ru to use FiberPool as Rack middleware. This will make sure each request runs in its own fiber:
use Rack::FiberPool run Wordchuck::Application
Step 4: Configure MySQL for async use
Set the adapter in database.yml to "em_mysql2" to run mysql in async mode with ActiveRecord and Rails:
development: adapter: em_mysql2
Step 5: Fix your rake tasks
When I enabled threaded mode in my production environment...
# Enable threaded mode
config.threadsafe!
# Enable threaded mode # config.threadsafe!
Step 6: Restart your app
At this point, restart your app, and you should be running async Rails!
One thing to note is that many gems aren't yet fiber-aware, so they will be blocking. You can still use them, just be aware that they'll prevent you from seeing the full performance benefit of running asynchronously.
To find out more about how this all works, watch the video at the end of Ilya's post, and read this article from .
» Wordchuck at the TechCrunch Disrupt Hackathon
I hit the TechCrunch Disrupt Hackathon this weekend to do a little hacking with 450 or so of my nerdiest friends. All in all, an awesome experience -- even the part where I had to get on stage and give a 60 second demo of my hack.
from TechCrunch interviewed me after I'd had a few too many red bulls... Here's her video of us chatting about the hackathon, Wordchuck, and salad bugs:
Read the rest of her article: An Illustrated Slice of TC Disrupt Hackathon Life
Other highlights:
* The midnight taco truck (thanks, BitTorrent!)
* Finding a spot to park the RV at 3:00 in the morning so I could take a quick nap before demo time
* Meeting some supercool fellow hackers, journalists and people I follow on Twitter
* And of course, awesome shirt:
And with that, back to coding! The 'Chuck has entered final launch sequence... stay tuned :)
» The Wordchuck Wagon
The Wordchuck wagon (my sweet 1993 24' Class C motorhome/office) is currently en route from Vancouver, BC, to San Francisco. Here we are, somewhere in Oregon (the wordchuck is not pictured):
» How to use check_box in nested model forms
This article will show you how to use the check_box helper in a nested model form using Rails 3.
In this example, I have two models with a many-to-many relationship - projects and languages
Because a project can have many languages and a language can have many projects, I'm going to use a :has_many association with the :through option and create a join model called project_languages to store the relationships:
class Language < ActiveRecord::Base has_many :project_languages has_many :projects, :through => :project_languages end
class Project < ActiveRecord::Base has_many :project_languages has_many :languages, :through => :project_languages end
The join model:
class ProjectLanguage < ActiveRecord::Base belongs_to :project belongs_to :language end
We need to do one more thing to set our models up properly - tell the project model to automatically include the project_languages model when it saves. To do this, we add accepts_nested_attributes_for to the model like so:
class Project < ActiveRecord::Base has_many :project_languages has_many :languages, :through => :project_languages accepts_nested_attributes_for :project_languages, :allow_destroy => true end
Using accepts_nested_attributes_for means we don't need to add anything special in the projects controller - it will automatically save the project_languages object when we save the project object.
In the edit form for my project, I want to list all of the languages that have been associated with the project, and then allow the user to check the box next to each language to set a flag in my nested project_languages model.
To give you more context for this functionality, part of the OpenGab awesomeness is that we have a rake task that automatically generates and deploys all of your translated .yml files. The flag we're setting with each check box indicates that all of the content for that language has been translated and is ready to be deployed to the production environment for the project. Languages that aren't checked remain associated with the project (i.e. the association in the project_languages model is not destroyed), but they will be ignored when the rake task to re-generate the yml files runs for the production environment.
The next step is to create the form in my project edit form view (this example is using Rails 3):
=form_for @project, :remote => true do |form|
Then within the form:
-for language in @project.project_languages =form.fields_for :project_languages, language do |pl| =pl.check_box :production =pl.label language.language.name %br
For each language that has been added to the project (through the nested project_languages join model), we're printing a check_box that will update an attribute in the project_languages model called "production".
This is what it looks like in the form:
This is the html that is generated:
"project[project_languages_attributes][0][production]" type="hidden" value="0" />"project_project_languages_attributes_0_production" name="project[project_languages_attributes][0][production]" type="checkbox" value="1" />
And that's it!