Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion fluent-react/.npmignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
.nyc_output
coverage
esm/.compiled
examples
example
src
test
makefile
Expand Down
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
.cache
dist
*.tgz
27 changes: 27 additions & 0 deletions fluent-react/example/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# @fluent/react Example

This tiny React app demonstrates how `@fluent/react` can integrate with React.

## Running

The example app requires a local build of `@fluent/react`. In the root of
your `fluent.js` clone install the build tools:

cd fluent.js/
npm install

Then build and package `@fluent/react`:

cd fluent.js/fluent-react/
npm install
make
npm pack
mv fluent-react-*.tgz example/fluent-react.tgz

Finally, change back to this directory, and build the example:

cd fluent.js/fluent-react/example/
npm install
npm start

Open http://localhost:1234 to see the example running.
25 changes: 25 additions & 0 deletions fluent-react/example/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"name": "fluent-react-example",
"version": "0.1.0",
"private": true,
"scripts": {
"start": "parcel serve public/index.html",
"build": "parcel build public/index.html"
},
"dependencies": {
"@fluent/bundle": "0.15.x",
"@fluent/langneg": "0.4.x",
"@fluent/react": "file:fluent-react.tgz",
"react": "16.8.x",
"react-dom": "16.8.x"
},
"devDependencies": {
"@types/react": "^16.9.32",
"@types/react-dom": "^16.9.6",
"parcel-bundler": "1.12.x"
},
"engines": {
"node": ">=10.0.0",
"browsers": "Firefox >= 57"
}
}
13 changes: 13 additions & 0 deletions fluent-react/example/public/en-US.ftl
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
hello = Hello, { $userName }!
hello-no-name = Hello, stranger!
type-name =
.placeholder = Your name

# $date (Date) - Current date, formatted as month and day.
today-date = Today is {$date}.
# $date (Date) - Current date, formatted as weekday.
today-weekday = It's {$date}.

sign-in-or-cancel = <signin>Sign in</signin> or <cancel>cancel</cancel>.
clicked-sign-in = You are now signed in.
clicked-cancel = OK, nevermind.
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Redux sync - a fluent-react example</title>
<title>@fluent/react Example</title>
</head>
<body>
<div id="root"></div>
<script src="../src/index.js"></script>
<script src="../src/index.tsx"></script>
</body>
</html>
15 changes: 15 additions & 0 deletions fluent-react/example/public/pl.ftl
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
hello = Cześć { $userName }!
hello-no-name = Witaj nieznajomy!
type-name =
.placeholder = Twoje imię

# $date (Date) - Current date, formatted as month and day.
today-date = Dziś jest {$date}.

# Commented out to demonstrate fallback.
# $date (Date) - Current date, formatted as weekday.
# today-weekday = Jest {$date}.

sign-in-or-cancel = <signin>Zaloguj</signin> albo <cancel>anuluj</cancel>.
clicked-sign-in = Brawo!
clicked-cancel = OK, nieważne.
41 changes: 41 additions & 0 deletions fluent-react/example/src/App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import React, { useState } from "react";
import { Localized } from "@fluent/react";
import { FluentDateTime } from "@fluent/bundle";
import { Hello } from "./Hello";
import { LocalizedSignIn } from "./SignIn";

export function App() {
let [date] = useState(() => new Date());
return <>
<Hello />

<Localized
id="today-date"
vars={{
date: new FluentDateTime(date.getTime(), {
month: "long",
day: "numeric",
})
}}
>
<p>
{"Today is {$date}."}
</p>
</Localized>

<Localized
id="today-weekday"
vars={{
date: new FluentDateTime(date.getTime(), {
weekday: "long",
})
}}
>
<p>
{"It's {$date}."}
</p>
</Localized>

<LocalizedSignIn />
</>;
}
29 changes: 29 additions & 0 deletions fluent-react/example/src/Hello.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import React, { useState } from "react";
import { Localized } from "@fluent/react";

export function Hello() {
let [userName, setUserName] = useState("");

return (
<div>
{userName ?
<Localized id="hello" vars={{ userName }}>
<h1>{'Hello, { $userName }!'}</h1>
</Localized>
:
<Localized id="hello-no-name">
<h1>Hello, stranger!</h1>
</Localized>
}

<Localized id="type-name" attrs={{ placeholder: true }}>
<input
type="text"
placeholder="Type your name"
onChange={evt => setUserName(evt.target.value)}
value={userName}
/>
</Localized>
</div>
);
}
25 changes: 25 additions & 0 deletions fluent-react/example/src/SignIn.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import React from "react";
import { Localized, withLocalization, WithLocalizationProps } from "@fluent/react";

function SignIn(props: WithLocalizationProps) {
function showAlert(id: string) {
const { getString } = props;
alert(getString(id));
}

return (
<div>
<Localized
id="sign-in-or-cancel"
elems={{
signin: <button onClick={() => showAlert('clicked-sign-in')}></button>,
cancel: <button className="text" onClick={() => showAlert('clicked-cancel')}></button>
}}
>
<p>{'<signin>Sign in</signin> or <cancel>cancel</cancel>.'}</p>
</Localized>
</div>
);
}

export const LocalizedSignIn = withLocalization(SignIn);
12 changes: 12 additions & 0 deletions fluent-react/example/src/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import React from "react";
import ReactDOM from "react-dom";

import { AppLocalizationProvider } from "./l10n";
import { App } from "./App";

ReactDOM.render(
<AppLocalizationProvider>
<App />
</AppLocalizationProvider>,
document.getElementById("root")
);
77 changes: 77 additions & 0 deletions fluent-react/example/src/l10n.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import React, { Children, useEffect, useState, ReactNode } from "react";

import { negotiateLanguages } from "@fluent/langneg";
import { FluentBundle, FluentResource } from "@fluent/bundle";
import { ReactLocalization, LocalizationProvider } from "@fluent/react";

// Parcel decorates filenames with cache-busting hashes.
const ftl = require("../public/*.ftl");

const DEFAULT_LOCALE = "en-US";
const AVAILABLE_LOCALES = {
"en-US": "English",
"pl": "Polish",
};

async function fetchMessages(locale: string): Promise<[string, string]> {
let response = await fetch(ftl[locale]);
let messages = await response.text();
return [locale, messages];
}

function* lazilyParsedBundles(fetchedMessages: Array<[string, string]>) {
for (let [locale, messages] of fetchedMessages) {
let resource = new FluentResource(messages);
let bundle = new FluentBundle(locale);
bundle.addResource(resource);
yield bundle;
}
}

interface AppLocalizationProviderProps {
children: ReactNode;
}

export function AppLocalizationProvider(props: AppLocalizationProviderProps) {
let [currentLocales, setCurrentLocales] = useState([DEFAULT_LOCALE]);
let [l10n, setL10n] = useState<ReactLocalization | null>(null);

useEffect(() => {
changeLocales(navigator.languages as Array<string>);
}, []);

async function changeLocales(userLocales: Array<string>) {
let currentLocales = negotiateLanguages(
userLocales,
Object.keys(AVAILABLE_LOCALES),
{ defaultLocale: DEFAULT_LOCALE }
);
setCurrentLocales(currentLocales);

let fetchedMessages = await Promise.all(
currentLocales.map(fetchMessages)
);

let bundles = lazilyParsedBundles(fetchedMessages);
setL10n(new ReactLocalization(bundles));
}

if (l10n === null) {
return <div>Loading…</div>;
}

return <>
<LocalizationProvider l10n={l10n}>
{Children.only(props.children)}
</LocalizationProvider>

<hr />
<select
onChange={event => changeLocales([event.target.value])}
value={currentLocales[0]}>
{Object.entries(AVAILABLE_LOCALES).map(
([code, name]) => <option key={code} value={code}>{name}</option>
)}
</select>
</>;
}
7 changes: 7 additions & 0 deletions fluent-react/example/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"compilerOptions": {
"esModuleInterop": true,
"strict": true,
"jsx": "react",
}
}
19 changes: 0 additions & 19 deletions fluent-react/examples/README.md

This file was deleted.

2 changes: 0 additions & 2 deletions fluent-react/examples/async-messages/.gitignore

This file was deleted.

24 changes: 0 additions & 24 deletions fluent-react/examples/async-messages/package.json

This file was deleted.

1 change: 0 additions & 1 deletion fluent-react/examples/async-messages/public/en-US.ftl

This file was deleted.

12 changes: 0 additions & 12 deletions fluent-react/examples/async-messages/public/index.html

This file was deleted.

1 change: 0 additions & 1 deletion fluent-react/examples/async-messages/public/pl.ftl

This file was deleted.

12 changes: 0 additions & 12 deletions fluent-react/examples/async-messages/src/App.js

This file was deleted.

12 changes: 0 additions & 12 deletions fluent-react/examples/async-messages/src/index.js

This file was deleted.

Loading