Railsで1st、2nd、3rd、4thなどの序数を表示する方法(翻訳)
Railsアプリケーションを開発するときに、数字を人間が読みやすい形式で表示する必要が生じることがよくあります。たとえば、「1」や「42」だけではなく、「1st」や「42nd」のような序数を表示したい場合があります。Railsは、Active Support のコア拡張機能でそれ用の優れたソリューションを提供しています。
🔗 以下のように書くよりも
序数を完全に避ける。つまり基本的な文字列式展開で表示位置を工夫してしのぐ。
position = 1
"You finished in position #{position}"
# => "You finished in position 1"
position = 32
"You finished in position #{position}"
# => "You finished in position 1"
🔗 以下のように書こう
Rails組み込みのordinal
メソッドやordinalize
メソッドを使う。
position = 1
"You finished in #{position.ordinalize} place"
# => "You finished in 1st place"
position = 11
"You finished in #{position.ordinalize} place"
# => "You finished in 11th place"
position = 22
"You finished in #{position.ordinalize} place"
# => "You finished in 22nd place"
position = 43
"You finished in #{position.ordinalize} place"
# => "You finished in 43rd place"
🔗 そうする理由
序数を使えば、特に「ランキング」「日付」「リスト」を扱うときのテキストが自然で読みやすいものになります。
コード例では英語の序数を示していますが、これらのメソッドは国際化に対応しているので他の言語にもローカライズできます(localizeは英国風に書けばlocaliseですね!)。
これはいつものように、Active Supportで拡張されたRailsツールキットの一部です。正しい序数サフィックスを決定し、アプリケーション全体で一貫した処理を確保するために独自のロジックをわざわざ記述して維持する必要はありません。
コード例で示したordinalize
は完全な序数(1st
や2nd
など)を返しますが、ordinal
のようにサフィックスだけ(st
やnd
など)を返すものもあります。
これらのメソッドをビューで頻繁に利用している場合や、特定のマークアップと組み合わせて利用している場合は、以下のようにロジックをヘルパーまたはデコレータに移動してビューを整理することを検討しましょう。
# app/helpers/number_helper.rb
module NumberHelper
def wrapped_ordinal(number)
tag.span(sanitize(number.to_s) << tag.span(number.ordinal, class: "ordinal"))
end
end
<!-- whatever.html.erb -->
<%= wrapped_ordinal(1) %>
#=> "<span>1<span class=\"ordinal\">st</span></span>"
🔗 そうしない理由があるとすれば
Rails以外のRubyプロジェクトで作業している場合は、依存関係にactivesupport gemを追加する必要があります。その場合、Rubyのコアクラスで多くのメソッドにパッチが適用されることになります。
ただし、ほとんどのRailsアプリケーションではordinal
やordinalize
を使うのが最善の方法です。これらは現場のテストを経ていて効率もよく、車輪の再発明や読みにくい出力で我慢する必要がありません。
概要
原著者の許諾を得て翻訳・公開いたします。
日本語タイトルは内容に即したものにしました。
参考: §7.3
ordinalize
-- Active Support コア拡張機能 - Railsガイドなお、英語ロケールに設定されていないRailsアプリで、国際化用のロケールyamlファイルやフォールバックなどが適切に設定されていない場合は、
ordinalize
やordinal
メソッドを呼び出すと"Translation missing: ja.number.nth.ordinalized"
エラーになります。参考: §3.6.6
config.i18n.fallbacks
-- Rails アプリケーションの設定項目 - Railsガイド参考: §3.2 訳文を与えて文字列を国際化する -- Rails 国際化(I18n)API - Railsガイド
また、
ordinalize
やordinal
はゼロや負のInteger
には対応していますが、当然ながらFloat
などには対応していません。