11

In my Rails 5 app I am using Liquid to let my users generate content.

Based on my users input, I init my template with something like this:

string   = "Order {{ order.id }} was created {{ order.date | date: '%A %d/%m-%Y' }}"
template = Liquid::Template.parse(string)
result   = template.render({'order' => {'id' => '123', 'date' => order.date}})

This would print something a la:

'Order 123 was created Sunday 14/01-2018'

But how do I build Liquid date localization into my Rails app?

It does not seem to be supported in the documentation. However Shopify themselves seems to have build localization into their Liquid implementation.

I suppose I would need to pass my template a locale (en, fr, etc.) and a locale file. My Rails locale file looks like this:

en:
  datetime: &datetime
    month_names:
      [~, January, February, March, April, May, June, July, August, September, October, November, December]
    day_names:
      [Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday]
    abbr_day_names:
      [~, Sun, Mon, Thue, Wed, Thu, Fri, Sat]
    formats:
       default: "%d/%m/%Y"
       long: "%A %d/%m-%Y"

And I call it with:

l(order.date, :format => :long, :locale => 'en')

I would love to have access to a similar date localization inside my Liquid template.

JohnSmith1976
  • 536
  • 2
  • 12
  • 35
  • You might be able to deliberately call `I18n.localize` ? http://www.stackednotion.com/blog/2015/01/03/formatting-dates-and-times-in-rails-with-i18n-localize/ seems relevant - it shows how to deliberately pass in a locale and use a customised date format (but note I've spent like maybe 5 whole seconds thinking about this...) – Taryn East Jan 24 '18 at 22:44
  • https://gist.github.com/biow0lf/1486342 ? – Ben Mar 05 '18 at 22:05
  • Thanks @Ben I've used this approach to register a filter that does `l(order.date, :format => :long, :locale => 'en')`. I'm gonna write it in as an answer if no one else comes up with a better solution. But it's not a perfect one, because it limits me to a set of predefined `formats`. – JohnSmith1976 Mar 06 '18 at 20:22

4 Answers4

2

I ended up using the link proveded by @Ben, and wrote up this solution:

# config/initializers/liquid_filters.rb
module I18nFilters
  def l(date, format)
    I18n.l(date, :format => format.to_sym)
  end
end

Liquid::Template.register_filter(I18nFilters)

Now, when invoking that new method:

{{ order.date | l: 'long' }}

it will print out:

'Sunday 14/01-2018'

with Sunday being whatever is in day_names withing the locale file.

JohnSmith1976
  • 536
  • 2
  • 12
  • 35
0

When you pass your date object with order.date

result   = template.render({'order' => {'id' => '123', 'date' => order.date}})

Can you pass a localized date or localized datetime? Then when it gets rendered it should be correct.

Otherwise, you could add the date to a span with class name you can target (for fallback) and "fix" it on the client side with a combination of pure Javascript and a library like Moment.js

# https://stackoverflow.com/a/39161134/793330
const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
engineerDave
  • 3,887
  • 26
  • 28
  • Hi @engineerDave modifying with js is a hack that I want to avoid. But the first suggestion seems more like a question to me. I'm not sure I understand it. – JohnSmith1976 Mar 05 '18 at 07:48
  • sorry words are hard. :) When you pass order.date to the liquid template, I would assume you know the locale of the person you're displaying the data for, if not you can do this within rails, http://guides.rubyonrails.org/i18n.html. This will allow you to pass the correctly localized date to the template. – engineerDave Mar 05 '18 at 21:40
0

It looks like you're missing only a reference to t method.

Instead of

string   = "Order {{ order.id }} was created {{ order.date | date: '%A %d/%m-%Y' }}"

Try with

string   = "Order {{ order.id }} was created {{ order.date | t: date: '%A %d/%m-%Y' }}"
Gustavo Toro
  • 450
  • 4
  • 10
0

You can do it by using the JavaScript Intl API.

Add this filter to .eleventy.js:

  eleventyConfig.addFilter("displayDate", function(date, locale) {
    return new Intl.DateTimeFormat(locale, { dateStyle: "long" }).format(date);
  });

Now you can show localized dates by using this in, for example, your Liquid template:

{{ date | displayDate: locale }}

Here, date contains the date and locale contains the locale.

edwin
  • 2,643
  • 20
  • 17