Skip to content
Seb Bacon edited this page Apr 1, 2011 · 24 revisions

Deployment notes

Deployed translations for the project live in locale/.

Translations live in the project page at [https://www.transifex.net/projects/p/alaveteli/ Transifex] and should be submitted there.

To deploy, say, English and Spanish translations at once:

  • Ensure their PO files are at locale/en/app.po and locale/es/app.po
  • Add define('OPTION_AVAILABLE_LOCALES', 'en es') to general/config

The pot-file at locale/app.pot acts as the template for PO files. When new translation strings have been added to the source, it can be updated using the script at script/generate_pot.sh. This looks for new translatable strings in the source and creates entries in the pot file.

Further down the line we should:

  • Write a script to pull translations from Transifex and commit them to the main Alaveteli repository
  • Write a script to push a new app.pot to Transifex

URL translations live in config/i18n-routes.yml; see below for more details.

Technical implementation details

I18n in URLs

We use the translate_routes plugin to localize URLs. This looks up URL segments as translation strings in a YAML file at config/i18n-routes.yml.

For the plugin to work correctly, it needs a single, named route for each possible route, meaning that routes like help.help_general '/help/:action', :action => :action won't work -- because the URL portion dynamically selects a controller action.

To see how the plugin sets up translatable routes, run the rake routes tasks. You'll see that for each named route in the routing table, there is a new, named route corresponding to each active locale; for example, if you are using Spanish and English, the admin_user_update route becomes two routes, admin_user_update_es and admin_user_update_en.

To create a new YAML template when your routes have changed, run rake translate_routes:update_yaml["es"] and then update i18n-routes.yml correspondingly.

Note that this workflow needs improving! We should probably keep each locale's routes in a separate YAML file and only load the ones we need at runtime (right now everything in i18n-routes.yml is loaded). Ideally, we would also make the translations come from the locale's PO file.

I18n in templates

Only parts of the templates are i18n-aware. These notes may be of help in continuing to add i18n strings to the source:

  • Simple strings: <% = _("String to translate") %>
  • Strings that include variables: give the translator a hand by inserting strings that can be interpolated, so the variable has meaning. For example, <%= "Nothing found for '" + h(@query) + "'" %> might become <%= _("Nothing found for '{{search_terms}}'", :search_terms => h(@query)) %>
  • Strings containing numbers: <%= n_('%d request', '%d requests', @quantity) % @quantity %>
  • We allow some inline HTML where it helps with meaningful context, e.g. _('<a href="%s">Browse all</a> or <a href="%s">ask us to add it</a>.') % [url1, url2]

Similar rules can apply to strings in the python source code, as long as you import _, n_, etc.

Overriding model field setters

We use the Globalize plugin to localize model fields. Where column "foo" has been marked in the model as :translates, globalize overrides foo.baz = 12 to actually set the value in column baz of table foo_translations.

A side effect of the way it does this is that if you wish to override a specific attribute setter, you will need to explicitly call the Globalize machinery; something like:

    def name=(name)
        globalize.write(self.class.locale || I18n.locale, "name", name)
        self["name"] = short_name
        # your other stuff here
    end

Searching

The find_first_by_<attr> and find_all_by_<attr> magic methods should work. If you want to do a more programmatic search, you will need to join on the translation table. For example:

          query = "#{translated_attr_name(someattr) = ? AND #{translated_attr_name('locale')} IN (?)"
          locales = Globalize.fallbacks(locale || I18n.locale).map(&:to_s)
          find(
            :first,
            :joins => :translations,
            :conditions => [query, value, locales],
            :readonly => false
          )
Clone this wiki locally