aboutsummaryrefslogtreecommitdiffstats
path: root/docs/developers
diff options
context:
space:
mode:
authorDave Whiteland <dave@mysociety.org>2014-06-24 13:11:38 +0100
committerDave Whiteland <dave@mysociety.org>2014-06-24 13:11:38 +0100
commit645ccba0f25fd5e123994f8ab1b3a02d9b8074b5 (patch)
tree6bf37d7ab357313d0daeab030c084c6b5d1ac15d /docs/developers
parent8b717f68db4d6bce2fdc8bc706620a2f0ceb3e75 (diff)
add i18n page (from wiki) to dev docs
Diffstat (limited to 'docs/developers')
-rw-r--r--docs/developers/i18n.md143
1 files changed, 143 insertions, 0 deletions
diff --git a/docs/developers/i18n.md b/docs/developers/i18n.md
new file mode 100644
index 000000000..480d0d954
--- /dev/null
+++ b/docs/developers/i18n.md
@@ -0,0 +1,143 @@
+---
+layout: page
+title: Internationalisation (for devs)
+---
+
+# Internationalisation in the code
+
+<p class="lead">
+ This page describes some technical aspects of internationalising the
+ Alaveteli code. It's mostly aimed at devs who are working on the
+ codebase &mdash; if you just want to translate Alaveteli into your
+ own langauge, see this page on
+ <a href="{{ site.baseurl }}customising/translation">Translating Alaveteli</a>
+ instead.
+</p>
+
+
+## Deployment notes
+
+Deployed translations for the project live in ``locale/``.
+
+Translations live in the project page at
+[Transifex](https://www.transifex.net/projects/p/alaveteli/) 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```
+ (for example, by downloading them from Transifex)
+ * Set <code><a href="{{ site.baseurl }}customising/config/#AVAILABLE_LOCALES">AVAILABLE_LOCALES</a></code>
+ to <code>en&nbsp;es</code>
+
+The ``pot``-file at ``locale/app.pot`` acts as the template for PO files. When
+new translation strings have been added to the source, this ``pot``-file 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.
+
+For more details about the translations, see the page about
+[translating Alaveteli]({{ site.baseurl }}customising/translation).
+
+
+## Technical implementation details
+
+### Getting the current locale
+
+This is complicated by the fact that there are two competing ways to define a
+locale+territory combination. The POSIX (and `gettext` and Transifex) way is
+like `en_GB`; the Rails way is like `en-US`. Because we are using gettext and
+Transifex for translations, we must deal with both. Wherever you need to know
+the Rails version of the currently selected locale, use `I18n.locale`; wherever
+you want to know the POSIX version of the locale, use `FastGettext.locale`.
+
+## I18n in templates
+
+Before you add i18n strings to the source, you should read
+[internationalisation guidelines](http://mysociety.github.io/internationalization.html)
+that apply to all our projects.
+
+Some hints for adding the strings into the Alaveteli code:
+
+* 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, for example:
+
+```
+_('<a href="{{browse_url}}">Browse all</a> or <a href="{{add_url}}">ask us to add it</a>.',
+ :browse_url => @browse_url, :add_url => @add_url)
+```
+
+Similar rules can apply to strings in the python source code, as long as you
+import ```_```, ```n_```, etc.
+
+## Programmatic access of translated PublicBodies
+
+Apart from the templates, the only other area of i18n currently implemented is
+in the PublicBodies.
+
+The implementation allows for getting different locales of a PublicBody like so:
+
+```ruby
+ PublicBody.with_locale("es") do
+ puts PublicBody.find(230).name
+ end
+```
+
+Usually, that's all the code you need to know about. There's a method
+```self.locale_from_params()``` available on all models which returns a locale
+specified as ```locale=xx``` in the query string, and which falls back to the
+default locale, that you can use in conjunction with the ```with_locale```
+method above. All the joining on internal translation tables should usually be
+handled automagically -- but there are some exceptions, that follow below.
+
+### Overriding model field setters
+
+Internally, we use the [Globalize plugin](https://rubygems.org/gems/globalize)
+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:
+
+```ruby
+ 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:
+
+```ruby
+ 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
+ )
+```
+
+You may also need to do some lower-level SQL joins or conditions. See
+```PublicBodyController.list``` for an example of a query that has a condition
+that is explicitly locale-aware (look for the ```locale_condition``` variable)
+
+
+## I18n in URLs
+
+We have tried using the [translate_routes plugin](https://github.com/raul/translate_routes)
+to localize URLs. This looks up URL segments as translation strings in a YAML
+file at```config/i18n-routes.yml```. However, we no longer use it because we
+found it was overly complex.