Refactor i18n messages organization and use HTTP content negotiation

This reorganizes the i18n messages to be under a single directory, instead of having a copy of messages per template engine. The messages are template agnostic and therefore we don't need more than one copy per locale.

The set of supported locales is now computed on startup by looking for JSON files in the `i18n/` dir, and grabbing the files' base names. This means that when new translations are provided for the app's examples, it will just start working.

The app's overall structure has been changes to flush things out more. Middleware and Routes modules are now auto-loaded by simply placing a module in their respective dirs: `middleware/` and `routes/`.

A new `intl` middleware was added which performs HTTP content negotiation to determine the best-fit locale for the request. It then loads the messages for that locale and preps the `res.locals.intl` object for rendering. This is only the first version of this middleware as it will be expanded to include more features soon.
Once this is merged, I can then work on creating a system for our custom formats and propagating those through the `intl` middleware, routes, and into the `res.locals.intl.formats` object for the templates.