diff --git a/types/fluent-langneg/fluent-langneg-tests.ts b/types/fluent-langneg/fluent-langneg-tests.ts new file mode 100644 index 0000000000..45eaa22ee8 --- /dev/null +++ b/types/fluent-langneg/fluent-langneg-tests.ts @@ -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' } +); diff --git a/types/fluent-langneg/index.d.ts b/types/fluent-langneg/index.d.ts new file mode 100644 index 0000000000..28abe2c2d9 --- /dev/null +++ b/types/fluent-langneg/index.d.ts @@ -0,0 +1,11 @@ +// Type definitions for fluent-langneg 0.1 +// Project: http://projectfluent.io +// Definitions by: Huy Nguyen +// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped + +export interface LanguageNegotiationOptions { + strategy?: 'filtering' | 'matching' | 'lookup'; + defaultLocale?: string; +} + +export function negotiateLanguages(requestedLocales: ReadonlyArray, availableLocales: ReadonlyArray, options?: LanguageNegotiationOptions): string[]; diff --git a/types/fluent-langneg/tsconfig.json b/types/fluent-langneg/tsconfig.json new file mode 100644 index 0000000000..665c5dc082 --- /dev/null +++ b/types/fluent-langneg/tsconfig.json @@ -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" + ] +} diff --git a/types/fluent-langneg/tslint.json b/types/fluent-langneg/tslint.json new file mode 100644 index 0000000000..3db14f85ea --- /dev/null +++ b/types/fluent-langneg/tslint.json @@ -0,0 +1 @@ +{ "extends": "dtslint/dt.json" } diff --git a/types/fluent-react/fluent-react-tests.tsx b/types/fluent-react/fluent-react-tests.tsx new file mode 100644 index 0000000000..225749d64e --- /dev/null +++ b/types/fluent-react/fluent-react-tests.tsx @@ -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 = () => ( + +

Hello, world!

+
+); + +// 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( + + Content + , + document.getElementById('root') +); + +// withLocalization examples: +interface Props { + getString: GetString; + otherProp: number; + someOtherProp: string; +} +function HelloButton(props: Props) { + const { getString } = props; + + return ( + + ); +} + +const LocalizedHelloButton = withLocalization(HelloButton); + +// Remove `getString` from list of required props: +const Test2 = () => ( + +); +// Should not allow `getString` prop: +const Test3 = () => ( + // $ExpectError + {}}/> +); + +// Should not allow any other props to be omitted: +const Test4 = () => ( + // $ExpectError + +); diff --git a/types/fluent-react/index.d.ts b/types/fluent-react/index.d.ts new file mode 100644 index 0000000000..5ffc93d874 --- /dev/null +++ b/types/fluent-react/index.d.ts @@ -0,0 +1,101 @@ +// Type definitions for fluent-react 0.8 +// Project: http://projectfluent.org +// Definitions by: 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; + parseMarkup?: MarkupParser; +} +export class LocalizationProvider extends React.Component { +} + +export class ReactLocalization { + constructor(bundles: IterableIterator); + getString(id: string, args?: object, fallback?: string): string; +} + +export interface LocalizedProps { + id: string; + attrs?: object; + [key: string]: any; +} + +export class Localized extends React.Component { +} + +// 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 = { + [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 + > = { + [P in Extract]?: InjectedProps[P] extends DecorationTargetProps[P] ? DecorationTargetProps[P] : never; + }; + +// Infers prop type from component C +export type GetProps = C extends React.ComponentType ? 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 = Pick>; + +// Injects `getString` and removes it from the prop requirements. Will not pass +// through `getString` if it's passed in during render. +export function withLocalization>>>( + component: C +): React.ComponentType, keyof Shared>>>; diff --git a/types/fluent-react/package.json b/types/fluent-react/package.json new file mode 100644 index 0000000000..e6696d08e7 --- /dev/null +++ b/types/fluent-react/package.json @@ -0,0 +1,6 @@ +{ + "private": true, + "dependencies": { + "csstype": "^2.2.0" + } +} diff --git a/types/fluent-react/tsconfig.json b/types/fluent-react/tsconfig.json new file mode 100644 index 0000000000..5a962376b4 --- /dev/null +++ b/types/fluent-react/tsconfig.json @@ -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" + ] +} diff --git a/types/fluent-react/tslint.json b/types/fluent-react/tslint.json new file mode 100644 index 0000000000..d88586e5bd --- /dev/null +++ b/types/fluent-react/tslint.json @@ -0,0 +1,3 @@ +{ + "extends": "dtslint/dt.json" +} diff --git a/types/fluent/fluent-tests.ts b/types/fluent/fluent-tests.ts new file mode 100644 index 0000000000..d2fcd4a6c4 --- /dev/null +++ b/types/fluent/fluent-tests.ts @@ -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); diff --git a/types/fluent/index.d.ts b/types/fluent/index.d.ts new file mode 100644 index 0000000000..56014044ab --- /dev/null +++ b/types/fluent/index.d.ts @@ -0,0 +1,37 @@ +// Type definitions for fluent 0.10 +// Project: http://projectfluent.org +// Definitions by: 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; diff --git a/types/fluent/tsconfig.json b/types/fluent/tsconfig.json new file mode 100644 index 0000000000..64e2460dcd --- /dev/null +++ b/types/fluent/tsconfig.json @@ -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" + ] +} diff --git a/types/fluent/tslint.json b/types/fluent/tslint.json new file mode 100644 index 0000000000..3db14f85ea --- /dev/null +++ b/types/fluent/tslint.json @@ -0,0 +1 @@ +{ "extends": "dtslint/dt.json" }