Skip to content
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

(@fluent/react) Add changeLocales and currentLocales on provider #501

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
5 changes: 5 additions & 0 deletions fluent-react/example/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Localized } from "@fluent/react";
import { FluentDateTime } from "@fluent/bundle";
import { Hello } from "./Hello";
import { SignIn } from "./SignIn";
import { LanguageSelector } from "./LanguageSelector";

export function App() {
let [date] = useState(() => new Date());
Expand Down Expand Up @@ -37,5 +38,9 @@ export function App() {
</Localized>

<SignIn />

<hr />

<LanguageSelector />
</>;
}
17 changes: 17 additions & 0 deletions fluent-react/example/src/LanguageSelector.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import React from "react";
import { useLocalization } from "@fluent/react";
import { AVAILABLE_LOCALES } from "./l10n";

export function LanguageSelector() {
const { changeLocales, currentLocales } = useLocalization()

return (
<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>
);
}
19 changes: 4 additions & 15 deletions fluent-react/example/src/l10n.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { ReactLocalization, LocalizationProvider } from "@fluent/react";
const ftl = require("../public/*.ftl");

const DEFAULT_LOCALE = "en-US";
const AVAILABLE_LOCALES = {
export const AVAILABLE_LOCALES = {
"en-US": "English",
"pl": "Polish",
};
Expand All @@ -33,7 +33,6 @@ interface AppLocalizationProviderProps {
}

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

useEffect(() => {
Expand All @@ -46,7 +45,6 @@ export function AppLocalizationProvider(props: AppLocalizationProviderProps) {
Object.keys(AVAILABLE_LOCALES),
{ defaultLocale: DEFAULT_LOCALE }
);
setCurrentLocales(currentLocales);

let fetchedMessages = await Promise.all(
currentLocales.map(fetchMessages)
Expand All @@ -60,18 +58,9 @@ export function AppLocalizationProvider(props: AppLocalizationProviderProps) {
return <div>Loading…</div>;
}

return <>
<LocalizationProvider l10n={l10n}>
return (
<LocalizationProvider l10n={l10n} changeLocales={changeLocales} initialLocales={navigator.languages}>
{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>
</>;
);
}
8 changes: 7 additions & 1 deletion fluent-react/src/context.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
import { createContext } from "react";
import { ReactLocalization } from "./localization";

export let FluentContext = createContext(new ReactLocalization([], null));
const defaultValue = {
l10n: new ReactLocalization([], null),
changeLocales: (_changeLocales: string[]) => undefined as void,
currentLocales: [] as string[],
Comment on lines +6 to +7
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we have a setter and a reader, maybe we could call they as locales and setLocales?

};

export let FluentContext = createContext(defaultValue);
2 changes: 1 addition & 1 deletion fluent-react/src/localized.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export interface LocalizedProps {
*/
export function Localized(props: LocalizedProps): ReactElement {
const { id, attrs, vars, elems, children: child = null } = props;
const l10n = useContext(FluentContext);
const { l10n } = useContext(FluentContext);

// Validate that the child element isn't an array
if (Array.isArray(child)) {
Expand Down
17 changes: 15 additions & 2 deletions fluent-react/src/provider.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { createElement, ReactNode, ReactElement } from "react";
import { createElement, ReactNode, ReactElement, useState } from "react";
import PropTypes from "prop-types";
import { FluentContext } from "./context";
import { ReactLocalization } from "./localization";

interface LocalizationProviderProps {
children?: ReactNode;
l10n: ReactLocalization;
changeLocales: (locales: string[]) => void;
initialLocales: string[];
}

/*
Expand All @@ -27,10 +29,21 @@ interface LocalizationProviderProps {
export function LocalizationProvider(
props: LocalizationProviderProps
): ReactElement {
let [locales, setLocales] = useState(props.initialLocales);

function changeLocales(locales: string[]) {
props.changeLocales(locales);
setLocales(locales);
Comment on lines +35 to +36
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There aren't any check if the prop.changeLocales was succeeded before to call setLocales. Maybe we could return a bool on changeLocales? Or use await props.changeLocales(locales) in order to fail on except?

}

return createElement(
FluentContext.Provider,
{
value: props.l10n
value: {
l10n: props.l10n,
changeLocales: changeLocales,
currentLocales: locales
}
},
props.children
);
Expand Down
6 changes: 3 additions & 3 deletions fluent-react/src/use_localization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import { ReactLocalization } from "./localization";
/*
* The `useLocalization` hook returns the FluentContext
*/
type useLocalization = () => { l10n: ReactLocalization }
type useLocalization = () => { l10n: ReactLocalization, changeLocales: (locales: string[]) => void, currentLocales: string[] }
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm writing the type (locales: string[]) => void 2~3 times. Maybe we could to name this type and export/import from somewhere?

export const useLocalization: useLocalization = () => {
const l10n = useContext(FluentContext);
const { l10n, changeLocales, currentLocales } = useContext(FluentContext);

return { l10n };
return { l10n, changeLocales, currentLocales };
};
2 changes: 1 addition & 1 deletion fluent-react/src/with_localization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export function withLocalization<P extends WithLocalizationProps>(
Inner: ComponentType<P>
): ComponentType<WithoutLocalizationProps<P>> {
function WithLocalization(props: WithoutLocalizationProps<P>): ReactElement {
const l10n = useContext(FluentContext);
const { l10n } = useContext(FluentContext);
// Re-bind getString to trigger a re-render of Inner.
const getString = l10n.getString.bind(l10n);
return createElement(Inner, { getString, ...props } as P);
Expand Down