On 10/06/2016 17:26, smalolep...@mozilla.com wrote:
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 =>
…);
This async-ness will not be acceptable in all circumstances. As a
somewhat random example: how would we localize the 'slow script' dialog,
for which we have to pause script and then show the dialog? Another
example: in docshell, some error page URLs are currently generated
synchronously in some circumstances (invalid host/uris, for instance).
Making such a location change asynchronous just because of localization
is going to break a *lot* of assumptions, not to mention require
rewriting a bunch of yucky docshell code that will then probably break
some more assumptions... It's much easier to just say "we'll make
everything async" when you have a greenfield project like b2g than to
retrospectively jam it into 20 years of history (ie Gecko).
Not all JS and C++ code that will want to localize things has access to
a document object, and for all consumers to have to create one just to
use localization features would be cumbersome (and, as I understand it,
would not work without also inserting all the stringbundle things you'd
need). Please can we make sure that we have a pure-JS/C++ API that is
usable without having to have a document? (Currently, you can create
nsIStringBundle instances via XPCOM, and PluralForm can be used as a jsm
but not from C++, which also already causes headaches.)
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.
I'm quite worried some of this won't be workable. For instance, XUL
panels make decisions about how big they need to be based on their
contents. We'll need to ensure that the content in such panels is
present and localized before attempting to show the panel. We can't just
add the attributes, show the panel, and hope for the best. If we insert
extra turns of the event loop in here because we're ending up waiting
for localization, that'll make it harder to deal with state changes (I
clicked this button twice, is the popup open or closed? etc. etc.)
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.
This isn't really true. If I have a <script> at the bottom of a
document, I expect to be able to modify the preceding DOM without
waiting for DOMContentLoaded. Likewise, if I'm in an XBL binding, I can
do certain things with the bound element immediately without attaching
event listeners.
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.
There's no reason not to have the names, but the order would have to be
defined, potentially just implicitly by the order in the string in the
canonical/default language (English in our case).
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.
This is still problematic in terms of markup though. It's not uncommon
to have 3 or more DTDs in a file, and I can just use an entity without
asking what bundle it's from. Having to specify it for any "non-main"
bundle would be problematic. Why can't we just fall back to using the
other available bundles?
Would you say introducing a new XUL element <link> is OK, or perhaps we should reuse
<html:link> here as well?
I defer to Neil on XUL.
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>?
You can load anything with the subscript loader, or invoke other XPCOM
interfaces, or use attributes that get interpreted as script. So the
answer depends a bit on what you mean by "include external script".
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.
This is very confusing. So you could have multiple bundle elements that
refer to the same bundle? You said earlier that "main" is the default
bundle, but if I have a XUL document with 50 different bindings loaded
(not exactly a lot / surprising in XUL) then how are they supposed to
have stringbundles - are they all supposed to have globally unique
identifiers/names ? It seems much more sensible to determine uniqueness
based on the resource URI, and irrespective of the name. I don't really
see the point of addressing bundles by the name apart from "it's more
convenient than URIs", and even that would go away if we actually don't
need to do that specifically and can just ask for "string foo".
The other way of dealing with the name uniqueness problem would be
considering each XBL binding its own 'namespace' of sorts, so that
'main' in one binding isn't the same as 'main' in another, but that has
issues with your using these names/ids as a perf optimization point. :-\
~ Gijs
_______________________________________________
dev-platform mailing list
dev-platform@lists.mozilla.org
https://lists.mozilla.org/listinfo/dev-platform