Feature #20310 » feature-33988-v1.patch
app/helpers/application_helper.rb | ||
---|---|---|
467 | 467 |
h(page.pretty_title), |
468 | 468 |
href, |
469 | 469 |
:title => (if options[:timestamp] && page.updated_on |
470 |
l(:label_updated_time, distance_of_time_in_words(Time.now, page.updated_on))
|
|
470 |
l(label_by_timestamp_format(:label_updated_time), format_timestamp(page.updated_on))
|
|
471 | 471 |
else |
472 | 472 |
nil |
473 | 473 |
end) |
... | ... | |
690 | 690 |
end |
691 | 691 | |
692 | 692 |
def authoring(created, author, options={}) |
693 |
l(options[:label] || :label_added_time_by, :author => link_to_user(author), :age => time_tag(created)).html_safe
|
|
693 |
l(label_by_timestamp_format(options[:label] || :label_added_time_by), :author => link_to_user(author), :age => time_tag(created)).html_safe
|
|
694 | 694 |
end |
695 | 695 | |
696 | 696 |
def time_tag(time) |
697 | 697 |
return if time.nil? |
698 | 698 | |
699 |
text = distance_of_time_in_words(Time.now, time)
|
|
699 |
text = format_timestamp(time)
|
|
700 | 700 |
if @project |
701 | 701 |
link_to(text, |
702 | 702 |
project_activity_path(@project, :from => User.current.time_to_date(time)), |
app/helpers/settings_helper.rb | ||
---|---|---|
224 | 224 |
end |
225 | 225 |
end |
226 | 226 | |
227 |
# Returns the options for the timestamp_format setting |
|
228 |
# Convert the date and time three days ago into each format and use it as an example |
|
229 |
def timestamp_format_setting_options |
|
230 |
%w[relative_time relative_time_with_absolute_time absolute_time].map do |f| |
|
231 |
["#{format_timestamp(Time.now.ago(3.days), f)} (#{l('label_' + f)})", f] |
|
232 |
end |
|
233 |
end |
|
234 | ||
227 | 235 |
def gravatar_default_setting_options |
228 | 236 |
[['Identicons', 'identicon'], |
229 | 237 |
['Monster ids', 'monsterid'], |
app/helpers/wiki_helper.rb | ||
---|---|---|
73 | 73 |
end |
74 | 74 | |
75 | 75 |
def wiki_content_update_info(content) |
76 |
l(:label_updated_time_by, :author => link_to_user(content.author), :age => time_tag(content.updated_on)).html_safe
|
|
76 |
authoring(content.updated_on, content.author, label: :label_updated_time_by)
|
|
77 | 77 |
end |
78 | 78 |
end |
app/views/issues/show.html.erb | ||
---|---|---|
40 | 40 |
<p class="author"> |
41 | 41 |
<%= authoring @issue.created_on, @issue.author %>. |
42 | 42 |
<% if @issue.created_on != @issue.updated_on %> |
43 |
<%= l(:label_updated_time, time_tag(@issue.updated_on)).html_safe %>.
|
|
43 |
<%= l(label_by_timestamp_format(:label_updated_time), time_tag(@issue.updated_on)).html_safe %>.
|
|
44 | 44 |
<% end %> |
45 | 45 |
</p> |
46 | 46 |
app/views/settings/_display.html.erb | ||
---|---|---|
17 | 17 | |
18 | 18 |
<p><%= setting_select :timespan_format, [["%.2f" % 0.75, 'decimal'], ['0:45 h', 'minutes']], :blank => false %></p> |
19 | 19 | |
20 |
<p><%= setting_select :timestamp_format, timestamp_format_setting_options %></p> |
|
21 | ||
20 | 22 |
<p><%= setting_select :user_format, @options[:user_format] %></p> |
21 | 23 | |
22 | 24 |
<p><%= setting_check_box :gravatar_enabled, :data => {:enables => '#settings_gravatar_default'} %> |
config/locales/en.yml | ||
---|---|---|
443 | 443 |
setting_date_format: Date format |
444 | 444 |
setting_time_format: Time format |
445 | 445 |
setting_timespan_format: Time span format |
446 |
setting_timestamp_format: Timestamp format |
|
446 | 447 |
setting_cross_project_issue_relations: Allow cross-project issue relations |
447 | 448 |
setting_cross_project_subtasks: Allow cross-project subtasks |
448 | 449 |
setting_issue_list_default_columns: Issues list defaults |
... | ... | |
869 | 870 |
label_f_hour: "%{value} hour" |
870 | 871 |
label_f_hour_plural: "%{value} hours" |
871 | 872 |
label_f_hour_short: "%{value} h" |
873 |
label_relative_time: Relative time |
|
874 |
label_relative_time_with_absolute_time: Relative time with absolute time |
|
875 |
label_absolute_time: Absolute time |
|
872 | 876 |
label_time_tracking: Time tracking |
873 | 877 |
label_change_plural: Changes |
874 | 878 |
label_statistics: Statistics |
... | ... | |
929 | 933 |
label_added_time_by: "Added by %{author} %{age} ago" |
930 | 934 |
label_updated_time_by: "Updated by %{author} %{age} ago" |
931 | 935 |
label_updated_time: "Updated %{value} ago" |
936 |
label_added_absolute_time_by: "Added by %{author} %{age}" |
|
937 |
label_updated_absolute_time_by: "Updated by %{author} %{age}" |
|
938 |
label_updated_absolute_time: "Updated %{value}" |
|
932 | 939 |
label_jump_to_a_project: Jump to a project... |
933 | 940 |
label_file_plural: Files |
934 | 941 |
label_changeset_plural: Changesets |
config/locales/ja.yml | ||
---|---|---|
744 | 744 |
label_added_time_by: "%{author} さんが%{age}前に追加" |
745 | 745 |
label_updated_time_by: "%{author} さんが%{age}前に更新" |
746 | 746 |
label_updated_time: "%{value}前に更新" |
747 |
label_added_absolute_time_by: "%{author} さんが%{age}に追加" |
|
748 |
label_updated_absolute_time_by: "%{author} さんが%{age}に更新" |
|
749 |
label_updated_absolute_time: "%{value}に更新" |
|
747 | 750 |
label_jump_to_a_project: プロジェクトへ移動... |
748 | 751 |
label_file_plural: ファイル |
749 | 752 |
label_changeset_plural: 更新履歴 |
config/settings.yml | ||
---|---|---|
171 | 171 |
default: '' |
172 | 172 |
timespan_format: |
173 | 173 |
default: 'minutes' |
174 |
timestamp_format: |
|
175 |
default: 'relative_time' |
|
174 | 176 |
user_format: |
175 | 177 |
default: :firstname_lastname |
176 | 178 |
format: symbol |
lib/redmine/i18n.rb | ||
---|---|---|
87 | 87 |
(include_date ? "#{format_date(local)} " : "") + ::I18n.l(local, **options) |
88 | 88 |
end |
89 | 89 | |
90 |
def format_timestamp(time, timestamp_format=nil) |
|
91 |
case (timestamp_format || Setting.timestamp_format) |
|
92 |
when 'relative_time' |
|
93 |
distance_of_time_in_words(Time.now, time) |
|
94 |
when 'relative_time_with_absolute_time' |
|
95 |
"#{distance_of_time_in_words(Time.now, time)}(#{format_time(time)})" |
|
96 |
when 'absolute_time' |
|
97 |
format_time(time) |
|
98 |
end |
|
99 |
end |
|
100 | ||
101 |
def label_by_timestamp_format(label_name) |
|
102 |
return label_name unless Setting.timestamp_format == 'absolute_time' |
|
103 | ||
104 |
label_name.to_s.gsub('_time', '_absolute_time').to_sym |
|
105 |
end |
|
106 | ||
90 | 107 |
def format_hours(hours) |
91 | 108 |
return "" if hours.blank? |
92 | 109 |
test/helpers/application_helper_test.rb | ||
---|---|---|
1774 | 1774 |
result = render_page_hierarchy(pages_by_parent_id, nil, :timestamp => true) |
1775 | 1775 |
assert_select_in( |
1776 | 1776 |
result, 'ul.pages-hierarchy li a[title=?]', |
1777 |
l(:label_updated_time, |
|
1778 |
distance_of_time_in_words(Time.now, parent_page.updated_on))) |
|
1777 |
l(:label_updated_time, format_timestamp(parent_page.updated_on))) |
|
1779 | 1778 |
assert_select_in( |
1780 | 1779 |
result, 'ul.pages-hierarchy li ul.pages-hierarchy a[title=?]', |
1781 |
l(:label_updated_time, |
|
1782 |
distance_of_time_in_words(Time.now, child_page.updated_on))) |
|
1780 |
l(:label_updated_time, format_timestamp(child_page.updated_on))) |
|
1783 | 1781 |
end |
1784 | 1782 | |
1785 | 1783 |
def test_render_page_hierarchy_when_action_is_export |
test/helpers/settings_helper_test.rb | ||
---|---|---|
29 | 29 |
options = date_format_setting_options('en') |
30 | 30 |
assert_include ["2015-07-14 (yyyy-mm-dd)", "%Y-%m-%d"], options |
31 | 31 |
end |
32 | ||
33 |
def test_timestamp_format_setting_options_should_include_human_readable_format |
|
34 |
sample_time = Time.now.ago(3.days) |
|
35 | ||
36 |
options = timestamp_format_setting_options |
|
37 |
assert_include ["3 days (Relative time)", 'relative_time'], options |
|
38 |
assert_include ["3 days(#{format_time(sample_time)}) (Relative time with absolute time)", 'relative_time_with_absolute_time'], options |
|
39 |
assert_include ["#{format_time(sample_time)} (Absolute time)", 'absolute_time'], options |
|
40 |
end |
|
32 | 41 |
end |
test/unit/lib/redmine/i18n_test.rb | ||
---|---|---|
22 | 22 |
class Redmine::I18nTest < ActiveSupport::TestCase |
23 | 23 |
include Redmine::I18n |
24 | 24 |
include ActionView::Helpers::NumberHelper |
25 |
include ActionView::Helpers::DateHelper |
|
25 | 26 | |
26 | 27 |
def setup |
27 | 28 |
User.current = nil |
... | ... | |
125 | 126 |
end |
126 | 127 |
end |
127 | 128 | |
129 |
def test_format_timestamp |
|
130 |
travel_to Time.utc(2023, 5, 31, 23, 59, 59) # Time.now => 2023/5/31 23:59:59 |
|
131 |
sample_time = Time.utc(2022, 1, 1, 0, 0, 0) |
|
132 | ||
133 |
with_settings :timestamp_format => 'relative_time' do |
|
134 |
assert_equal 'over 1 year', format_timestamp(sample_time) |
|
135 |
end |
|
136 |
with_settings :timestamp_format => 'relative_time_with_absolute_time', :date_format => '%d/%m/%Y', :time_format => '%H:%M' do |
|
137 |
assert_equal 'over 1 year(01/01/2022 00:00)', format_timestamp(sample_time) |
|
138 |
end |
|
139 |
with_settings :timestamp_format => 'absolute_time', :date_format => '%d/%m/%Y', :time_format => '%H:%M' do |
|
140 |
assert_equal '01/01/2022 00:00', format_timestamp(sample_time) |
|
141 |
end |
|
142 | ||
143 |
# If there is an argument, it takes precedence over the set value |
|
144 |
with_settings :timestamp_format => 'absolute_time', :date_format => '%d/%m/%Y', :time_format => '%H:%M' do |
|
145 |
assert_equal 'over 1 year', format_timestamp(sample_time, 'relative_time') |
|
146 |
end |
|
147 |
end |
|
148 | ||
149 |
def test_label_by_timestamp_format |
|
150 |
with_settings :timestamp_format => 'relative_time' do |
|
151 |
assert_equal :label_added_time_by, label_by_timestamp_format(:label_added_time_by) |
|
152 |
assert_equal :label_updated_time_by, label_by_timestamp_format(:label_updated_time_by) |
|
153 |
assert_equal :label_updated_time, label_by_timestamp_format(:label_updated_time) |
|
154 |
end |
|
155 |
with_settings :timestamp_format => 'relative_time_with_absolute_time' do |
|
156 |
assert_equal :label_added_time_by, label_by_timestamp_format(:label_added_time_by) |
|
157 |
assert_equal :label_updated_time_by, label_by_timestamp_format(:label_updated_time_by) |
|
158 |
assert_equal :label_updated_time, label_by_timestamp_format(:label_updated_time) |
|
159 |
end |
|
160 |
with_settings :timestamp_format => 'absolute_time' do |
|
161 |
assert_equal :label_added_absolute_time_by, label_by_timestamp_format(:label_added_time_by) |
|
162 |
assert_equal :label_updated_absolute_time_by, label_by_timestamp_format(:label_updated_time_by) |
|
163 |
assert_equal :label_updated_absolute_time, label_by_timestamp_format(:label_updated_time) |
|
164 |
end |
|
165 |
end |
|
166 | ||
128 | 167 |
def test_number_to_human_size_for_each_language |
129 | 168 |
valid_languages.each do |lang| |
130 | 169 |
set_language_if_valid lang |