aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--Gemfile1
-rw-r--r--Gemfile.lock3
-rw-r--r--app/assets/javascripts/application.js3
-rw-r--r--app/assets/javascripts/i18n/extended.coffee24
-rw-r--r--app/assets/stylesheets/components/_tables.sass21
-rw-r--r--app/javascript/vehicle_journeys/components/ConfirmModal.js6
-rw-r--r--app/javascript/vehicle_journeys/components/Filters.js18
-rw-r--r--app/javascript/vehicle_journeys/components/Navigate.js5
-rw-r--r--app/javascript/vehicle_journeys/components/ToggleArrivals.js2
-rw-r--r--app/javascript/vehicle_journeys/components/Tools.js4
-rw-r--r--app/javascript/vehicle_journeys/components/VehicleJourney.js10
-rw-r--r--app/javascript/vehicle_journeys/components/VehicleJourneys.js18
-rw-r--r--app/javascript/vehicle_journeys/components/tools/EditVehicleJourney.js20
-rw-r--r--app/javascript/vehicle_journeys/components/tools/VehicleJourneyInfoButton.js4
-rw-r--r--app/views/calendars/_form_advanced.html.slim2
-rw-r--r--app/views/layouts/application.html.slim2
-rw-r--r--app/views/routes/_form.html.slim2
-rw-r--r--app/views/time_tables/edit.html.slim2
-rw-r--r--app/views/time_tables/index.html.slim2
-rw-r--r--app/views/vehicle_journeys/index.html.slim2
-rw-r--r--app/views/workbenches/show.html.slim2
-rw-r--r--config/deploy.rb2
-rw-r--r--config/environments/development.rb1
-rw-r--r--config/locales/en.yml5
-rw-r--r--config/locales/fr.yml4
-rw-r--r--config/locales/vehicle_journeys.en.yml120
-rw-r--r--config/locales/vehicle_journeys.fr.yml121
-rw-r--r--lib/tasks/ci.rake13
-rw-r--r--package.json4
-rw-r--r--spec/javascript/preprocessor.js15
-rw-r--r--spec/javascript/vehicle_journeys/components/VehicleJourneys_spec.js7
-rw-r--r--spec/javascript/vehicle_journeys/components/__snapshots__/VehicleJourneys_spec.js.snap20
33 files changed, 303 insertions, 164 deletions
diff --git a/.gitignore b/.gitignore
index acdb5e230..dd4d057ef 100644
--- a/.gitignore
+++ b/.gitignore
@@ -15,6 +15,8 @@
/tmp
*~
public/assets/
+public/javascripts/i18n.js
+public/javascripts/translations.js
# for vim users
*.swp
diff --git a/Gemfile b/Gemfile
index 9103c5a51..e886d1c3b 100644
--- a/Gemfile
+++ b/Gemfile
@@ -103,6 +103,7 @@ gem 'will_paginate-bootstrap'
gem 'gretel'
gem 'country_select'
gem 'flag-icons-rails'
+gem 'i18n-js'
# Format Output
gem 'json'
diff --git a/Gemfile.lock b/Gemfile.lock
index 2988f6e8f..046167e69 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -271,6 +271,8 @@ GEM
multi_xml (>= 0.5.2)
i18n (0.9.4)
concurrent-ruby (~> 1.0)
+ i18n-js (3.0.4)
+ i18n (~> 0.6, >= 0.6.6)
i18n-tasks (0.9.15)
activesupport (>= 4.0.2)
ast (>= 2.1.0)
@@ -644,6 +646,7 @@ DEPENDENCIES
gretel
has_array_of!
htmlbeautifier
+ i18n-js
i18n-tasks
inherited_resources
jbuilder (~> 2.0)
diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js
index 4c5aff22f..6a79f7e8e 100644
--- a/app/assets/javascripts/application.js
+++ b/app/assets/javascripts/application.js
@@ -22,3 +22,6 @@
//= require_directory .
// require('whatwg-fetch')
// require('babel-polyfill')
+//= require "i18n"
+//= require "i18n/extended"
+//= require "i18n/translations"
diff --git a/app/assets/javascripts/i18n/extended.coffee b/app/assets/javascripts/i18n/extended.coffee
new file mode 100644
index 000000000..aeb67bd09
--- /dev/null
+++ b/app/assets/javascripts/i18n/extended.coffee
@@ -0,0 +1,24 @@
+#= require i18n
+
+decorateI18n = (_i18n)->
+ _i18n.tc = (key, opts={}) ->
+ out = _i18n.t(key, opts)
+ out += " " if _i18n.locale == "fr"
+ out + ":"
+
+ _i18n.model_name = (model, opts={}) ->
+ last_key = if opts.plural then "other" else "one"
+ _i18n.t("activerecord.models.#{model}.#{last_key}")
+
+ _i18n.attribute_name = (model, attribute, opts={}) ->
+ _i18n.t("activerecord.attributes.#{model}.#{attribute}")
+
+ _i18n.enumerize = (enumerize, key, opts={}) ->
+ I18n.t("enumerize.#{enumerize}.#{key}")
+
+ _i18n
+
+module?.exports = decorateI18n
+
+if I18n?
+ decorateI18n(I18n)
diff --git a/app/assets/stylesheets/components/_tables.sass b/app/assets/stylesheets/components/_tables.sass
index 35e1122f3..1e02ad586 100644
--- a/app/assets/stylesheets/components/_tables.sass
+++ b/app/assets/stylesheets/components/_tables.sass
@@ -9,7 +9,6 @@
font-weight: 700
border-bottom: 2px solid $darkgrey
vertical-align: middle
-
> a
position: relative
display: block
@@ -326,6 +325,26 @@
padding: 6px 8px
border-bottom: 2px solid rgba($grey, 0.5)
border-top: 1px solid rgba($grey, 0.5)
+ text-transform: capitalize
+
+ .info-button
+ position: absolute
+ width: 20px
+ height: 20px
+ top: 0
+ right: 0
+ margin: 6px 8px
+ button
+ border: none
+ background: $blue
+ border-radius: 20px
+ width: 100%
+ height: 100%
+ font-size: 12px
+ line-height: 14px
+ color: white
+ outline: none
+
.td
position: relative
padding: 6px 8px
diff --git a/app/javascript/vehicle_journeys/components/ConfirmModal.js b/app/javascript/vehicle_journeys/components/ConfirmModal.js
index 3bfc852fb..75e8a3932 100644
--- a/app/javascript/vehicle_journeys/components/ConfirmModal.js
+++ b/app/javascript/vehicle_journeys/components/ConfirmModal.js
@@ -7,7 +7,7 @@ export default function ConfirmModal({dispatch, modal, onModalAccept, onModalCan
<div className='modal-dialog'>
<div className='modal-content'>
<div className='modal-body'>
- <p> Voulez-vous valider vos modifications avant de changer de page? </p>
+ <p> {I18n.t('vehicle_journeys.vehicle_journeys_matrix.modal_confirm')} </p>
</div>
<div className='modal-footer'>
<button
@@ -31,11 +31,11 @@ export default function ConfirmModal({dispatch, modal, onModalAccept, onModalCan
</div>
</div>
)
-}
+}
ConfirmModal.propTypes = {
vehicleJourneys: PropTypes.array.isRequired,
modal: PropTypes.object.isRequired,
onModalAccept: PropTypes.func.isRequired,
onModalCancel: PropTypes.func.isRequired
-} \ No newline at end of file
+}
diff --git a/app/javascript/vehicle_journeys/components/Filters.js b/app/javascript/vehicle_journeys/components/Filters.js
index 2bd912e3e..f8697c930 100644
--- a/app/javascript/vehicle_journeys/components/Filters.js
+++ b/app/javascript/vehicle_journeys/components/Filters.js
@@ -46,10 +46,10 @@ export default function Filters({filters, pagination, missions, onFilter, onRese
<div className='ffg-row'>
{/* Plage horaire */}
<div className='form-group togglable'>
- <label className='control-label'>Plage horaire au départ de la course</label>
+ <label className='control-label'>{I18n.t("vehicle_journeys.form.departure_range.label")}</label>
<div className='filter_menu'>
<div className='form-group time filter_menu-item'>
- <label className='control-label time'>Début</label>
+ <label className='control-label time'>{I18n.t("vehicle_journeys.form.departure_range.start")}</label>
<div className='form-inline'>
<div className='input-group time'>
<input
@@ -73,7 +73,7 @@ export default function Filters({filters, pagination, missions, onFilter, onRese
</div>
</div>
<div className='form-group time filter_menu-item'>
- <label className='control-label time'>Fin</label>
+ <label className='control-label time'>{I18n.t("vehicle_journeys.form.departure_range.end")}</label>
<div className='form-inline'>
<div className='input-group time'>
<input
@@ -101,7 +101,7 @@ export default function Filters({filters, pagination, missions, onFilter, onRese
{/* Switch avec/sans horaires */}
<div className='form-group has_switch'>
- <label className='control-label pull-left'>Afficher les courses sans horaires</label>
+ <label className='control-label pull-left'>{I18n.t("vehicle_journeys.form.show_journeys_without_schedule")}</label>
<div className='form-group pull-left' style={{padding: 0}}>
<div className='checkbox'>
<label>
@@ -110,8 +110,8 @@ export default function Filters({filters, pagination, missions, onFilter, onRese
onChange={onToggleWithoutSchedule}
checked={filters.query.withoutSchedule}
></input>
- <span className='switch-label' data-checkedvalue='Non' data-uncheckedvalue='Oui'>
- {filters.query.withoutSchedule ? 'Oui' : 'Non'}
+ <span className='switch-label' data-checkedvalue={I18n.t("no")} data-uncheckedvalue={I18n.t("yes")}>
+ {filters.query.withoutSchedule ? I18n.t("yes") : I18n.t("no")}
</span>
</label>
</div>
@@ -122,7 +122,7 @@ export default function Filters({filters, pagination, missions, onFilter, onRese
<div className="ffg-row">
{/* Switch avec/sans calendrier */}
<div className='form-group has_switch'>
- <label className='control-label pull-left'>Afficher les courses avec calendrier</label>
+ <label className='control-label pull-left'>{I18n.t("vehicle_journeys.form.show_journeys_with_calendar")}</label>
<div className='form-group pull-left' style={{padding: 0}}>
<div className='checkbox'>
<label>
@@ -131,8 +131,8 @@ export default function Filters({filters, pagination, missions, onFilter, onRese
onChange={onToggleWithoutTimeTable}
checked={filters.query.withoutTimeTable}
></input>
- <span className='switch-label' data-checkedvalue='Non' data-uncheckedvalue='Oui'>
- {filters.query.withoutTimeTable ? 'Oui' : 'Non'}
+ <span className='switch-label' data-checkedvalue={I18n.t("no")} data-uncheckedvalue={I18n.t("yes")}>
+ {filters.query.withoutTimeTable ? I18n.t("yes") : I18n.t("no")}
</span>
</label>
</div>
diff --git a/app/javascript/vehicle_journeys/components/Navigate.js b/app/javascript/vehicle_journeys/components/Navigate.js
index 0158b8392..24843babc 100644
--- a/app/javascript/vehicle_journeys/components/Navigate.js
+++ b/app/javascript/vehicle_journeys/components/Navigate.js
@@ -17,8 +17,7 @@ export default function Navigate({ dispatch, vehicleJourneys, pagination, status
if(status.fetchSuccess == true) {
return (
<div className="pagination">
- Liste des horaires {minVJ} à {maxVJ} sur {pagination.totalCount}
-
+ {I18n.t("vehicle_journeys.vehicle_journeys_matrix.pagination", {minVJ, maxVJ, total:pagination.totalCount})}
<form className='page_links' onSubmit={e => {e.preventDefault()}}>
<button
onClick={e => {
@@ -53,4 +52,4 @@ Navigate.propTypes = {
status: PropTypes.object.isRequired,
pagination: PropTypes.object.isRequired,
dispatch: PropTypes.func.isRequired
-} \ No newline at end of file
+}
diff --git a/app/javascript/vehicle_journeys/components/ToggleArrivals.js b/app/javascript/vehicle_journeys/components/ToggleArrivals.js
index 9e7089be5..9a2b0097f 100644
--- a/app/javascript/vehicle_journeys/components/ToggleArrivals.js
+++ b/app/javascript/vehicle_journeys/components/ToggleArrivals.js
@@ -5,7 +5,7 @@ import PropTypes from 'prop-types'
export default function ToggleArrivals({filters, onToggleArrivals}) {
return (
<div className='has_switch form-group inline'>
- <label htmlFor='toggleArrivals' className='control-label'>Afficher et éditer les horaires d'arrivée</label>
+ <label htmlFor='toggleArrivals' className='control-label'>{I18n.t('vehicle_journeys.form.show_arrival_time')}</label>
<div className='form-group'>
<div className='checkbox'>
<label>
diff --git a/app/javascript/vehicle_journeys/components/Tools.js b/app/javascript/vehicle_journeys/components/Tools.js
index ee02e5a68..22ea44283 100644
--- a/app/javascript/vehicle_journeys/components/Tools.js
+++ b/app/javascript/vehicle_journeys/components/Tools.js
@@ -44,8 +44,8 @@ export default class Tools extends Component {
<DeleteVehicleJourneys disabled={!this.hasPolicy("destroy") || !editMode}/>
</ul>
- <span className='info-msg'>{actions.getSelected(vehicleJourneys).length} course(s) sélectionnée(s)</span>
- <button className='btn btn-xs btn-link pull-right' onClick={onCancelSelection}>Annuler la sélection</button>
+ <span className='info-msg'>{I18n.t('vehicle_journeys.vehicle_journeys_matrix.selected_journeys', {count: actions.getSelected(vehicleJourneys).length})}</span>
+ <button className='btn btn-xs btn-link pull-right' onClick={onCancelSelection}>{I18n.t('vehicle_journeys.vehicle_journeys_matrix.cancel_selection')}</button>
</div>
)
}
diff --git a/app/javascript/vehicle_journeys/components/VehicleJourney.js b/app/javascript/vehicle_journeys/components/VehicleJourney.js
index 99a458f50..4a9432231 100644
--- a/app/javascript/vehicle_journeys/components/VehicleJourney.js
+++ b/app/javascript/vehicle_journeys/components/VehicleJourney.js
@@ -23,7 +23,7 @@ export default class VehicleJourney extends Component {
let ttURL = refURL + '/time_tables/' + tt.id
return (
- <a href={ttURL} title='Voir le calendrier'><span className='fa fa-calendar' style={{ color: (tt.color ? tt.color : '#4B4B4B')}}></span></a>
+ <a href={ttURL} title={I18n.t('vehicle_journeys.vehicle_journeys_matrix.show_timetable')}><span className='fa fa-calendar' style={{ color: (tt.color ? tt.color : '#4B4B4B')}}></span></a>
)
}
@@ -32,7 +32,7 @@ export default class VehicleJourney extends Component {
let ttURL = refURL + '/purchase_windows/' + tt.id
return (
- <a href={ttURL} title='Voir le calendrier commercial'><span className='fa fa-calendar' style={{color: (tt.color ? tt.color : '')}}></span></a>
+ <a href={ttURL} title={I18n.t('vehicle_journeys.vehicle_journeys_matrix.show_purchase_window')}><span className='fa fa-calendar' style={{color: (tt.color ? tt.color : '')}}></span></a>
)
}
@@ -65,7 +65,7 @@ export default class VehicleJourney extends Component {
}
>
<div className='strong mb-xs'>{this.props.value.short_id || '-'}</div>
- <div>{this.props.value.published_journey_name && this.props.value.published_journey_name != "non renseigné" ? this.props.value.published_journey_name : '-'}</div>
+ <div>{this.props.value.published_journey_name && this.props.value.published_journey_name != I18n.t('undefined') ? this.props.value.published_journey_name : '-'}</div>
<div>{this.props.value.journey_pattern.short_id || '-'}</div>
<div>{this.props.value.company ? this.props.value.company.name : '-'}</div>
<div>
@@ -100,7 +100,7 @@ export default class VehicleJourney extends Component {
<div key={i} className='td text-center'>
<div className={'cellwrap' + (this.cityNameChecker(vj) ? ' headlined' : '')}>
{this.props.filters.toggleArrivals &&
- <div data-headline='Arrivée à'>
+ <div data-headline={I18n.t("vehicle_journeys.form.arrival_at")}>
<span className={((this.isDisabled(this.props.value.deletable, vj.dummy) || this.props.filters.policy['vehicle_journeys.update'] == false) ? 'disabled ' : '') + 'input-group time'}>
<input
type='number'
@@ -131,7 +131,7 @@ export default class VehicleJourney extends Component {
<span className='sb sb-chrono sb-lg text-warning' data-textinside={vj.delta}></span>
}
</div>
- <div data-headline='Départ à'>
+ <div data-headline={I18n.t("vehicle_journeys.form.departure_at")}>
<span className={((this.isDisabled(this.props.value.deletable, vj.dummy) || this.props.filters.policy['vehicle_journeys.update'] == false) ? 'disabled ' : '') + 'input-group time'}>
<input
type='number'
diff --git a/app/javascript/vehicle_journeys/components/VehicleJourneys.js b/app/javascript/vehicle_journeys/components/VehicleJourneys.js
index ae852b35a..01e07ee0c 100644
--- a/app/javascript/vehicle_journeys/components/VehicleJourneys.js
+++ b/app/javascript/vehicle_journeys/components/VehicleJourneys.js
@@ -106,14 +106,14 @@ export default class VehicleJourneys extends Component {
<div className='col-lg-12'>
{(this.props.status.fetchSuccess == false) && (
<div className='alert alert-danger mt-sm'>
- <strong>Erreur : </strong>
- la récupération des missions a rencontré un problème. Rechargez la page pour tenter de corriger le problème.
+ <strong>{I18n.tc("error")}</strong>
+ {I18n.t("vehicle_journeys.vehicle_journeys_matrix.fetching_error")}
</div>
)}
{ this.vehicleJourneysList().errors && this.vehicleJourneysList().errors.length && _.some(this.vehicleJourneysList(), 'errors') && (
<div className="alert alert-danger mt-sm">
- <strong>Erreur : </strong>
+ <strong>{I18n.tc("error")}</strong>
{this.vehicleJourneysList().map((vj, index) =>
vj.errors && vj.errors.map((err, i) => {
return (
@@ -129,12 +129,12 @@ export default class VehicleJourneys extends Component {
<div className={'table table-2entries mt-sm mb-sm' + ((this.vehicleJourneysList().length > 0) ? '' : ' no_result')}>
<div className='t2e-head w20'>
<div className='th'>
- <div className='strong mb-xs'>ID course</div>
- <div>Nom course</div>
- <div>ID mission</div>
- <div>Transporteur</div>
- <div>Calendriers</div>
- { this.hasFeature('purchase_windows') && <div>Calendriers Commerciaux</div> }
+ <div className='strong mb-xs'>{I18n.attribute_name("vehicle_journey", "id")}</div>
+ <div>{I18n.attribute_name("vehicle_journey", "name")}</div>
+ <div>{I18n.attribute_name("vehicle_journey", "journey_pattern_id")}</div>
+ <div>{I18n.model_name("company")}</div>
+ <div>{I18n.model_name("time_table", "plural": true)}</div>
+ { this.hasFeature('purchase_windows') && <div>{I18n.model_name("purchase_window", "plural": true)}</div> }
</div>
{this.stopPoints().map((sp, i) =>{
return (
diff --git a/app/javascript/vehicle_journeys/components/tools/EditVehicleJourney.js b/app/javascript/vehicle_journeys/components/tools/EditVehicleJourney.js
index f6a0e3c61..d3c01f154 100644
--- a/app/javascript/vehicle_journeys/components/tools/EditVehicleJourney.js
+++ b/app/javascript/vehicle_journeys/components/tools/EditVehicleJourney.js
@@ -59,7 +59,7 @@ export default class EditVehicleJourney extends Component {
<div className='modal-dialog'>
<div className='modal-content'>
<div className='modal-header'>
- <h4 className='modal-title'>Informations</h4>
+ <h4 className='modal-title'>{I18n.t('vehicle_journeys.form.infos')}</h4>
<span type="button" className="close modal-close" data-dismiss="modal">&times;</span>
</div>
@@ -69,7 +69,7 @@ export default class EditVehicleJourney extends Component {
<div className='row'>
<div className='col-lg-6 col-md-6 col-sm-6 col-xs-12'>
<div className='form-group'>
- <label className='control-label'>Nom de la course</label>
+ <label className='control-label'>{I18n.attribute_name('vehicle_journey', 'journey_name')}</label>
<input
type='text'
ref='published_journey_name'
@@ -82,7 +82,7 @@ export default class EditVehicleJourney extends Component {
</div>
<div className='col-lg-6 col-md-6 col-sm-6 col-xs-12'>
<div className='form-group'>
- <label className='control-label'>Mission</label>
+ <label className='control-label'>{I18n.attribute_name('vehicle_journey', 'journey_pattern')}</label>
<input
type='text'
className='form-control'
@@ -96,7 +96,7 @@ export default class EditVehicleJourney extends Component {
<div className='row'>
<div className='col-lg-6 col-md-6 col-sm-6 col-xs-12'>
<div className='form-group'>
- <label className='control-label'>Numéro de train</label>
+ <label className='control-label'>{I18n.attribute_name('vehicle_journey', 'company')}</label>
<input
type='text'
ref='published_journey_identifier'
@@ -109,7 +109,7 @@ export default class EditVehicleJourney extends Component {
</div>
<div className='col-lg-6 col-md-6 col-sm-6 col-xs-12'>
<div className='form-group'>
- <label className='control-label'>Transporteur</label>
+ <label className='control-label'>{I18n.attribute_name('vehicle_journey', 'company')}</label>
<CompanySelect2
editModal={this.props.modal.type == "edit"}
editMode={this.editMode()}
@@ -124,29 +124,29 @@ export default class EditVehicleJourney extends Component {
<div className='row'>
<div className='col-lg-6 col-md-6 col-sm-6 col-xs-12'>
<div className='form-group'>
- <label className='control-label'>Mode de transport</label>
+ <label className='control-label'>{I18n.attribute_name('vehicle_journey', 'transport_mode')}</label>
<input
type='text'
className='form-control'
- value={window.I18n.fr.enumerize.transport_mode[this.props.modal.modalProps.vehicleJourney.transport_mode]}
+ value={I18n.enumerize('transport_mode', this.props.modal.modalProps.vehicleJourney.transport_mode)}
disabled={true}
/>
</div>
</div>
<div className='col-lg-6 col-md-6 col-sm-6 col-xs-12'>
<div className='form-group'>
- <label className='control-label'>Sous mode de transport</label>
+ <label className='control-label'>{I18n.attribute_name('vehicle_journey', 'transport_submode')}</label>
<input
type='text'
className='form-control'
- value={window.I18n.fr.enumerize.transport_submode[this.props.modal.modalProps.vehicleJourney.transport_submode]}
+ value={I18n.enumerize('transport_submode', this.props.modal.modalProps.vehicleJourney.transport_submode)}
disabled={true}
/>
</div>
</div>
</div>
<div className='form-group'>
- <label className='control-label'>Signature métier</label>
+ <label className='control-label'>{I18n.attribute_name('vehicle_journey', 'checksum')}</label>
<input
type='text'
ref='checksum'
diff --git a/app/javascript/vehicle_journeys/components/tools/VehicleJourneyInfoButton.js b/app/javascript/vehicle_journeys/components/tools/VehicleJourneyInfoButton.js
index a63a1d701..538bbdbd6 100644
--- a/app/javascript/vehicle_journeys/components/tools/VehicleJourneyInfoButton.js
+++ b/app/javascript/vehicle_journeys/components/tools/VehicleJourneyInfoButton.js
@@ -10,7 +10,7 @@ export default class VehicleJourneyInfoButton extends Component {
render() {
return (
- <li className='st_action'>
+ <div className='info-button'>
<button
type='button'
data-toggle='modal'
@@ -19,7 +19,7 @@ export default class VehicleJourneyInfoButton extends Component {
>
<span className='fa fa-info'></span>
</button>
- </li>
+ </div>
)
}
}
diff --git a/app/views/calendars/_form_advanced.html.slim b/app/views/calendars/_form_advanced.html.slim
index b4154166b..e796e2e36 100644
--- a/app/views/calendars/_form_advanced.html.slim
+++ b/app/views/calendars/_form_advanced.html.slim
@@ -2,7 +2,7 @@
= javascript_tag do
| window.actionType = "#{raw params[:action]}";
- | window.I18n = #{(I18n.backend.send(:translations)[I18n.locale].to_json).html_safe};
+ // | window.I18n = #{(I18n.backend.send(:translations)[I18n.locale].to_json).html_safe};
| window.timetablesUrl = "#{calendar_url(@calendar).html_safe}";
= javascript_pack_tag 'calendars/edit.js'
diff --git a/app/views/layouts/application.html.slim b/app/views/layouts/application.html.slim
index 34b373295..3921c8701 100644
--- a/app/views/layouts/application.html.slim
+++ b/app/views/layouts/application.html.slim
@@ -13,6 +13,8 @@ html lang=I18n.locale
= javascript_pack_tag 'application'
= javascript_include_tag 'application'
+ = javascript_tag do
+ | I18n.locale = '#{I18n.locale}'
body
= render 'layouts/navigation/main_nav'
diff --git a/app/views/routes/_form.html.slim b/app/views/routes/_form.html.slim
index 29e5be3d2..81f719437 100644
--- a/app/views/routes/_form.html.slim
+++ b/app/views/routes/_form.html.slim
@@ -27,7 +27,7 @@
// Get JSON data for route stop points
= javascript_tag do
| window.itinerary_stop = "#{URI.escape(route_json_for_edit(@route))}";
- | window.I18n = #{(I18n.backend.send(:translations)[I18n.locale].to_json).html_safe};
+ // | window.I18n = #{(I18n.backend.send(:translations)[I18n.locale].to_json).html_safe};
/ StopPoints Reactux component
= javascript_pack_tag 'routes/edit.js'
diff --git a/app/views/time_tables/edit.html.slim b/app/views/time_tables/edit.html.slim
index e1c566ff4..d8cffb1b0 100644
--- a/app/views/time_tables/edit.html.slim
+++ b/app/views/time_tables/edit.html.slim
@@ -8,6 +8,6 @@
= javascript_tag do
| window.actionType = "#{raw params[:action]}";
- | window.I18n = #{(I18n.backend.send(:translations)[I18n.locale].to_json).html_safe};
+ // | window.I18n = #{(I18n.backend.send(:translations)[I18n.locale].to_json).html_safe};
= javascript_pack_tag 'time_tables/edit.js'
diff --git a/app/views/time_tables/index.html.slim b/app/views/time_tables/index.html.slim
index f58fbb5ea..6913712a0 100644
--- a/app/views/time_tables/index.html.slim
+++ b/app/views/time_tables/index.html.slim
@@ -61,6 +61,6 @@
= replacement_msg t('time_tables.search_no_results')
= javascript_tag do
- | window.I18n = #{(I18n.backend.send(:translations).to_json).html_safe};
+ // | window.I18n = #{(I18n.backend.send(:translations).to_json).html_safe};
= javascript_pack_tag 'date_filters'
diff --git a/app/views/vehicle_journeys/index.html.slim b/app/views/vehicle_journeys/index.html.slim
index caa8450a0..d53d8b50c 100644
--- a/app/views/vehicle_journeys/index.html.slim
+++ b/app/views/vehicle_journeys/index.html.slim
@@ -29,7 +29,7 @@
| window.features = #{raw @features};
| window.all_missions = #{(@all_missions.to_json).html_safe};
| window.custom_fields = #{(@custom_fields.to_json).html_safe};
- | window.I18n = #{(I18n.backend.send(:translations).to_json).html_safe};
+ // | window.I18n = #{(I18n.backend.send(:translations).to_json).html_safe};
- if has_feature?(:vehicle_journeys_return_route)
= javascript_tag do
diff --git a/app/views/workbenches/show.html.slim b/app/views/workbenches/show.html.slim
index a162ca334..aae34c51b 100644
--- a/app/views/workbenches/show.html.slim
+++ b/app/views/workbenches/show.html.slim
@@ -72,6 +72,6 @@
= replacement_msg t('referentials.search_no_results')
= javascript_tag do
- | window.I18n = #{(I18n.backend.send(:translations).to_json).html_safe};
+ // | window.I18n = #{(I18n.backend.send(:translations).to_json).html_safe};
= javascript_pack_tag 'date_filters'
diff --git a/config/deploy.rb b/config/deploy.rb
index 9be023adc..fc60113ce 100644
--- a/config/deploy.rb
+++ b/config/deploy.rb
@@ -78,7 +78,7 @@ namespace :deploy do
run "ln -nfs #{shared_path}/tmp/imports #{release_path}/tmp/imports"
end
after 'deploy:update_code', 'deploy:symlink_shared'
- before 'deploy:assets:precompile', 'deploy:symlink_shared'
+ before 'deploy:assets:precompile', 'deploy:symlink_shared', "deploy:i18n_js_export"
desc "Make group writable all deployed files"
task :group_writable do
diff --git a/config/environments/development.rb b/config/environments/development.rb
index 1d2fee44f..446e72190 100644
--- a/config/environments/development.rb
+++ b/config/environments/development.rb
@@ -95,6 +95,7 @@ Rails.application.configure do
config.i18n.available_locales = [:fr, :en]
config.middleware.insert_after(ActionDispatch::Static, Rack::LiveReload) if ENV['LIVERELOAD']
+ config.middleware.use I18n::JS::Middleware
config.development_toolbar = false
if ENV['TOOLBAR'] && File.exists?("config/development_toolbar.rb")
config.development_toolbar = OpenStruct.new
diff --git a/config/locales/en.yml b/config/locales/en.yml
index e59960f95..8af8067db 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -3,6 +3,7 @@ en:
"false": "No"
"unknown": "Unknown"
+
time:
formats:
hour: "%Hh%M"
@@ -61,3 +62,7 @@ en:
reflex_data: 'Reflex datas'
objectid: 'ID'
brandname: IBOO
+ error: "Error"
+ undefined: 'undefined'
+ "yes": yes
+ "no": no
diff --git a/config/locales/fr.yml b/config/locales/fr.yml
index 175b71ebc..e1f52ff55 100644
--- a/config/locales/fr.yml
+++ b/config/locales/fr.yml
@@ -61,3 +61,7 @@ fr:
reflex_data: 'Données Reflex'
objectid: 'ID'
brandname: IBOO
+ error: "Erreur"
+ undefined: 'non renseigné'
+ "yes": oui
+ "no": non
diff --git a/config/locales/vehicle_journeys.en.yml b/config/locales/vehicle_journeys.en.yml
index abb1da530..0c8a75b0c 100644
--- a/config/locales/vehicle_journeys.en.yml
+++ b/config/locales/vehicle_journeys.en.yml
@@ -1,7 +1,14 @@
en:
vehicle_journeys:
vehicle_journeys_matrix:
+ cancel_selection: "Cancel Selection"
+ fetching_error: "There has been a problem fetching the data. Please reload the page to try again."
line_routes: "Line's routes"
+ modal_confirm: 'Do you want to save mofications before moving on to the next page ?'
+ pagination: "Schedules %{minVJ} to %{maxVJ} over %{total}"
+ selected_journeys: "%{count} selected journeys"
+ show_purchase_window: 'Show the purchase window'
+ show_timetable: 'Show calendar'
vehicle_journey:
title_stopless: "Vehicle journey %{name}"
title: "Vehicle journey leaving from %{stop} at %{time}"
@@ -25,44 +32,54 @@ en:
title_stopless: "Update vehicle journey %{name}"
title: "Update vehicle journey %{name} leaving from %{stop} at %{time}"
form:
- stop_title: "Stop"
- departure: "Departure"
+ arrival_at: "Arrival at"
arrival: "Arrival"
- to_arrivals: "Copy departures to arrivals"
- to_departures: "Copy arrivals to departures"
- time_tables: "Associated calendars to vehicle journey"
- slide: "Shift"
- slide_title: "Shift all vehicle passing times"
+ departure_at: "Departure at"
+ departure: "Departure"
+ departure_range:
+ label: Journey departure range
+ start: Start
+ end: End
+ infos: Informations
set: "Set"
- to: "at"
- slide_departure: "departure time at first stop"
+ show_arrival_time: "Show and edit arrival times"
+ show_journeys_with_calendar: "Show journeys with calendar"
+ show_journeys_without_schedule: "Show journeys without schedule"
slide_arrival: "arrival time at first stop"
- submit_timed: "Create vehicle journey"
+ slide_departure: "departure time at first stop"
+ slide_title: "Shift all vehicle passing times"
+ slide: "Shift"
+ stop_title: "Stop"
+ submit_frequency_edit: "Edit frequency vehicle journey"
submit_frequency: "Create frequency vehicle journey"
submit_timed_edit: "Edit vehicle journey"
- submit_frequency_edit: "Edit frequency vehicle journey"
+ submit_timed: "Create vehicle journey"
+ time_tables: "Associated calendars to vehicle journey"
+ to_arrivals: "Copy departures to arrivals"
+ to_departures: "Copy arrivals to departures"
+ to: "at"
timeless:
title: "Timeless vehicle journeys"
vehicle_journeys: "Vehicle journeys with times at stop"
vehicles_list: "Vehicle journeys list"
show:
- title: "Vehicle Journey %{vehicle journey}"
- stop_title: "Stop"
- departure: "Departure"
arrival: "Arrival"
- time_tables: "Calendars list"
bounding: "From %{start} to %{end}"
- translation_form: "Vehicle journey translations"
+ departure: "Departure"
journey_frequencies: "Timeband"
+ stop_title: "Stop"
+ time_tables: "Calendars list"
+ title: "Vehicle Journey %{vehicle journey}"
+ translation_form: "Vehicle journey translations"
index:
- title: "Vehicle journeys on route %{route}"
- vehicle_journeys: "Departure's times"
- selection: "Filter on"
- selection_all: "All"
+ advanced_search: "Advanced Search"
select_journey_patterns: "Select journey pattern"
select_time_tables: "Enter a timetable"
+ selection_all: "All"
+ selection: "Filter on"
time_range: "Departure time threshold"
- advanced_search: "Advanced Search"
+ title: "Vehicle journeys on route %{route}"
+ vehicle_journeys: "Departure's times"
time_filter:
time_range_filter: "Filter"
sidebar:
@@ -78,40 +95,47 @@ en:
other: "vehicle journeys"
attributes:
vehicle_journey:
- line: "Line"
- route: "Route"
- journey_pattern: "Journey Pattern"
- time_tables: "Calendars"
- time_slot: "Time Slot"
- company: "Company"
- number: "Number"
+ accessible: "Accessible"
+ arrival_time: "Arrival"
+ checksum: "Checksum"
comment: "Comments"
- status_value: "Status Value"
- transport_mode: "Transport Mode"
- mobility_restricted_suitability: "PRM accessibility"
+ company: "Company"
+ created_at: Created at
+ creator_id: "Created by"
+ departure_time: "Departure"
+ facility: "Facility"
flexible_service: "On demond transportation"
- unspecified_mrs: "Not specified"
- accessible: "Accessible"
+ footnote_ids: "Footnotes"
+ id: "Journey ID"
+ journey_frequency_ids: "Timeband"
+ journey_name: "Name of the journey"
+ journey_pattern_id: "Pattern ID"
+ journey_pattern: "Journey Pattern"
+ line: "Line"
+ mobility_restricted_suitability: "PRM accessibility"
+ name: "Journey Name"
not_accessible: "Not accessible"
- unspecified_fs: "Not specified"
+ number: "Number"
+ object_version: "Version"
+ objectid: "Neptune identifier"
on_demand_fs: "On demand service"
- regular_fs: "Regular service"
- published_journey_name: "Published Name"
published_journey_identifier: "Published Identifier"
- facility: "Facility"
- vehicle_type_identifier: "Vehicle Type Identifier"
+ published_journey_name: "Published Name"
+ purchase_window: "Purchase availability"
+ regular_fs: "Regular service"
+ route: "Route"
+ status_value: "Status Value"
+ time_slot: "Time Slot"
time_table_ids: "Calendar list"
- vehicle_journey_at_stop_ids: "Time list"
- journey_frequency_ids: "Timeband"
- objectid: "Neptune identifier"
- object_version: "Version"
- created_at: Created at
+ time_tables: "Calendars"
+ train_number: "Train number"
+ transport_mode: "Transport Mode"
+ transport_submode: "Transport Submode"
+ unspecified_fs: "Not specified"
+ unspecified_mrs: "Not specified"
updated_at: Updated at
- creator_id: "Created by"
- footnote_ids: "Footnotes"
- departure_time: "Departure"
- arrival_time: "Arrival"
- purchase_window: "Purchase availability"
+ vehicle_journey_at_stop_ids: "Time list"
+ vehicle_type_identifier: "Vehicle Type Identifier"
errors:
models:
vehicle_journey:
diff --git a/config/locales/vehicle_journeys.fr.yml b/config/locales/vehicle_journeys.fr.yml
index ca8475812..6bf167234 100644
--- a/config/locales/vehicle_journeys.fr.yml
+++ b/config/locales/vehicle_journeys.fr.yml
@@ -1,7 +1,14 @@
fr:
vehicle_journeys:
vehicle_journeys_matrix:
+ cancel_selection: "Annuler la sélection"
+ fetching_error: "La récupération des missions a rencontré un problème. Rechargez la page pour tenter de corriger le problème."
line_routes: "Séquences d'arrêts de la ligne"
+ modal_confirm: 'Voulez-vous valider vos modifications avant de changer de page?'
+ pagination: "Liste des horaires %{minVJ} à %{maxVJ} sur %{total}"
+ selected_journeys: "%{count} course(s) sélectionnée(s)"
+ show_purchase_window: 'Voir le calendrier commercial'
+ show_timetable: 'Voir le calendrier'
vehicle_journey:
title_stopless: "Course %{name}"
title: "Course partant de %{stop} à %{time}"
@@ -25,44 +32,55 @@ fr:
title_stopless: "Editer la course %{name}"
title: "Editer la course partant de %{stop} à %{time}"
form:
- stop_title: "Arrêt"
- departure: "Départ"
+ arrival_at: "Arrivée à"
arrival: "Arrivée"
- to_arrivals: "Copie départs vers arrivées"
- to_departures: "Copie arrivées vers départs"
- time_tables: "Calendriers associés à la course"
- slide: "Décaler"
- slide_title: "Décaler l'ensemble des horaires de course"
+ departure_at: "Départ à"
+ departure: "Départ"
+ departure_range:
+ label: Plage horaire au départ de la course
+ start: Début
+ end: Fin
+ infos: Informations
set: "Fixer"
- to: "à"
- slide_departure: "horaire de départ au 1° arrêt à"
+ show_arrival_time: "Afficher et éditer les horaires d'arrivée"
+ show_journeys_with_calendar: "Afficher les courses avec calendrier"
+ show_journeys_without_schedule: "Afficher les courses sans horaires"
slide_arrival: "horaire d'arrivée au 1° arrêt à"
- submit_timed: "Créer course"
+ slide_departure: "horaire de départ au 1° arrêt à"
+ slide_title: "Décaler l'ensemble des horaires de course"
+ slide: "Décaler"
+ stop_title: "Arrêt"
+ submit_frequency_edit: "Editer course en fréquence"
submit_frequency: "Créer course en fréquence"
submit_timed_edit: "Editer course"
- submit_frequency_edit: "Editer course en fréquence"
+ submit_timed: "Créer course"
+ time_tables: "Calendriers associés à la course"
+ to_arrivals: "Copie départs vers arrivées"
+ to_arrivals: "Copie départs vers arrivées"
+ to_departures: "Copie arrivées vers départs"
+ to: "à"
timeless:
title: "Courses sans horaire"
vehicle_journeys: "Courses ayant des horaires"
vehicles_list: "Liste des courses"
show:
- title: "Course au départ de %{stop} à %{time} sur la séquence %{route}"
- stop_title: "Arrêt"
- departure: "Départ"
arrival: "Arrivée"
- time_tables: "Liste des calendriers"
bounding: "De %{start} à %{end}"
- translation_form: "Cloner la course"
+ departure: "Départ"
journey_frequencies: "Créneau horaire"
+ stop_title: "Arrêt"
+ time_tables: "Liste des calendriers"
+ title: "Course au départ de %{stop} à %{time} sur la séquence %{route}"
+ translation_form: "Cloner la course"
index:
- title: "Horaires de '%{route}'"
- vehicle_journeys: "Horaires de départ aux arrêts"
- selection: "Filtrer sur"
- selection_all: "Tous"
+ advanced_search: "Recherche avancée"
select_journey_patterns: "Sélectionner une mission"
select_time_tables: "Saisir un calendrier"
+ selection_all: "Tous"
+ selection: "Filtrer sur"
time_range: "Seuil horaire au départ"
- advanced_search: "Recherche avancée"
+ title: "Horaires de '%{route}'"
+ vehicle_journeys: "Horaires de départ aux arrêts"
time_filter:
time_range_filter: "Filtrer"
sidebar:
@@ -78,40 +96,47 @@ fr:
other: "courses"
attributes:
vehicle_journey:
- line: "Ligne"
- route: "Séquence d'arrêt"
- journey_pattern: "Mission"
- time_tables: "Calendriers"
- time_slot: "Fréquence"
- company: "Transporteur"
- number: "Numéro"
+ accessible: "Accessible"
+ arrival_time: "Arrivée"
+ checksum: "Signature métier"
comment: "Commentaires"
- status_value: "Etat de trafic"
- transport_mode: "Mode de transport"
- mobility_restricted_suitability: "Accessibilité PMR"
+ company: "Transporteur"
+ created_at: "Créé le"
+ creator_id: "Créé par"
+ departure_time: "Départ"
+ facility: "Equipement"
flexible_service: "Transport à la demande"
- unspecified_mrs: "Non spécifié"
- accessible: "Accessible"
+ footnote_ids: "Notes de bas de page"
+ id: "ID Course"
+ journey_frequency_ids: "Créneau horaire"
+ journey_name: "Nom de la course"
+ journey_pattern_id: "ID Mission"
+ journey_pattern: "Mission"
+ line: "Ligne"
+ mobility_restricted_suitability: "Accessibilité PMR"
+ name: "Nom Course"
not_accessible: "Non accessible"
- unspecified_fs: "Non spécifié"
+ number: "Numéro"
+ object_version: "Version"
+ objectid: "Identifiant Neptune"
on_demand_fs: "Service à la demande"
- regular_fs: "Service régulier"
- published_journey_name: "Nom public"
published_journey_identifier: "Identifiant public"
- facility: "Equipement"
- vehicle_type_identifier: "Type d'identifiant du véhicule"
+ published_journey_name: "Nom public"
+ purchase_window: "Disponibilité commerciale"
+ regular_fs: "Service régulier"
+ route: "Séquence d'arrêt"
+ status_value: "Etat de trafic"
+ time_slot: "Fréquence"
time_table_ids: "Liste des calendriers"
- vehicle_journey_at_stop_ids: "Liste des horaires"
- journey_frequency_ids: "Créneau horaire"
- objectid: "Identifiant Neptune"
- object_version: "Version"
- created_at: "Créé le"
+ time_tables: "Calendriers"
+ train_number: "Numéro de train"
+ transport_mode: "Mode de transport"
+ transport_submode: "Sous-mode de transport"
+ unspecified_fs: "Non spécifié"
+ unspecified_mrs: "Non spécifié"
updated_at: "Edité le"
- creator_id: "Créé par"
- footnote_ids: "Notes de bas de page"
- departure_time: "Départ"
- arrival_time: "Arrivée"
- purchase_window: "Disponibilité commerciale"
+ vehicle_journey_at_stop_ids: "Liste des horaires"
+ vehicle_type_identifier: "Type d'identifiant du véhicule"
errors:
models:
vehicle_journey:
diff --git a/lib/tasks/ci.rake b/lib/tasks/ci.rake
index fdd813516..c46cf7416 100644
--- a/lib/tasks/ci.rake
+++ b/lib/tasks/ci.rake
@@ -31,15 +31,16 @@ namespace :ci do
sh "bundle exec bundle-audit check --update"
end
- task :spec => ["ci:assets","spec"]
-
task :assets do
sh "RAILS_ENV=test bundle exec rake assets:precompile"
end
- task :jest => "ci:assets" do
- sh "yarn --no-progress install" # Hack to force install jest after webpack
- sh "node_modules/.bin/jest"
+ task :i18n_js_export do
+ sh "RAILS_ENV=test bundle exec rake i18n:js:export"
+ end
+
+ task :jest do
+ sh "node_modules/.bin/jest" unless ["CHOUETTE_JEST_DISABLED"]
end
desc "Deploy after CI"
@@ -59,4 +60,4 @@ namespace :ci do
end
desc "Run continuous integration tasks (spec, ...)"
-task :ci => ["ci:setup", "ci:spec", "ci:jest", "cucumber", "ci:check_security", "ci:deploy", "ci:clean"]
+task :ci => ["ci:setup", "ci:assets", "ci:i18n_js_export", "spec", "ci:jest", "cucumber", "ci:check_security", "ci:deploy", "ci:clean"]
diff --git a/package.json b/package.json
index e80f5231e..25b158e3d 100644
--- a/package.json
+++ b/package.json
@@ -49,6 +49,10 @@
"roots": [
"<rootDir>/spec/javascript"
],
+ "transform": {
+ "^.+\\.coffee$": "<rootDir>/spec/javascript/preprocessor.js",
+ "^.+\\.jsx?$": "babel-jest"
+ },
"testEnvironment": "jest-environment-jsdom-global",
"setupFiles": [
"<rootDir>/spec/javascript/spec_helper.js",
diff --git a/spec/javascript/preprocessor.js b/spec/javascript/preprocessor.js
new file mode 100644
index 000000000..a2de8e4be
--- /dev/null
+++ b/spec/javascript/preprocessor.js
@@ -0,0 +1,15 @@
+'use strict';
+
+var coffee = require('coffeescript');
+
+module.exports = {
+ process: function(src, filename) {
+ if (coffee.helpers.isCoffee(filename)) {
+ return coffee.compile(src, {
+ 'bare': false,
+ 'inlineMap': true
+ })
+ }
+ return src;
+ }
+};
diff --git a/spec/javascript/vehicle_journeys/components/VehicleJourneys_spec.js b/spec/javascript/vehicle_journeys/components/VehicleJourneys_spec.js
index 87151c64b..2a84cb9ca 100644
--- a/spec/javascript/vehicle_journeys/components/VehicleJourneys_spec.js
+++ b/spec/javascript/vehicle_journeys/components/VehicleJourneys_spec.js
@@ -1,6 +1,13 @@
import React, { Component } from 'react'
import VehicleJourneys from '../../../../app/javascript/vehicle_journeys/components/VehicleJourneys'
import renderer from 'react-test-renderer'
+import fs from 'fs'
+
+import I18n from '../../../../public/javascripts/i18n'
+import decorateI18n from '../../../../app/assets/javascripts/i18n/extended.coffee'
+window.I18n = decorateI18n(I18n)
+I18n.locale = "fr"
+eval(fs.readFileSync('./public/javascripts/translations.js')+'')
describe('stopPointHeader', () => {
set('features', () => {
diff --git a/spec/javascript/vehicle_journeys/components/__snapshots__/VehicleJourneys_spec.js.snap b/spec/javascript/vehicle_journeys/components/__snapshots__/VehicleJourneys_spec.js.snap
index 703f727d7..cdd34cbbd 100644
--- a/spec/javascript/vehicle_journeys/components/__snapshots__/VehicleJourneys_spec.js.snap
+++ b/spec/javascript/vehicle_journeys/components/__snapshots__/VehicleJourneys_spec.js.snap
@@ -19,19 +19,19 @@ exports[`stopPointHeader should display the city name 1`] = `
<div
className="strong mb-xs"
>
- ID course
+ ID Course
</div>
<div>
- Nom course
+ Nom Course
</div>
<div>
- ID mission
+ ID Mission
</div>
<div>
- Transporteur
+ transporteur
</div>
<div>
- Calendriers
+ calendrier
</div>
</div>
<div
@@ -109,19 +109,19 @@ exports[`stopPointHeader with the "long_distance_routes" feature should display
<div
className="strong mb-xs"
>
- ID course
+ ID Course
</div>
<div>
- Nom course
+ Nom Course
</div>
<div>
- ID mission
+ ID Mission
</div>
<div>
- Transporteur
+ transporteur
</div>
<div>
- Calendriers
+ calendrier
</div>
</div>
<div