User:Waldo/Internationalization API: Difference between revisions

Jump to navigation Jump to search
no edit summary
(Add more implementation details info)
No edit summary
Line 105: Line 105:
=== Implementation ===
=== Implementation ===


ECMA-402 currently exposes <code>Intl.Collator</code>, <code>Intl.DateTimeFormatter</code>, and <code>Intl.NumberFormatter</code> objects.  The spec also permits initializing an existing object as one of these, for a wrinkle.  The fundamental ICU data structures providing the relevant functionality are <code>UCollator*</code>, <code>UNumberFormat*</code>, and <code>UDateFormat*</code>, opaque pointers all.  Instances are created using <code>u{col,num,date}_open</code>, passing in appropriate arguments.  For objects ''created'' by the constructor, the pointer is stored in a reserved slot as a private value.  For objects merely ''initialized'' by the constructor, the ICU data structures must be (inefficiently!) created anew every time.
ECMA-402 currently exposes <code>Intl.Collator</code>, <code>Intl.DateTimeFormatter</code>, and <code>Intl.NumberFormatter</code> objects.  The spec also permits initializing an existing object as one of these, for a small wrinkle.  The fundamental ICU data structures providing the relevant functionality are <code>UCollator*</code>, <code>UNumberFormat*</code>, and <code>UDateFormat*</code>, opaque pointers all.  Instances are created using <code>u{col,num,date}_open</code>, passing in appropriate arguments.  For objects ''created'' by the constructor, the pointer is stored in a reserved slot as a private value.  For objects merely ''initialized'' by the constructor, the ICU data structures must be (inefficiently!) created anew every time. (This difference should not be observable, except through performance-timing, because the only structures consulted to create the ICU structure are internal ones , operations on which aren't observable.)


Every object initialized as an Intl object has an associated set of internal properties.  In ECMA-402 these properties are represented using ES5's traditional double-bracket notation: <code><nowiki>[[calendar]]</nowiki></code>, <code><nowiki>[[initializedIntlObject]]</nowiki></code>, and so on.  The "ideal" means of implementing these properties would probably be ES6 private names, but they're not stable or well-understood enough to be specified yet (let alone implemented).  In the meantime we associate ECMA-402 internal properties with objects using a weak map.  Any object initialized as an <code>Intl</code> object has an internal <code><nowiki>[[initializedIntlObject]]</nowiki></code> property.  This is implemented by placing all such objects as keys in a weak map (<code>internalsMap</code> in <code>builtin/Intl.js</code>).  The corresponding value is an ''internals object''.  The internals object is an object with properties corresponding to the other internal properties on the object, named naturally -- "calendar", "initializedDateTimeFormat", and so on (no brackets).
Every object initialized as an Intl object has an associated set of internal properties.  In ECMA-402 these properties are represented using ES5's traditional double-bracket notation: <code><nowiki>[[calendar]]</nowiki></code>, <code><nowiki>[[initializedIntlObject]]</nowiki></code>, and so on.  The "ideal" means of implementing these properties would probably be ES6 private names, but they're not stable or well-understood enough to be specified yet (let alone implemented).  In the meantime we associate ECMA-402 internal properties with objects using a weak map.  Any object initialized as an <code>Intl</code> object has an internal <code><nowiki>[[initializedIntlObject]]</nowiki></code> property.  This is implemented by placing all such objects as keys in a weak map (<code>internalsMap</code> in <code>builtin/Intl.js</code>).  The corresponding value is an ''internals object''.
 
Checking whether an object has been initialized as an <code>Intl</code> object is encapsulated by the <code>isInitializedIntlObject</code> method in {{source|js/src/builtin/Intl.js}}.  The <code>getInternals</code> function in the same file is used to encapsulate weak map access to an internals object.  These methods ensure the weak map mechanism is only an implementation detail encoded in a very few places.
 
Internals objects are objects with null <code><nowiki>[[Prototype]]</nowiki></code>, with properties corresponding to the other internal properties on the object, named naturally -- "calendar", "initializedDateTimeFormat", and so on (no brackets). Accessing any internal property is simply a matter of doing <code>internals.calendar</code>: this is safe because, with the <code><nowiki>[[Prototype]]</nowiki></code> nulled out, property accesses can't touch any script-visible state.  Internal properties are added and set during the initialization process.  They are lazily consulted to construct an ICU structure when collation/formatting/etc. actually occurs in the <code>js::intl_CompareStrings</code>, <code>js::intl_FormatNumber</code>, and <code>js::intl_FormatDateTime</code> functions.  (Although not ''directly'' there, but rather in sub-methods called when the ICU structure isn't cached, or when the object was initialized as an <code>Intl</code> object but wasn't actually one -- see again the "inefficiently" bit above.)


=== Known issues ===
=== Known issues ===
Confirmed users
446

edits

Navigation menu