Skip to content

Commit 873b409

Browse files
authored
Create fluent-sequence 0.1.0 (#273)
1 parent 706385e commit 873b409

16 files changed

+245
-117
lines changed

fluent-sequence/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
fluent-sequence.js
2+
compat.js

fluent-sequence/.npmignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
docs
2+
test
3+
makefile

fluent-sequence/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Changelog
2+
3+
## fluent-sequence 0.1.0 (August 17, 2018)
4+
5+
The initial release based on `fluent` 0.7.0.

fluent-sequence/README.md

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
# fluent-sequence
2+
3+
`fluent-sequence` provides mapping functions from string identifiers to
4+
`MessageContext` instances taken from synchronous or asynchronous sequences.
5+
It's part of Project Fluent, a localization framework designed to unleash the
6+
expressive power of the natural language.
7+
8+
9+
## Installation
10+
11+
`fluent-sequence` can be used both on the client-side and the server-side.
12+
You can install it from the npm registry or use it as a standalone script (as
13+
the `FluentSequence` global).
14+
15+
npm install fluent-sequence
16+
17+
18+
## How to use
19+
20+
An ordered iterable of `MessageContext` instances can represent the current
21+
negotiated fallback chain of languages. This iterable can be used to find the
22+
best existing translation for a given identifier.
23+
24+
`fluent-sequence` provides two mapping functions: `mapContextSync`, and
25+
`mapContextAsync`. They can be used to find the first `MessageContext` in the
26+
given iterable which contains the translation with the given identifier. If
27+
the iterable is ordered according to the result of a language negotiation the
28+
returned `MessageContext` contains the best available translation.
29+
30+
A simple function which formats translations based on the identifier might
31+
be implemented as follows:
32+
33+
```js
34+
import {mapContextSync} from "fluent-sequence";
35+
36+
function formatString(id, args) {
37+
// contexts is a negotiated iterable of MessageContext instances.
38+
let ctx = mapContextSync(contexts, id);
39+
40+
if (ctx === null) {
41+
return id;
42+
}
43+
44+
let msg = ctx.getMessage(id);
45+
return ctx.format(msg, args);
46+
}
47+
```
48+
49+
When passing a synchronous iterator to `mapContextSync`, wrap it in
50+
`CachedSyncIterable` from the [`cached-iterable`][] package. When passing an
51+
asynchronous iterator to `mapContextAsync`, wrap it in `CachedAsyncIterable`.
52+
This allows multiple calls to `mapContext*` without advancing and eventually
53+
depleting the iterator.
54+
55+
56+
## Learn more
57+
58+
Find out more about Project Fluent at [projectfluent.org][], including
59+
documentation of the Fluent file format ([FTL][]), links to other packages and
60+
implementations, and information about how to get involved.
61+
62+
63+
[`cached-iterable`]: https://www.npmjs.com/package/cached-iterable
64+
[projectfluent.org]: https://projectfluent.org
65+
[FTL]: https://projectfluent.org/fluent/guide/

fluent-sequence/makefile

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
PACKAGE := fluent-sequence
2+
GLOBAL := FluentSequence
3+
4+
include ../common.mk
5+
6+
build: $(PACKAGE).js compat.js
7+
8+
$(PACKAGE).js: $(SOURCES)
9+
@rollup $(CURDIR)/src/index.js \
10+
--config $(ROOT)/bundle_config.js \
11+
--banner "/* $(PACKAGE)@$(VERSION) */" \
12+
--amd.id $(PACKAGE) \
13+
--name $(GLOBAL) \
14+
--output.file $@
15+
@echo -e " $(OK) $@ built"
16+
17+
compat.js: $(SOURCES)
18+
@rollup $(CURDIR)/src/index.js \
19+
--config $(ROOT)/compat_config.js \
20+
--banner "/* $(PACKAGE)@$(VERSION) */" \
21+
--amd.id $(PACKAGE) \
22+
--name $(GLOBAL) \
23+
--output.file $@
24+
@echo -e " $(OK) $@ built"
25+
26+
clean:
27+
@rm -f $(PACKAGE).js compat.js
28+
@echo -e " $(OK) clean"

fluent-sequence/package.json

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
{
2+
"name": "fluent-sequence",
3+
"description": "Manage ordered sequences of MessageContexts",
4+
"version": "0.1.0",
5+
"homepage": "https://projectfluent.org",
6+
"author": "Mozilla <[email protected]>",
7+
"license": "Apache-2.0",
8+
"contributors": [
9+
{
10+
"name": "Zibi Braniecki",
11+
"email": "[email protected]"
12+
},
13+
{
14+
"name": "Staś Małolepszy",
15+
"email": "[email protected]"
16+
}
17+
],
18+
"directories": {
19+
"lib": "./src"
20+
},
21+
"main": "./fluent-sequence.js",
22+
"module": "./src/index.js",
23+
"repository": {
24+
"type": "git",
25+
"url": "https://github.com/projectfluent/fluent.js.git"
26+
},
27+
"keywords": [
28+
"fluent",
29+
"ftl"
30+
],
31+
"engines": {
32+
"node": ">=8.9.0"
33+
},
34+
"devDependencies": {
35+
"cached-iterable": "^0.2.1"
36+
}
37+
}

fluent-sequence/src/index.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
/*
2+
* @module fluent-sequence
3+
* @overview Manage ordered sequences of MessageContexts.
4+
*/
5+
6+
export {default as mapContextSync} from "./map_sync";
7+
export {default as mapContextAsync} from "./map_async";

fluent-sequence/src/map_async.js

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
* Asynchronously map an identifier or an array of identifiers to the best
3+
* `MessageContext` instance(s).
4+
*
5+
* @param {AsyncIterable} iterable
6+
* @param {string|Array<string>} ids
7+
* @returns {Promise<MessageContext|Array<MessageContext>>}
8+
*/
9+
export default async function mapContextAsync(iterable, ids) {
10+
if (!Array.isArray(ids)) {
11+
for await (const context of iterable) {
12+
if (context.hasMessage(ids)) {
13+
return context;
14+
}
15+
}
16+
}
17+
18+
let remainingCount = ids.length;
19+
const foundContexts = new Array(remainingCount).fill(null);
20+
21+
for await (const context of iterable) {
22+
for (const [index, id] of ids.entries()) {
23+
if (!foundContexts[index] && context.hasMessage(id)) {
24+
foundContexts[index] = context;
25+
remainingCount--;
26+
}
27+
28+
// Return early when all ids have been mapped to contexts.
29+
if (remainingCount === 0) {
30+
return foundContexts;
31+
}
32+
}
33+
}
34+
35+
return foundContexts;
36+
}

fluent-sequence/src/map_sync.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/*
2+
* Synchronously map an identifier or an array of identifiers to the best
3+
* `MessageContext` instance(s).
4+
*
5+
* @param {Iterable} iterable
6+
* @param {string|Array<string>} ids
7+
* @returns {MessageContext|Array<MessageContext>}
8+
*/
9+
export default function mapContextSync(iterable, ids) {
10+
if (!Array.isArray(ids)) {
11+
return getContextForId(iterable, ids);
12+
}
13+
14+
return ids.map(
15+
id => getContextForId(iterable, id)
16+
);
17+
}
18+
19+
/*
20+
* Find the best `MessageContext` with the translation for `id`.
21+
*/
22+
function getContextForId(iterable, id) {
23+
for (const context of iterable) {
24+
if (context.hasMessage(id)) {
25+
return context;
26+
}
27+
}
28+
29+
return null;
30+
}

fluent/test/fallback_async_test.js renamed to fluent-sequence/test/fallback_async_test.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import assert from 'assert';
22

3-
import { CachedAsyncIterable } from 'cached-iterable';
3+
import {CachedAsyncIterable} from 'cached-iterable';
44
import MessageContext from './message_context_stub';
5-
import { mapContextAsync } from '../src/index';
5+
import {mapContextAsync} from '../src/index';
66

77
suite('Async Fallback — single id', function() {
88
let ctx1, ctx2, generateMessages;

fluent/test/fallback_sync_test.js renamed to fluent-sequence/test/fallback_sync_test.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import assert from 'assert';
22

3-
import { CachedSyncIterable } from 'cached-iterable';
3+
import {CachedSyncIterable} from 'cached-iterable';
44
import MessageContext from './message_context_stub';
5-
import { mapContextSync } from '../src/index';
5+
import {mapContextSync} from '../src/index';
66

77
suite('Sync Fallback — single id', function() {
88
let ctx1, ctx2;
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
export default class MessageContext {
2+
_setMessages(ids) {
3+
this.ids = ids;
4+
}
5+
6+
hasMessage(id) {
7+
return this.ids.includes(id);
8+
}
9+
10+
getMessage(id) {
11+
if (this.hasMessage(id)) {
12+
return id.toUpperCase();
13+
}
14+
}
15+
16+
format(msg) {
17+
return msg;
18+
}
19+
}

fluent/CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
# Changelog
22

3+
## Unreleased
4+
5+
- Move `mapContext*` functions to `fluent-sequence`. (#273)
6+
7+
The `mapContextSync` and `mapContextAsync` functions previously exported
8+
by the `fluent` package have been moved to the new `fluent-sequence`
9+
package. `fluent-sequence` 0.1.0 corresponds to the exact implementation
10+
of these functions from `fluent` 0.7.0.
11+
312
## fluent 0.7.0 (July 24, 2018)
413

514
- Implement support for Fluent Syntax 0.6.

fluent/package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@
4444
"node": ">=8.9.0"
4545
},
4646
"devDependencies": {
47-
"cached-iterable": "^0.2.1",
4847
"sinon": "^4.2.2"
4948
}
5049
}

fluent/src/fallback.js

Lines changed: 0 additions & 110 deletions
This file was deleted.

0 commit comments

Comments
 (0)