From 512f07375f7a7952aa6143e4c8bd47353d60fe0c Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Mon, 11 Aug 2025 22:36:26 +0000 Subject: [PATCH 1/8] Initial plan From c09bc80329bcb1ed682da8bf20b7ab4907c224ae Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 11 Aug 2025 22:46:03 +0000 Subject: [PATCH 2/8] Implement hash style that returns structured hash data Co-authored-by: markets <576701+markets@users.noreply.github.com> --- lib/jekyll-timeago/core.rb | 40 +++++++++++++++++++++++++++++++++---- spec/jekyll-timeago_spec.rb | 34 +++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 4 deletions(-) diff --git a/lib/jekyll-timeago/core.rb b/lib/jekyll-timeago/core.rb index 394c640..dda242d 100644 --- a/lib/jekyll-timeago/core.rb +++ b/lib/jekyll-timeago/core.rb @@ -15,7 +15,7 @@ module Core DEFAULT_THRESHOLD = 0 # Available styles - STYLES = %w(short array) + STYLES = %w(short array hash) # Available "only" options ONLY_OPTIONS = %w(years months weeks days) @@ -65,15 +65,26 @@ def validate_only(only) def time_ago_to_now days_passed = (@to - @from).to_i - return t(:today) if days_passed == 0 - return t(:yesterday) if days_passed == 1 - return t(:tomorrow) if days_passed == -1 + # Handle special cases for hash style + if @style == "hash" + case days_passed + when 0 then return { days: 0 } + when 1 then return { days: 1 } + when -1 then return { days: 1 } + end + else + return t(:today) if days_passed == 0 + return t(:yesterday) if days_passed == 1 + return t(:tomorrow) if days_passed == -1 + end past_or_future = @from < @to ? :past : :future slots = build_time_ago_slots(days_passed.abs) if @style == "array" slots + elsif @style == "hash" + build_hash_output(days_passed.abs) else t(past_or_future, date_range: to_sentence(slots)) end @@ -114,6 +125,27 @@ def build_only_slots(days_passed) [translate_unit(unit, count)] end + # Build hash output for hash style + def build_hash_output(days_passed) + # If "only" option is specified, return single unit hash + if @only + unit = @only.to_sym + count = calculate_total_in_unit(days_passed, unit) + return { unit => count } + end + + # Calculate components with natural unit conversions + components = calculate_natural_components(days_passed) + + # Select components based on depth and threshold + selected = select_components(components, days_passed) + + # Convert to hash format + result = {} + selected.each { |unit, count| result[unit] = count } + result + end + # Calculate total time in specified unit def calculate_total_in_unit(days_passed, unit) case unit diff --git a/spec/jekyll-timeago_spec.rb b/spec/jekyll-timeago_spec.rb index 7ae20f3..81e20d8 100644 --- a/spec/jekyll-timeago_spec.rb +++ b/spec/jekyll-timeago_spec.rb @@ -79,6 +79,7 @@ it 'allows threshold configuration' do expect(timeago(sample_date.prev_day(366), sample_date, threshold: 0.1)).to eq('1 year ago') + expect(timeago(sample_date.prev_day(366), sample_date, threshold: 0.1, style: :hash)).to eq({years: 1}) end it 'applies rounding rules for natural language' do @@ -131,6 +132,33 @@ expect(timeago(sample_date.prev_day(160), sample_date, style: :array, locale: :es)).to eq(['5 meses', '1 semana']) end + it 'allows hash style formatting' do + expect(timeago(sample_date.prev_day(365), sample_date, style: :hash)).to eq({years: 1}) + expect(timeago(sample_date.prev_day(365), sample_date, "style" => "hash")).to eq({years: 1}) + expect(timeago(sample_date.prev_day(160), sample_date, style: :hash)).to eq({months: 5, weeks: 1}) + expect(timeago(sample_date.prev_day(500), sample_date, style: :hash)).to eq({years: 1, months: 4}) + expect(timeago(sample_date.prev_day(10), sample_date, style: :hash)).to eq({weeks: 1, days: 3}) + end + + it 'allows hash style with special cases' do + expect(timeago(sample_date, sample_date, style: :hash)).to eq({days: 0}) + expect(timeago(sample_date.prev_day, sample_date, style: :hash)).to eq({days: 1}) + expect(timeago(sample_date.next_day, sample_date, style: :hash)).to eq({days: 1}) + end + + it 'allows hash style with future times' do + expect(timeago(sample_date.next_day(7), sample_date, style: :hash)).to eq({weeks: 1}) + expect(timeago(sample_date.next_day(365), sample_date, style: :hash)).to eq({years: 1}) + expect(timeago(sample_date.next_day(1000), sample_date, style: :hash)).to eq({years: 2, months: 9}) + end + + it 'allows hash style with depth control' do + expect(timeago(sample_date.prev_day(500), sample_date, style: :hash, depth: 1)).to eq({years: 1}) + expect(timeago(sample_date.prev_day(500), sample_date, style: :hash, depth: 2)).to eq({years: 1, months: 4}) + expect(timeago(sample_date.prev_day(500), sample_date, style: :hash, depth: 3)).to eq({years: 1, months: 4, weeks: 2}) + expect(timeago(sample_date.prev_day(500), sample_date, style: :hash, depth: 4)).to eq({years: 1, months: 4, weeks: 2, days: 1}) + end + it 'allows "only" option to accumulate time into single unit' do # Test "only: :days" expect(timeago(sample_date.prev_day(7), sample_date, only: :days)).to eq('7 days ago') @@ -162,6 +190,12 @@ # Test with array style expect(timeago(sample_date.prev_day(365), sample_date, only: :weeks, style: :array)).to eq(['52 weeks']) expect(timeago(sample_date.prev_day(30), sample_date, only: :months, style: :array)).to eq(['1 month']) + + # Test with hash style + expect(timeago(sample_date.prev_day(365), sample_date, only: :weeks, style: :hash)).to eq({weeks: 52}) + expect(timeago(sample_date.prev_day(30), sample_date, only: :months, style: :hash)).to eq({months: 1}) + expect(timeago(sample_date.prev_day(365), sample_date, only: :days, style: :hash)).to eq({days: 365}) + expect(timeago(sample_date.prev_day(365), sample_date, only: :years, style: :hash)).to eq({years: 1}) end it 'allows "only" option with different locales' do From 878d662397581c191d0aaccd971c93b42722ab5b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 11 Aug 2025 22:48:32 +0000 Subject: [PATCH 3/8] Complete hash style implementation with documentation and CLI support Co-authored-by: markets <576701+markets@users.noreply.github.com> --- README.md | 15 ++++++++++++++- bin/timeago | 2 +- spec/jekyll-timeago_spec.rb | 7 +++++++ 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 5c0bfe4..f8e537e 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ Main features: - Compute distance of dates, in words: `1 week and 2 days ago`, `5 months ago` - Future times: `in 1 year` -- Alternative formats: short (`2y and 1mo ago`) and array (`['2 years', '1 month']`) +- Alternative formats: short (`2y and 1mo ago`), array (`['2 years', '1 month']`), and hash (`{years: 2, months: 1}`) - Out of the box support for `Jekyll` projects, available as a Liquid Filter and as a Liquid Tag - Localization: `hace 3 semanas` - Level of detail customization @@ -140,6 +140,17 @@ Use `:array` style for structured data: => ["5 months", "1 week"] ``` +Use `:hash` style for structured hash data: + +```ruby +>> timeago(Date.today.prev_day(365), style: :hash) +=> {:years=>1} +>> timeago(Date.today.prev_day(160), style: :hash) +=> {:years=>0, :months=>5, :weeks=>1} +>> timeago(Date.today.prev_day(500), style: :hash) +=> {:years=>1, :months=>4} +``` + #### `only` Use the `only` option to accumulate all time into a single unit. Supported values are `:years`, `:months`, `:weeks`, and `:days`: @@ -188,6 +199,8 @@ il y a environ 2 années et 6 mois 2y ago > timeago 2016-1-1 2018-1-1 -l es -s short hace 2a y 1d +> timeago 2016-1-1 2018-1-1 --style hash +{:years=>2, :days=>1} > timeago 2016-1-1 2018-1-1 --only weeks 104 weeks ago > timeago 2016-1-1 2018-1-1 --only months -s short diff --git a/bin/timeago b/bin/timeago index f8bf150..3d3a9df 100755 --- a/bin/timeago +++ b/bin/timeago @@ -36,7 +36,7 @@ parser = OptionParser.new do |opts| options[:locale] = locale end - opts.on("-s", "--style STYLE", "Uses the provided style (short, array)") do |style| + opts.on("-s", "--style STYLE", "Uses the provided style (short, array, hash)") do |style| options[:style] = style end diff --git a/spec/jekyll-timeago_spec.rb b/spec/jekyll-timeago_spec.rb index 81e20d8..65b0f11 100644 --- a/spec/jekyll-timeago_spec.rb +++ b/spec/jekyll-timeago_spec.rb @@ -237,12 +237,19 @@ expect(`bin/timeago 2016-1-1 2018-1-1 --locale ru --style short`).to match("2г и 1д назад") end + it 'with hash style' do + expect(`bin/timeago 2016-1-1 2018-1-1 --style hash`).to match("{:years=>2, :days=>1}") + expect(`bin/timeago 2016-1-1 2018-1-1 -s hash`).to match("{:years=>2, :days=>1}") + expect(`bin/timeago 2016-1-1 2016-2-1 --style hash`).to match("{:months=>1, :days=>1}") + end + it 'with only option' do expect(`bin/timeago 2016-1-1 2018-1-1 --only weeks`).to match("104 weeks ago") expect(`bin/timeago 2016-1-1 2018-1-1 -o months`).to match("24 months ago") expect(`bin/timeago 2016-1-1 2016-2-1 --only days`).to match("31 days ago") expect(`bin/timeago 2016-1-1 2018-1-1 -l fr --only months`).to match("il y a environ 24 mois") expect(`bin/timeago 2016-1-1 2018-1-1 --only weeks -s short`).to match("104w ago") + expect(`bin/timeago 2016-1-1 2018-1-1 --only weeks --style hash`).to match("{:weeks=>104}") end end end From 05a2c5bfb96c50e8613c632aa06450c9ad6aa818 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 11 Aug 2025 23:25:11 +0000 Subject: [PATCH 4/8] Implement localized hash keys and refactor to reuse existing methods Co-authored-by: markets <576701+markets@users.noreply.github.com> --- README.md | 20 ++++++++++++ lib/jekyll-timeago/core.rb | 61 ++++++++++++++++++------------------- spec/jekyll-timeago_spec.rb | 17 +++++++++++ 3 files changed, 67 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index f8e537e..b721d9a 100644 --- a/README.md +++ b/README.md @@ -151,6 +151,15 @@ Use `:hash` style for structured hash data: => {:years=>1, :months=>4} ``` +Hash keys are automatically localized based on the locale: + +```ruby +>> timeago(Date.today.prev_day(500), style: :hash, locale: :es) +=> {:años=>1, :meses=>4} +>> timeago(Date.today.prev_day(160), style: :hash, locale: :fr) +=> {:années=>0, :mois=>5, :semaines=>1} +``` + #### `only` Use the `only` option to accumulate all time into a single unit. Supported values are `:years`, `:months`, `:weeks`, and `:days`: @@ -170,6 +179,15 @@ Use the `only` option to accumulate all time into a single unit. Supported value => "hace 12 meses" ``` +The `only` option also works with hash style and provides localized keys: + +```ruby +>> timeago(Date.today.prev_day(365), only: :months, style: :hash) +=> {:months=>12} +>> timeago(Date.today.prev_day(365), only: :months, style: :hash, locale: :es) +=> {:meses=>12} +``` + ## Localization By default, `jekyll-timego` already provides translations for some languages. You can check the list [here](lib/locales/). However, you are able to provide your own translations, or even override the originals, easily. @@ -201,6 +219,8 @@ il y a environ 2 années et 6 mois hace 2a y 1d > timeago 2016-1-1 2018-1-1 --style hash {:years=>2, :days=>1} +> timeago 2016-1-1 2018-1-1 --style hash --locale es +{:años=>2, :días=>1} > timeago 2016-1-1 2018-1-1 --only weeks 104 weeks ago > timeago 2016-1-1 2018-1-1 --only months -s short diff --git a/lib/jekyll-timeago/core.rb b/lib/jekyll-timeago/core.rb index dda242d..ac85919 100644 --- a/lib/jekyll-timeago/core.rb +++ b/lib/jekyll-timeago/core.rb @@ -68,9 +68,9 @@ def time_ago_to_now # Handle special cases for hash style if @style == "hash" case days_passed - when 0 then return { days: 0 } - when 1 then return { days: 1 } - when -1 then return { days: 1 } + when 0 then return { localized_unit_name(:days) => 0 } + when 1 then return { localized_unit_name(:days) => 1 } + when -1 then return { localized_unit_name(:days) => 1 } end else return t(:today) if days_passed == 0 @@ -84,7 +84,7 @@ def time_ago_to_now if @style == "array" slots elsif @style == "hash" - build_hash_output(days_passed.abs) + build_time_ago_slots(days_passed.abs, format_as_hash: true) else t(past_or_future, date_range: to_sentence(slots)) end @@ -103,10 +103,18 @@ def translate_unit(unit, count) end end - # Builds time ranges with natural unit conversions: ['1 month', '5 days'] - def build_time_ago_slots(days_passed) + # Get localized unit name for hash keys (always plural form) + def localized_unit_name(unit) + # Extract the unit name from the plural form translation + translated = t(unit, count: 2) + # Remove any count prefix (e.g. "2 años" -> "años") + translated.gsub(/^\d+\s+/, '').to_sym + end + + # Builds time ranges with natural unit conversions: ['1 month', '5 days'] or {:months => 1, :days => 5} + def build_time_ago_slots(days_passed, format_as_hash: false) # If "only" option is specified, calculate total time in that unit - return build_only_slots(days_passed) if @only + return build_only_slots(days_passed, format_as_hash: format_as_hash) if @only # Calculate components with natural unit conversions components = calculate_natural_components(days_passed) @@ -114,36 +122,27 @@ def build_time_ago_slots(days_passed) # Select components based on depth and threshold selected = select_components(components, days_passed) - # Convert to translated strings - selected.map { |unit, count| translate_unit(unit, count) } + # Format output based on requested format + if format_as_hash + result = {} + selected.each { |unit, count| result[localized_unit_name(unit)] = count } + result + else + # Convert to translated strings + selected.map { |unit, count| translate_unit(unit, count) } + end end # Build time slots when "only" option is specified - def build_only_slots(days_passed) + def build_only_slots(days_passed, format_as_hash: false) unit = @only.to_sym count = calculate_total_in_unit(days_passed, unit) - [translate_unit(unit, count)] - end - - # Build hash output for hash style - def build_hash_output(days_passed) - # If "only" option is specified, return single unit hash - if @only - unit = @only.to_sym - count = calculate_total_in_unit(days_passed, unit) - return { unit => count } - end - # Calculate components with natural unit conversions - components = calculate_natural_components(days_passed) - - # Select components based on depth and threshold - selected = select_components(components, days_passed) - - # Convert to hash format - result = {} - selected.each { |unit, count| result[unit] = count } - result + if format_as_hash + { localized_unit_name(unit) => count } + else + [translate_unit(unit, count)] + end end # Calculate total time in specified unit diff --git a/spec/jekyll-timeago_spec.rb b/spec/jekyll-timeago_spec.rb index 65b0f11..074b860 100644 --- a/spec/jekyll-timeago_spec.rb +++ b/spec/jekyll-timeago_spec.rb @@ -140,12 +140,25 @@ expect(timeago(sample_date.prev_day(10), sample_date, style: :hash)).to eq({weeks: 1, days: 3}) end + it 'allows hash style with localized keys' do + expect(timeago(sample_date.prev_day(365), sample_date, style: :hash, locale: :es)).to eq({años: 1}) + expect(timeago(sample_date.prev_day(160), sample_date, style: :hash, locale: :es)).to eq({meses: 5, semanas: 1}) + expect(timeago(sample_date.prev_day(500), sample_date, style: :hash, locale: :fr)).to eq({années: 1, mois: 4}) + expect(timeago(sample_date.prev_day(10), sample_date, style: :hash, locale: :fr)).to eq({semaines: 1, jours: 3}) + end + it 'allows hash style with special cases' do expect(timeago(sample_date, sample_date, style: :hash)).to eq({days: 0}) expect(timeago(sample_date.prev_day, sample_date, style: :hash)).to eq({days: 1}) expect(timeago(sample_date.next_day, sample_date, style: :hash)).to eq({days: 1}) end + it 'allows hash style with special cases and localized keys' do + expect(timeago(sample_date, sample_date, style: :hash, locale: :es)).to eq({días: 0}) + expect(timeago(sample_date.prev_day, sample_date, style: :hash, locale: :es)).to eq({días: 1}) + expect(timeago(sample_date.next_day, sample_date, style: :hash, locale: :fr)).to eq({jours: 1}) + end + it 'allows hash style with future times' do expect(timeago(sample_date.next_day(7), sample_date, style: :hash)).to eq({weeks: 1}) expect(timeago(sample_date.next_day(365), sample_date, style: :hash)).to eq({years: 1}) @@ -196,6 +209,10 @@ expect(timeago(sample_date.prev_day(30), sample_date, only: :months, style: :hash)).to eq({months: 1}) expect(timeago(sample_date.prev_day(365), sample_date, only: :days, style: :hash)).to eq({days: 365}) expect(timeago(sample_date.prev_day(365), sample_date, only: :years, style: :hash)).to eq({years: 1}) + + # Test with hash style and localized keys + expect(timeago(sample_date.prev_day(365), sample_date, only: :weeks, style: :hash, locale: :es)).to eq({semanas: 52}) + expect(timeago(sample_date.prev_day(30), sample_date, only: :months, style: :hash, locale: :fr)).to eq({mois: 1}) end it 'allows "only" option with different locales' do From 9eb04f9383fb183ee2f4146470e06eb4fb522602 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 11 Aug 2025 23:39:11 +0000 Subject: [PATCH 5/8] Optimize hash style performance by eliminating duplicate slot computation Co-authored-by: markets <576701+markets@users.noreply.github.com> --- lib/jekyll-timeago/core.rb | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/lib/jekyll-timeago/core.rb b/lib/jekyll-timeago/core.rb index ac85919..67de56f 100644 --- a/lib/jekyll-timeago/core.rb +++ b/lib/jekyll-timeago/core.rb @@ -81,10 +81,8 @@ def time_ago_to_now past_or_future = @from < @to ? :past : :future slots = build_time_ago_slots(days_passed.abs) - if @style == "array" + if @style == "array" || @style == "hash" slots - elsif @style == "hash" - build_time_ago_slots(days_passed.abs, format_as_hash: true) else t(past_or_future, date_range: to_sentence(slots)) end @@ -112,9 +110,9 @@ def localized_unit_name(unit) end # Builds time ranges with natural unit conversions: ['1 month', '5 days'] or {:months => 1, :days => 5} - def build_time_ago_slots(days_passed, format_as_hash: false) + def build_time_ago_slots(days_passed) # If "only" option is specified, calculate total time in that unit - return build_only_slots(days_passed, format_as_hash: format_as_hash) if @only + return build_only_slots(days_passed) if @only # Calculate components with natural unit conversions components = calculate_natural_components(days_passed) @@ -122,8 +120,8 @@ def build_time_ago_slots(days_passed, format_as_hash: false) # Select components based on depth and threshold selected = select_components(components, days_passed) - # Format output based on requested format - if format_as_hash + # Format output based on current style + if @style == "hash" result = {} selected.each { |unit, count| result[localized_unit_name(unit)] = count } result @@ -134,11 +132,11 @@ def build_time_ago_slots(days_passed, format_as_hash: false) end # Build time slots when "only" option is specified - def build_only_slots(days_passed, format_as_hash: false) + def build_only_slots(days_passed) unit = @only.to_sym count = calculate_total_in_unit(days_passed, unit) - if format_as_hash + if @style == "hash" { localized_unit_name(unit) => count } else [translate_unit(unit, count)] From 8846a3bfefd8d56c9ab3dee5490dd6d5bda8adb6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 11 Aug 2025 23:51:58 +0000 Subject: [PATCH 6/8] Refactor special cases to work for both array and hash styles with DRY code Co-authored-by: markets <576701+markets@users.noreply.github.com> --- lib/jekyll-timeago/core.rb | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/lib/jekyll-timeago/core.rb b/lib/jekyll-timeago/core.rb index 67de56f..0f8914a 100644 --- a/lib/jekyll-timeago/core.rb +++ b/lib/jekyll-timeago/core.rb @@ -65,12 +65,12 @@ def validate_only(only) def time_ago_to_now days_passed = (@to - @from).to_i - # Handle special cases for hash style - if @style == "hash" + # Handle special cases for array and hash styles + if @style == "array" || @style == "hash" case days_passed - when 0 then return { localized_unit_name(:days) => 0 } - when 1 then return { localized_unit_name(:days) => 1 } - when -1 then return { localized_unit_name(:days) => 1 } + when 0 then return handle_special_case(:today) + when 1 then return handle_special_case(:yesterday) + when -1 then return handle_special_case(:tomorrow) end else return t(:today) if days_passed == 0 @@ -109,6 +109,19 @@ def localized_unit_name(unit) translated.gsub(/^\d+\s+/, '').to_sym end + # Handle special cases (today, yesterday, tomorrow) for array and hash styles + def handle_special_case(key) + case @style + when "array" + [t(key)] + when "hash" + case key + when :today then { localized_unit_name(:days) => 0 } + when :yesterday, :tomorrow then { localized_unit_name(:days) => 1 } + end + end + end + # Builds time ranges with natural unit conversions: ['1 month', '5 days'] or {:months => 1, :days => 5} def build_time_ago_slots(days_passed) # If "only" option is specified, calculate total time in that unit From e6e85ab9945bcbcd05c6363ed426f502d84e95ec Mon Sep 17 00:00:00 2001 From: Marc Anguera Insa Date: Tue, 12 Aug 2025 02:14:34 +0200 Subject: [PATCH 7/8] simplify --- README.md | 28 ++++++---------------------- lib/jekyll-timeago/core.rb | 28 ++++++++-------------------- spec/jekyll-timeago_spec.rb | 36 +++--------------------------------- 3 files changed, 17 insertions(+), 75 deletions(-) diff --git a/README.md b/README.md index b721d9a..befcb83 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ Main features: - Localization: `hace 3 semanas` - Level of detail customization - CLI -- Approximate distance, with customizable threshold, ie: `366 days` becomes `1 year ago` instead of `1 year and 1 day ago` +- Approximate distance, with customizable threshold: `366 days` becomes `1 year ago` instead of `1 year and 1 day ago` In fact, `jekyll-timeago` started as an extension for the [Liquid](https://github.com/Shopify/liquid) template engine, to be used in Jekyll backed sites. But actually, you can use it easily on any Ruby project and even as a tool from the [terminal](#cli)! @@ -138,6 +138,8 @@ Use `:array` style for structured data: => ["1 year"] >> timeago(Date.today.prev_day(160), style: :array) => ["5 months", "1 week"] +>> timeago(Date.today.prev_day(160), style: :array, locale: :es) +=> ["5 meses", "1 semana"] ``` Use `:hash` style for structured hash data: @@ -146,18 +148,9 @@ Use `:hash` style for structured hash data: >> timeago(Date.today.prev_day(365), style: :hash) => {:years=>1} >> timeago(Date.today.prev_day(160), style: :hash) -=> {:years=>0, :months=>5, :weeks=>1} ->> timeago(Date.today.prev_day(500), style: :hash) -=> {:years=>1, :months=>4} -``` - -Hash keys are automatically localized based on the locale: - -```ruby ->> timeago(Date.today.prev_day(500), style: :hash, locale: :es) -=> {:años=>1, :meses=>4} ->> timeago(Date.today.prev_day(160), style: :hash, locale: :fr) -=> {:années=>0, :mois=>5, :semaines=>1} +=> {:months=>5, :weeks=>1} +>> timeago(Date.today.prev_day(160), style: :hash, locale: :es) +=> {:meses=>5, :semanas=>1} ``` #### `only` @@ -177,15 +170,8 @@ Use the `only` option to accumulate all time into a single unit. Supported value => "52w ago" >> timeago(Date.today.prev_day(365), only: :months, locale: :es) => "hace 12 meses" -``` - -The `only` option also works with hash style and provides localized keys: - -```ruby >> timeago(Date.today.prev_day(365), only: :months, style: :hash) => {:months=>12} ->> timeago(Date.today.prev_day(365), only: :months, style: :hash, locale: :es) -=> {:meses=>12} ``` ## Localization @@ -219,8 +205,6 @@ il y a environ 2 années et 6 mois hace 2a y 1d > timeago 2016-1-1 2018-1-1 --style hash {:years=>2, :days=>1} -> timeago 2016-1-1 2018-1-1 --style hash --locale es -{:años=>2, :días=>1} > timeago 2016-1-1 2018-1-1 --only weeks 104 weeks ago > timeago 2016-1-1 2018-1-1 --only months -s short diff --git a/lib/jekyll-timeago/core.rb b/lib/jekyll-timeago/core.rb index 0f8914a..3638b3f 100644 --- a/lib/jekyll-timeago/core.rb +++ b/lib/jekyll-timeago/core.rb @@ -65,13 +65,14 @@ def validate_only(only) def time_ago_to_now days_passed = (@to - @from).to_i - # Handle special cases for array and hash styles - if @style == "array" || @style == "hash" - case days_passed - when 0 then return handle_special_case(:today) - when 1 then return handle_special_case(:yesterday) - when -1 then return handle_special_case(:tomorrow) - end + if @style == "hash" + return { localized_unit_name(:days) => 0 } if days_passed == 0 + return { localized_unit_name(:days) => 1 } if days_passed == 1 + return { localized_unit_name(:days) => -1 } if days_passed == -1 + elsif @style == "array" + return [t(:today)] if days_passed == 0 + return [t(:yesterday)] if days_passed == 1 + return [t(:tomorrow)] if days_passed == -1 else return t(:today) if days_passed == 0 return t(:yesterday) if days_passed == 1 @@ -109,19 +110,6 @@ def localized_unit_name(unit) translated.gsub(/^\d+\s+/, '').to_sym end - # Handle special cases (today, yesterday, tomorrow) for array and hash styles - def handle_special_case(key) - case @style - when "array" - [t(key)] - when "hash" - case key - when :today then { localized_unit_name(:days) => 0 } - when :yesterday, :tomorrow then { localized_unit_name(:days) => 1 } - end - end - end - # Builds time ranges with natural unit conversions: ['1 month', '5 days'] or {:months => 1, :days => 5} def build_time_ago_slots(days_passed) # If "only" option is specified, calculate total time in that unit diff --git a/spec/jekyll-timeago_spec.rb b/spec/jekyll-timeago_spec.rb index 074b860..280f705 100644 --- a/spec/jekyll-timeago_spec.rb +++ b/spec/jekyll-timeago_spec.rb @@ -79,7 +79,6 @@ it 'allows threshold configuration' do expect(timeago(sample_date.prev_day(366), sample_date, threshold: 0.1)).to eq('1 year ago') - expect(timeago(sample_date.prev_day(366), sample_date, threshold: 0.1, style: :hash)).to eq({years: 1}) end it 'applies rounding rules for natural language' do @@ -126,6 +125,7 @@ end it 'allows array style formatting' do + expect(timeago(sample_date, sample_date, style: :array)).to eq(['today']) expect(timeago(sample_date.prev_day(365), sample_date, style: :array)).to eq(['1 year']) expect(timeago(sample_date.prev_day(365), sample_date, "style" => "array")).to eq(['1 year']) expect(timeago(sample_date.prev_day(160), sample_date, style: :array)).to eq(['5 months', '1 week']) @@ -133,42 +133,15 @@ end it 'allows hash style formatting' do + expect(timeago(sample_date, sample_date, style: :hash)).to eq({days: 0}) + expect(timeago(sample_date, sample_date, style: :hash, locale: :es)).to eq({días: 0}) expect(timeago(sample_date.prev_day(365), sample_date, style: :hash)).to eq({years: 1}) expect(timeago(sample_date.prev_day(365), sample_date, "style" => "hash")).to eq({years: 1}) expect(timeago(sample_date.prev_day(160), sample_date, style: :hash)).to eq({months: 5, weeks: 1}) expect(timeago(sample_date.prev_day(500), sample_date, style: :hash)).to eq({years: 1, months: 4}) expect(timeago(sample_date.prev_day(10), sample_date, style: :hash)).to eq({weeks: 1, days: 3}) - end - - it 'allows hash style with localized keys' do - expect(timeago(sample_date.prev_day(365), sample_date, style: :hash, locale: :es)).to eq({años: 1}) expect(timeago(sample_date.prev_day(160), sample_date, style: :hash, locale: :es)).to eq({meses: 5, semanas: 1}) expect(timeago(sample_date.prev_day(500), sample_date, style: :hash, locale: :fr)).to eq({années: 1, mois: 4}) - expect(timeago(sample_date.prev_day(10), sample_date, style: :hash, locale: :fr)).to eq({semaines: 1, jours: 3}) - end - - it 'allows hash style with special cases' do - expect(timeago(sample_date, sample_date, style: :hash)).to eq({days: 0}) - expect(timeago(sample_date.prev_day, sample_date, style: :hash)).to eq({days: 1}) - expect(timeago(sample_date.next_day, sample_date, style: :hash)).to eq({days: 1}) - end - - it 'allows hash style with special cases and localized keys' do - expect(timeago(sample_date, sample_date, style: :hash, locale: :es)).to eq({días: 0}) - expect(timeago(sample_date.prev_day, sample_date, style: :hash, locale: :es)).to eq({días: 1}) - expect(timeago(sample_date.next_day, sample_date, style: :hash, locale: :fr)).to eq({jours: 1}) - end - - it 'allows hash style with future times' do - expect(timeago(sample_date.next_day(7), sample_date, style: :hash)).to eq({weeks: 1}) - expect(timeago(sample_date.next_day(365), sample_date, style: :hash)).to eq({years: 1}) - expect(timeago(sample_date.next_day(1000), sample_date, style: :hash)).to eq({years: 2, months: 9}) - end - - it 'allows hash style with depth control' do - expect(timeago(sample_date.prev_day(500), sample_date, style: :hash, depth: 1)).to eq({years: 1}) - expect(timeago(sample_date.prev_day(500), sample_date, style: :hash, depth: 2)).to eq({years: 1, months: 4}) - expect(timeago(sample_date.prev_day(500), sample_date, style: :hash, depth: 3)).to eq({years: 1, months: 4, weeks: 2}) expect(timeago(sample_date.prev_day(500), sample_date, style: :hash, depth: 4)).to eq({years: 1, months: 4, weeks: 2, days: 1}) end @@ -209,10 +182,7 @@ expect(timeago(sample_date.prev_day(30), sample_date, only: :months, style: :hash)).to eq({months: 1}) expect(timeago(sample_date.prev_day(365), sample_date, only: :days, style: :hash)).to eq({days: 365}) expect(timeago(sample_date.prev_day(365), sample_date, only: :years, style: :hash)).to eq({years: 1}) - - # Test with hash style and localized keys expect(timeago(sample_date.prev_day(365), sample_date, only: :weeks, style: :hash, locale: :es)).to eq({semanas: 52}) - expect(timeago(sample_date.prev_day(30), sample_date, only: :months, style: :hash, locale: :fr)).to eq({mois: 1}) end it 'allows "only" option with different locales' do From 76f9c872798db294a8f50a974f5df166e6d7dacd Mon Sep 17 00:00:00 2001 From: Marc Anguera Insa Date: Tue, 12 Aug 2025 15:48:56 +0200 Subject: [PATCH 8/8] small fixes --- README.md | 2 +- lib/jekyll-timeago/core.rb | 1 - lib/locales/{ja.yaml => ja.yml} | 0 spec/jekyll-timeago_spec.rb | 4 ++++ 4 files changed, 5 insertions(+), 2 deletions(-) rename lib/locales/{ja.yaml => ja.yml} (100%) diff --git a/README.md b/README.md index befcb83..750cbe1 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ Main features: - Future times: `in 1 year` - Alternative formats: short (`2y and 1mo ago`), array (`['2 years', '1 month']`), and hash (`{years: 2, months: 1}`) - Out of the box support for `Jekyll` projects, available as a Liquid Filter and as a Liquid Tag -- Localization: `hace 3 semanas` +- Localization: `hace 3 semanas`, `3週間前`, `il y a environ 3 semaines` - Level of detail customization - CLI - Approximate distance, with customizable threshold: `366 days` becomes `1 year ago` instead of `1 year and 1 day ago` diff --git a/lib/jekyll-timeago/core.rb b/lib/jekyll-timeago/core.rb index 3638b3f..246ec10 100644 --- a/lib/jekyll-timeago/core.rb +++ b/lib/jekyll-timeago/core.rb @@ -127,7 +127,6 @@ def build_time_ago_slots(days_passed) selected.each { |unit, count| result[localized_unit_name(unit)] = count } result else - # Convert to translated strings selected.map { |unit, count| translate_unit(unit, count) } end end diff --git a/lib/locales/ja.yaml b/lib/locales/ja.yml similarity index 100% rename from lib/locales/ja.yaml rename to lib/locales/ja.yml diff --git a/spec/jekyll-timeago_spec.rb b/spec/jekyll-timeago_spec.rb index 280f705..d3c621d 100644 --- a/spec/jekyll-timeago_spec.rb +++ b/spec/jekyll-timeago_spec.rb @@ -97,6 +97,8 @@ it 'allows localization' do expect(timeago(sample_date.prev_day(100), sample_date, locale: :fr)).to eq('il y a environ 3 mois et 1 semaine') expect(timeago(sample_date.prev_day(100), sample_date, locale: :ru)).to eq('3 месяца и неделю назад') + expect(timeago(sample_date.prev_day(100), sample_date, locale: :it)).to eq('3 mesi e 1 settimana fa') + expect(timeago(sample_date.prev_day(100), sample_date, locale: :pt)).to eq('3 meses e 1 semana atrás') end it 'allows short style formatting' do @@ -116,6 +118,8 @@ expect(timeago(sample_date.prev_day(365), sample_date, locale: :ru, style: :short)).to eq('1г назад') expect(timeago(sample_date.prev_day(365), sample_date, locale: :es, style: :short)).to eq('hace 1a') expect(timeago(sample_date.prev_day(30), sample_date, locale: :de, style: :short)).to eq('vor 1mo') + expect(timeago(sample_date.prev_day(120), sample_date, locale: :ca, style: :short)).to eq('fa 4m') + expect(timeago(sample_date.prev_day(120), sample_date, locale: :ja, style: :short)).to eq('4月前') end it 'allows complex combinations with short style' do