Internationalization¶
MVC::Keayl::I18n is a translation and localization backend. It loads locale
files into one store, looks up translations by dotted key, interpolates and
pluralizes them, localizes dates, times, and numbers, and integrates with
controllers, views, and forms.
The backend¶
1 2 3 4 5 6 7 8 9 10 | |
load-locales reads every .yml, .yaml, and .json file in a directory.
Each file's top-level keys are locales, and their values are merged into one
store, so en.yml and en/forms.yml combine:
1 2 3 4 5 | |
load-file loads a single file and store-translations merges a hash directly:
1 | |
Translation¶
translate (aliased t) looks up a dotted key in the current locale:
1 2 | |
Named placeholders written %{name} are replaced by the matching argument. A
missing interpolation argument raises X::MVC::Keayl::I18n::MissingInterpolation.
Pluralization¶
When a count argument is given and the entry is a hash of plural categories,
the category is chosen by the locale's rule and %{count} is interpolated:
1 2 3 | |
The English rule is one/other. MVC::Keayl::I18n::Pluralization ships rules
for languages whose plurals differ, including French (0 and 1 are one),
Russian (one/few/many), and Polish. Register another with
register-plural-rule:
1 2 3 | |
Missing translations, defaults, and fallback¶
A missing key returns the placeholder translation missing: <locale>.<key>, or
raises X::MVC::Keayl::I18n::MissingTranslation when the backend is built with
raise-on-missing => True.
A default is consulted before reporting a key missing. A single default is a
literal string. A list is a chain: each entry is tried as a translation key, and
the last entry doubles as a literal fallback:
1 2 | |
When use-fallbacks is on, a region locale falls back to its base locale before
the default locale, so en-CA resolves through en.
Localization¶
localize (aliased l) formats a Date, DateTime, or number against the
locale's format data:
1 2 3 | |
Format strings live under date.formats, time.formats, and so on, and use
strftime directives. Month and day names come from date.month_names,
date.day_names, and their abbreviated variants, and %p reads time.am/time.pm.
Numbers are formatted from the number section of the store:
1 2 3 4 | |
Per-request locale¶
locale returns the active locale. set-locale changes the backend default,
and with-locale applies a locale for the duration of a block and resets it
afterwards:
1 | |
MVC::Keayl::I18n::Locale resolves a request's locale from several sources.
resolve-locale tries strategies in order and returns the first acceptable
match, falling back to a default:
1 2 3 4 5 6 7 | |
The param strategy reads ?locale=fr, header parses Accept-Language by
quality, subdomain reads the first host label, and domain reads the host
suffix. parse-accept-language and the per-source subs are available on their
own.
locale-url-options builds the options that carry a locale into generated URLs,
merged through MVC::Keayl::Routing::UrlHelpers' default-url-options:
1 | |
Controller and view integration¶
Configure I18n in config/application.json and the application wires a backend
into every controller:
1 2 3 4 5 6 7 8 | |
Each request resolves the locale from the configured strategies, sets it for the
duration of the action, and resets it afterwards. Controllers gain translate
(t), localize (l), current-locale, and default-url-options. A leading
dot is a lazy key resolved against the controller and action, so in
WidgetsController#show self.t('.title') looks up widgets.show.title:
1 2 3 | |
Views expose t, translate, l, and localize as helpers:
1 2 | |
Model and form translation¶
The backend provides the ActiveModel-style translation surface:
1 2 3 | |
translate-error walks the message chain from the most specific
activerecord.errors.models.<model>.attributes.<attr>.<type> to the generic
errors.messages.<type>.
FormBuilder consults the backend for labels, placeholders, and submit text
when one is present. The form helpers pass the controller's backend through:
1 2 3 4 | |
Labels read helpers.label.<model>.<attr>, placeholders (when placeholder is
True) read helpers.placeholder.<model>.<attr>, and submit text reads
helpers.submit.<model>.<create|update> with the model name interpolated as
%{model}. Each falls back to the humanized attribute or Save without a
translation.