class String # Selects the part based upon count. Giving you control over the syntax. # # The syntax: # * "{$N}".pluralize_for(int) # * "{post|posts}".pluralize_for(int) # * "one post ~~ more posts".pluralize_for(int) # * "no posts ~~ one post ~~ more posts".pluralize_for(int) # * "no posts ~~ one post ~~$N<6: more posts ~~else: large amount".pluralize_for(int) # * "click {1:here} for more info".pluralize_for(int) { |array| array[1] = link_to(array[i], url) if array[i] # # Tip: ~~$N>=3:-syntax is eval'ed, so check your source code! Also, if you decide to use it, it's better to specify it everywhere, not just the last parts. def pluralize_for(count) # get the value properly, so we can manipulate it str = self.to_s.clone # examine which part of it we need to fetch str = __get_partialized_string(str, count) # replace the count value, if any left str.gsub!("{$N}", count.to_s) if str.include?("{$N}") # replace {single|plural} with either single or plural if str =~ /\{([^|\{]*)\|([^\}]*)\}/ single = $1.clone plural = $2.clone str.gsub!(/\{([^|\{]*)\|([^\}]*)\}/, (count == 1 ? single : plural)) end # do some replacements with {1:foo} if block_given? # find the substitution parts matched = str.scan(/\{(\d+):([^\}]+)\}/) # do some reordering array = [] matched.each do |x| array[x[0].to_i] = x[1].to_s end # let the others edit it if they like yield array # replace the block with the new values array.size.times do |x| str.gsub!(/\{#{x}:([^\}]+)\}/,array[x].to_s) end end str end private def __get_partialized_string(str, count) parts = str.split('~~') if parts.size > 1 array = case parts.size when 2 then ['$N==1:', 'else:'] when 3 then ['$N==0:', '$N==1:', 'else:'] else ['$N==1:','$N!=1:'] end parts.size.times do |i| parts[i] = array[i] + parts[i] unless parts[i] =~ /^\S*:/ c = parts[i].split(/:\s*/,2) if c[0] == 'else' return c[1] else return c[1] if eval(c[0].gsub('$N',count.to_s)) end end end return str end end