Problem
Currently, Rails I18n provides basic interpolation functionality, which often requires additional formatting or processing in the view layer. This leads to several issues:
- Increased complexity in views, mixing presentation logic with I18n.
- Difficulty in maintaining consistency across different views using the same translations.
- 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 separatorspluralize
: Pluralizes a wordupcase
: Converts text to uppercasedowncase
: Converts text to lowercasecapitalize
: 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
- Cleaner Views: Reduces the amount of formatting logic in views.
- Improved Consistency: Ensures consistent formatting across all uses of a translation.
- Enhanced Locale Files: Allows for more expressive and self-contained translations.
- Flexibility: Enables easy changes to formatting without modifying view code.
- DRY Principle: Reduces repetition of formatting logic across different views.
Potential Concerns
- 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.
- Complexity: While this adds some complexity to the I18n system, it significantly simplifies view logic.
- 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: