Get this man hooked up to the wagon! It's great to see this level of thought going into Rails I18n, and equally wonderful to know that his efforts could positively impact the framework.
On Apr 21, 5:08 am, geekQ <[email protected]> wrote: > We have been working on a Rails application for a big company, that > will be > rolled out in many countries. We have carefully followed Rails > development over > the last 8 months and tried out different tool sets for > internationalization: > Rails 2.1 together with the gettext 1.93 gem, ActiveSupport.I18n as > part of > Rails 2.3 with and without fast_gettext. > > All our approaches still required extensive monkey patching resulting > in high, > unexpected efforts. The solutions work in 95% of all cases, which is > probably > sufficient for most Rails applications, but in our case it is not. > > We think it is possible to implement a reliable 100% correct > localization with > reasonable effort, but some important principles have to be considered > in the > Rails core though. > > # Internationalization principles > > ### Separation of roles > > Often software developers are not able to or are not allowed to create > translations of their applications' texts for several reasons: > > * There are only a few developers who perfectly speak several > languages. > * For commercial-grade applications the exact wording usually is > controlled by > the marketing department. > * In open source projects it should be possible for enthusiastic non- > technical > users to contribute improvements or complete translations. > Consequentially, > some open source projects have defined even [more roles][gnome- > roles]. > > Important note: non-developers need [tools][poedit] for editing > language files! > > ### Streamlining the development and translation process > > Identifying messages by a symbol in a YAML file (like in Rails 2.3) is > problematic, because it breaks the developer's flow: you have to stop > coding, > come up with a good identifier (symbol) name for your message, go to a > YAML > file, and type in the message. > > Later on the translator does not know a message's context and needs to > open > two YAML files side by side - one contains the context and the other > one gets > filled with the translations. In contrast to that, the [gettext > approach][gettext-approach] works smoothly - for C and for Python; for > open > source and for commercial projects. > > _('Archive is invalid') > _('%{attribute} must not be empty') % attr > > are both easier to write and easier to translate. > > With command line tools such as [msgfmt -cv][msgfmt] you can also > check the > well-formnedess and completeness of your transaltions as part of the > *continuous build process*. > > A reliable, high-quality, feature rich parsing tool for Ruby and for > Rails > still needs to be implemented, but [ruby-gettext][] is a good starting > point. > > ### Linguistically correct translations > > ActiveRecord validations support the concept of error messages and > full error > messages. From a linguistical point of view this does not work: there > is no > way to infer a correct full message from its short message counterpart > and > vice versa. The string concatenation approach used by Rails (almost) > works for > English but rarely for other languages. > > If you can not infer one message from another, the distinction does > not make > sense. You only need one kind of message, preferably with a > placeholder for > the attribute name. (see the example above.) > > The current implementation is both overengineered and not sufficient: > > # lib/active_record/validations.rb:196 > full_messages << attr_name + I18n.t > ('activerecord.errors.format.separator', > :default => ' ') + message > > The main problem with this solution is: if a language needs a > different > separator for different parts of the sentence, then it will probably > also > differ in more vital aspects. For example, it might insist on a > different > order of words in a sentence. > > A message can only be translated as a whole. Hence, it should be > possible to > provide custom ActiveRecord validation messages at any time. For us it > was > only possible with [a dirty hack][custom-validation-messages]. > > Usage of string concatenation for building error messages in the > framework > makes it [extremely complicated][remove-prefix] to avoid the > corruption of > error messages with a prefix derived from attribute/relation names. > > *String concatenation should never be used to create human-readable > messages. > Use string interpolation instead (as it has been used in other > frameworks and > platforms for decades).* > > In addition, ActiveRecord should allow for proc-based validation > messages: > > validates_format_of account, :message => proc {...} > > Of course, a robust pluralization implementation, as provided by > gettext, is > important, too. > > ### Locale selection > > All the different localization libraries try to select an appropriate > locale > corresponding to their own rules and in a transparent way. The > corresponding > logic is often buried deep in the library's implementation and cannot > be fixed > using monkey patching. > > Even if our application only offers English and Italian, for example, > the > gettext library with its ActiveRecord extensions sometimes shows > validation > messages in Greek (depending on the user's browser settings). Of > course, > libraries and Rails should be able to provide translations in a plenty > of > languages, but the application should have the last word in the > decision, > which subset of possible languages is offered to the user. > > A callback in the application controller which can be overridden by an > application developer would be an advantage. A before_filter would > also do, > but it has to be executed before all other before_filters. > > # initializer/internationalization.rb > offer_locales :en_UK, :en_ZA, :nl > default_text_domain 'myapp' > > # application_controller.rb > class ApplicationController > def compute_effective_locale > # application specific implementation, that uses > # > # params[:lang] > # cookies[:lang] > # request.headers['Accept-language'] > # default_locale > # > # to compute the effective locale > end > end > > A default implementation with priority order [query parameter, cookie, > browser > setting] can be provided, but almost any non-trivial application needs > its own > rules. > > ### Syntax > > If the handling of text messages needs to be refactored anyway, it > would be > advantageous to switch to the less invasive, proven, and familiar > gettext > syntax: > > _("The billing system is not available. Please, try again later.") > > instead of > > I18n.t(:billing_not_available) > > Providing context for translation: > > "Gadget|Title" => (German) "Bezeichnung" > > The word "Title" is translated differently depending on its context. > Hierarchical contexts are not needed, that is YAML files with deeper > nesting > as in Rails 2.3 do not make sense. > > ### Implementation backends > > The current interface for plugging in different localization storage > backends > is a nice intention, but in this case flexibility is not needed. A > perfectly > designed and working backend would be sufficient. Other - less > successful - > frameworks and platforms such as django, pylons, and Microsoft.NET > have much > more powerful internationalization/localization features and they all > support > only one backend. Localization in Python frameworks is based on > gettext, .NET > uses resource files. Both technologies are mature and they are > supported by a > large set of tools for maintaining translations. The obvious choice > for Rails > would be gettext, then. > > # Conclusion > > *It is not possible to implement a sustainable internationalization > solution as > a gem, as a plugin, or as a collection of monkey patches. Important > principles > must be considered in the Rails core, especially in ActiveRecord/ > ActiveModel, > to make applications fully internationalizable. This would be an > important > step to make Rails enterprise-ready.* > > We offer an industrial-strength internationalization implementation > for Rails3 > and all the needed refactoring of validation code. But we wanted to > check > upfront, if the community is interested in such an implementation and > if > there's a chance that these changes would be integrated into the Rails > trunk. > > Vladimir Dobriakov ([email protected])http://blog.geekq.net > > Maik Schmidt ([email protected])http://maik-schmidt.de > > [gnome-roles]:http://live.gnome.org/TranslationProject/LocalisationGuide#head-99ad8... > [poedit]:http://www.poedit.net/ > [gettext-approach]:http://www.gnu.org/software/gettext/manual/gettext.html#Mark-Keywords > [msgfmt]:http://www.gnu.org/software/gettext/manual/gettext.html#msgfmt-Invoca... > [remove-prefix]:http://blog.geekq.net/2009/04/09/i18n-remove-validation-message-prefix/ > [custom-validation-messages]:http://blog.geekq.net/2009/04/08/activerecord-i18n-validation-message/ > [ruby-gettext]:http://rubyforge.org/projects/gettext/ --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Core" group. To post to this group, send email to [email protected] To unsubscribe from this group, send email to [email protected] For more options, visit this group at http://groups.google.com/group/rubyonrails-core?hl=en -~----------~----~----~----~------~----~------~--~---
