Skip to content

Commit

Permalink
Simplify API (tc39#5)
Browse files Browse the repository at this point in the history
* Drop MessageResource primordial & make MessageFormat immutable

* Drop format() method

* fixup: [spec] `npm run build`

Co-authored-by: eemeli <[email protected]>
  • Loading branch information
eemeli and eemeli authored Feb 22, 2022
1 parent 0d42767 commit ffbceb0
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 50 deletions.
81 changes: 32 additions & 49 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,72 +34,48 @@ The MF2 specification is still being developed by the working group.
The API below is based upon one proposal under consideration,
but should not be considered representative of a consensus among the working group.
In particular, the API shapes of
`MessageFormatOptions`, `MessageData`, `MessageResourceData`, and `ResolvedMessageFormatOptions`
`MessageFormatOptions`, `MessageData`, `MessageResource`, and `ResolvedMessageFormatOptions`
will depend upon the data model chosen by the working group.

### MessageData and MessageResourceData
This proposal introduces one new primordial to ECMAScript, `Intl.MessageFormat`.
The other `interface` descriptions below are intended to represent plain objects.

The `MessageData` and `MessageResourceData` interfaces will be defined by
### MessageData and MessageResource

The `MessageData` and `MessageResource` interfaces will be defined by
the MF2 data model developed by the MF2 working group.
`MessageData` contains a parsed representation of a single message for a particular locale.
`MessageResourceData` containts a potentially hierarchical collection of `MessageData` objects.

```ts
interface MessageData {}

interface MessageResourceData {}
```

### MessageResource

A `MessageResource` is a group of related messages for a single locale.
Messages can be organized in a flat structure, or in hierarchy, using paths.
Conceptually, it is similar to a file containing a set of messages,
but there are no constrains implied on the underlying implementation.

A `MessageResource` instance may be constructed either from a string containing
the MF2 syntax representation of a message resource,
or from an otherwise constructed `MessageResourceData` object.

```ts
interface MessageResource {
static from(source: string): MessageResource;

new (data: MessageResourceData): MessageResource;

// Not directly used by formatting
data: MessageResourceData;

id: string;
interface MessageData {}

getMessage(path: string[]): MessageData | undefined;
}
interface MessageResource {}
```

### MessageFormat

The `Intl.MessageFormat` constructor creates `MessageFormat` instances for a given locale,
`MessageFormatOptions` and an optional set of `MessageResource`s.
`MessageFormatOptions` and a `MessageResource`.
The remaining operations are defined on `MessageFormat` instances.

If a string is used as the `resource` argument,
it will be parsed as a MF2 syntax representation of a message resource.

```ts
interface MessageFormat {
new (
locales: string | string[],
options?: MessageFormatOptions,
...resources: MessageResource[]
options: MessageFormatOptions | null,
resource: MessageResource | string
): MessageFormat;

addResource(resource: MessageResource);

format(
msgPath: string | string[] | { resId: string; path: string[] },
values?: Record<string, unknown>,
onError?: (error: Error, value: MessageValue) => void
): string;

getMessage(
msgPath: string | string[] | { resId: string; path: string[] },
msgPath: string | string[],
values?: Record<string, unknown>,
onError?: (error: Error, value: MessageValue) => void
): ResolvedMessage | undefined;
Expand Down Expand Up @@ -136,23 +112,27 @@ interface MessageFormatOptions {
...
}

interface ResolvedMessageFormatOptions {
locales: string[],
localeMatcher: 'best fit' | 'lookup';
resource: MessageResource;
...
}

type MessageFormatterFunction = (
locales: string[],
options: Record<string, unknown>,
...args: MessageValue[]
) => MessageValue
```
#### format() and getMessage()
#### getMessage()
For formatting a message, two methods are provided: `format()` and `getMessage()`.
The first of these will always return a simple string,
while the latter returns a `ResolvedMessage` object or `undefined` if the message was not found.
These methods have the following arguments:
For formatting a message, the `getMessage()` method is provided,
returning a `ResolvedMessage` object or `undefined` if the message was not found.
This method has the following arguments:
- `msgPath` identifies the message from those available in the current resources.
If all added resources share the same `id` value,
the path may be given as a string or a string array.
- `msgPath` identifies the message from those available in the current resource.
- `values` are to lookup variable references used in the `MessageData`.
- `onError` argument defines an error handler that will be called if
message resolution or formatting fails.
Expand All @@ -161,8 +141,11 @@ These methods have the following arguments:
### MessageValue
`ResolvedMessage` is intended to provide a building block for the localization of messages
in contexts where its representation as a plain string would not be sufficient.
`ResolvedMessage` is intended to provide a building block for the localization of messages anywhere,
including contexts where its representation as a plain string would not be sufficient.
`ResolvedMessage` extends a base interface `MessageValue`,
with its `value` property providing an iterator of other `MessageValue`s.
The `source` of a `MessageValue` provides an opaque identifier for the value,
such as `"$foo"` for a variable.
The `meta` of a `MessageValue` is a map of resolved metadata for the value in question.
Expand Down
2 changes: 1 addition & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -2290,7 +2290,7 @@
.clause-attributes-tag a {
color: #884400;
}
</style></head><body><div id="menu-toggle">☰</div><div id="menu-spacer"></div><div id="menu"><div id="menu-search"><input type="text" id="menu-search-box" placeholder="Search..."><div id="menu-search-results" class="inactive"></div></div><div id="menu-pins"><div class="menu-pane-header">Pins</div><ul id="menu-pins-list"></ul></div><div class="menu-pane-header">Table of Contents</div><div id="menu-toc"><ol class="toc"><li><span class="item-toggle-none"></span><a href="#sec-demo-clause" title="This is an emu-clause"><span class="secnum">1</span> This is an emu-clause</a></li><li><span class="item-toggle-none"></span><a href="#sec-copyright-and-software-license" title="Copyright &amp; Software License"><span class="secnum">A</span> Copyright &amp; Software License</a></li></ol></div></div><div id="spec-container"><h1 class="version">Stage -1 Draft / February 8, 2022</h1><h1 class="title">Proposal Title Goes Here</h1>
</style></head><body><div id="menu-toggle">☰</div><div id="menu-spacer"></div><div id="menu"><div id="menu-search"><input type="text" id="menu-search-box" placeholder="Search..."><div id="menu-search-results" class="inactive"></div></div><div id="menu-pins"><div class="menu-pane-header">Pins</div><ul id="menu-pins-list"></ul></div><div class="menu-pane-header">Table of Contents</div><div id="menu-toc"><ol class="toc"><li><span class="item-toggle-none"></span><a href="#sec-demo-clause" title="This is an emu-clause"><span class="secnum">1</span> This is an emu-clause</a></li><li><span class="item-toggle-none"></span><a href="#sec-copyright-and-software-license" title="Copyright &amp; Software License"><span class="secnum">A</span> Copyright &amp; Software License</a></li></ol></div></div><div id="spec-container"><h1 class="version">Stage -1 Draft / February 17, 2022</h1><h1 class="title">Proposal Title Goes Here</h1>

<emu-clause id="sec-demo-clause">
<h1><span class="secnum">1</span> This is an emu-clause</h1>
Expand Down

0 comments on commit ffbceb0

Please sign in to comment.