Skip to content

Instantly share code, notes, and snippets.

@billybonks
Last active August 28, 2018 06:22
Show Gist options
  • Save billybonks/925a37e70dcde840a4205d065ea937e7 to your computer and use it in GitHub Desktop.
Save billybonks/925a37e70dcde840a4205d065ea937e7 to your computer and use it in GitHub Desktop.
Translations

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"}}
@lcpriest
Copy link

lcpriest commented Oct 2, 2016

Forms and list labels can share the same copy. <- Are list labels table headers?

@lcpriest
Copy link

lcpriest commented Oct 2, 2016

other: '{{count}} {{objects}} have been successfully deleted'

@lcpriest
Copy link

lcpriest commented Oct 2, 2016

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

  i18nScope: Ember.computed('formObject.id', 'modelName', function() {
    const plural = this.get('modelName').pluralize();
    let messageKey;

    if (!this.get('formObject.id')) {
      messageKey = `${plural}.new`;
    } else {
      messageKey = `${plural}.edit`;
    }
    return messageKey;
  }),

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).

@billybonks
Copy link
Author

thanks @lcpriest

@jkleinsc
Copy link

jkleinsc commented Oct 5, 2016

@billybonks in general I think this concept works but I have a couple of comments/concerns:

  1. One the model labels I think having different labels for edit and new is overkill - I think the "default" values will be sufficient.
  2. As far as crud operations go, I'm not sure how often we are performing crud operations on multiple records, so I'm not sure we need the distinction there as well. Also I don't know how you would handle passing in multiple objects to the translation - eg in
other: 'Something went wrong updating these records {{object}}'

What is object? A concatenation of object names? Also, maybe this is a US thing but if we do need singular/plural labels I would rather label them as singular and plural vs one and other.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment