Enhanced I18n Interpolation with Piping

Problem

Currently, Rails I18n provides basic interpolation functionality, which often requires additional formatting or processing in the view layer. This leads to several issues:

  1. Increased complexity in views, mixing presentation logic with I18n.
  2. Difficulty in maintaining consistency across different views using the same translations.
  3. Limited flexibility in locale files, requiring developers to create multiple translation keys for similar content with different formatting.

Proposed Solution

Back in my Angular days I used to use piping like so {{ something | foo }}. I’d like to propose enhancing the existing interpolation logic with a piping feature.

Implementation

I created a proof-of-concept gem that allows me to use this syntax in my app, which it desperately needs it as my views are becoming more and more complex.

(Happy to change/discuss the addition of ${} instead of re-using %{}.

The proposed implementation introduces a new syntax for advanced interpolation using ${} with pipes (|):

"${variable | pipe1 | pipe2 | ...}"

Standard interpolation with %{} would continue to work as before for backwards compatibility.

Examples

Current approach:

# config/locales/en.yml
en:
  users:
    count: "There are %{count} users"
<!-- app/views/users/index.html.erb -->
<%= t('users.count', count: number_with_delimiter(@users.count)) %>

Proposed approach:

# config/locales/en.yml
en:
  users:
    count: "There are ${count | number_with_delimiter} users"
<!-- app/views/users/index.html.erb -->
<%= t('users.count', count: @users.count) %>

More complex example:

en:
  items:
    summary: "Showing %{from} - %{to} of ${total | number_with_delimiter} ${item | pluralize:%{total}}"
<%= t('items.summary', from: 1, to: 10, total: 1234, item: 'item') %>
# Output: "Showing 1 - 10 of 1,234 items"

I’m aware that the current implementation is not as flexible as (just as an example) the existing number_with_delimiter since we can’t pass any options, although that shouldn’t be too hard to do, but for my proof of concept I just didn’t need it.

Supported Pipes

Initially, this can support the following pipes:

  • number_with_delimiter: Formats numbers with thousands separators
  • pluralize: Pluralizes a word
  • upcase: Converts text to uppercase
  • downcase: Converts text to lowercase
  • capitalize: Capitalizes the first character

Which from my own use-case, are the most common pipes I tend to reach to in my locales. But ideally it should support everything that ActionView supports.

Benefits

  1. Cleaner Views: Reduces the amount of formatting logic in views.
  2. Improved Consistency: Ensures consistent formatting across all uses of a translation.
  3. Enhanced Locale Files: Allows for more expressive and self-contained translations.
  4. Flexibility: Enables easy changes to formatting without modifying view code.
  5. DRY Principle: Reduces repetition of formatting logic across different views.

Potential Concerns

  1. Performance: The impact on performance should be evaluated. This is something I will closely monitor in my app going forward, although I expect it to be minimal.
  2. Complexity: While this adds some complexity to the I18n system, it significantly simplifies view logic.
  3. Learning Curve: New syntax and pipes to learn, but should be intuitive for developers familiar with Rails helpers.

Next Steps

I’d love to hear some thoughts on this proposal before I start doing anything. I do believe this would enhance the I18n system with much needed features.

I’ll leave the proof-of-concept gem here: GitHub - games-directory/i18n-inflections: A gem that provides advanced interpolation and piping features for Rails I18n

The way it works, (I know it’s obvious from tests and code) is: Screenshot 2024-08-22 at 13 54 07

Screenshot 2024-08-22 at 13 55 21