These are my thoughts, on how the translation files should be modeled, take into consideration the following postulates:
- Web applications are modeled around their data.
- Web applications data models have the following states.
- Saved
- Deleted
- Updated
- Empty
- Created
- Loading
- CRUD Operations
- Copy Should be consistent
- They are plural
- They are singular
- Forms and table headers can share the same copy.
- All models forms have
- placeholders
- hints
In order to have scalable, maintainable and clean translation files we should, model them according to their data models.
This means:
- Every model should have it's name translated in singular and plural,
- Every attribute should have a translation 1 to 1 relationship.
Model names could share the same namespace as attributes, but that could cause conflicts, so we would rather keep them seperate.
Take the following application models:
Model = Ember.Data.Model.extend({
name: DS.string(),
age: DS.number(),
})
Model = Ember.Data.Model.extend({
surname: DS.date(),
age: DS.number(),
})
The resultant translation file would look as follows:
modelNames:{
patient:{
one: 'patient'
other: 'patients
},
inventory:{
one: 'inventory'
other: 'inventory items'
}
}
models: {
patient: {
labels: {
default: {
firstName: 'First Name',
lastName: 'Last Name'
},
edit: {
firstName: 'Change First Name',
lastName: 'Change Last Name'
},
new: {
firstName: 'Set your first name',
lastName: 'Set your Last Name'
}
},
placeholders: {
firstName: 'Enter your first bame',
lastName: 'Enter your first last Name'
},
hints: {
firstName: 'This is the name that your parents gave you, unless you changed it',
lastName: 'this is the name you share with your family, , unless you changed it'
}
},
inventory: {
labels: {
default: {
name: 'Name',
quantity: 'Quantity'
},
edit: {
quantity: 'How many are there now'
},
},
placeholders: {
name: 'Name of inventory item',
quantity: 'Quantity of item'
},
hints: {
name: 'What do you call',
quantity: 'Go to storage and count :)'
}
}
}
Here is an example of crud operation message translations:
en: {
messages: {
empty: {
one: "no {{objects}} were found
},
loading: {
success: {
one: 'Successfully loaded {{object}}',
other: 'Successfully loaded {{count}} {{object}}'
},
error: {
one: 'oops, something happend when loading {{object}}',
other: 'Loading {{count}} {{object}}'
},
delete: {
success: {
one: '{{object}} Successfully deleted',
other: '{{count}} {{object}} have been successfully deleted'
},
error: {
one: 'Something went wrong deleting {{object}}',
other: 'Something went wrong deleting these records {{object}}'
},
confirmation: {
one: 'Are you sure you wish to delete this {{object}}?'
other: 'Are you sure you wish to delete {{object}}?'
}
},
save: {
success: {
one: '{{object}} Successfully saved'
other: '{{object}} have been Successfully saved'
},
error: {
one: 'Something went wrong saving {{object}}'
other: 'Something went wrong saving these records {{object}}'
}
},
update: {
success: {
one: '{{object}} Successfully updated'
other: '{{object}} have been Successfully updated'
},
error: {
one: 'Something went wrong updating {{object}}'
other: 'Something went wrong updating these records {{object}}'
}
},
}
}
Since the translations are now organised, it is easy to generated localised forms, or build helpers for CRUD operation copy
here is an example helper for crud operations
{{translate-message "messages.delete_singular" object=(t "model.lab._one")}}
or a more magical one
{{translate-message "messages.delete" model="lab" count=1}} // displays plural delete
{{translate-message "messages.delete" model="lab" count=2}} // displays plural save
inputs can be wrapped in a {{translated-input}} wrapper
{{translated-input model='invoice' property="price" class="required pricing-override-price"}}
I find this much cleaner - but I even went a step further and embedded it into the form library I use:
https://github.com/advocately/ember-form-for-i18n
Specifically here:
https://github.com/advocately/ember-form-for-i18n/blob/master/addon/components/form-field.js#L150.
This covers labels, placeholders and hints.
Alert message are still handled outside of the library, but they are in a mixin and hook into the save process.
flashMessages.i18nSuccess(${scope}.success);Where scope is
So essentially, as long as your translation file is defined, your forms will generate their structure themselves (placeholders and hints only render if they exist in the translation files).