jshcrowthe / wc-i18n

A web component centric solution for i18n (inspired by pkaske/i18-n and ebidel/i18n-msg). Designed for individual web components that come with translations built into the component.
https://jshcrowthe.github.io/wc-i18n
MIT License
6 stars 5 forks source link

Version 2.0 #6

Closed jshcrowthe closed 8 years ago

jshcrowthe commented 8 years ago

Version 2.0 Release

I have decided to approach the problem a little differently. In doing so I have made some breaking changes but have simplified the API drastically.

Breaking Changes

Lets get these out of the way up front. Lots of changes:

Before the API required way to much boilerplate to actually get functioning well. This refactor has eliminated a lot of that and simplified it to three things. Consider the component below:

<link rel="import" href="../polymer/polymer.html">
<link rel="import" href="../wc-i18n/wc-i18n.html">

<dom-module id="v2-comp">
  <template>
    <style>
      :host {
        display: block;
      }
    </style>
    <h1>[[_i18n.KEY_NAME]]</h1>
  </template>
  <script>
    Polymer({
      is: 'v2-comp',
      behaviors: [
        WCI18n('v2-comp')
      ]
    });
  </script>
</dom-module>

There are 3 keys to using this component:

The first two points are the only boilerplate required to bootstrap your component's translations. The first is pretty self explanatory, HTML import wc-i18n.html into your application. The second is the inclusion of the WCI18n behavior. This is a function that must be called with the name of your component (the same value that is set as the is attribute). It will then, for local dev, look in the locales directory for the locales as before.

After those two steps, you simply use the _i18n object provided to you as a part of the behavior. You are also given 3 methods that you can use:

NOTE: In all instances, the language, if not passed, defaults to WCI18n.getLocale()

Most people will use the _i18n object and data bind to it inside of their applications.

Prod Use

gulp-wc-i18n supports both v1 and v2 of wc-i18n. You can, in your build pipeline, use that tool to inline locales for you.

marcelklehr commented 8 years ago

Hey! Great to see someone else is thinking about this!

I have the following question regarding this proposal: How will translations be loaded? I would like to allow the page author to specify where they come from and allow the component author to just make use of the translate function. I think a <link>-style custom element for specifying where translations come from would still be a nice thing, as it's declarative.

marcelklehr commented 8 years ago

Oh, and using <html lang=""> as input would make sense, too, IMO.

jshcrowthe commented 8 years ago

@marcelklehr the translations are being loaded in two different ways (depending on the environment):

Dev

The files are loaded via AJAX (in my implementation I use fetch instead of XMLHttpRequest). Based on which language is currently set for the application (ATM v2 ofwc-i18n only allows 1).

Prod

You would either inline your resources (similar to how it is done in https://github.com/PolymerElements/app-localize-behavior) at dev time or you can use a tool like https://github.com/jshcrowthe/gulp-wc-i18n to inline them for you at build time. Either way, you don't want to have a network request, per component, to render text to the screen (that can get costly real fast).

Again, app-localize-behavior handles this by letting you pass a resources prop or by specifying the location of 1 large locale file. This file gets cached so using AJAX to load it (which IMO isn't optimal due to the network request), totally works because the request is really only made once.

Customizing locale loading

So, to your point. We could definitely allow the extension of the loading behavior and look for an optional function loadLocales function (or something of the like). However this solution is focused around component translations as opposed to page level.

If we wanted to add a function as a property of the WCI18n object, we could totally allow for this. I just haven't built that functionality currently (though it wouldn't be difficult at all). If that was something you wanted to PR after I merge this v2 branch, then I'd be all for supporting it.

jshcrowthe commented 8 years ago

NOTE: The API for this component has changed since the original PR. See the updated README.md for the updated API

marcelklehr commented 8 years ago

I made assumptions about the architecture of Polymer apps that turned out to be wrong. I think the current version is very good. To improve it further, http://formatjs.io/ could be used (especially the ICU message format is really worth adopting). Also, from reading the README I'm not sure where the app-global language is set (for this <html lang=""> could be used, but I don't know if this is still the state of-the-art way to do that ;) ).

jshcrowthe commented 8 years ago

Originally I wanted to use the IntlMessageFormat but the polyfill for the Intl object with its locales is huge.

That said http://caniuse.com/#feat=internationalization shows that IE 11 even supports this (Safari 9.1 was the only straggler), so maybe the Polyfill need is moot.

It'd even let us extend the API a little and make it more flexible.

jshcrowthe commented 8 years ago

For the default language, I would lean towards navigator.language or en as defaults.

The only problem is building the language fallback when you get two codes that need to fallback to a common root:

e.g.

These both fallback to en

The declarative method would be to define the language on any component as they will all end up using the same value.