core/server.py:  `ApplicationWebSocket.set_locale()` has been renamed to `ApplicationWebSocket.set_locales()` to be able to support multiple locales so that if the user's preferred language isn't available it can fall back to however many locales the user's browser has ben configured to prefer.  It still supports taking a string though.
core/server.py:  `ApplicationWebSocket.set_locales()` no longer requires the user be authenticated.  This should allow setting the client's locale very early in the connection/authentication process (before any messages are delivered by the server).
core/server.py:  `ApplicationWebSocket.set_locales()` now sets `self.user_locale` instead of the server's global locale.  This makes a lot more sense for a lot of reasons :)
core/server.py:  `ApplicationWebSocket.send_js_translation()` now tries to use `self.user_locales` if available and falls back to the server's configured locale.
core/server.py:  `ApplicationWebSocket.send_js_translation()` now accepts a 'package' keyword argument to be compatible with using the `pkg_resources` module for discovering and retrieving translation files.
core/server.py:  The global `user_locale` has been renamed to `server_locale` to more accurately reflect what it is.
gateone.js:  `GateOne.Net.onOpen()` now asks the server to send localizations via `GateOne.i18n.setLocales(navigator.languages)`.  Unfortunately this step doesn't happen until *after* a lot of strings are loaded so it doesn't work for everything (e.g. the main page of the settings panel).  I'm going to see what I can do about that.
gateone.js:  When swapping workspaces via `GateOne.Visual.swapWorkspaces()` the 'data-title' attribute will now be swapped along with everything else.  This fixes the (never reported) bug where workspaces would show the wrong title in grid view when mousing over them after a swap.  FYI: You can swap workspaces in grid view using drag & drop.  Try it!
gateone.js:  Optimized some things here and there (replaced stuff in brackets with dot equivalents).
setup.py:  The message that displays which entry points were added has been moved to the end of the script so that it doesn't scroll by too fast to be seen.
JavaScript (everywhere):  Wrapped loads of strings with `GateOne.i18n.gettext()`