mirror of
https://github.com/gosticks/DefinitelyTyped.git
synced 2026-10-03 14:27:04 +00:00
Merge pull request #32235 from huy-nguyen/add-fluent-project
Add type definitions for project fluent's constituent packages (fluent, fluent-react and fluent-langneg)
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
import { negotiateLanguages } from 'fluent-langneg';
|
||||
|
||||
const supportedLocales = negotiateLanguages(
|
||||
['en-US', 'pl'], // requested locales
|
||||
['de', 'en-US', 'pl'], // available locales
|
||||
{ defaultLocale: 'en-US' }
|
||||
);
|
||||
Vendored
+11
@@ -0,0 +1,11 @@
|
||||
// Type definitions for fluent-langneg 0.1
|
||||
// Project: http://projectfluent.io
|
||||
// Definitions by: Huy Nguyen <https://github.com/huy-nguyen>
|
||||
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
|
||||
|
||||
export interface LanguageNegotiationOptions {
|
||||
strategy?: 'filtering' | 'matching' | 'lookup';
|
||||
defaultLocale?: string;
|
||||
}
|
||||
|
||||
export function negotiateLanguages(requestedLocales: ReadonlyArray<string>, availableLocales: ReadonlyArray<string>, options?: LanguageNegotiationOptions): string[];
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"lib": [
|
||||
"es6"
|
||||
],
|
||||
"noImplicitAny": true,
|
||||
"noImplicitThis": true,
|
||||
"strictNullChecks": true,
|
||||
"strictFunctionTypes": true,
|
||||
"baseUrl": "../",
|
||||
"typeRoots": [
|
||||
"../"
|
||||
],
|
||||
"types": [],
|
||||
"noEmit": true,
|
||||
"forceConsistentCasingInFileNames": true
|
||||
},
|
||||
"files": [
|
||||
"index.d.ts",
|
||||
"fluent-langneg-tests.ts"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{ "extends": "dtslint/dt.json" }
|
||||
@@ -0,0 +1,60 @@
|
||||
import { Localized, LocalizationProvider, withLocalization, GetString } from 'fluent-react';
|
||||
import { FluentBundle, ftl } from 'fluent';
|
||||
import * as ReactDOM from 'react-dom';
|
||||
|
||||
// Localized examples:
|
||||
const Test = () => (
|
||||
<Localized id="hello-world">
|
||||
<p>Hello, world!</p>
|
||||
</Localized>
|
||||
);
|
||||
|
||||
// LocalizationProvider examples:
|
||||
function* generateBundles(currentLocales: string[]) {
|
||||
for (const locale of currentLocales) {
|
||||
const bundle = new FluentBundle(locale);
|
||||
bundle.addMessages(ftl`some-message = Hello`);
|
||||
yield bundle;
|
||||
}
|
||||
}
|
||||
|
||||
ReactDOM.render(
|
||||
<LocalizationProvider bundles={generateBundles(['en-US'])}>
|
||||
Content
|
||||
</LocalizationProvider>,
|
||||
document.getElementById('root')
|
||||
);
|
||||
|
||||
// withLocalization examples:
|
||||
interface Props {
|
||||
getString: GetString;
|
||||
otherProp: number;
|
||||
someOtherProp: string;
|
||||
}
|
||||
function HelloButton(props: Props) {
|
||||
const { getString } = props;
|
||||
|
||||
return (
|
||||
<button onClick={() => alert(getString('hello'))}>
|
||||
👋
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
const LocalizedHelloButton = withLocalization(HelloButton);
|
||||
|
||||
// Remove `getString` from list of required props:
|
||||
const Test2 = () => (
|
||||
<LocalizedHelloButton otherProp={2} someOtherProp='abc'/>
|
||||
);
|
||||
// Should not allow `getString` prop:
|
||||
const Test3 = () => (
|
||||
// $ExpectError
|
||||
<LocalizedHelloButton otherProp={2} someOtherProp='abc' getString={() => {}}/>
|
||||
);
|
||||
|
||||
// Should not allow any other props to be omitted:
|
||||
const Test4 = () => (
|
||||
// $ExpectError
|
||||
<LocalizedHelloButton otherProp={2}/>
|
||||
);
|
||||
Vendored
+101
@@ -0,0 +1,101 @@
|
||||
// Type definitions for fluent-react 0.8
|
||||
// Project: http://projectfluent.org
|
||||
// Definitions by: Huy Nguyen <https://github.com/huy-nguyen>
|
||||
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
|
||||
// TypeScript Version: 2.8
|
||||
|
||||
import * as React from 'react';
|
||||
import {
|
||||
FluentBundle,
|
||||
} from 'fluent';
|
||||
|
||||
export interface Node {
|
||||
TEXT_NODE: 3;
|
||||
nodeType: number;
|
||||
localName?: string;
|
||||
textContext: string;
|
||||
}
|
||||
|
||||
export type MarkupParser = (str: string) => Node[];
|
||||
|
||||
export interface Context {
|
||||
l10n: ReactLocalization;
|
||||
parseMarkup: MarkupParser;
|
||||
}
|
||||
export interface LocalizationProviderProps {
|
||||
bundles: IterableIterator<FluentBundle>;
|
||||
parseMarkup?: MarkupParser;
|
||||
}
|
||||
export class LocalizationProvider extends React.Component<LocalizationProviderProps> {
|
||||
}
|
||||
|
||||
export class ReactLocalization {
|
||||
constructor(bundles: IterableIterator<FluentBundle>);
|
||||
getString(id: string, args?: object, fallback?: string): string;
|
||||
}
|
||||
|
||||
export interface LocalizedProps {
|
||||
id: string;
|
||||
attrs?: object;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
export class Localized extends React.Component<LocalizedProps> {
|
||||
}
|
||||
|
||||
// Inspired by react-redux's type definition:
|
||||
/**
|
||||
* A property P will be present if:
|
||||
* - it is present in DecorationTargetProps
|
||||
*
|
||||
* Its value will be dependent on the following conditions
|
||||
* - if property P is present in InjectedProps and its definition extends the definition
|
||||
* in DecorationTargetProps, then its definition will be that of DecorationTargetProps[P]
|
||||
* - if property P is not present in InjectedProps then its definition will be that of
|
||||
* DecorationTargetProps[P]
|
||||
* - if property P is present in InjectedProps but does not extend the
|
||||
* DecorationTargetProps[P] definition, its definition will be that of InjectedProps[P]
|
||||
*/
|
||||
export type Matching<InjectedProps, DecorationTargetProps> = {
|
||||
[P in keyof DecorationTargetProps]: P extends keyof InjectedProps
|
||||
? InjectedProps[P] extends DecorationTargetProps[P]
|
||||
? DecorationTargetProps[P]
|
||||
: InjectedProps[P]
|
||||
: DecorationTargetProps[P];
|
||||
};
|
||||
|
||||
/**
|
||||
* a property P will be present if :
|
||||
* - it is present in both DecorationTargetProps and InjectedProps
|
||||
* - InjectedProps[P] can satisfy DecorationTargetProps[P]
|
||||
* ie: decorated component can accept more types than decorator is injecting
|
||||
*
|
||||
* For decoration, inject props or ownProps are all optionally
|
||||
* required by the decorated (right hand side) component.
|
||||
* But any property required by the decorated component must be satisfied by the injected property.
|
||||
*/
|
||||
export type Shared<
|
||||
InjectedProps,
|
||||
DecorationTargetProps extends Shared<InjectedProps, DecorationTargetProps>
|
||||
> = {
|
||||
[P in Extract<keyof InjectedProps, keyof DecorationTargetProps>]?: InjectedProps[P] extends DecorationTargetProps[P] ? DecorationTargetProps[P] : never;
|
||||
};
|
||||
|
||||
// Infers prop type from component C
|
||||
export type GetProps<C> = C extends React.ComponentType<infer P> ? P : never;
|
||||
|
||||
export type GetString = (id: string, args?: object) => string;
|
||||
|
||||
export interface InjectedProps {
|
||||
getString: GetString;
|
||||
}
|
||||
|
||||
// Taken from
|
||||
// https://github.com/Microsoft/TypeScript/wiki/What%27s-new-in-TypeScript#predefined-conditional-types
|
||||
export type Omit<T, K> = Pick<T, Exclude<keyof T, K>>;
|
||||
|
||||
// Injects `getString` and removes it from the prop requirements. Will not pass
|
||||
// through `getString` if it's passed in during render.
|
||||
export function withLocalization<C extends React.ComponentType<Matching<InjectedProps, GetProps<C>>>>(
|
||||
component: C
|
||||
): React.ComponentType<Omit< GetProps<C>, keyof Shared<InjectedProps, GetProps<C>>>>;
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"csstype": "^2.2.0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"lib": [
|
||||
"es6",
|
||||
"dom"
|
||||
],
|
||||
"noImplicitAny": true,
|
||||
"noImplicitThis": true,
|
||||
"strictNullChecks": true,
|
||||
"strictFunctionTypes": true,
|
||||
"jsx": "preserve",
|
||||
"baseUrl": "../",
|
||||
"typeRoots": [
|
||||
"../"
|
||||
],
|
||||
"types": [],
|
||||
"noEmit": true,
|
||||
"forceConsistentCasingInFileNames": true
|
||||
},
|
||||
"files": [
|
||||
"index.d.ts",
|
||||
"fluent-react-tests.tsx"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"extends": "dtslint/dt.json"
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
import { FluentBundle, ftl, FluentResource } from 'fluent';
|
||||
|
||||
const bundle1 = new FluentBundle('en-US');
|
||||
|
||||
const errors1 = bundle1.addMessages(ftl`
|
||||
-brand-name = Foo 3000
|
||||
welcome = Welcome, { $name }, to { -brand-name }!
|
||||
`);
|
||||
|
||||
if (errors1.length) {
|
||||
// syntax errors are per-message and don't break the whole resource
|
||||
}
|
||||
|
||||
const welcome = bundle1.getMessage('welcome');
|
||||
|
||||
bundle1.format(welcome, { name: 'Anna' });
|
||||
|
||||
// FluentBundle constructor examples:
|
||||
const bundle2 = new FluentBundle(['en-US']);
|
||||
|
||||
const bundle3 = new FluentBundle(['en-US'], { useIsolating: false });
|
||||
|
||||
const bundle4 = new FluentBundle(['en-US'], {
|
||||
useIsolating: true,
|
||||
functions: {
|
||||
NODE_ENV: () => 'production'
|
||||
}
|
||||
});
|
||||
|
||||
// FluentBundle addMessages examples:
|
||||
bundle1.addMessages('foo = Foo');
|
||||
bundle2.getMessage('foo');
|
||||
|
||||
// FluentBundle addResource examples:
|
||||
const a = FluentResource.fromString('foo');
|
||||
bundle1.addResource(a);
|
||||
bundle2.getMessage('foo');
|
||||
|
||||
// FluentBundle format examples:
|
||||
const errors2: any[] = [];
|
||||
bundle1.addMessages('hello = Hello, { $name }!');
|
||||
const hello = bundle2.getMessage('hello');
|
||||
bundle3.format(hello, { name: 'Jane' }, errors2);
|
||||
bundle3.format(hello, undefined, errors2);
|
||||
Vendored
+37
@@ -0,0 +1,37 @@
|
||||
// Type definitions for fluent 0.10
|
||||
// Project: http://projectfluent.org
|
||||
// Definitions by: Huy Nguyen <https://github.com/huy-nguyen>
|
||||
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
|
||||
// TypeScript Version: 2.2
|
||||
|
||||
export interface FluentBundleContructorOptions {
|
||||
functions?: object;
|
||||
useIsolating?: boolean;
|
||||
transform?: (...args: any[]) => any;
|
||||
}
|
||||
|
||||
export class FluentType {
|
||||
constructor(value: any, opts: object);
|
||||
toString(bundle: FluentBundle): string;
|
||||
valueOf(): any;
|
||||
}
|
||||
|
||||
export class FluentNone extends FluentType {}
|
||||
export class FluentNumber extends FluentType {}
|
||||
export class FluentDateTime extends FluentType {}
|
||||
|
||||
export type FluentNode = FluentType | string;
|
||||
|
||||
export class FluentResource extends Map {
|
||||
static fromString(source: string): FluentResource;
|
||||
}
|
||||
|
||||
export class FluentBundle {
|
||||
constructor(locales: string | string[], options?: FluentBundleContructorOptions);
|
||||
addMessages(source: string): string[];
|
||||
getMessage(id: string): FluentNode[];
|
||||
format(message: FluentNode[], args?: object, errors?: string[]): string;
|
||||
addResource(res: FluentResource): string[];
|
||||
}
|
||||
|
||||
export function ftl(strings: TemplateStringsArray): string;
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"lib": [
|
||||
"es6"
|
||||
],
|
||||
"noImplicitAny": true,
|
||||
"noImplicitThis": true,
|
||||
"strictNullChecks": true,
|
||||
"strictFunctionTypes": true,
|
||||
"baseUrl": "../",
|
||||
"typeRoots": [
|
||||
"../"
|
||||
],
|
||||
"types": [],
|
||||
"noEmit": true,
|
||||
"forceConsistentCasingInFileNames": true
|
||||
},
|
||||
"files": [
|
||||
"index.d.ts",
|
||||
"fluent-tests.ts"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{ "extends": "dtslint/dt.json" }
|
||||
Reference in New Issue
Block a user