-
Notifications
You must be signed in to change notification settings - Fork 79
Introduce FluentResource and MessageContext.addResource #217
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
It sounds like What are the benefits of introducing this new class over using existing let res1 = new MessageContext(locales);
res1.addMessages(source1);
let res2 = new MessageContext(locales);
res2.addMessages(source2);
// Throw if res1.locales ≠ res2.locales.
let ctx = MessageContext.from(res1, res2); If we prefer to not throw in the constructor, we could also go for an API which is explicit about the locales of the context. In the snippet below, let ctx = new MessageContext(locales);
ctx.addMessages(res1);
ctx.addMessages(res2); |
Mostly scope. As far as I understand, FTLResource will:
I agree that it's possible to use a |
One thing that I expect from this.locales = Array.isArray(locales) ? locales : [locales];
this._terms = new Map();
this._messages = new Map();
this._functions = functions;
this._useIsolating = useIsolating;
this._transform = transform;
this._intls = new WeakMap(); would just leave this.locale = locale; // just one
this._terms = new Map();
this._messages = new Map(); Not sure if we should even do |
I think I'm still not understanding something. @zbraniecki Can you explain what you suggest the internal structure of |
I suggest no change.
Yeah, in the mock patch I just do: addMessages(source) {
const [entries, errors] = parse(source);
this.loadEntries(entries, errors);
return errors;
}
loadResource(res) {
this.loadEntries(res._entries);
} where addMessages parses, and loadResource just unpackages the structure for its entries. The rest looks the same as today.
Yes. You create them once, and pass them around eventually consuming them in MessageContext.
I don't think I understand. L10nRegistry will just cache parsed FTLResources in the FileSource. It will invalidate cache when source gets removed/updated. |
I recall that on Tuesday you said that If this is correct, then I think #220 will be important in reducing the memory footprint because it will make I'm not opposed to the idea of introducing |
I think so. In the model I'm proposing here, MessageContext does not get cached. Only FTLResource does.
In result we parsed 12 files twice, and cache two contexts, one with 12 files, second with 13. In my proposal we would:
In result we would only cache 13 files, and parse each file once. |
I talked to @zbraniecki about this last week. The memory footprint of copying simple strings should be OK when translations are copied from Introducing
|
@zbraniecki also suggested that rather than flatten and copy the translations from |
Here's an early API design which I've been thinking about: class FluentDocument extends Map {
constructor(entries, errors = []) {
super(entries);
this.errors = errors;
}
}
class MessageContext {
// …
static parseDocument(source) {
// Alternatively, create the instance
// of FluentDocument inside of parse().
let [entries, errors] = parse(source);
return new FluentDocument(entries, errors);
}
addDocument(doc) {
let errors = [];
for (let [id, entry] of doc) {
if (id.charAt(0) === "-") {
// Add to terms
} else {
// Add to messages
}
}
return doc.errors.concat(errors);
}
addMessages(source) {
let doc = this.parseDocument(source);
return this.addDocument(doc);
}
} |
On Bugzilla, @zbraniecki said (comment):
We do have CSSStyleSheets and JS Programs (MDN), though. I'm looking for something like that but more suitable to Fluent and the fact that the FTL files contain translated content. I think calling them documents comes pretty close. |
I'd move parsing out of That would leave The Term and Message bit made me wonder a bit, but I think that's good that way, since |
This sounds good as well. I mostly suggested that parsing be in |
As for the naming, I expect the
I see the opportunity of thought in an html document, not so much in a fluent file.
Also a bit of a load to carry for a poor little fluent file, but closer in my book. Just my 2 cents as someone that's not a native speaker, so "close in my book" has little to do with the actual English language ;-) |
Last comment: I do think we should name things Maybe only do that in cases that are really close to fluent itself, and in bindings and above favor |
It's not completely internal. It's the name of the top-level AST node in the spec. I'll file an issue in the spec repo about this. (Update: projectfluent/fluent#149) |
We talked about |
This was implemented in #244. |
The current public API of
MessageContext
makes it quite challenging to apply onto a dynamic state model like DOM, especially with caching and performance in mind.If I understand correctly, @stasm wants to keep
MessageContext
immutable. That's quite possible, if we assume that creating new MessageContexts is cheap.It will come especially useful in the environment where Fluent works in DOM with lazily loaded Web Components.
In such model we either have an inherently dynamic list of resources per context, or dynamic list of contexts. In the former case, we'd want to start with
["res1.ftl", "res2.ftl"]
and then switch to["res1.ftl", "res2.ftl", "res3.ftl"]
without having to reparse res1/res2.In the latter case, we'd want to start with
["res1.ftl", "rest2.ftl"]
and then add a new context["res1.ftl", "res3.ftl"]
without having to reparse res1.At this point
MessageContext
is basically a storage for two types of data - a combination of ftl resources plus a memoizer for Intl objects (plus algorithms of to resolve the entries).I'll talk about memoizer in a separate issue, and here will focus on the set of fluent entries.
If we could allow the user of Fluent to store parsed resources it would become possible to create caches of FTL resources that can be mixed/matched making it cheap to recreate
MessageContext
whenever the list of resources changes.One argument Stas brought against this model is that an API that accepts an AST would need such AST to be documented and standardized, and that's a huge effort for something we don't intend to keep frozen.
I'd like to suggest a potential solution for that - a new class
FTLResource
which has a constructor, and can be accepted intoMessageContext
. An example of how it might look like:The only piece we need to standardize is the constructor for the
FTLResource
and one new method which accepts an object of that type.This allows the
res
to be cached and fed to newMessageContext with no parsing cost at all making
MessageContext` actually just an immutable combination of resources.The added benefit is that in Firefox scenario, we could easily introduce
L10nRegistry.prefetch
method to fetch resources eagerly, parse them, and have them ready for when MessageContext is needed. That would be an equivalent ofCachedIterable.touchNext
except that it wouldn't have to rely on a complete list of resources needed for a context, and wouldn't have to prematurely initialize the context.Instead, it would react to
<link/>
being inserted by triggering a prefetch which would load and parse the file into cache.Then, when
MessageContext
is constructed it would load already prefetched resources.It seems like a cleaner and lighter architecture for the DOM needs, without much increase in complexity or API surface.
@stasm, @Pike - thoughts?
The text was updated successfully, but these errors were encountered: