diff options
author | Pratik Naik <pratiknaik@gmail.com> | 2009-01-27 15:12:21 +0000 |
---|---|---|
committer | Pratik Naik <pratiknaik@gmail.com> | 2009-01-27 15:12:21 +0000 |
commit | c06eecfbc280da3295b73ef882e6a7c3b632c156 (patch) | |
tree | ec98383a98fc8a2ee93e46937fb14ec0c851eafa /railties/doc/guides/html | |
parent | 94fde8c63439bc86265fadbd293dbd28b808d830 (diff) | |
download | rails-c06eecfbc280da3295b73ef882e6a7c3b632c156.tar.gz rails-c06eecfbc280da3295b73ef882e6a7c3b632c156.tar.bz2 rails-c06eecfbc280da3295b73ef882e6a7c3b632c156.zip |
Regenerate html
Diffstat (limited to 'railties/doc/guides/html')
-rw-r--r-- | railties/doc/guides/html/form_helpers.html | 74 | ||||
-rw-r--r-- | railties/doc/guides/html/i18n.html | 126 |
2 files changed, 140 insertions, 60 deletions
diff --git a/railties/doc/guides/html/form_helpers.html b/railties/doc/guides/html/form_helpers.html index 5329d604b1..2693f29a9a 100644 --- a/railties/doc/guides/html/form_helpers.html +++ b/railties/doc/guides/html/form_helpers.html @@ -80,7 +80,7 @@ <li><a href="#_common_options">Common options</a></li> - <li><a href="#_individual_components">Individual Components</a></li> + <li><a href="#_individual_components">Individual components</a></li> </ul> </li> @@ -670,16 +670,16 @@ Dates and times are not representable by a single input element. Instead you hav </li>
<li>
<p>
-Other helpers use the _tag suffix to indicate whether a helper is a barebones helper or one that operates on model objects. With dates and times, <tt>select\_date</tt>, <tt>select\_time</tt> and <tt>select_datetime</tt> are the barebones helpers, <tt>date_select</tt>, <tt>time_select</tt> and <tt>datetime_select</tt> are the equivalent model object helpers.
+Other helpers use the _tag suffix to indicate whether a helper is a barebones helper or one that operates on model objects. With dates and times, <tt>select_date</tt>, <tt>select_time</tt> and <tt>select_datetime</tt> are the barebones helpers, <tt>date_select</tt>, <tt>time_select</tt> and <tt>datetime_select</tt> are the equivalent model object helpers.
</p>
</li>
</ol></div>
-<div class="paragraph"><p>Both of these families of helpers will create a series of select boxes for the different components (year, month, day etc...).</p></div>
+<div class="paragraph"><p>Both of these families of helpers will create a series of select boxes for the different components (year, month, day etc.).</p></div>
<h3 id="_barebones_helpers">4.1. Barebones helpers</h3>
<div class="paragraph"><p>The <tt>select_*</tt> family of helpers take as their first argument an instance of Date, Time or DateTime that is used as the currently selected value. You may omit this parameter, in which case the current date is used. For example</p></div>
<div class="listingblock">
<div class="content">
-<pre><tt><%= select_date Date::today, :prefix => :start_date %></tt></pre>
+<pre><tt><%= select_date Date.today, :prefix => :start_date %></tt></pre>
</div></div>
<div class="paragraph"><p>outputs (with actual option values omitted for brevity)</p></div>
<div class="listingblock">
@@ -691,7 +691,7 @@ Other helpers use the _tag suffix to indicate whether a helper is a barebones he <div class="paragraph"><p>The above inputs would result in <tt>params[:start_date]</tt> being a hash with keys <tt>:year</tt>, <tt>:month</tt>, <tt>:day</tt>. To get an actual Time or Date object you would have to extract these values and pass them to the appropriate constructor, for example</p></div>
<div class="listingblock">
<div class="content">
-<pre><tt>Date::civil(params[:start_date][:year].to_i, params[:start_date][:month].to_i, params[:start_date][:day].to_i)</tt></pre>
+<pre><tt>Date.civil(params[:start_date][:year].to_i, params[:start_date][:month].to_i, params[:start_date][:day].to_i)</tt></pre>
</div></div>
<div class="paragraph"><p>The <tt>:prefix</tt> option is the key used to retrieve the hash of date components from the <tt>params</tt> hash. Here it was set to <tt>start_date</tt>, if omitted it will default to <tt>date</tt>.</p></div>
<h3 id="_model_object_helpers_2">4.2. Model object helpers</h3>
@@ -713,7 +713,7 @@ The model object helpers for dates and times submit parameters with special name <div class="content">
<pre><tt>{:person => {'birth_date(1i)' => '2008', 'birth_date(2i)' => '11', 'birth_date(3i)' => '22'}}</tt></pre>
</div></div>
-<div class="paragraph"><p>When this is passed to <tt>Person.new</tt> (or <tt>update_attributes</tt>), Active Record spots that these parameters should all be used to construct the <tt>birth_date</tt> attribute and uses the suffixed information to determine in which order it should pass these parameters to functions such as <tt>Date::civil</tt>.</p></div>
+<div class="paragraph"><p>When this is passed to <tt>Person.new</tt> (or <tt>update_attributes</tt>), Active Record spots that these parameters should all be used to construct the <tt>birth_date</tt> attribute and uses the suffixed information to determine in which order it should pass these parameters to functions such as <tt>Date.civil</tt>.</p></div>
<h3 id="_common_options">4.3. Common options</h3>
<div class="paragraph"><p>Both families of helpers use the same core set of functions to generate the individual select tags and so both accept largely the same options. In particular, by default Rails will generate year options 5 years either side of the current year. If this is not an appropriate range, the <tt>:start_year</tt> and <tt>:end_year</tt> options override this. For an exhaustive list of the available options, refer to the <a href="http://api.rubyonrails.org/classes/ActionView/Helpers/DateHelper.html">API documentation</a>.</p></div>
<div class="paragraph"><p>As a rule of thumb you should be using <tt>date_select</tt> when working with model objects and <tt>select_date</tt> in others cases, such as a search form which filters results by date.</p></div>
@@ -725,19 +725,19 @@ The model object helpers for dates and times submit parameters with special name <td class="content">In many cases the built in date pickers are clumsy as they do not aid the user in working out the relationship between the date and the day of the week.</td>
</tr></table>
</div>
-<h3 id="_individual_components">4.4. Individual Components</h3>
-<div class="paragraph"><p>Occasionally you need to display just a single date component such as a year or a month. Rails provides a series of helpers for this, one for each component <tt>select_year</tt>, <tt>select_month</tt>, <tt>select_day</tt>, <tt>select_hour</tt>, <tt>select_minute</tt>, <tt>select_second</tt>. These helpers are fairly straightforward. By default they will generate a input named after the time component (for example "year" for <tt>select_year</tt>, "month" for <tt>select_month</tt> etc.) although this can be override with the <tt>:field_name</tt> option. The <tt>:prefix</tt> option works in the same way that it does for <tt>select_date</tt> and <tt>select_time</tt> and has the same default value.</p></div>
+<h3 id="_individual_components">4.4. Individual components</h3>
+<div class="paragraph"><p>Occasionally you need to display just a single date component such as a year or a month. Rails provides a series of helpers for this, one for each component <tt>select_year</tt>, <tt>select_month</tt>, <tt>select_day</tt>, <tt>select_hour</tt>, <tt>select_minute</tt>, <tt>select_second</tt>. These helpers are fairly straightforward. By default they will generate a input named after the time component (for example "year" for <tt>select_year</tt>, "month" for <tt>select_month</tt> etc.) although this can be overriden with the <tt>:field_name</tt> option. The <tt>:prefix</tt> option works in the same way that it does for <tt>select_date</tt> and <tt>select_time</tt> and has the same default value.</p></div>
<div class="paragraph"><p>The first parameter specifies which value should be selected and can either be an instance of a Date, Time or DateTime, in which case the relevant component will be extracted, or a numerical value. For example</p></div>
<div class="listingblock">
<div class="content">
<pre><tt><%= select_year(2009) %>
<%= select_year(Time.now) %></tt></pre>
</div></div>
-<div class="paragraph"><p>Will produce the same output if the current year is 2009 and the value chosen by the user can be retrieved by <tt>params[:date][:year]</tt>.</p></div>
+<div class="paragraph"><p>will produce the same output if the current year is 2009 and the value chosen by the user can be retrieved by <tt>params[:date][:year]</tt>.</p></div>
</div>
<h2 id="_uploading_files">5. Uploading Files</h2>
<div class="sectionbody">
-<div class="paragraph"><p>A common task is uploading some sort of file, whether it’s a picture of a person or a CSV file containing data to process. The most important thing to remember with file uploads is that the form’s encoding <strong>MUST</strong> be set to multipart/form-data. If you forget to do this the file will not be uploaded. This can be done by passing <tt>:multi_part => true</tt> as an HTML option. This means that in the case of <tt>form_tag</tt> it must be passed in the second options hash and in the case of <tt>form_for</tt> inside the <tt>:html</tt> hash.</p></div>
+<div class="paragraph"><p>A common task is uploading some sort of file, whether it’s a picture of a person or a CSV file containing data to process. The most important thing to remember with file uploads is that the form’s encoding <strong>MUST</strong> be set to "multipart/form-data". If you forget to do this the file will not be uploaded. This can be done by passing <tt>:multi_part => true</tt> as an HTML option. This means that in the case of <tt>form_tag</tt> it must be passed in the second options hash and in the case of <tt>form_for</tt> inside the <tt>:html</tt> hash.</p></div>
<div class="paragraph"><p>The following two forms both upload a file.</p></div>
<div class="listingblock">
<div class="content">
@@ -751,7 +751,7 @@ The model object helpers for dates and times submit parameters with special name </div></div>
<div class="paragraph"><p>Rails provides the usual pair of helpers: the barebones <tt>file_field_tag</tt> and the model oriented <tt>file_field</tt>. The only difference with other helpers is that you cannot set a default value for file inputs as this would have no meaning. As you would expect in the first case the uploaded file is in <tt>params[:picture]</tt> and in the second case in <tt>params[:person][:picture]</tt>.</p></div>
<h3 id="_what_gets_uploaded">5.1. What gets uploaded</h3>
-<div class="paragraph"><p>The object in the <tt>params</tt> hash is an instance of a subclass of IO. Depending on the size of the uploaded file it may in fact be a StringIO or an instance of File backed by a temporary file. In both cases the object will have an <tt>original_filename</tt> attribute containing the name the file had on the user’s computer and a <tt>content_type</tt> attribute containing the MIME type of the uploaded file. The following snippet saves the uploaded content in <tt>#{RAILS_ROOT}/public/uploads</tt> under the same name as the original file (assuming the form was the one in the previous example).</p></div>
+<div class="paragraph"><p>The object in the <tt>params</tt> hash is an instance of a subclass of IO. Depending on the size of the uploaded file it may in fact be a StringIO or an instance of File backed by a temporary file. In both cases the object will have an <tt>original_filename</tt> attribute containing the name the file had on the user’s computer and a <tt>content_type</tt> attribute containing the MIME type of the uploaded file. The following snippet saves the uploaded content in <tt>#{Rails.root}/public/uploads</tt> under the same name as the original file (assuming the form was the one in the previous example).</p></div>
<div class="listingblock">
<div class="content"><!-- Generator: GNU source-highlight 2.9
by Lorenzo Bettini
@@ -773,14 +773,14 @@ http://www.gnu.org/software/src-highlite --> </tr></table>
</div>
<h3 id="_dealing_with_ajax">5.2. Dealing with Ajax</h3>
-<div class="paragraph"><p>Unlike other forms making an asynchronous file upload form is not as simple as replacing <tt>form_for</tt> with <tt>remote_form_for</tt>. With an AJAX form the serialization is done by javascript running inside the browser and since javascript cannot read files from your hard drive the file cannot be uploaded. The most common workaround is to use an invisible iframe that serves as the target for the form submission.</p></div>
+<div class="paragraph"><p>Unlike other forms making an asynchronous file upload form is not as simple as replacing <tt>form_for</tt> with <tt>remote_form_for</tt>. With an Ajax form the serialization is done by JavaScript running inside the browser and since JavaScript cannot read files from your hard drive the file cannot be uploaded. The most common workaround is to use an invisible iframe that serves as the target for the form submission.</p></div>
</div>
<h2 id="_customising_form_builders">6. Customising Form Builders</h2>
<div class="sectionbody">
-<div class="paragraph"><p>As mentioned previously the object yielded by <tt>form_for</tt> and <tt>fields_for</tt> is an instance of FormBuilder (or a subclass thereof). Form builders encapsulate the notion of displaying a form elements for a single object. While you can of course write helpers for your forms in the usual way you can also subclass FormBuilder and add the helpers there. For example</p></div>
+<div class="paragraph"><p>As mentioned previously the object yielded by <tt>form_for</tt> and <tt>fields_for</tt> is an instance of FormBuilder (or a subclass thereof). Form builders encapsulate the notion of displaying form elements for a single object. While you can of course write helpers for your forms in the usual way you can also subclass FormBuilder and add the helpers there. For example</p></div>
<div class="listingblock">
<div class="content">
-<pre><tt><% form_for @person do |f| %>
+<pre><tt><% form_for @person do |f| %>
<%= text_field_with_label f, :first_name %>
<% end %></tt></pre>
</div></div>
@@ -798,7 +798,7 @@ by Lorenzo Bettini http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="font-weight: bold"><span style="color: #0000FF">class</span></span> LabellingFormBuilder <span style="color: #990000"><</span> FormBuilder
- <span style="font-weight: bold"><span style="color: #0000FF">def</span></span> text_field attribute<span style="color: #990000">,</span> options<span style="color: #990000">=</span><span style="color: #FF0000">{}</span>
+ <span style="font-weight: bold"><span style="color: #0000FF">def</span></span> text_field<span style="color: #990000">(</span>attribute<span style="color: #990000">,</span> options<span style="color: #990000">=</span><span style="color: #FF0000">{}</span><span style="color: #990000">)</span>
label<span style="color: #990000">(</span>attribute<span style="color: #990000">)</span> <span style="color: #990000">+</span> text_field<span style="color: #990000">(</span>attribute<span style="color: #990000">,</span> options<span style="color: #990000">)</span>
<span style="font-weight: bold"><span style="color: #0000FF">end</span></span>
<span style="font-weight: bold"><span style="color: #0000FF">end</span></span></tt></pre></div></div>
@@ -808,13 +808,13 @@ http://www.gnu.org/software/src-highlite --> <div class="content">
<pre><tt><%= render :partial => f %></tt></pre>
</div></div>
-<div class="paragraph"><p>If <tt>f</tt> is an instance of FormBuilder then this will render the <em>form</em> partial, setting the partial’s object to the form builder. If the form builder is of class LabellingFormBuilder then the <em>labelling_form</em> partial would be rendered instead.</p></div>
+<div class="paragraph"><p>If <tt>f</tt> is an instance of FormBuilder then this will render the <tt>form</tt> partial, setting the partial’s object to the form builder. If the form builder is of class LabellingFormBuilder then the <tt>labelling_form</tt> partial would be rendered instead.</p></div>
</div>
<h2 id="_understanding_parameter_naming_conventions">7. Understanding Parameter Naming Conventions</h2>
<div class="sectionbody">
-<div class="paragraph" id="parameter_names"><p>As you’ve seen in the previous sections, values from forms can be at the top level of the <tt>params</tt> hash or nested in another hash. For example in a standard create
+<div class="paragraph" id="parameter_names"><p>As you’ve seen in the previous sections, values from forms can be at the top level of the <tt>params</tt> hash or nested in another hash. For example in a standard <tt>create</tt>
action for a Person model, <tt>params[:model]</tt> would usually be a hash of all the attributes for the person to create. The <tt>params</tt> hash can also contain arrays, arrays of hashes and so on.</p></div>
-<div class="paragraph"><p>Fundamentally HTML forms don’t know about any sort of structured data, all they generate is name-value pairs. The arrays and hashes you see in your application are the result of some parameter naming conventions that Rails uses.</p></div>
+<div class="paragraph"><p>Fundamentally HTML forms don’t know about any sort of structured data, all they generate is name-value pairs, where pairs are just plain strings. The arrays and hashes you see in your application are the result of some parameter naming conventions that Rails uses.</p></div>
<div class="admonitionblock">
<table><tr>
<td class="icon">
@@ -824,8 +824,8 @@ action for a Person model, <tt>params[:model]</tt> would usually be a hash of al <div class="paragraph"><p>You may find you can try out examples in this section faster by using the console to directly invoke Rails' parameter parser. For example</p></div>
<div class="listingblock">
<div class="content">
-<pre><tt>ActionController::RequestParser.parse_query_parameters "name=fred&phone=0123456789"
-#=> {"name"=>"fred", "phone"=>"0123456789"}</tt></pre>
+<pre><tt>ActionController::UrlEncodedPairParser.parse_query_parameters "name=fred&phone=0123456789"
+# => {"name"=>"fred", "phone"=>"0123456789"}</tt></pre>
</div></div>
</td>
</tr></table>
@@ -838,11 +838,9 @@ action for a Person model, <tt>params[:model]</tt> would usually be a hash of al </div></div>
<div class="paragraph"><p>the <tt>params</tt> hash will contain</p></div>
<div class="listingblock">
-<div class="content"><!-- Generator: GNU source-highlight 2.9
-by Lorenzo Bettini
-http://www.lorenzobettini.it
-http://www.gnu.org/software/src-highlite -->
-<pre><tt><span style="color: #FF0000">{</span><span style="color: #FF0000">'person'</span> <span style="color: #990000">=></span> <span style="color: #FF0000">{</span><span style="color: #FF0000">'name'</span> <span style="color: #990000">=></span> <span style="color: #FF0000">'Henry'</span><span style="color: #FF0000">}}</span></tt></pre></div></div>
+<div class="content">
+<pre><tt>{'person' => {'name' => 'Henry'}}</tt></pre>
+</div></div>
<div class="paragraph"><p>and <tt>params["name"]</tt> will retrieve the submitted value in the controller.</p></div>
<div class="paragraph"><p>Hashes can be nested as many levels as required, for example</p></div>
<div class="listingblock">
@@ -851,11 +849,9 @@ http://www.gnu.org/software/src-highlite --> </div></div>
<div class="paragraph"><p>will result in the <tt>params</tt> hash being</p></div>
<div class="listingblock">
-<div class="content"><!-- Generator: GNU source-highlight 2.9
-by Lorenzo Bettini
-http://www.lorenzobettini.it
-http://www.gnu.org/software/src-highlite -->
-<pre><tt><span style="color: #FF0000">{</span><span style="color: #FF0000">'person'</span> <span style="color: #990000">=></span> <span style="color: #FF0000">{</span><span style="color: #FF0000">'address'</span> <span style="color: #990000">=></span> <span style="color: #FF0000">{</span><span style="color: #FF0000">'city'</span> <span style="color: #990000">=></span> <span style="color: #FF0000">'New York'</span><span style="color: #FF0000">}}}</span></tt></pre></div></div>
+<div class="content">
+<pre><tt>{'person' => {'address' => {'city' => 'New York'}}}</tt></pre>
+</div></div>
<div class="paragraph"><p>Normally Rails ignores duplicate parameter names. If the parameter name contains [] then they will be accumulated in an array. If you wanted people to be able to input multiple phone numbers, your could place this in the form:</p></div>
<div class="listingblock">
<div class="content">
@@ -872,8 +868,8 @@ http://www.gnu.org/software/src-highlite --> <input name="addresses[][line2]" type="text"/>
<input name="addresses[][city]" type="text"/></tt></pre>
</div></div>
-<div class="paragraph"><p>This would result in <tt>params[:addresses]</tt> being an array of hashes with keys <tt>line1</tt>, <tt>line2</tt> and <tt>city</tt>. Rails decides to start accumulating values in a new hash whenever it encounters a input name that already exists in the current hash.</p></div>
-<div class="paragraph"><p>The one restriction is that although hashes can be nested arbitrarily deep then can be only one level of "arrayness". Arrays can be usually replaced by hashes, for example instead of having an array of model objects one can have a hash of model objects keyed by their id, an array index or some other parameter.</p></div>
+<div class="paragraph"><p>This would result in <tt>params[:addresses]</tt> being an array of hashes with keys <tt>line1</tt>, <tt>line2</tt> and <tt>city</tt>. Rails decides to start accumulating values in a new hash whenever it encounters an input name that already exists in the current hash.</p></div>
+<div class="paragraph"><p>There’s a restriction, however, while hashes can be nested arbitrarily, only one level of "arrayness" is allowed. Arrays can be usually replaced by hashes, for example instead of having an array of model objects one can have a hash of model objects keyed by their id, an array index or some other parameter.</p></div>
<div class="admonitionblock">
<table><tr>
<td class="icon">
@@ -888,7 +884,7 @@ http://www.gnu.org/software/src-highlite --> <div class="listingblock">
<div class="content">
<pre><tt><% form_for @person do |person_form| %>
- <%= person_form.text_field :name%>
+ <%= person_form.text_field :name %>
<% for address in @person.addresses %>
<% person_form.fields_for address, :index => address do |address_form|%>
<%= address_form.text_field :city %>
@@ -907,12 +903,10 @@ http://www.gnu.org/software/src-highlite --> </div></div>
<div class="paragraph"><p>This will result in a <tt>params</tt> hash that looks like</p></div>
<div class="listingblock">
-<div class="content"><!-- Generator: GNU source-highlight 2.9
-by Lorenzo Bettini
-http://www.lorenzobettini.it
-http://www.gnu.org/software/src-highlite -->
-<pre><tt><span style="color: #FF0000">{</span><span style="color: #FF0000">'person'</span> <span style="color: #990000">=></span> <span style="color: #FF0000">{</span><span style="color: #FF0000">'name'</span> <span style="color: #990000">=></span> <span style="color: #FF0000">'Bob'</span><span style="color: #990000">,</span> <span style="color: #FF0000">'address'</span> <span style="color: #990000">=></span> <span style="color: #FF0000">{</span> <span style="color: #FF0000">'23'</span> <span style="color: #990000">=></span> <span style="color: #FF0000">{</span><span style="color: #FF0000">'city'</span> <span style="color: #990000">=></span> <span style="color: #FF0000">'Paris'</span><span style="color: #FF0000">}</span><span style="color: #990000">,</span> <span style="color: #FF0000">'45'</span> <span style="color: #990000">=></span> <span style="color: #FF0000">{</span><span style="color: #FF0000">'city'</span> <span style="color: #990000">=></span> <span style="color: #FF0000">'London'</span><span style="color: #FF0000">}</span> <span style="color: #FF0000">}}}</span></tt></pre></div></div>
-<div class="paragraph"><p>Rails knows that all these inputs should be part of the person hash because you called <tt>fields_for</tt> on the first form builder. By specifying an <tt>:index</tt> option you’re telling rails that instead of naming the inputs <tt>person[address][city]</tt> it should insert that index surrounded by [] between the address and the city. If you pass an Active Record object as we did then Rails will call <tt>to_param</tt> on it, which by default returns the database id. This is often useful as it is then easy to locate which Address record should be modified. You can pass numbers with some other significance, strings or even nil (which will result in an array parameter being created).</p></div>
+<div class="content">
+<pre><tt>{'person' => {'name' => 'Bob', 'address' => {'23' => {'city' => 'Paris'}, '45' => {'city' => 'London'}}}}</tt></pre>
+</div></div>
+<div class="paragraph"><p>Rails knows that all these inputs should be part of the person hash because you called <tt>fields_for</tt> on the first form builder. By specifying an <tt>:index</tt> option you’re telling rails that instead of naming the inputs <tt>person[address][city]</tt> it should insert that index surrounded by [] between the address and the city. If you pass an Active Record object as we did then Rails will call <tt>to_param</tt> on it, which by default returns the database id. This is often useful as it is then easy to locate which Address record should be modified. You can pass numbers with some other significance, strings or even <tt>nil</tt> (which will result in an array parameter being created).</p></div>
<div class="paragraph"><p>To create more intricate nestings, you can specify the first part of the input name (<tt>person[address]</tt> in the previous example) explicitly, for example</p></div>
<div class="listingblock">
<div class="content">
@@ -937,7 +931,7 @@ http://www.gnu.org/software/src-highlite --> </div>
<h2 id="_building_complex_forms">8. Building Complex forms</h2>
<div class="sectionbody">
-<div class="paragraph"><p>Many apps grow beyond simple forms editing a single object. For example when creating a Person you might want to allow the user to (on the same form) create multiple address records (home, work etc.). When later editing that person the user should be able to add, remove or amend addresses as necessary. While this guide has shown you all the pieces necessary to handle this, Rails does not yet have a standard end-to-end way of accomplishing this, but many have come up with viable approaches. These include:</p></div>
+<div class="paragraph"><p>Many apps grow beyond simple forms editing a single object. For example when creating a Person you might want to allow the user to (on the same form) create multiple address records (home, work, etc.). When later editing that person the user should be able to add, remove or amend addresses as necessary. While this guide has shown you all the pieces necessary to handle this, Rails does not yet have a standard end-to-end way of accomplishing this, but many have come up with viable approaches. These include:</p></div>
<div class="ulist"><ul>
<li>
<p>
diff --git a/railties/doc/guides/html/i18n.html b/railties/doc/guides/html/i18n.html index 60253145de..b0d52c0ff5 100644 --- a/railties/doc/guides/html/i18n.html +++ b/railties/doc/guides/html/i18n.html @@ -59,13 +59,15 @@ </ul> </li> <li> - <a href="#_internationalize_your_application">Internationalize your application</a> + <a href="#_internationalizing_your_application">Internationalizing your application</a> <ul> <li><a href="#_adding_translations">Adding Translations</a></li> <li><a href="#_adding_date_time_formats">Adding Date/Time formats</a></li> + <li><a href="#_organization_of_locale_files">Organization of locale files</a></li> + </ul> </li> <li> @@ -128,7 +130,26 @@ <div id="preamble">
<div class="sectionbody">
<div class="paragraph"><p>The Ruby I18n (shorthand for <em>internationalization</em>) gem which is shipped with Ruby on Rails (starting from Rails 2.2) provides an easy-to-use and extensible framework for <strong>translating your application to a single custom language</strong> other than English or for <strong>providing multi-language support</strong> in your application.</p></div>
-<div class="paragraph"><p>In the process of <em>localizing</em> your application you’ll probably want to do following two things:</p></div>
+<div class="paragraph"><p>The process of "internationalization" usually means to abstract all strings and other locale specific bits (such as date or currency formats) out of your application. The process of "localization" means to provide translations and localized formats for these bits. <a href="#1">[1]</a></p></div>
+<div class="paragraph"><p>So, in the process of <em>internationalizing</em> your Rails application you have to:</p></div>
+<div class="ulist"><ul>
+<li>
+<p>
+Ensure you have support for i18n
+</p>
+</li>
+<li>
+<p>
+Tell Rails where to find locale dictionaries
+</p>
+</li>
+<li>
+<p>
+Tell Rails how to set, preserve and switch locale
+</p>
+</li>
+</ul></div>
+<div class="paragraph"><p>In the process of <em>localizing</em> your application you’ll probably want to do following three things:</p></div>
<div class="ulist"><ul>
<li>
<p>
@@ -140,6 +161,11 @@ Replace or supplement Rail’s default locale — eg. date a Abstract texts in your application into keyed dictionaries — eg. flash messages, static texts in your views, etc
</p>
</li>
+<li>
+<p>
+Store the resulting dictionaries somewhere
+</p>
+</li>
</ul></div>
<div class="paragraph"><p>This guide will walk you through the I18n API and contains a tutorial how to internationalize a Rails application from the start.</p></div>
<div class="admonitionblock">
@@ -237,6 +263,14 @@ http://www.gnu.org/software/src-highlite --> hello<span style="color: #990000">:</span> <span style="color: #FF0000">"Hello world"</span></tt></pre></div></div>
<div class="paragraph"><p>This means, that in the <tt>:en</tt> locale, the key <em>hello</em> will map to <em>Hello world</em> string. Every string inside Rails is internationalized in this way, see for instance Active Record validation messages in the <a href="http://github.com/rails/rails/blob/master/activerecord/lib/active_record/locale/en.yml"><tt>activerecord/lib/active_record/locale/en.yml</tt></a> file or time and date formats in the <a href="http://github.com/rails/rails/blob/master/activesupport/lib/active_support/locale/en.yml"><tt>activesupport/lib/active_support/locale/en.yml</tt></a> file. You can use YAML or standard Ruby Hashes to store translations in the default (Simple) backend.</p></div>
<div class="paragraph"><p>The I18n library will use <strong>English</strong> as a <strong>default locale</strong>, ie. if you don’t set a different locale, <tt>:en</tt> will be used for looking up translations.</p></div>
+<div class="admonitionblock">
+<table><tr>
+<td class="icon">
+<img src="./images/icons/note.png" alt="Note" />
+</td>
+<td class="content">The i18n library takes <strong>pragmatic approach</strong> to locale keys (after <a href="http://groups.google.com/group/rails-i18n/browse_thread/thread/14dede2c7dbe9470/80eec34395f64f3c?hl=en">some discussion</a>), including only the <em>locale</em> ("language") part, like <tt>:en</tt>, <tt>:pl</tt>, not the <em>region</em> part, like <tt>:en-US</tt> or <tt>:en-UK</tt>, which are traditionally used for separating "languages" and "regional setting" or "dialects". (For instance, in the <tt>:en-US</tt> locale you would have $ as a currency symbol, while in <tt>:en-UK</tt>, you would have €. Also, insults would be different in American and British English :) Reason for this pragmatic approach is that most of the time, you usually care about making your application available in different "languages", and working with locales is much simpler this way. However, nothing stops you from separating regional and other settings in the traditional way. In this case, you could eg. inherit from the default <tt>en</tt> locale and then provide UK specific settings in a <tt>:en-UK</tt> dictionary.</td>
+</tr></table>
+</div>
<div class="paragraph"><p>The <strong>translations load path</strong> (<tt>I18n.load_path</tt>) is just a Ruby Array of paths to your translation files that will be loaded automatically and available in your application. You can pick whatever directory and translation file naming scheme makes sense for you.</p></div>
<div class="admonitionblock">
<table><tr>
@@ -304,7 +338,7 @@ http://www.gnu.org/software/src-highlite --> <td class="content">Following examples rely on having locales loaded into your application available as an array of strings like <tt>["en", "es", "gr"]</tt>. This is not inclued in current version of Rails 2.2 — forthcoming Rails version 2.3 will contain easy accesor <tt>available_locales</tt>. (See <a href="http://github.com/svenfuchs/i18n/commit/411f8fe7">this commit</a> and background at <a href="http://rails-i18n.org/wiki/pages/i18n-available_locales">Rails I18n Wiki</a>.)</td>
</tr></table>
</div>
-<div class="paragraph"><p>We have to include support for getting available locales manually in an initializer like this:</p></div>
+<div class="paragraph"><p>So, for having available locales easily available in Rails 2.2, we have to include this support manually in an initializer, like this:</p></div>
<div class="listingblock">
<div class="content"><!-- Generator: GNU source-highlight 2.9
by Lorenzo Bettini
@@ -424,7 +458,7 @@ http://www.gnu.org/software/src-highlite --> <span style="font-weight: bold"><span style="color: #0000FF">end</span></span></tt></pre></div></div>
<div class="paragraph"><p>Every helper method dependent on <tt>url_for</tt> (eg. helpers for named routes like <tt>root_path</tt> or <tt>root_url</tt>, resource routes like <tt>books_path</tt> or <tt>books_url</tt>, etc.) will now <strong>automatically include the locale in the query string</strong>, like this: <tt>http://localhost:3001/?locale=ja</tt>.</p></div>
<div class="paragraph"><p>You may be satisfied with this. It does impact the readability of URLs, though, when the locale "hangs" at the end of every URL in your application. Moreover, from the architectural standpoint, locale is usually hierarchically above the other parts of application domain: and URLs should reflect this.</p></div>
-<div class="paragraph"><p>You probably want URLs look like this: <tt>www.example.com/en/books</tt> versus <tt>www.example.com/nl/books</tt>. This is achievable with the over-riding <tt>default_url_options</tt> strategy: you just have to set up your routes with <a href="http://api.rubyonrails.org/classes/ActionController/Resources.html#M000354"><tt>path_prefix</tt></a> option in this way:</p></div>
+<div class="paragraph"><p>You probably want URLs look like this: <tt>www.example.com/en/books</tt> (which loads English locale) and <tt>www.example.com/nl/books</tt> (which loads Netherlands locale). This is achievable with the "over-riding <tt>default_url_options</tt>" strategy from above: you just have to set up your routes with <a href="http://api.rubyonrails.org/classes/ActionController/Resources.html#M000354"><tt>path_prefix</tt></a> option in this way:</p></div>
<div class="listingblock">
<div class="content"><!-- Generator: GNU source-highlight 2.9
by Lorenzo Bettini
@@ -432,7 +466,7 @@ http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="font-style: italic"><span style="color: #9A1900"># config/routes.rb</span></span>
map<span style="color: #990000">.</span>resources <span style="color: #990000">:</span>books<span style="color: #990000">,</span> <span style="color: #990000">:</span>path_prefix <span style="color: #990000">=></span> <span style="color: #FF0000">'/:locale'</span></tt></pre></div></div>
-<div class="paragraph"><p>Now, when you call <tt>books_path</tt> method you should get <tt>"/en/books"</tt> (for the default locale). An URL like <tt>http://localhost:3001/nl/books</tt> should load the Netherlands locale, then, and so on.</p></div>
+<div class="paragraph"><p>Now, when you call <tt>books_path</tt> method you should get <tt>"/en/books"</tt> (for the default locale). An URL like <tt>http://localhost:3001/nl/books</tt> should load the Netherlands locale, then, and following calls to <tt>books_path</tt> should return <tt>"/nl/books"</tt> (because the locale changed).</p></div>
<div class="paragraph"><p>Of course, you need to take special care of root URL (usually "homepage" or "dashboard") of your application. An URL like <tt>http://localhost:3001/nl</tt> will not work automatically, because the <tt>map.root :controller => "dashboard"</tt> declaration in your <tt>routes.rb</tt> doesn’t take locale into account. (And rightly so. There’s only one "root" URL.)</p></div>
<div class="paragraph"><p>You would probably need to map URLs like these:</p></div>
<div class="listingblock">
@@ -452,13 +486,35 @@ map<span style="color: #990000">.</span>dashboard <span style="color: #FF0000">' </tr></table>
</div>
<h3 id="_setting_locale_from_the_client_supplied_information">2.6. Setting locale from the client supplied information</h3>
-<div class="paragraph"><p># TODO: Accept-Language, GeoIP, etc. Explain why it is not such a good idea in most cases.</p></div>
-<div class="paragraph"><p>OK! Now you’ve initialized I18n support for your application and told it which locale should be used and how to preserve it between requests. With that in place you’re now ready for the really interesting stuff.</p></div>
+<div class="paragraph"><p>In specific cases, it would make sense to set locale from client supplied information, ie. not from URL. This information may come for example from users' preffered language (set in their browser), can be based on users' geographical location inferred from their IP, or users can provide it simply by choosing locale in your application interface and saving it to their profile. This approach is more suitable for web-based applications or services, not for websites — see the box about <em>sessions</em>, <em>cookies</em> and RESTful architecture above.</p></div>
+<h4 id="_using_accept_language">2.6.1. Using Accept-Language</h4>
+<div class="paragraph"><p>One source of client supplied information would be an <tt>Accept-Language</tt> HTTP header. People may <a href="http://www.w3.org/International/questions/qa-lang-priorities">set this in their browser</a> or other clients (such as <em>curl</em>).</p></div>
+<div class="paragraph"><p>A trivial implementation of using <tt>Accept-Language</tt> header would be:</p></div>
+<div class="listingblock">
+<div class="content"><!-- Generator: GNU source-highlight 2.9
+by Lorenzo Bettini
+http://www.lorenzobettini.it
+http://www.gnu.org/software/src-highlite -->
+<pre><tt><span style="font-weight: bold"><span style="color: #0000FF">def</span></span> set_locale
+ logger<span style="color: #990000">.</span>debug <span style="color: #FF0000">"* Accept-Language: #{request.env['HTTP_ACCEPT_LANGUAGE']}"</span>
+ I18n<span style="color: #990000">.</span>locale <span style="color: #990000">=</span> extract_locale_from_accept_language_header
+ logger<span style="color: #990000">.</span>debug <span style="color: #FF0000">"* Locale set to '#{I18n.locale}'"</span>
+<span style="font-weight: bold"><span style="color: #0000FF">end</span></span>
+private
+<span style="font-weight: bold"><span style="color: #0000FF">def</span></span> extract_locale_from_accept_language_header
+ request<span style="color: #990000">.</span>env<span style="color: #990000">[</span><span style="color: #FF0000">'HTTP_ACCEPT_LANGUAGE'</span><span style="color: #990000">].</span>scan<span style="color: #990000">(</span><span style="color: #FF6600">/^[a-z]{2}/</span><span style="color: #990000">).</span>first
+<span style="font-weight: bold"><span style="color: #0000FF">end</span></span></tt></pre></div></div>
+<div class="paragraph"><p>Of course, in production environment you would need much robust code, and could use a plugin such as Iaian Hecker’s <a href="http://github.com/iain/http_accept_language">http_accept_language</a>.</p></div>
+<h4 id="_using_geoip_or_similar_database">2.6.2. Using GeoIP (or similar) database</h4>
+<div class="paragraph"><p>Another way of choosing the locale from client’s information would be to use a database for mapping client IP to region, such as <a href="http://www.maxmind.com/app/geolitecountry">GeoIP Lite Country</a>. The mechanics of the code would be very similar to the code above — you would need to query database for user’s IP, and lookup your preffered locale for the country/region/city returned.</p></div>
+<h4 id="_user_profile">2.6.3. User profile</h4>
+<div class="paragraph"><p>You can also provide users of your application with means to set (and possibly over-ride) locale in your application interface, as well. Again, mechanics for this approach would be very similar to the code above — you’d probably let users choose a locale from a dropdown list and save it to their profile in database. Then you’d set the locale to this value.</p></div>
</div>
-<h2 id="_internationalize_your_application">3. Internationalize your application</h2>
+<h2 id="_internationalizing_your_application">3. Internationalizing your application</h2>
<div class="sectionbody">
-<div class="paragraph"><p>The process of "internationalization" usually means to abstract all strings and other locale specific bits out of your application. The process of "localization" means to then provide translations and localized formats for these bits. <a href="#1">[1]</a></p></div>
-<div class="paragraph"><p>So, let’s internationalize something. You most probably have something like this in one of your applications:</p></div>
+<div class="paragraph"><p>OK! Now you’ve initialized I18n support for your Ruby on Rails application and told it which locale should be used and how to preserve it between requests. With that in place, you’re now ready for the really interesting stuff.</p></div>
+<div class="paragraph"><p>Let’s <em>internationalize</em> our application, ie. abstract every locale-specific parts, and that <em>localize</em> it, ie. provide neccessary translations for these abstracts.</p></div>
+<div class="paragraph"><p>You most probably have something like this in one of your applications:</p></div>
<div class="listingblock">
<div class="content"><!-- Generator: GNU source-highlight 2.9
by Lorenzo Bettini
@@ -483,7 +539,7 @@ ActionController<span style="color: #990000">::</span>Routing<span style="color: <img src="images/i18n/demo_untranslated.png" alt="rails i18n demo untranslated" title="rails i18n demo untranslated" />
</span></p></div>
<h3 id="_adding_translations">3.1. Adding Translations</h3>
-<div class="paragraph"><p>Obviously there are <strong>two strings that are localized to English</strong>. In order to internationalize this code replace these strings with calls to Rails' <tt>#t</tt> helper with a key that makes sense for the translation:</p></div>
+<div class="paragraph"><p>Obviously there are <strong>two strings that are localized to English</strong>. In order to internationalize this code, <strong>replace these strings</strong> with calls to Rails' <tt>#t</tt> helper with a key that makes sense for the translation:</p></div>
<div class="listingblock">
<div class="content"><!-- Generator: GNU source-highlight 2.9
by Lorenzo Bettini
@@ -499,7 +555,7 @@ http://www.gnu.org/software/src-highlite --> <span style="font-style: italic"><span style="color: #9A1900"># app/views/home/index.html.erb</span></span>
<span style="color: #FF0000"><h1><%=t :hello_world %></h1></span>
<span style="color: #FF0000"><p><%= flash[:notice] %></p></span></tt></pre></div></div>
-<div class="paragraph"><p>When you now render this view it will show an error message that tells you that the translations for the keys :hello_world and :hello_flash are missing.</p></div>
+<div class="paragraph"><p>When you now render this view, it will show an error message which tells you that the translations for the keys <tt>:hello_world</tt> and <tt>:hello_flash</tt> are missing.</p></div>
<div class="paragraph"><p><span class="image">
<img src="images/i18n/demo_translation_missing.png" alt="rails i18n demo translation missing" title="rails i18n demo translation missing" />
</span></p></div>
@@ -508,10 +564,10 @@ http://www.gnu.org/software/src-highlite --> <td class="icon">
<img src="./images/icons/note.png" alt="Note" />
</td>
-<td class="content">Rails adds a <tt>t</tt> (<tt>translate</tt>) helper method to your views so that you do not need to spell out <tt>I18n.t</tt> all the time. Additionally this helper will catch missing translations and wrap the resulting error message into a <span class="translation_missing">.</td>
+<td class="content">Rails adds a <tt>t</tt> (<tt>translate</tt>) helper method to your views so that you do not need to spell out <tt>I18n.t</tt> all the time. Additionally this helper will catch missing translations and wrap the resulting error message into a <tt><span class="translation_missing"></tt>.</td>
</tr></table>
</div>
-<div class="paragraph"><p>So let’s add the missing translations (i.e. do the "localization" part):</p></div>
+<div class="paragraph"><p>So let’s add the missing translations into the dictionary files (i.e. do the "localization" part):</p></div>
<div class="listingblock">
<div class="content"><!-- Generator: GNU source-highlight 2.9
by Lorenzo Bettini
@@ -530,7 +586,7 @@ pirate<span style="color: #990000">:</span> <div class="paragraph"><p><span class="image">
<img src="images/i18n/demo_translated_en.png" alt="rails i18n demo translated to english" title="rails i18n demo translated to english" />
</span></p></div>
-<div class="paragraph"><p>And when you change the URL to pass the pirate locale you get:</p></div>
+<div class="paragraph"><p>And when you change the URL to pass the pirate locale (<tt>http://localhost:3000?locale=pirate</tt>), you’ll get:</p></div>
<div class="paragraph"><p><span class="image">
<img src="images/i18n/demo_translated_pirate.png" alt="rails i18n demo translated to pirate" title="rails i18n demo translated to pirate" />
</span></p></div>
@@ -576,29 +632,59 @@ pirate<span style="color: #990000">:</span> <td class="content">Right now you might need to add some more date/time formats in order to make the I18n backend work as expected. Of course, there’s a great chance that somebody already did all the work by <strong>translating Rails’s defaults for your locale</strong>. See the <a href="http://github.com/svenfuchs/rails-i18n/tree/master/rails/locale">rails-i18n repository at Github</a> for an archive of various locale files. When you put such file(s) in <tt>config/locale/</tt> directory, they will automatically ready for use.</td>
</tr></table>
</div>
+<h3 id="_organization_of_locale_files">3.3. Organization of locale files</h3>
+<div class="paragraph"><p>When you are using the default SimpleStore, shipped with the i18n library, you store dictionaries in plain-text files on the disc. Putting translations for all parts of your application in one file per locale could be hard to manage. You can store these files in a hierarchy which makes sense to you.</p></div>
+<div class="paragraph"><p>For example, your <tt>config/locale</tt> directory could look like this:</p></div>
+<div class="listingblock">
+<div class="content">
+<pre><tt>|-defaults
+|---es.rb
+|---en.rb
+|-models
+|---book
+|-----es.rb
+|-----en.rb
+|-views
+|---defaults
+|-----es.rb
+|-----en.rb
+|---books
+|-----es.rb
+|-----en.rb
+|---users
+|-----es.rb
+|-----en.rb
+|---navigation
+|-----es.rb
+|-----en.rb</tt></pre>
+</div></div>
+<div class="paragraph"><p>This way, you can separate model and model attribute names from text inside views, and all of this from the "defaults" (eg. date and time formats).</p></div>
+<div class="paragraph"><p>Other stores for the i18n library could provide different means of such separation.</p></div>
+<div class="paragraph"><p>Do check the <a href="http://rails-i18n.org/wiki">Rails i18n Wiki</a> for list of tools available for managing translations.</p></div>
</div>
<h2 id="_overview_of_the_i18n_api_features">4. Overview of the I18n API features</h2>
<div class="sectionbody">
-<div class="paragraph"><p>The following purposes are covered:</p></div>
+<div class="paragraph"><p>You should have good understanding of using the i18n library now, knowing all neccessary aspects of internationalizing a basic Rails application. In the following chapters, we’ll cover it’s features in more depth.</p></div>
+<div class="paragraph"><p>Covered are features like these:</p></div>
<div class="ulist"><ul>
<li>
<p>
-lookup translations
+looking up translations
</p>
</li>
<li>
<p>
-interpolate data into translations
+interpolating data into translations
</p>
</li>
<li>
<p>
-pluralize translations
+pluralizing translations
</p>
</li>
<li>
<p>
-localize dates, numbers, currency etc.
+localizing dates, numbers, currency etc.
</p>
</li>
</ul></div>
|