Thanks for a lot of great feedback, Gijs!

W dniu piątek, 10 czerwca 2016 11:49:16 UTC+2 użytkownik Gijs Kruitbosch 
napisał:

> Mutation observers or mutation events? How do you decide which elements 
> you observe? Observing the entire DOM tree seems like it'd likely be 
> terrible for performance once we start mutating the DOM. Have you done 
> any measurements on the performance of this approach when large amounts 
> of DOM are inserted (ie not about:support :-) )? How do you decide on 
> which documents you add these observers to?

We use Mutation Observers. Actually, just one per document, which observes 
document.documentElement for subtree inserts and changes to the data-l10n-* 
attributes.  I don't currently have perf numbers for large DOM inserts but 
generally we've been very satisfied with this approach in Firefox OS.  We saw 
perf wins even on low-memory handsets.  I'm sure we'll measure a lot more once 
we're closer to having a working fork of Firefox.

> MutationObservers are async, and dtd localization in XHTML is currently 
> synchronous on parsing. That seems like a large change that will cause a 
> lot of problems relating to reflow / flashes of unlocalized content 
> (keep in mind we use l10n data for style as well), tests that expect 
> synchronous changes as a result of actions, as well as issues where we 
> would want the localized changes in elements that aren't in the page DOM 
> (so constructed in JS, but not included in the DOM (yet)). You don't 
> mention a JS/C++ API, which we need for e.g. strings we pass to message 
> boxes or into the argument strings for about:neterror/about:certerror. 
> What are your plans in that department?

These are all valid concerns.  The API is async by design, which allow us to 
also do runtime fallback on missing or broken translations.

    document.l10n.get('main').formatValue('hello', { user: '…' }).then(hello => 
…);

In this example 'main' is the name of the bundle and 'hello' is an identifier 
of a translation.  We used this API in Firefox OS and it has proven to be 
versatile and easy to use.  It turns out that there are very few use-cases when 
it's necessary to use this API.  Usually it OK to pass string _identifiers_ 
around and only elem.setAttribute('data-l10n-id', id) when it's time to show it 
to the user.

Same goes for tests:  if we have good tests for the Mutation Observer, then in 
other tests we could just test if the data-l10n-id was properly set.

We could expose something like document.l10n.translateFragment to deal with 
node trees which are not yet attached to the DOM, although working on 
data-l10n-id and then just translating once (via the observer) when the nodes 
are inserted would be our preferred approach.

FOUCs can also be a problem and something that's constantly on our radar.  The 
Firefox OS experience allows us to be optimistic, and we're sure to follow up 
with much more perf testing in the near future to make sure we don't regress.

 
> > 1) HTML API

> >
> > The open questions are:
> >
> > * Would it be better to instead use custom elements like
> > <l10n-bundle> <l10n-source src="…"/> </l10n-bundle>?
> 
> Less markup is better, so please don't wrap in more custom elements.

The idea of <l10n-bundle> element came about when considering where to expose 
the JS API (like formatValue above).  Similar to <stringbundle> in XUL, one 
idea was to expose it on the element itself: 
document.querySelector('l10n-bundle').formatValue(…).  As you can see, we 
solved it with document.l10n.get() for now.

Having it on an element has one more interesting consequence:  it's widely 
understood that you need to wait for DOMContentLoaded or readystate === 
'interactive' to query the element and start using the API.  With 
document.l10n.get() it might look like those bundles are available 
synchronously while in reality we still need to query the <links> to even 
create them.

> I don't have a strong opinion on custom elements over <link> ones, 
> though I'd note that there's existing architecture for link elements 
> being added/modified/removed that fire specific events to chrome code 
> that you may be able to leverage.

That's great to know, we're definitely interested in this!

> It's not clear to me why we need a key/value object rather than a 
> sequence as we use now. Perhaps just a semicolon-separated string with 
> \; as an escape for literal ; ? That'd certainly be easier to read/write.

That's an interesting alternative.  One reason we went for named args is that 
they make it much easier for localizers to understand what they're translating.

> Otherwise, it also seems wrong to require the bundle name 
> (data-l10n-bundle) on every localized element. The observer should be 
> able to simply iterate through the stringbundles in declaration order 
> until it finds a matching symbol.

Yes, that's definitely the plan and it's even implemented right now.  The 
default bundle is called 'main' and data-l10n-bundle="main" is implied if 
missing from the localizable node.


> > 2) XUL API

> I think so. Again, I'd prefer not to have a wrapper element.

Would you say introducing a new XUL element <link> is OK, or perhaps we should 
reuse <html:link> here as well?

 
> > 3) XBL API
> >
> > For XBL, we plan to use the same XUL bindings but inside of the
> > anonymous content.  Again, this creates a localization bundle object
> > which is available via the document.l10n collection.
> >
> > <content> <xul:localization name="tabbrowser"> <xul:source
> > src="/browser/tabbrowser.ftl"/> </xul:localization> <xul:label
> > data-l10n-bundle="tabbrowser" data-l10n-id="foo"></xul:label>
> > </content>

One more question here about XBL, related to the XUL API.  If we go for <link> 
elements in XUL, I think it would make sense to keep things consistent in XBL 
as well.  If I understand correctly, XBL doesn't support <script> tags which 
would allow us to add the required behavior to make those <link> elements work. 
 With <localization> we can bind the desired behavior via more XBL.  Are there 
other ways to include external scripts in XBL other than 1) more XBL, and 2) 
Cu.import() in <constructor>?


> > Open questions:
> >
> > * We understand that this creates and destroys the element each time
> > the parent is bound/unbound. Is there UI that does that on a
> > timing-sensitive path extensively? That'd be good to measure.
> 
> I'm not sure. I'd assume that you can/want/should just cache the 
> contents of bundles in a JSM or equivalent, though, so that the actual 
> element instantiation should be reasonably quick once the resource has 
> loaded? This would also help in the case where you have 500 identical 
> XUL elements that are all bound to include the same localization resource...

Great point.  Right now bundle names are expected to be unique and if one 
already exists in the document.l10n collection, the XBL binding won't create a 
new one.  And we only remove them when no other bindings are in use.


> > 4) Performance measuring

> > Question: Which performance tests should we run to ensure that L20n
> > is indeed not regressing performance of Firefox?
> 
> tpaint, ts_paint, sessionrestore, sessionrestore_no_auto_restore, 
> tsvg-opacity, tart, cart
> 
> (and their e10s equivalents, of course) would be my prime suspects. IIRC 
> these come under "other,svgr" in try syntax, but trychooser can confirm 
> this for you (hover over suites tells you what tests they run).
> 
> See https://wiki.mozilla.org/Buildbot/Talos/Tests for descriptions, 
> which also explains why I'm listing tsvg-opacity. :-)

Thanks, this is very helpful indeed!

-Staś


_______________________________________________
dev-platform mailing list
dev-platform@lists.mozilla.org
https://lists.mozilla.org/listinfo/dev-platform

Reply via email to