-
Notifications
You must be signed in to change notification settings - Fork 24
Localization
Umlaut (as of version 4.0) provides support for localization -- displaying in different languages -- via Rails' standard i18n feature. Umlaut localization was originally contributed by @ronan-mch of the Royal Library of Denmark.
Umlaut is an expansive and very extensible application; not all areas may as of yet been localized. If you discover an area or a particular service which is not yet localized but which you would like to be, please let us know. However, the Royal Library of Denmark is already using Danish-localized Umlaut, so it is sufficiently complete for at least some real use cases.
At present, only Danish translation is built-into Umlaut; you can create additional translation files in your local app, or better yet contribute them back to Umlaut. In order to make a new translation, copy Umlaut's English translation file at https://github.com/team-umlaut/umlaut/blob/master/config/locales/en.yml to a new language abbreviation in your local app (eg ./config/locales/fr.yml
), and translate all values.
A local translation file can also be used to change textual labels used in Umlaut even in English, overriding specified labels from Umlaut's distribution translation file. You can copy only parts of the original translation file, and override them locally, and the distribution values will be used for other keys you do not override.
The current locale is specified by the umlaut.locale
URL parameter, for instance, in a URL: /resolve?title=something¨aut.locale=da
.
If no locale is present in the URL, the setting of I18n.default_locale
will be used.
In the future, we might make locale-specifying URL's prettier, maybe something like /en/resolve?title=
, but this is not operative at present. Let us know if it's important for your use case.
You don't need to do anything to turn on localization, it's already on, and will be activated if umlaut.locale
is present as a query param.
However, you may wish to set I18n.default_locale
in your config/application.rb
file. You may also wish to specify which locales your app allows and supports by setting eg config.i18n.available_locales = [:en, :da]
.
If you'd like a UI element for changing the locale to show up, add show_localization_selector true
to your local app/controllers/umlaut_controller.rb
config block. But you can also customize your Umlaut header to provide your own locale selection UI. You can use Umlaut's default as a guide if you like.
Standard Rails I18n provides a feature where you can specify 'fallbacks' -- if the Spanish locale is selected, but a translation is not available in Spanish, you might want to fallback to the English translation.
Since Umlaut is so extensible and constantly changing, it might be hard for other translations to keep up with English, and if this is an acceptable fallback for your context it might be wise. In your config/application.rb
, specify for instance:
config.i18n.fallbacks =[:en]
There are some cases where the translation files are organized and used systematically to deal with Umlaut's flexibility and pluggability.
The titles and optional prompts of sections of the Umlaut resolve menu screen are controlled by I18n translation files, in a way organized by the section's div_id
. To find out a section's div_id, you can look at the source code where default configuration for display sections is done.
Or you can use a web browser's dev tools to look for the id
attribute on the div
wrapping a given umlaut_section (a bit messier HTML than it could be sorry):
<div id="excerpts">
<div class="umlaut" style="">
<div class="umlaut-section excerpts">
So for umlaut display section with div_id excerpts
, the title and prompt are configured in the i18n translation file like:
en:
umlaut:
display_sections:
excerpts:
title: Limited Excerpts
prompt: "A limited preview which may include table of contents, index, and other selected pages."
You can of course look at the existing Umlaut translation file to find a key you want to override here too. You can create a local file at ./config/locales/en.yml
and over-ride just certain keys in it.
The title
key actually may not be specified in the translation file, because as a default Umlaut will use the name of the ServiceTypeValue that is handled by the display section.
Umlaut ServiceResponses are categorized into types, or as they are called in Umlaut (for unfortunate historical reasons) ServiceTypeValue's. For instance, fulltext
, excerpts
, document_delivery
, highlighted_links
("see also" links) -- are all identifiers for ServiceTypeValues.
Sometimes Umlaut needs to refer to responses of a certain type by name, when creating UI. For instance "Full text links" or "request services". These names are also used as the default titles of a display section -- a display section that only displays fulltext
will by default use the name of the fulltext
ServiceTypeValue as it's title heading.
These names are controlled in the i18n translation file too, under umlaut.service_type_names
, and using standard Rails i18n pluralization functionality to specify a singular and plural name:
en:
umlaut:
service_type_names:
fulltext:
one: fulltext link
other: fulltext links
table_of_contents:
one: table of contents
other: tables of contents
The core of Umlaut funcationality is Service plugins that create ServiceResponses, individual elements of generated content that usually display on the screen.
If a Service simply generates a ServiceResponse with fixed strings, of course it can not be translated into other langauges/locales:
# not internationalized:
request.add_service_response(
:service => self,
:service_type_value => :fulltext,
:display_text => "A link to great things",
:notes => "Click here to get great things",
:url => "http://greatthings.example.org"
)
For basic cases, to make this i18n-able (translatable), the service can include keys display_text_i18n
and notes_i18n
, whose values are keys to be looked up in a translation file. The literal display_text
and notes
values can be left as defaults:
request.add_service_response(
:service => self,
:service_type_value => :fulltext,
:display_text => "A link to great things",
:display_text_i18n => "display_text",
:notes => "Click here to get great things",
:notes_i18n => "notes",
:url => "..."
)
The values of display_text_i18n
and notes_i18n
are keys that will be looked up in in a Rails i18n translation file, under a scope defined by the service name.
Let's say this service is defined by a class called GreatThings. :display_text_i18n => 'display_text'
means to look up the key display_text
in the scope umlaut.services.great_things
(underscore/lowercase version of class name).
en:
umlaut:
services:
great_things:
display_text: A link to great things
Actually, the translation lookup will try two keys, one scoped as umlaut.services.%{service_id}
, and if not found, then as umlaut.services.%{service_class_name_with_underscores}
as above. This lets apps over-ride keys for a specific configured service, when multiple services of the same class are configured.
The above works fine if you want to use a single static i18n lookup for display_text or notes, but what if you need to call an i18n translation with placeholders, or otherwise do something more complicated?
The Service architecture lets a service define a method transform_view_data(hash)
to transform the ServiceResponse hash on demand at display time, using custom logic.
Let's say we want to count the number of great things, and name the link eg "8 Great Things".
We might have an i18n translation key like:
en:
umlaut:
services:
great_things:
display_text: %{count} Great Things
Then in our GreatThings service plugin, we might create the ServiceResponse with no display text at all, but saving the 'count' in the ServiceResponse for later:
request.add_service_response(
:service => self,
:count => some_count,
:service_type_value => :fulltext,
:url => "..."
)
And then our Service would implement:
def transform_view_data(hash)
hash[:display_text] = self.translate("display_text", :count => hash[:count])
return hash
end
-
Use the
translate
method that Umlaut gives to all services, this will look up scoped by serviceID, then by service class name. -
Store placeholder parameters you might need in the ServiceResponse, you can use whatever arbitrary key names you want, they'll be waiting for you.
-
Use
transform_view_data
to add in the localized text on demand and on display. Do not do this:``` request.add_service_response( :display_text => I18n.t("something", :count => something), :display_text => translate("something", :count => something) ```
- Why? Because services run in threads, and it's difficult to ensure the right I18n.locale is set in the bg thread when the service is running. And even if it were, this would freeze the language in the ServiceResponse; we'd rather let the user switch back and forth between languages without regenerating service responses.
(TODO: Provide Umlaut migration that does this?)
Using localisation may cause problems if your collation is not set to UTF8 in your MySQL database. The problem arises when using the locale selector dropdown; Rails will force UTF8 when sending a form, which will cause a collations error if the Umlaut database has not been created with a UTF8 collation (latin1_swedish_ci is the default). In order to update your collation you can run the following SQL statements, replacing umlaut_db with the name of your umlaut db:
ALTER DATABASE umlaut_db CHARACTER SET utf8 COLLATE utf8_general_ci;
ALTER TABLE `umlaut_db`.`clickthroughs`CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;
ALTER TABLE `umlaut_db`.`dispatched_services` CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;
ALTER TABLE `umlaut_db`.`permalinks` CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;
ALTER TABLE `umlaut_db`.`referent_values` CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;
ALTER TABLE `umlaut_db`.`referents` CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;
ALTER TABLE `umlaut_db`.`requests` CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;
ALTER TABLE `umlaut_db`.`schema_migrations` CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;
ALTER TABLE `umlaut_db`.`service_responses` CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;
ALTER TABLE `umlaut_db`.`sfx_urls` CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;