The Ruby on Rails I18n core api

posted: July 19th, 2008 · by: Sven

in: Globalization, Programming · tagged as: , , ·  151 comments »

Future versions of Rails will ship with a minimalistic, yet powerful I18n/L10n api baked in.

The following post is about technical api and implementation details. You can read more about the motivation and reasoning behind this work here.

The pivotal point of the new I18n api in Rails is the I18n module which is provided as a gem and shipped with Rails in ActiveSupport’s vendor directory. This module comes with the following features:

  • The main translation method #translate which is used to lookup translations.
  • The #localize method which is used to localize Date, DateTime and Time objects.
  • It stores the current locale in Thread.current.
  • It stores a default locale which is used when no locale has been passed or set.
  • It stores a backend which carries the actual implementation for the translate and localize methods.
  • It comes with a default exception handler which catches exceptions that are raised in the backend.

Both the backend and the exception handler can be swapped with different implementations. Also, #translate is aliased to #t and #localize is aliased to #l for convenience.

#translate supports the following common I18n features which are implemented in the provided Simple backend and should be implemented in all future backends:

  • Lookup of translations by a locale and nested (scoped, namespaced) keys.
  • Defaults that will be used if the lookup does not yield a translation.
  • Interpolation of values to a translation string.
  • Pluralization of translations depending on a :count option.

Lookup, scope and nested keys

Translations are looked up by keys which can be both Symbols or Strings, so these calls are equivalent:


I18n.t :message
I18n.t 'message'

#translate also takes a :scope option which can contain one or many additional keys that will be used to specify a “namespace” or scope for a translation key:


I18n.t :invalid, :scope => [:active_record, :error_messages]

This looks up the :invalid message in the ActiveRecord error messages.

Additionally, both the key and scopes can be specified as dot separated keys as in:


I18n.translate :"active_record.error_messages.invalid"

Thus the following calls are equivalent:


I18n.t 'active_record.error_messages.invalid'
I18n.t 'error_messages.invalid', :scope => :active_record
I18n.t :invalid, :scope => 'active_record.error_messages'
I18n.t :invalid, :scope => [:active_record :error_messages]

Defaults

When a default option is given its value will be returned if the translation is missing:


I18n.t :missing, :default => 'Not here'
# => 'Not here'

If the default value is a Symbol it will be used as a key and translated. One can provide multiple values as default. The first one that results in a value will be returned.

E.g. the following first tries to translate the key :missing and then the key :also_missing. As both do not yield a result the string ‘Not here’ will be returned:


I18n.t :missing, :default => [:also_missing, 'Not here']
# => 'Not here'

Interpolation

All options besides :default and :scope that are passed to #translate will be interpolated to the translation:


I18n.backend.store_translations 'en-US', :thanks => 'Thanks {{name}}!'
I18n.translate :thanks, :name => 'Jeremy'
# => 'Thanks Jeremy!'

If a translation uses :default or :scope as a interpolation variable an I18n::ReservedInterpolationKey exception is raised. If a translation expects an interpolation variable but it has not been passed to #translate an I18n::MissingInterpolationArgument exception is raised.

Pluralization

The :count interpolation variable has a special role in that it both is interpolated to the translation and used to pick a pluralization from the translations according to the pluralization rules defined by CLDR:


I18n.backend.store_translations 'en-US', :inbox => {
  :one => '1 message', 
  :other => '{{count}} messages'
}
I18n.translate :inbox, :count => 2
# => '2 messages'

The algorithm for pluralizations in en-US is as simple as:


entry[count == 1 ? 0 : 1]  

I.e. the translation denoted as :one is regarded as singular, the other is used as plural (including the count being zero).

If the lookup for the key does not return an Hash suitable for pluralization an I18n::InvalidPluralizationData exception is raised.

Bulk and namespace lookup

To lookup multiple translations at once an array of keys can be passed:


I18n.t [:odd, :even], :scope => 'active_record.error_messages'
# => ["must be odd", "must be even"]

Also, a key can translate to a (potentially nested) hash as grouped translations. E.g. one can receive all ActiveRecord error messages as a Hash with:


I18n.t 'active_record.error_messages'
# => { :inclusion => "is not included in the list", :exclusion => ... }

Setting and passing a locale

The locale can be either set pseudo-globally to I18n.locale (which uses Thread.current like, e.g., Time.zone) or can be passed as an option to #translate and #localize.

If no locale is passed I18n.locale is used:


I18n.locale = 'de-DE'
I18n.t :foo 
I18n.l Time.now

Explicitely passing a locale:


I18n.t :foo, :locale => 'de-DE'
I18n.l Time.now, :locale => 'de-DE'

I18n.locale defaults to I18n.default_locale which defaults to 'en-US'. The default locale can be set:


I18n.default_locale = 'de-DE'

Using a different backend

A different backend can be set on the I18n module:


I18n.backend = I18n::Backend::Gettext

The I18n gem (and thus Rails) only ships with the Simple backend which is tailored to Rails’ needs. Other backends can be provided as external solutions.

Exceptions and exception handlers

The #translate method catches exceptions that are thrown in the backend and passes them to the exception handler that is defined as I18n.exception_handler and defaults to I18n#default_exception_handler.

In #default_exception_handler all exceptions are re-raised except for MissingTranslationData exceptions. When a MissingTranslationData exception has been caught the #default_exception_handler will return the exception’s error message.

This behaviour is particulary useful during, e.g., view developement when the developer does not want to switch contexts (add a translated string to the view, define the key and translation somewhere else, go back to the view, …) because otherwise the application would break because of a missing translation.

On the other hand in different contexts a different exception handling might be useful. E.g. the default exception handling does not allow to catch missing translations during automated tests easily. For this purpose a different exception handler can be specified. The specified exception handler must be a method on the I18n module:


module I18n
  def just_raise_that_exception(*args)
    raise args.first
  end
end

I18n.exception_handler = :just_raise_that_exception

This would re-raise all caught exceptions including MissingTranslationData.

Another example where the default behaviour is less desirable is the Rails TranslationHelper which provides a method #translate. When a MissingTranslationData exception occurs in this context the helper wraps the message into a span with the css class translation_missing.

To do so the helper forces I18n#translate to raise exceptions no matter what exception handler is defined by setting the :raise option:


I18n.t :foo, :raise => true # always re-raises exceptions from the backend

Populating the translations storage

Libraries can use I18n.load_translations to populate the translations storage:


# in active_support.rb
I18n.load_translations 'active_support/locale/en-US.yml'

# in active_support/locale/en-US.yml
en-US:
  date:
    formats:
      default: "%Y-%m-%d"
      # ...

The Simple backend can load YAML files as well as plain Ruby files. If you want to store translations in Ruby make sure the file evaluates to a plain Ruby Hash like so:


# translations in Ruby
{ :'en-US' => {
  :date => { 
    :formats => {
      :default => "%Y-%m-%d"
      # ...
    }
  }
}}

Other backends might add capabilities to load from different sources like, e.g., SQL for a database backend or PO/MO files for a gettext backend.

Get involved!

If you’d like to join us working on Ruby on Rails’s future I18n support, provide feedback or ask questions please do so! You can find our Google Group over at http://groups.google.com/group/rails-i18n.

Leave a comment

151 Comments

  1. ste said July 19th, 2008 at 03:57 PM  

    “the first translation is regarded as singular, the second is used as plural (including the count being zero).”

    How do you solve the problem of displaying a different phrase in the case of count being zero? E.g. let’s say I wanted to display the strings “No messages”, “One message” and “3 messages”; is this possible?

  2. Clément Joubert said July 20th, 2008 at 02:39 PM  

    Minimalistic, maybe, but still one of the most (I’d say the most) thought-through implementation of L18n / I10n for use in Rails. Most issues encountered with plugins become a vague souvenir with this !

  3. Stephan Soller said July 20th, 2008 at 03:30 PM  

    Thanks for all the great work and the good overview Sven! It’s really good to see all this stuff getting into Rails.

    Ste, regarding the pluralization: You can change the pluralization algorithm in the locale. E.g. that it maps a count of zero to the first array element of a locale entry, a count of 1 to the second element and all other counts to the third element.

    Algorithm for pluralizations in @en-US@:

    entry[count == 0 || count == 1 ? count : 2]

    Translations:

    I18n.store_translations ‘en-US’, :inbox => [‘no messages’, ‘1 message’, ‘{{count}} messages’] I18n.translate :inbox, :count => 0 # => ‘no messages’ I18n.translate :inbox, :count => 5 # => ‘5 messages’

  4. Sven said July 20th, 2008 at 06:06 PM  

    Hey ste, Stephan,

    actually, Stephan, one can not. We took this out for various reasons, most importantly sticking to what’s necessary for Rails being localized to en-US. The en-US pluralization algorithm is currently hardcoded in #pluralize:

    http://github.com/rails/rails/tree/master/activesupport/lib/active_support/vendor/i18n-0.0.1/lib/i18n/backend/simple.rb

    Obviously it won’t be too hard to implement custom logic in a different backend though: just create your own backend module, provide a method #pluralize and include the Simple backend module. Then use it with I18n.backend = FexiblyPluralizingBackend … or whatever.

  5. Fjan said July 20th, 2008 at 06:53 PM  

    The code probably looks nicer if you add something like:

    class Symbol def t(x);I18n::t(x);end end

    Then in your code you can simply do a more Rails-like: :message.t

  6. Seymour said July 20th, 2008 at 07:28 PM  

    I looked at some localization plugins a while ago, but didn’t like any of them. Instead I started doing my own, which was not as advanced as your, but had some neat ideas imho. I never finished it but maybe you find this useful (maybe you already had these ideas but dumped them):

    My main prio was to make it simple to use and easy to retrofit. So I too introduced the method #t (like h is used).

    <%= t "Information" %>

    <%= link_to t “Show all”, :action => “show” %>

    But I just put it in front of my existing strings. If the the chosen language to translate into was, say Swedish Chef, and if there was no Swedish Chef translation, it would fall back to the default that’s already there (“Show all”).

    If there was a Swedish Chef “Hum Dum Bork” in the structure connected to “Show all”, it would display that instead.

    If “Show all” later was changed in the code into “Show everything”, when looked up it would be added to the translation structure as a new entry since it didn’t exist.

    The old “Show all” would not be used anymore, something that would become obvious because the access counter for “Show all” would stop ticking. Reset the counters, exercise the code with the test suites, observe any new strings or not used strings via a web-gui for handling translations. Correct it.

    Of course, hunting for strings in the code to change could be avoided by adding an English translation stating that “Show all” (in the code) would be translated into “Show everything” (from the structure).

    So what I am missing (afai understand) from I18n is the following:

    • I18n.t :missing …without a translation and without a default, should return “Missing”. And can I include I18n to just use t directly?

    • An exercise mode to add all looked up translation strings (good for retrofit, or if you slip and don’t update like you should).

  7. Sven said July 20th, 2008 at 07:31 PM  

    Hey Fjan,

    we’ve been there before but for various reasons we finally agreed to abstain from anything like that - at least for the I18n gem that would go into Rails core.

    This sort of stuff can still be easily added in plugins though if people think it makes sense.

    Personally, by now I don’t think it does, because you wouldn’t call #t on the current context this way - like a view or controller in Rails. In the end it’s really a preference though and for that reason we sticked to the simplest thing possible for the I18n gem and left both Symbol#t and String#t undefined.

  8. Sven said July 20th, 2008 at 07:39 PM  

    Hey Seymour,

    you can do most of what you’re mentioning with the I18n gem with a slightly different flavor of syntax.

    If I get what you’re saying you are using default strings as keys. This is something which we regard as a bad practice for anything but very simple projects. Plugins building on the I18n api can still implement something like that easily though if they want.

    Also, notice that there’s a #t helper provided with Rails. So you can call <%= t :key %> in your views.

    If you want #t to return something different in case the key is missing and you don’t want to pass a default string you can always hook in a different exception handler (e.g. one that turns the key into a slightly better readable string).

    Stuff like excercise modes, gui translation edit modes etc. would be way to special and heavyweight to include them to Rails directly. Also … if we did it … what would poor plugin devs like us have to do then anymore ;) No, really, this is the sort of stuff we hope to (continue to) happen in plugin-land.

  9. dirk lüsebrink said July 20th, 2008 at 08:05 PM  

    i’m coming from a time where ASCII was all you ever wanted but i know i can’t hold up the progress and so am making friends with I18M and the like.

    Getting a standard I18N API inside rails is way better than any extension/plugin/gem bolted-on later.

    But in one way this goes way to far for my taste. Forcing every exception taking a codepath through the Translation code stack per default looks totally wrong and bloated to me. I would prefer keeping the default behaviour as it is and offer an options for the ones who really think they must support tranlated exception traces.

    Exceptions are communication with the developer, not with the users. And we also don’t write localized methods names and variables.

  10. Sven said July 20th, 2008 at 08:54 PM  

    Hey Dirk,

    not sure how you mean throwing an exception on an unexpected state is bloated, but using exceptions to communicate things like these from a backend to a frontend is a pretty common (and useful) pattern.

    And yes, it’s for communication between developers. That’s what was implemented here, isn’t it?

  11. Anders Engström said July 20th, 2008 at 10:46 PM  

    This looks really nice. While minimalistic, the API covers pretty much anything you need.

    I’ve written an i18n module that behaves similar to this API (but without the scoped keys). One thing that might be useful (but could be implemented in a custom backend) is to be able to execute a Proc when resolving a key.

    This allows me to do stuff like (in an ERB template):

    <%= _(:time, model.created_at) %>
    

    (where “_” is similar to #translate).

    The :time key is declared as:

    Localization.in_context("en") do |l|
        l.instance_eval do 
           define :time, proc{|time|
               if time.today?
                   "Today"
               elsif ....
           }        
    
            # ....
    
        end
    end
    
  12. Peter De Berdt said July 20th, 2008 at 11:45 PM  

    One aspect of l18n that still seems to be unaddressed is number localization. It’s a problem we European face in about every application that deals with numbers with decimal fractions. I’ve invested quite some time trying to find a clean and uninvasive (read: heavy monkeypatching with ugly things going on) to make Rails transparently handle “1.250,52” instead of “1,250.52” notations but haven’t find any option that would fit the bill.

    Although it is true that most bigger localization plugins nowadays just override the default number formatting helpers (numberto_currency and the likes), but when you want comma delimited decimal fraction to automatically be used in f.textfield :field_name, things start to go terribly wrong.

    Maybe I have missed something so blantly obvious, I like to hope so actually, but my fear is that I haven’t. What I came up with aliassing all number related getters and setters, then redefining them to replace dots with comma’s and feed that to the forms, but even there it still didn’t cover all bases.

    Maybe a thinktank like the l18n group can see the light. It just surprised me that no one but us has ever had to deal with this before.

  13. Fjan said July 21st, 2008 at 10:03 AM  

    :message.t

    you wouldn’t call #t on the current context this way - like a view or controller in Rails.

    Actually I do it that way in my own I18n thing (yes, I too didn’t like what was out there and built my own). I simply start each view with a method that sets a global:

     <% set_context(:login_view) %>
    

    And then simply call the t method on any literal in the view:

     <%= :Password.t %>
    

    The t method simply looks this up in a hash of hashes like your module does. The good thing about this is that the views remain very readable.

  14. Fjan said July 21st, 2008 at 10:12 AM  

    @Peter: transparently handle “1.250,52” instead of “1,250.52”

    Yes, I ran into that too. It gets even more complicated if you know that the French apparently like their numbers without thousand separators at all, so you have three versions. I ended up rolling my own there too. The Rails source code uses a clever regexp that takes care of all the work and is easily modified.

  15. KC Jones said July 21st, 2008 at 11:42 PM  

    After reading this and Sven’s blog post, I think I get it. And I appreciate that this fills a huge, gaping hole in a very lighthanded way - especially once a variety of backends have been developed. Can’t wait.

    One question: will this work have any impact on the ability of plugin developers to support per-locale templates? Or was that considered poor practice?

    I haven’t needed it in my nascent, simple localizations. And it seems to create serious maintenance / lifecycle issues, but it also seems pretty useful for some gnarly localizations.

  16. Sven said July 22nd, 2008 at 01:13 AM  

    Hey Fjan, Peter,

    you guys certainly have a point with the transparent number formatting in forms. Mind to register to the Rails I18n group and discuss things over there? http://groups.google.com/group/rails-i18n

    Hey KC Jones,

    thanks for the feedback :) At this point I don’t think the Rails I18n api has any impact on per-locale templates. If you use them in any way, you can continue to do so. Our patch does not touch this matter in any way.

    That said we’re certainly going to reinvestigate this topic in plugin land (can only speak for upcoming Globalize 2 here). At the end of the day it’s definitely something that belongs into the I18n/L10n toolbox.

    Generally speaking with this patch we did not aim to solve each and every problem in Rails core. We aimed to get started with the most important (and most often re-implemented) things and we’re definitely going to have a second iteration of the whole process (i.e.: check out existing implementations, extract + cherrypick common solutions, discuss + review them, finally bring them to core if that really, really makes sense).

  17. Aleksandr said July 23rd, 2008 at 09:00 AM  

    Will the new l18n api have a solution to extract the keys from the application like GetText does (rake updatepo)? Because copy-pasting them manually into the translation file can be a bitch if you’re dealing with a lot of languages.

  18. Mark said July 24th, 2008 at 11:08 AM  

    Is possible to use strings instead of symbols? It doesn’t seems very smart to repeat twice the translations :( :anenglishmessage => “An english message”

    English strings should be default and you want to translate them you could you a gettext-style, example _(‘Translate me’)

  19. Sven said July 24th, 2008 at 08:44 PM  

    Hey Aleksandr,

    no, the api is an api :) What you’re looking for is a tool that scrapes an application for keys (or rather base language translations). Although a useful tool, this certainly belongs into a plugin.

    Hey Mark,

    we’ve gone back and forth and back and forth endlessly discussing default strings and whether to support them in a way as solutions as Gettext, Globalize, Gibberish, … do. We finally decided against it because we really wanted to only rely on “the most simple thing that ever could work” for the Rails core api. And this definitely does not include default strings as keys (which is what you mean by “gettext-style”).

    We think it’s actually a bad practice for anything else than a very small project - backed by lots of experiences with said solutions. Thus, don’t recommend that any more. (Most important reason being default-translations-as-keys getting out of sync with the translation data … resulting in major headaches at times.)

    BUT that does not mean that future Rails plugins can’t implement this approach. They can. Both String#t and Symbol#t are left undefined by the API and plugin developers can implement whatever they think is useful here.

  20. Ben said July 25th, 2008 at 03:13 PM  

    Hey Sven,

    gute arbeit! Ich hoffe wir sehen uns bei BoR! :-)

    Gruss Ben

  21. Sven said July 26th, 2008 at 02:03 PM  

    Hey Ben,

    na klar!

    :)

  22. Glenn said July 29th, 2008 at 03:39 PM  

    I would think that in the simple backend impl, if the entry for a key is an Array (pluralizable), then :count value should default to 1 if not specified. Currently, it will simply return a concatenation of the two values (singular + plural).

    This can be easily fixed by changing the pluralize(entry, count) method in the simple.rb, by removing the “and count” check to the first line and adding a default value to the second line:

    def pluralize(entry, count) return entry unless entry.is_a?(Array) count ||= 1 raise InvalidPluralizationData.new(entry, count) unless entry.size == 2 entry[count == 1 ? 0 : 1] end

    Does anyone see any reason why this shouldn’t be the standard functionality?

  23. Sven said July 31st, 2008 at 01:16 PM  

    Hey Glenn,

    I agree it’s weird that it concatenates the Strings (it really does?). That’s not useful in any case.

    On the other hand I wonder why we would pick a default count here. My first guess would be that it would be more in line with the “spirit” of the rest of the API to return the actual pluralization data array here (like you could also lookup whole chunks of the hash, e.g.)

    It would be up to the user then to know this and do something useful with it. Actually this would even allow to implement pluralization in user land. So, why not?

  24. Glenn said July 31st, 2008 at 02:03 PM  

    Hi Sven,

    Very good points. I have implemented my own custom backend as you described doing, and I added my own pluralization logic. It does work, however, now the Rails Core localizations are all missing from my app. I think the problem is that I’m not setting my I18n backend at the correct time. Probably, the Core is adding all of it’s localizations at some point during the very start of the app’s init. Then after that, I call: I18n.backend = I18n::Backend::Custom which resets the backend and erases all the Core’s localizations.

    I was first setting the I18n.backend in my ApplicationHelper (which is where I also call I18n.backend.populate with my local file.

    Then I tried setting the backend in an config/initializer called I18n.rb This also doesn’t work.

    So, my question is, where do you set this backend, so that the Core strings remain in tact?

  25. Glenn said July 31st, 2008 at 03:06 PM  

    Ok, So I put the call at the end of my custom.rb file where I actually define my Custom backend, and now everything seems to be working ok.

    Sometimes, you just have to stop and sit outside for a bit, and the answer will come to you.

  26. Sven said August 1st, 2008 at 10:10 AM  

    Hey Glenn,

    please register to the Rails I18n Google Group at http://groups.google.com/group/rails-i18n and let people know about your work over there. There’s already another plugin (YAML-based, by Iain) in the oven and people are helping each other trying out their code and fixing issues.

    I guess that’s the way better plattform for discussing such things :)

  27. Andrew Roth said October 23rd, 2008 at 05:07 PM  

    Hey, where can I find the rubydocs?

  28. Peter said October 29th, 2008 at 10:06 AM  

    There is a huge disadvantage, too, associated with choosing short(ish) symbols or strings as translation keys, as opposed to the Globalize “Translate me!”.t approach, and that is that the code becomes very difficult to read, and thus to maintain. In practice, the keys tend to look like I18n.t :accloginrefuse_pt2, which conveys very little to the programmer. This is not something to be ignored, as it reduces the maintainability of the code, incurring higher costs.

    One important point is that Globalize offered translation of base language strings into the base language itself, which covers the case very neatly of when management wants to change strings — something which really is not that common anyway: you are exaggerating that aspect quite considerably. For instance, “Please enter your password”.t can be “translated” to “Please enter your secret password” or whatever management would require. And let’s face it, management is not very likely to tamper with strings like “Cancel”, “Save” and suchlike. And I speak from many years of experience. Dismissing long translation key strings is not necessarily something which will ease development.

    Take a look at an internationalized application, for instance the sample demo app on github. It’s a very small application, and a tutorial one at that — but there is very little relationship between what can be read in the views and what will be seen on screen.

    Another important aspect has to do with legacy applications. I’m currently working with several large applications, in a collaborative environment, based on Globalize. If Globalize 2 doesn’t support the old syntax at least in some measure, well, then it will be almost impossible to upgrade to Rails 2.2 or beyond.

    It doesn’t have to be much more complicated than this:

    ################################################################
    # Define a new backend, inheriting from the default Simple one #
    ################################################################
    
    module I18n
      module Backend
        class GlobalizeErsatz < Simple
          # Add code to load SQL after the usual .yml and .rb files
          # have been loaded. Also code to disable splitting on full stops
          # in keys where necessary.
        end
      end
    end
    
    I18n.backend = I18n::Backend::GlobalizeErsatz.new
    
    
    ################################################################
    # It takes the same .rb and .yml files as Simple, for the very #
    # basic translations.                                          #
    ################################################################
    
    LOCALES_DIRECTORY = File.join(RAILS_ROOT, 'config', 'locales')
    LOCALE_FILES = Dir[ File.join(LOCALES_DIRECTORY, '*.{rb,yml}') ]
    
    LOCALES = LOCALE_FILES.collect do |locale_file|
      File.basename(File.basename(locale_file, ".rb"), ".yml")
    end.uniq.sort
    
    
    I18n.load_path += LOCALE_FILES
    
    
    ################################################################
    # Re-implement the classical Globalize string extensions       #
    ################################################################
    
    class String
    
      def translate
        I18n.t self, :default => self
      end
    
      def t
        translate
      end
    
      def tn(namespace)
        I18n.t self, :scope => namespace, :default => self
      end
    
      def /(val)
        if sub!('%d', '{{count}}')
          I18n.t self, :count => val, :default => self
        elsif sub!('%s', '{{s}}')
          I18n.t self, :s => val, :default => self
        else
          translate
        end
      end
    
    end
    
  29. Sven said October 29th, 2008 at 11:06 AM  

    Hi Peter,

    that “classical” Globalize way of using default strings as keys certainly works for some projects.

    We’ve seen people more and more moving away from it though and using fixed keys instead (that also are easy to recognize as keys) - be it that they’ve set the Globalize base language to some fantasy locale like “dev” or simply move to a different solution.

    For the I18n gem we’ve aimed to provide a foundation for building plugins on top of it. That’s what you can do. It is true that with Globalize we believe we’ve learned something from the past when we’ve settled with separating keys and defaults. That doesn’t mean that your implementation needs to do the same.

    Also, of course the fullstops/dots as key separators are a limitation. We’ve been thinking about making this optional (you could still use arrays of keys), but we want to see how widespread that need really is.

    So if you really want this, why not just implement what you’ve layed out above as a plugin and publish it?

    Having settled with a common API in Rails does not mean that we can not experiment with different solutions any more :)

  30. Sven said October 29th, 2008 at 11:11 AM  

    Oh, one more thing ;)

    Of course instead of <%= “Please enter your password”.t %> you can still use <%= t “Please enter your password” %> and use that as a key. So you can have readable keys if you perfer to.

  31. Seb said December 4th, 2008 at 09:35 PM  

    Hi,

    Thanks for your work !

    There is a little mistake. You wrote well first time: I18n.t :invalid, :scope => [:activerecord, :errormessages] But second time, you miss the ‘,’ I18n.t :invalid, :scope => [:activerecord :errormessages]

    Seb

  32. Miika said December 16th, 2008 at 10:06 PM  

    Hi

    I made an exception handler that tries to find default translation. I’d like to see this kind of feature in the default implementation… module I18n def self.findtranslationfrom_default(*args) if MissingTranslationData === args.first && args[1] != I18n.default_locale return self.translate(args[2], :locale => I18n.default_locale) end defaultexceptionhandler(*args) end

    end

  33. Sam said January 20th, 2009 at 06:07 PM  

    New bug: If you have in file “config/fr.yml” activerecord: models: attributes: article: title: “Le champ Titre” price: “Le champ Prix errors: messages: exclusion: “est déjà pris !” notanumber: “n’est pas un nombre”

    And in view: for exclusion message, you have “Le champ Titre est déja pris !”. So, you aren’t message “Le champ Prix n’est pas un nombre” but “Price n’est pas un nombre”. A bug, missing “t” function before actionview ?

  34. Norstone Wooden said December 24th, 2009 at 09:30 AM  

    Hi,

    Thanks for your work !

  35. Rolf said May 20th, 2010 at 05:51 PM  

    Ruby, right ? Why not? Very nice explanations, Sven ! Keep up the good work.

  36. Robert said June 12th, 2010 at 08:29 AM  

    Very nice article indeed ! I heard abut Ruby but never tried. Seems quite pro …

  37. Paul said July 29th, 2010 at 11:19 AM  

    Ruby is still a modern language. This says much about its quality ! Long live ruby !

  38. joel said September 13th, 2010 at 11:12 AM  

    very nice post. I’ll give a try on ruby

  39. Andre said November 2nd, 2010 at 06:51 PM  

    Thanks for the tutorial, I’m gonna use it on my Seotons website.

  40. rishi said November 12th, 2010 at 07:41 AM  

    business analyst business analyst interview questions web desgn company It is the most comfortable site and made in great manner so that reader could get maximum information and learn many things. This is one of the best blogs This is highly informatics, crisp and clear. I think that Everything has been described in systematic I have read.

  41. Resveratrol said November 20th, 2010 at 02:11 AM  

    Ruby on Rails is a great, great framework – coming from the mouth of a long time PHP Developer.

  42. as said November 29th, 2010 at 09:56 AM  

    wdsadsadsad

  43. shurdul said December 3rd, 2010 at 03:22 PM  

    very nice and informative post i really appreciate it gift for girlfriends

    cna certification

  44. shurdul said December 3rd, 2010 at 03:26 PM  

    its a very out class work gift for girlfriends

    cna certification

  45. morewanted said December 3rd, 2010 at 08:28 PM  

    We are using an object persistence library for Java similar to Basically, we took the main ideas from / System Prevalence, but made some changes miami laser hair

  46. Interview Questions and Answers said December 13th, 2010 at 07:27 PM  

    My mother is a good docter. She do a lot of surgery in her life. Im very proud of her. She dedicated all her life to help people. My father told me bout this. They have a good comminucation bout their proffesion.

  47. Testing Interview Questions and Answers said December 13th, 2010 at 07:33 PM  

    Excellent site, keep up the good work my colleagues would love this. I read a lot of blogs on a daily basis and for the most part, people lack substance but, I just wanted to make a quick comment to say I’m glad I found your blog.

  48. Jane Howard said December 27th, 2010 at 03:31 PM  

    great post - I will keep this in mind when I get to work on my next ruby project.

    Anne Smith Mother of the Groom Dresses (Writer)

  49. vision without glasses said January 8th, 2011 at 09:32 PM  

    Still struggling to get my head around ruby on rails. Need to focus down.

  50. Sundresses for Women said January 11th, 2011 at 07:25 AM  

    The new api is great. Thanks for the tutorial Sundresses for Women

  51. anokhi said January 18th, 2011 at 09:59 PM  

    Well, the article is in reality the top-quality on this exemplary theme. I accord with your decisions and will thirstily look forward to your following updates. Only telling thanks will not just be adequate, for the great limpidity in your writing. I will now grab your rss feed to continue informed of any updates. Delicious work and much success in your business relations. Saab Turbo

  52. villafan said January 19th, 2011 at 07:53 PM  

    Thanks for the info here. It is very well put together.

  53. mike geary said January 20th, 2011 at 01:46 PM  

    What a great site.I wish i came across this site earlier . It could have saved a lot of time and effort. Thanks

  54. Davie Jacob said January 21st, 2011 at 04:16 PM  

    The pivotal point of the new I18n api in Rails is the I18n module which is provided as a gem and shipped . las vegas website design

  55. elena peterson said January 21st, 2011 at 05:49 PM  

    Thanks Sven Fuchs for such an interesting article. I have learnt a lot thanks to you

  56. Eczema said January 23rd, 2011 at 09:57 PM  

    Simply, admirable what you have done here. It is pleasing to look you express from the heart and your clarity on this significant content can be easily looked. Remarkable post and will look forward to your future update.

    Torah B. Skin Analyst for Dyshidrotic Eczema

  57. rroselovely2 said January 24th, 2011 at 07:05 AM  

    Thanks this post really opened my eyes. it is not only eye opening rather very beneficial for the people those who want to do something good in his life. testking 70-649

  58. joe barry said January 26th, 2011 at 11:38 AM  

    Great posting. This has baffled me for ages . joe barry

  59. johnny said January 26th, 2011 at 09:03 PM  

    aw spot on dude, just what i was looking for, cheers.



    euro millions results

  60. cheap contacts online said January 26th, 2011 at 10:38 PM  

    It seems so clear to me now cheap contacts online

  61. freshlook color contacts said January 26th, 2011 at 10:42 PM  

    Great blog, everything so clear and sharp freshlook color contacts

  62. cutea5girl said January 27th, 2011 at 01:45 PM  

    Can’t believe that ruby still hasn;t fixed this issue in their new update.

    Anne Smith @ Mother of the Groom Dresses

  63. Cricket Live Streaming said January 31st, 2011 at 10:24 PM  

    s possible to use strings instead of symbols? It doesn’t seems very smart to repeat twice the translations :( :anenglishmessage => “An english message”

    Cricket Live Streaming

  64. Joan said February 3rd, 2011 at 12:57 PM  

    this is actually the best way to program this, nicely done.

    I saw a crude example on another site but it wasn’t as good.

    computer

  65. Florian said February 4th, 2011 at 01:36 PM  

    Wow, sehr schöne Übersicht, aber verdammt viel Informationen. Werde mich da mal reinarbeiten, vielen Dank, der Artikel ist wirklich sehr informativ.

  66. Parking Games Online said February 6th, 2011 at 12:59 PM  

    Wonderful article, thanks for putting this together! This is obviously one great post. Thanks for the valuable information and insights you have so provided here.

    Parking Games Online

  67. bobby said February 7th, 2011 at 01:34 PM  

    wow that seemed complicated… thanks for sharing that with us though :) permanent hair removal

  68. QQQ said February 7th, 2011 at 06:35 PM  

    Finally we kissed and the passion scale went sky high and I knew I was onto a good thing - sex was a certainty free porn videos. She never hesitated when I began to fondle her breasts and she willingly exposed them for me mobile porn. They were firm and I suspected a breast enhancement but said nothing - they still felt good and I was enjoying them and gradually working my way further south free porn tube. She was a step ahead of me and before I could completely undress her she moved on me atk hairy and I was suddenly having my pants pulled down and I was enjoying one of he best cock sucking hairy pussy experiences I had ever had. ABB728019394

  69. noreen said February 8th, 2011 at 11:32 AM  

    Thanks for the info here

  70. John Green said February 10th, 2011 at 08:08 AM  

    You’re not the regular blog writer, man. You surely have something powerful to contribute to the World Wide Web. Such a wonderful blog. I will return for more. drugstore.com

  71. prestiti convenienti said February 10th, 2011 at 08:29 AM  

    Yes, but can you afford the massive financial and technical outlays implicit in the iPhone studio system?

    prestiti convenienti

  72. Hadie Danker said February 11th, 2011 at 03:04 PM  

    great post - I will keep this in mind when I get to work on my next ruby project.

  73. williamk said February 14th, 2011 at 05:19 AM  

    I’m still learning from you, but I’m making my way to the top as well. I absolutely liked reading everything that is written on your blog.Keep the information coming. I enjoyed it! heat pump prices

  74. Rodrigez said February 14th, 2011 at 08:53 AM  

    Thanks, this is some good code and it was easy to implement on my Aspire Timeline I recently bought.

  75. joe robbins said February 17th, 2011 at 03:49 PM  

    Thank you for sharing these thoughts.Its good to read some post about this nowadays.Its significant and by some means sharing this to readers like me, would make me want to surf the web to have the ability to get significantly more fantastic suggestions.

    Rift Guide rift mage builds Rift Mage Souls

  76. andrea said February 17th, 2011 at 04:08 PM  

    Wonderful article, thanks for putting this together! This is obviously one great post. Thanks for the valuable information and insights you have so provided here. Nurse practitioner programs

  77. texas holdem regeln said February 22nd, 2011 at 01:10 PM  

    Surely i gonna to be amazing one. Very much information .. really a great effort…… innovating ideas are mixed with some modification that result to be very much helpful.

  78. jeni martin said February 23rd, 2011 at 12:37 PM  

    Recently I came across your blog and read along. I thought I would leave my first comment. AOT do not know what to say except that I liked reading. Nice blog, I’ll keep visiting this blog often. custom term paper AND Buy Dissertation AND Thesis

  79. jeni martin said February 24th, 2011 at 08:44 AM  

    Brilliant blog. I found your post very interesting, I think is a brilliant writer. I added your blog to my favorites and will return in the future.

    Buy Research Paper AND Buy Term Paper

  80. John said February 24th, 2011 at 04:09 PM  

    Not bad but I’ll stick to python :)

  81. arabic alphabet said February 25th, 2011 at 05:31 PM  

    The old “Show all” would not be used anymore, something that would become obvious because the access counter for “Show all” would stop ticking. Reset the counters, exercise the code with the test suites, observe any new strings or not used strings via a web-gui for handling translations. Correct it. Learn arabic alphabet letters easily using our interactive animated lessons and a 500 years old method of teaching the Arabic letters in Europe.

  82. jimmy said February 26th, 2011 at 08:44 AM  

    I am so glad that you are celebrating this so much. I think this is such a great thing to do.birds for adoption.The idea behind this is so good.

  83. Riftguide said March 1st, 2011 at 01:55 PM  

    Hello thanks for wonderful post. I enjoyed reading to this article.

    Rift Guide Rift Cleric Builds Rift Warrior Builds Guide

  84. Convert Youtube Video said March 1st, 2011 at 03:01 PM  

    Thanks a lot for this information i think that what you have write is true and a

    lot of user can be read more about this tread

    downloadyoutubevideos

  85. free hot girls said March 2nd, 2011 at 09:22 AM  

    Where is the updated ruby on rails content?

  86. roofers long island said March 2nd, 2011 at 11:17 AM  

    you have to do is submit a creative and looks like VERY NICE blog.

  87. How fast to lose weight said March 5th, 2011 at 04:25 AM  

    There is currently some useful information that regarding to health problem around this subject on the net and some are most definitely better than others. You have caught the detail here just right which makes for a refreshing change – thanks

  88. ovarian cysts treatment said March 5th, 2011 at 10:25 PM  

    Wow, you have raised some valid points here. ovarian cysts treatment

  89. jesus christ wallpaper said March 10th, 2011 at 10:46 AM  

    Thanks for this very informative post. I’ve been developing websites for a few years now, and this definitely helps.

  90. essay help said March 11th, 2011 at 12:21 PM  

    I believe this is great especially for beginners and users with almost no experience, as expected i learned something new and hope to continue this learning momentum here.

  91. cloudy1576 said March 11th, 2011 at 03:54 PM  

    Few lines that i read more than one time apart from the lines describing the actual moment of aforesaid article. Korfu mietwagen

  92. machine tool mart said March 13th, 2011 at 07:42 AM  

    Sensational info. I look forward to seeing more

    Thanks & Regards, machine tool mart

  93. granite counter tops PA said March 14th, 2011 at 05:43 PM  

    It’s amazing what open source software will do for you.

    ………………………………………………. granite counters

  94. masters in education said March 15th, 2011 at 07:23 PM  

    very nice post. I’ll give a try on ruby. masters in education

  95. ultralight sleeping bags said March 16th, 2011 at 04:55 PM  

    Railing right along.

  96. roger said March 17th, 2011 at 03:59 AM  

    Warning… Lots of Porn sites here!

  97. symptoms of vertigo said March 17th, 2011 at 02:32 PM  

    Ruby on Rails is a great, great framework – coming from the mouth of a long time PHP Developer.symptoms of vertigo

  98. General Electric Appliances said March 17th, 2011 at 02:34 PM  

    very nice and informative post i really appreciate it. General Electric Appliances

  99. penis advantage book said March 17th, 2011 at 11:23 PM  

    Great blog on ruby on rails penis advantage book

  100. Dating Sites said March 18th, 2011 at 03:29 PM  

    It is the most comfortable site and made in great manner so that reader could get maximum information and learn many things. This is one of the best blogs This is highly informatics, crisp and clear. I think that Everything has been described in systematic I have read. Dating Sites

  101. tod said March 18th, 2011 at 09:25 PM  

    Thanks for the ruby on rails information. waiting room furniture

  102. Matt said March 21st, 2011 at 06:03 AM  

    i have read your blog and find that your articles are amazing, i have added this into my bookmark. thanks a lot. make easy money on the internet.

  103. iklan baris said March 23rd, 2011 at 03:32 AM  

    Thanks for the valuable information. Your post saved me some time.

  104. akon 2011 said March 24th, 2011 at 06:31 AM  

    Thanks for the valuable information. Your post saved me some time. akon 2011

  105. akon 2011 said March 24th, 2011 at 07:47 AM  

    Thanks for the valuable information. Your post saved me some time.

  106. TinaTinka said March 24th, 2011 at 03:19 PM  

    Very nice and useful article. Help a lot. Thanks. Keep up a good work. TV Stands for Flat Screens

  107. blue films said March 25th, 2011 at 07:27 AM  

    I would like to show thanks to you for bailing me out of this type of situation. Just after looking out throughout the search engines and meeting tricks which are not powerful, I figured my life was done. Living without the presence of solutions to the difficulties you’ve solved through your report is a crucial case, as well as the ones that could have in a negative way affected my entire career if I hadn’t encountered your blog. blue film|hollywood blue films

  108. Sildenafil said March 28th, 2011 at 02:36 PM  

    I have found here much useful information for yourself. Many thanks to the editors for the info.

  109. Mike 007 said March 29th, 2011 at 01:07 PM  

    I’ve had a very interesting career. I get to do amazing things and work with amazing people and travel and learn languages - things most people don’t get the opportunity to do. travel to Europe Great Cities of Italy Europe Tours

  110. bose said March 30th, 2011 at 09:52 AM  

    Hello, stainless steel stair railings:From your blog i got the helpful information for my studying course.If the default value is a Symbol it will be used as a key and translated. One can provide multiple values as default. The first one that results in a value will be returned.nice sharing. Regards, Bose

  111. Cinema training said April 2nd, 2011 at 12:59 PM  

    Extraordinary article as well as advantageous also. Your writing on different issues have attracted many visitor of your site. I am finding useful information there almost every week.

  112. 80s t shirts said April 4th, 2011 at 01:27 AM  

    This is very inspirational and i am desperately looking forward to it..thanks indeed

  113. Nuru Massage said April 5th, 2011 at 11:44 AM  

    dear ,i have came to reading your feature. I t was high thought . But the topic you describe was helpful for coding.

  114. San Diego Printing said April 8th, 2011 at 09:39 AM  

    This is a smart blog. I mean it. You have so much knowledge about this issue, and so much passion. You also know how to make people rally behind it, obviously from the responses.

  115. jamesk said April 10th, 2011 at 07:00 AM  

    You made various nice points there. I did a search on the matter and found nearly all persons will consent with your wrote. price pfister kitchen faucets | ge profile refrigerator | ge dryer parts

  116. nigga said April 10th, 2011 at 11:08 PM  

    lololo what a great article

  117. jonesr said April 11th, 2011 at 01:34 AM  

    This is a good site thanks for the post and the comments folks haha lord and taylor coupons is good too

  118. Qinz said April 12th, 2011 at 10:33 AM  

    Then I tried setting the backend in an config/ initializer called I18n.rb This also doesn ’ t work. So,my question is,where do you set this backend,so that the Core strings remain in tact? meriahkan pesta ulang tahun Garudafood | dampak yang membekas dari radiasi nuklir | jadwal pertandingan liga ti-phone | tukar link gratis |

  119. Angela T. said April 12th, 2011 at 03:52 PM  

    I´m waiting for future publications. Regards. Red Robin Coupons

  120. Cloud Computing said April 16th, 2011 at 03:45 PM  

    You can read more about the motivation and reasoning behind this work thanks. Cloud Computing

  121. dubai properties said April 17th, 2011 at 02:46 PM  

    impressive i like interesting is “ome neat ideas imho. I never finished it but maybe you find this useful (maybe you already had these ideas but dumped them)” property to buy in Dubai | sell dubai properties

  122. avio karte said April 18th, 2011 at 05:52 AM  

    Appreciate your information.I will be back soon and follow up with a response.putovanje s djecom

  123. linaa01 said April 19th, 2011 at 01:06 PM  

    Have visited quite a few times, but this is the first time I have watched this video. In fact the theme I am reading is new to me. Good to read this one. Anyway I have found a good resource Austin Homes for Rent

  124. ada said April 20th, 2011 at 11:30 AM  

    andler can be swapped with different implementations. Bed Sets

  125. rajeevsmart said April 21st, 2011 at 12:50 PM  

    The fact that your blog entry here just uncovered some of the coolest new knowledge and online social trends in one go. How firkin’ cool is that! Austin Home Search

  126. slots canada said April 22nd, 2011 at 08:04 AM  

    The post is written in very a good manner and it entails many useful information for me. I am happy to find your distinguished way of writing the post.i will be happy to see you writing on new subject.

  127. rajeevsmart said April 22nd, 2011 at 10:32 AM  

    This is a very intriguing post, I was looking for this info. Just so you know I located your blog page when I was researching for blogs like mine, so please check out my site sometime and leave me a comment to let me know what you think. Austin Remodeling Companies

  128. rajeevsmart said April 23rd, 2011 at 10:16 AM  

    A very touching story, share with us! Thank you, nice article, I love it. Great thanks for sharing this article post.

    Anchor Text: Austin TX MLS

  129. heat pumps prices said April 23rd, 2011 at 11:49 AM  

    great api, i can use it now. could you offer your rss url?

  130. newguide said April 26th, 2011 at 07:03 AM  

    Upiq.com actually finds much cheaper flights & hotels prices than Momondo because Upiq compares much more travel sites than Momondo. You can check it out at http://www.upiq.com

  131. cialis club library said April 27th, 2011 at 11:22 AM  

    The content which is found in this article was very cordial. I really liked it very much. Thanks a lot for posting such an informative site in this post. Thanks a lot!

  132. Inner tube said April 28th, 2011 at 07:28 AM  

    Certainly helpful for me and other readers also as I am finding so many good comments here.

  133. traprenovatie kosten said May 2nd, 2011 at 06:41 AM  

    Thanks for nice info. It’s useful for me. Can you give me some more information with details? I will wait for your next post.

  134. traprenovatie prijzen said May 2nd, 2011 at 06:42 AM  

    I recently came across your blog and have been reading along. I thought I would leave my first comment. I don’t know what to say except that I have enjoyed reading. Nice blog, I will keep visiting this blog very often.

  135. The Town Crier said May 2nd, 2011 at 01:51 PM  

    This is a nice code, I can apply this to my responds area

  136. Porno said May 4th, 2011 at 07:40 PM  

    Geiler Sex zum Runterlanden? Du willst Porno dann habe ich was geiles für Dich. Schau mal rein

  137. adi said May 7th, 2011 at 09:28 AM  

    After reading this blog and after Sven, I think I understand. And I appreciate that this fills a gaping hole opened in a very lighthanded - especially once a variety of backends have been developed. Can not wait.

    One question: Does this work has any impact on the ability of developers to support plugins for templates town? Or is that considered a bad practice?

    I have not needed in my nascent, single locations. And it seems that creating serious maintenance problems or http://recenthits.comlife cycle, but also seems quite useful for some twisted locations.

  138. Nokia Mobile Prices said May 7th, 2011 at 04:59 PM  

    Nokia Mobile Prices In Pakistan 2011 China Mobile Prices In Pakistan Samsung Mobile Prices In Pakistan

  139. five star holidays said May 8th, 2011 at 09:58 AM  

    Thanks I called it “impossible mission”. How could I come up with some innovative ideas to this piece of design that is by many considered as one of the best in graphic design ever.

  140. cheap all inclusive holidays said May 8th, 2011 at 10:25 AM  

    awesome news. As a developer based in the Netherlands this is something that will be immediately and permanently useful.

  141. best android apps said May 9th, 2011 at 07:54 AM  

    Keeping your Android phone safe should be a key concern. You have tons of valuable data that is stored on that. Not only do you not want your personal information getting into the hands of the wrong person.

  142. heat pumps prices said May 11th, 2011 at 03:49 PM  

    thanks for sharing this core api which can help me learn some ideas now.

  143. touchscreen said May 12th, 2011 at 10:36 AM  

    Thanks for your time to discuss this, I feel very much at heart and love to learn more about this subject. If possible, obtain the know-how, you may update your blog anymore touchscreen

  144. best crib mattress said May 12th, 2011 at 02:59 PM  

    thank for sharing this code and can you offer the rss url to subscribe?

  145. Okey oyunu said May 12th, 2011 at 03:36 PM  

    Tüm dünya artik okey oyunu oynuyor. Yillardir bir çok oyun programi olmasina ragmen, içlerinden en güzeli olarak nitelendirebilecegimiz tek bir site göze çarpmaktadir. Diger tüm okey oyunu programlarinin aksine ücretsiz olmasi ve 3 boyutlu olarak hizmet vermesi mükemmel bir gelismedir. Sizlerde www. okey-oyunu.com adresinden bu essiz okey oyununu indirebilirsiniz. Kullanimi çok basit ve Türkçe dil seçenegi ile kolaylikla oyuna baslayabilirsiniz. Ister kendi ülkenizden, isterseniz dünyanin tüm farkli bölgelerinden dilediginiz oyun odalarini seçerek, oyuna hemen baslayabilirsiniz. Okey oyunu oynamak için artik arkadas bile aramaniza gerek kalmadan, bilgisayarinizdan 100 binlerce üye ile online olarak okey oyununu oynamanin zevkine varabilirsiniz.

  146. gaurav said May 16th, 2011 at 08:04 AM  

    It inspires the readers who has that great desire to lead a better and happier life. Thanks for sharing this information and hope to read more from you. Great information…

  147. it services companies said May 19th, 2011 at 12:30 AM  

    Well This post remind my old days when i was just started these things as I was new one but now i fully understand this stuff and must appreciate how positive you write

  148. term paper said May 20th, 2011 at 02:10 PM  

    Thanks for uniqueness, much appreciate this!

  149. p said May 21st, 2011 at 05:05 PM  







    chaussures nike lunarhaze+ white black red [cn3340] - €49.99 : nike tn,requin tn,tn nike,tn requin,nike requin,basket tn,chaussures tn
    nike tn,requin tn,tn nike,tn requin,nike bw,basket tn,chaussures tn : nike free 3.0 3 - Kvinner sko Menn sk
    Nous avons une satisfaction garantie à 100%. Si vous n’êtes pas satisfait avec votre produit dans les 365 jours suivant la réception vous pouvez l’envoyer de nouveau à nous pour un remboursement complet.

    Il est 24 heures période de traitement une fois le paiement re?u. Une fois que les chaussures sont expédiée, vous recevrez un email de notre part avec numéro de suivi afin que vous mai suivre votre commande. Vous aurez vos produits dans 3-5 jours d’affaires (sans compter les week-ends ou jours fériés). La plupart des commandes sont traitées et re?ues par les clients dans les 3 jours.



  150. porno said May 23rd, 2011 at 10:39 AM  

    I do agree with all of the ideas you have presented in your post. They’re really convincing and will definitely work. Still, the posts are too short for newbies. Could you please extend them a bit from next time? Thanks for the post.

  151. porno said May 23rd, 2011 at 10:39 AM  

    good comment. thanks you friends.

    I’ve surfed the net more than three hours today, however, I haven’t found such useful information. Thanks a lot, it is really useful to me

Sorry, comments are closed for this article.

artweb design
Sven Fuchs
Grünberger Str. 65
10245 Berlin, Germany


http://www.artweb-design.de

Fon +49 (30) 47 98 69 96
Fax +49 (30) 47 98 69 97