Feature: Added support for English am/pm meridian time format.
This commit is contained in:
parent
04ce38a6f8
commit
50e3b98955
14 changed files with 63 additions and 25 deletions
|
@ -348,6 +348,9 @@ class _i18nSingleton extends Spine.Module
|
|||
S = timeObject.getSeconds()
|
||||
M = timeObject.getMinutes()
|
||||
H = timeObject.getHours()
|
||||
l = (H + 11) % 12 + 1
|
||||
l = ' ' + l if l < 10
|
||||
|
||||
format = format
|
||||
.replace(/dd/, @formatNumber(d, 2))
|
||||
.replace(/d/, d)
|
||||
|
@ -358,4 +361,6 @@ class _i18nSingleton extends Spine.Module
|
|||
.replace(/SS/, @formatNumber(S, 2))
|
||||
.replace(/MM/, @formatNumber(M, 2))
|
||||
.replace(/HH/, @formatNumber(H, 2))
|
||||
.replace(/l/, l)
|
||||
.replace(/P/, if H >= 12 then 'pm' else 'am')
|
||||
format
|
||||
|
|
|
@ -164,6 +164,8 @@ or
|
|||
record.sub!('SS', format('%<second>02d', second: timestamp.sec.to_s))
|
||||
record.sub!('MM', format('%<minute>02d', minute: timestamp.min.to_s))
|
||||
record.sub!('HH', format('%<hour>02d', hour: timestamp.hour.to_s))
|
||||
record.sub!('l', timestamp.strftime('%l'))
|
||||
record.sub!('P', timestamp.strftime('%P'))
|
||||
"#{record} (#{timezone})"
|
||||
end
|
||||
|
||||
|
|
|
@ -20,7 +20,9 @@ msgstr ""
|
|||
#. - 'yy' - last 2 digits of year
|
||||
#. - 'SS' - 2-digit second
|
||||
#. - 'MM' - 2-digit minute
|
||||
#. - 'HH' - 2-digit hour
|
||||
#. - 'HH' - 2-digit hour (24h)
|
||||
#. - 'l' - hour (12h)
|
||||
#. - 'P' - Meridian indicator ('am' or 'pm')
|
||||
msgid "FORMAT_DATE"
|
||||
msgstr "mm/dd/yyyy"
|
||||
|
||||
|
@ -34,9 +36,11 @@ msgstr "mm/dd/yyyy"
|
|||
#. - 'yy' - last 2 digits of year
|
||||
#. - 'SS' - 2-digit second
|
||||
#. - 'MM' - 2-digit minute
|
||||
#. - 'HH' - 2-digit hour
|
||||
#. - 'HH' - 2-digit hour (24h)
|
||||
#. - 'l' - hour (12h)
|
||||
#. - 'P' - Meridian indicator ('am' or 'pm')
|
||||
msgid "FORMAT_DATETIME"
|
||||
msgstr "mm/dd/yyyy HH:MM"
|
||||
msgstr "mm/dd/yyyy l:MM P"
|
||||
|
||||
#: db/seeds/settings.rb
|
||||
msgid "\"Database\" stores all attachments in the database (not recommended for storing large amounts of data). \"Filesystem\" stores the data in the filesystem. You can switch between the modules even on a system that is already in production without any loss of data."
|
||||
|
|
|
@ -32,7 +32,9 @@ class Generators::TranslationCatalog::TranslationCatalogGenerator < Rails::Gener
|
|||
#. - 'yy' - last 2 digits of year
|
||||
#. - 'SS' - 2-digit second
|
||||
#. - 'MM' - 2-digit minute
|
||||
#. - 'HH' - 2-digit hour
|
||||
#. - 'HH' - 2-digit hour (24h)
|
||||
#. - 'l' - hour (12h)
|
||||
#. - 'P' - Meridian indicator ('am' or 'pm')
|
||||
LEGEND
|
||||
|
||||
def extract_strings(path)
|
||||
|
@ -91,6 +93,9 @@ class Generators::TranslationCatalog::TranslationCatalogGenerator < Rails::Gener
|
|||
|
||||
POT_HEADER
|
||||
|
||||
# Add the default date/time format strings for 'en_US' as translations to
|
||||
# the source catalog file. They will be read into the Translation model
|
||||
# and can be customized via the translations admin GUI.
|
||||
pot += <<~FORMAT_STRINGS if !options['addon_path']
|
||||
#. Default date format to use for the current locale.
|
||||
#{DATE_FORMAT_LEGEND}
|
||||
|
@ -100,7 +105,7 @@ class Generators::TranslationCatalog::TranslationCatalogGenerator < Rails::Gener
|
|||
#. Default date/time format to use for the current locale.
|
||||
#{DATE_FORMAT_LEGEND}
|
||||
msgid "FORMAT_DATETIME"
|
||||
msgstr "mm/dd/yyyy HH:MM"
|
||||
msgstr "mm/dd/yyyy l:MM P"
|
||||
|
||||
FORMAT_STRINGS
|
||||
|
||||
|
|
|
@ -1362,7 +1362,13 @@ QUnit.test("check replace tags", assert => {
|
|||
yfull = localTime.getFullYear()
|
||||
M = formatNumber(localTime.getMinutes(), 2)
|
||||
H = formatNumber(localTime.getHours(), 2)
|
||||
return m + '/' + d + '/' + yfull + ' ' + H + ':' + M
|
||||
l = (H + 11) % 12 + 1
|
||||
if (l < 10) {
|
||||
l = ' ' + l
|
||||
}
|
||||
P = H >= 12 ? 'pm' : 'am'
|
||||
|
||||
return m + '/' + d + '/' + yfull + ' ' + l + ':' + M + ' ' + P
|
||||
}
|
||||
|
||||
var message = "<div>#{user.firstname} #{user.lastname}</div>"
|
||||
|
|
|
@ -217,8 +217,11 @@ QUnit.test('i18n', assert => {
|
|||
translated = App.i18n.translateContent('Enables user authentication via %s. Register your app first at [%s](%s).', 'XXX', 'YYY', 'http://lalala')
|
||||
assert.equal(translated, 'Enables user authentication via XXX. Register your app first at <a href="http://lalala" target="_blank">YYY</a>.', 'en-us - link')
|
||||
|
||||
timestamp = App.i18n.translateTimestamp('2012-11-06T21:07:24Z', offset)
|
||||
assert.equal(timestamp, '11/06/2012 21:07', 'en - timestamp translated correctly')
|
||||
timestamp = App.i18n.translateTimestamp('2012-11-06T09:07:24Z', offset)
|
||||
assert.equal(timestamp, '11/06/2012 9:07 am', 'en - timestamp translated correctly (pm)')
|
||||
|
||||
timestamp = App.i18n.translateTimestamp('2012-11-06T22:07:24Z', offset)
|
||||
assert.equal(timestamp, '11/06/2012 10:07 pm', 'en - timestamp translated correctly (pm)')
|
||||
|
||||
timestamp = App.i18n.translateTimestamp('', offset);
|
||||
assert.equal(timestamp, '', 'en - timestamp translated correctly')
|
||||
|
@ -242,7 +245,7 @@ QUnit.test('i18n', assert => {
|
|||
assert.equal(date, undefined, 'en - date translated correctly')
|
||||
|
||||
date = App.i18n.timeFormat()
|
||||
assert.deepEqual(date, { "FORMAT_DATE": "mm/dd/yyyy", "FORMAT_DATETIME": "mm/dd/yyyy HH:MM" }, 'timeFormat property')
|
||||
assert.deepEqual(date, { "FORMAT_DATE": "mm/dd/yyyy", "FORMAT_DATETIME": "mm/dd/yyyy l:MM P" }, 'timeFormat property')
|
||||
|
||||
// Verify that the datepicker gets the correct format too.
|
||||
el_date = App.UiElement.date.render({name: 'test', value: '2018-07-06'})
|
||||
|
|
|
@ -54,7 +54,7 @@ QUnit.test( "model ui basic tests", assert => {
|
|||
assert.equal( App.viewPrint( ticket, 'state' ), 'open')
|
||||
assert.equal( App.viewPrint( ticket, 'state_id' ), 'open')
|
||||
assert.equal( App.viewPrint( ticket, 'not_existing' ), '-')
|
||||
assert.equal( App.viewPrint( ticket, 'updated_at' ), '<time class="humanTimeFromNow " datetime="2014-11-07T23:43:08.000Z" title="11/07/2014 23:43">11/07/2014</time>')
|
||||
assert.equal( App.viewPrint( ticket, 'updated_at' ), '<time class="humanTimeFromNow " datetime="2014-11-07T23:43:08.000Z" title="11/07/2014 11:43 pm">11/07/2014</time>')
|
||||
assert.equal( App.viewPrint( ticket, 'date' ), '02/07/2015')
|
||||
assert.equal( App.viewPrint( ticket, 'textarea' ), '<div>some new</div><div>line</div>')
|
||||
assert.equal( App.viewPrint( ticket, 'link1' ), '<a href="http://zammad.com" target="blank">closed</a>')
|
||||
|
@ -65,7 +65,7 @@ QUnit.test( "model ui basic tests", assert => {
|
|||
let attr = App.Ticket.configure_attributes.find(e => { return e.name == 'updated_at' })
|
||||
attr.include_timezone = true
|
||||
|
||||
assert.equal( App.viewPrint( ticket, 'updated_at' ), '<time class="humanTimeFromNow " datetime="2014-11-07T23:43:08.000Z" title="11/07/2014 23:43 Example/Timezone" timezone="Example/Timezone">11/07/2014</time>')
|
||||
assert.equal( App.viewPrint( ticket, 'updated_at' ), '<time class="humanTimeFromNow " datetime="2014-11-07T23:43:08.000Z" title="11/07/2014 11:43 pm Example/Timezone" timezone="Example/Timezone">11/07/2014</time>')
|
||||
|
||||
attr.include_timezone = false
|
||||
stub.restore()
|
||||
|
|
|
@ -362,9 +362,14 @@ QUnit.test("check pretty date", assert => {
|
|||
yshort = date.getYear()-100
|
||||
M = date.getMinutes()
|
||||
H = date.getHours()
|
||||
l = (H + 11) % 12 + 1
|
||||
if (l < 10) {
|
||||
l = ' ' + l
|
||||
}
|
||||
P = H >= 12 ? 'pm' : 'am'
|
||||
|
||||
// YYYY-MM-DD HH::MM
|
||||
return (m < 10 ? '0':'') + m + '/' + (d < 10 ? '0':'') + d + '/' + (yfull) + ' ' + (H < 10 ? '0':'') + H + ':' + (M < 10 ? '0':'') + M
|
||||
return (m < 10 ? '0':'') + m + '/' + (d < 10 ? '0':'') + d + '/' + (yfull) + ' ' + l + ':' + (M < 10 ? '0':'') + M + ' ' + P
|
||||
}
|
||||
|
||||
});
|
||||
|
|
|
@ -60,7 +60,7 @@ RSpec.describe NotificationFactory::Slack do
|
|||
.to match(%r{Updated by #{current_user.fullname}})
|
||||
.and match(%r{state: aaa -> bbb})
|
||||
.and match(%r{group: xxx -> yyy})
|
||||
.and match(%r{pending_time: 04/01/2019 12:00 \(Europe/Berlin\) -> 04/02/2019 01:00 \(Europe/Berlin\)})
|
||||
.and match(%r{pending_time: 04/01/2019 12:00 pm \(Europe/Berlin\) -> 04/02/2019 1:00 am \(Europe/Berlin\)})
|
||||
.and match(%r{#{article.body}\z})
|
||||
end
|
||||
end
|
||||
|
@ -90,7 +90,7 @@ RSpec.describe NotificationFactory::Slack do
|
|||
it 'returns a hash with body: <ticket customer, escalation time, & body>' do
|
||||
expect(template[:body])
|
||||
.to match(%r{A ticket \(#{ticket.title}\) from "#{ticket.customer.fullname}"})
|
||||
.and match(%r{is escalated since "04/01/2019 12:00 \(Europe/Berlin\)"!})
|
||||
.and match(%r{is escalated since "04/01/2019 12:00 pm \(Europe/Berlin\)"!})
|
||||
.and match(%r{#{article.body}\z})
|
||||
end
|
||||
end
|
||||
|
|
|
@ -56,7 +56,7 @@ RSpec.describe Translation do
|
|||
end
|
||||
|
||||
it 'contains the translation for "FORMAT_DATE_TIME"' do
|
||||
expect(described_class.strings_for_locale('en-us')['FORMAT_DATETIME']).to have_attributes(translation: 'mm/dd/yyyy HH:MM', translation_file: 'i18n/zammad.pot')
|
||||
expect(described_class.strings_for_locale('en-us')['FORMAT_DATETIME']).to have_attributes(translation: 'mm/dd/yyyy l:MM P', translation_file: 'i18n/zammad.pot')
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -210,7 +210,7 @@ RSpec.describe Translation do
|
|||
end
|
||||
|
||||
it 'adds the en-us FORMAT_DATETIME entry' do
|
||||
expect(described_class.find_source('en-us', 'FORMAT_DATETIME')).to have_attributes(is_synchronized_from_codebase: true, synchronized_from_translation_file: 'i18n/zammad.pot', target: 'mm/dd/yyyy HH:MM')
|
||||
expect(described_class.find_source('en-us', 'FORMAT_DATETIME')).to have_attributes(is_synchronized_from_codebase: true, synchronized_from_translation_file: 'i18n/zammad.pot', target: 'mm/dd/yyyy l:MM P')
|
||||
end
|
||||
|
||||
it 'adds the custom translated entry with content' do
|
||||
|
|
|
@ -69,12 +69,20 @@ RSpec.describe Translation do
|
|||
expect(described_class.timestamp('en-us', 'Invalid/TimeZone', '2018-10-10T10:00:00Z0')).to eq(Time.zone.parse('2018-10-10T10:00:00Z0').to_s)
|
||||
end
|
||||
|
||||
it 'en-us with timestamp as string' do
|
||||
expect(described_class.timestamp('en-us', 'Europe/Berlin', '2018-10-10T10:00:00Z0')).to eq('10/10/2018 12:00 (Europe/Berlin)')
|
||||
it 'en-us with timestamp as string (am)' do
|
||||
expect(described_class.timestamp('en-us', 'Europe/Berlin', '2018-10-10T01:00:00Z0')).to eq('10/10/2018 3:00 am (Europe/Berlin)')
|
||||
end
|
||||
|
||||
it 'en-us with time object' do
|
||||
expect(described_class.timestamp('en-us', 'Europe/Berlin', Time.zone.parse('2018-10-10T10:00:00Z0'))).to eq('10/10/2018 12:00 (Europe/Berlin)')
|
||||
it 'en-us with timestamp as string (pm)' do
|
||||
expect(described_class.timestamp('en-us', 'Europe/Berlin', '2018-10-10T10:00:00Z0')).to eq('10/10/2018 12:00 pm (Europe/Berlin)')
|
||||
end
|
||||
|
||||
it 'en-us with time object (am)' do
|
||||
expect(described_class.timestamp('en-us', 'Europe/Berlin', Time.zone.parse('2018-10-10T01:00:00Z0'))).to eq('10/10/2018 3:00 am (Europe/Berlin)')
|
||||
end
|
||||
|
||||
it 'en-us with time object (pm)' do
|
||||
expect(described_class.timestamp('en-us', 'Europe/Berlin', Time.zone.parse('2018-10-10T10:00:00Z0'))).to eq('10/10/2018 12:00 pm (Europe/Berlin)')
|
||||
end
|
||||
|
||||
it 'de-de with timestamp as string' do
|
||||
|
|
|
@ -375,7 +375,7 @@ RSpec.describe 'Ticket > Update > Full Quote Header', current_user_id: -> { curr
|
|||
expected
|
||||
.created_at
|
||||
.in_time_zone('Europe/London')
|
||||
.strftime('%m/%d/%Y %H:%M')
|
||||
.strftime('%m/%d/%Y %1I:%M %P')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -58,7 +58,7 @@ class NotificationFactoryRendererTest < ActiveSupport::TestCase
|
|||
timezone: 'Europe/Berlin',
|
||||
template: template,
|
||||
).render
|
||||
assert_equal('11/12/2016 13:00 (Europe/Berlin)', result)
|
||||
assert_equal('11/12/2016 1:00 pm (Europe/Berlin)', result)
|
||||
|
||||
template = "\#{ticket.created_by.firstname}"
|
||||
result = described_class.new(
|
||||
|
@ -80,7 +80,7 @@ class NotificationFactoryRendererTest < ActiveSupport::TestCase
|
|||
timezone: 'Europe/Berlin',
|
||||
template: template,
|
||||
).render
|
||||
assert_equal('11/12/2016 15:00 (Europe/Berlin)', result)
|
||||
assert_equal('11/12/2016 3:00 pm (Europe/Berlin)', result)
|
||||
|
||||
template = "\#{ticket.updated_by.firstname}"
|
||||
result = described_class.new(
|
||||
|
|
|
@ -1194,7 +1194,7 @@ class TicketNotificationTest < ActiveSupport::TestCase
|
|||
assert_match(%r{1 low}, result[:body])
|
||||
assert_match(%r{2 normal}, result[:body])
|
||||
assert_match(%r{Pending till}, result[:body])
|
||||
assert_match('01/11/2015 19:33 (America/St_Lucia)', result[:body])
|
||||
assert_match('01/11/2015 7:33 pm (America/St_Lucia)', result[:body])
|
||||
assert_match(%r{update}, result[:body])
|
||||
assert_no_match(%r{pending_till}, result[:body])
|
||||
assert_no_match(%r{i18n}, result[:body])
|
||||
|
@ -1322,7 +1322,7 @@ class TicketNotificationTest < ActiveSupport::TestCase
|
|||
)
|
||||
|
||||
assert_match('Ticket is escalated (some notification template test 1 Bobs\'s resumé', result[:subject])
|
||||
assert_match('is escalated since "04/01/2019 06:00 (America/St_Lucia)"!', result[:body])
|
||||
assert_match('is escalated since "04/01/2019 6:00 am (America/St_Lucia)"!', result[:body])
|
||||
|
||||
end
|
||||
|
||||
|
|
Loading…
Reference in a new issue