--- layout: page title: Internationalisation (for devs) --- # Internationalisation in the code
This page describes some technical aspects of internationalising the Alaveteli code. It's mostly aimed at devs who are working on the codebase — if you just want to translate Alaveteli into your own language, see translating Alaveteli instead.
## Deployment notes Deployed translations for the project live in ``locale/``. We encourage translations to be done on Transifex because translators can work through its web interface rather than needing to edit the `.po` and `.pot` files directly. Ultimately, Transifex just captures translators' work and turns it into the files that Alaveteli needs (using gettext). ### How to get the latest translations onto your site For example, to deploy 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) * SetAVAILABLE_LOCALES
to en es
### What to do if you don't have complete translations for an older release of Alaveteli
Before a new release of Alaveteli is made, the translation files are
pulled from Transifex and added to Alaveteli's ``locale/`` directory in
github. These represent the most complete translations for the previous
release. Then the files in Transifex are updated with any new strings
that need to be translated for the upcoming release. At this point old
strings that are no longer used in the new release are also removed. The
latest [release tag](https://github.com/mysociety/alaveteli/releases)
for a release in github should contain the most complete translations
for that release from Transifex.
If you're using an older release of Alaveteli and you want to add to or
change the translations, you can edit the .po files directly using a
local program such as [PoEdit](http://poedit.net/).
### How to add new strings to the translations
You need to do this if you've added any new strings to the code that need
translations (or if you change an existing one).
To update the
`.po` or `.pot` files
for each language, run:
bundle exec rake gettext:store_model_attributes
followed by:
bundle exec rake gettext:find
If `gettext:find` only creates the file `locale/im-config.pot` then you need to
unset the `TEXTDOMAIN` environment variable and try again.
For more details about the translations, see the page about
[translating Alaveteli]({{ page.baseurl }}/docs/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.
* for the Rails version of the currently selected locale, use `I18n.locale`
* for 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:
```
_('Browse all or ask us to add it.',
:browse_url => @browse_url, :add_url => @add_url)
```
Similar rules can apply to strings in the Ruby source code.
## 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://github.com/globalize/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_