Comparing version 0.3.0 to 0.4.0
@@ -0,1 +1,2 @@ | ||
import { AnyReplacements, IcuReplacements, XmlReplacements } from "./types"; | ||
export interface PluralOptions { | ||
@@ -11,1 +12,3 @@ other: string; | ||
export declare function Plural(pluralizeFor: string, options: PluralOptions): string; | ||
export declare const splitReplacements: <X>(replacements: AnyReplacements<X>) => [IcuReplacements, XmlReplacements<X>]; | ||
export declare const assign: <T, U>(target: T, source: U) => T & U; |
@@ -19,1 +19,26 @@ const spaceRegex = /\s/g; | ||
} | ||
export const splitReplacements = (replacements) => { | ||
const icu = {}; | ||
const xml = {}; | ||
for (const key in replacements) { | ||
if (replacements.hasOwnProperty(key)) { | ||
const value = replacements[key]; | ||
if (typeof value === "function") { | ||
xml[key] = value; | ||
} | ||
else { | ||
icu[key] = value; | ||
} | ||
} | ||
} | ||
return [icu, xml]; | ||
}; | ||
export const assign = (target, source) => { | ||
const to = Object(target); | ||
for (const nextKey in source) { | ||
if (Object.prototype.hasOwnProperty.call(source, nextKey)) { | ||
to[nextKey] = source[nextKey]; | ||
} | ||
} | ||
return to; | ||
}; |
@@ -1,2 +0,2 @@ | ||
import { Replacements, ReactReplacements } from "./types"; | ||
export default function parseICU(icuString: string, replacements: Replacements | ReactReplacements): string; | ||
import { IcuReplacements } from "./types"; | ||
export default function parseIcu(icuString: string, replacements: IcuReplacements): string; |
@@ -5,3 +5,3 @@ const TOKEN = { | ||
}; | ||
export default function parseICU(icuString, replacements) { | ||
export default function parseIcu(icuString, replacements) { | ||
if (!replacements) | ||
@@ -8,0 +8,0 @@ return icuString; |
@@ -1,11 +0,10 @@ | ||
/// <reference types="react" /> | ||
import { Replacements, Messages, MFunc, SetupOptions, ReactReplacements } from "./types"; | ||
import { IcuReplacements, Messages, MFunc, SetupOptions, AnyReplacements } from "./types"; | ||
import { CachedFormatter } from "./format"; | ||
export interface TFunc { | ||
(message: string, replacements?: Replacements, id?: string): string; | ||
lookup?: (id: string, replacements?: Replacements, defaultMessage?: string) => string; | ||
setup?: (options?: SetupOptions) => any; | ||
date?: (value: any, formatName?: string, locale?: string) => string; | ||
number?: (value: any, formatName?: string, locale?: string) => string; | ||
$?: (message: string, replacements?: ReactReplacements, id?: string) => React.ReactNode[]; | ||
(message: string, replacements?: IcuReplacements, id?: string): string; | ||
lookup: (id: string, replacements?: IcuReplacements, defaultMessage?: string) => string; | ||
setup: (options?: SetupOptions) => any; | ||
date: (value: any, formatName?: string, locale?: string) => string; | ||
number: (value: any, formatName?: string, locale?: string) => string; | ||
$: <X>(message: string, replacements?: AnyReplacements<X>, id?: string) => (X | string)[]; | ||
_i18nInstance?: I18n; | ||
@@ -17,3 +16,3 @@ } | ||
messages: Messages; | ||
idGenerator: (message: string) => any; | ||
idGenerator: (message: string) => string; | ||
dateFormatter: CachedFormatter; | ||
@@ -25,4 +24,4 @@ numberFormatter: CachedFormatter; | ||
getKey(key: string, locale?: string): MFunc | String; | ||
generateId(message: string): any; | ||
lookup(id: string, replacements?: Replacements, defaultMessage?: string): string; | ||
generateId(message: string): string; | ||
lookup(id: string, replacements?: IcuReplacements, defaultMessage?: string): string; | ||
setup(options?: SetupOptions): SetupOptions; | ||
@@ -29,0 +28,0 @@ } |
import createCachedFormatter, { numberFormatOptions, dateTimeFormatOptions } from "./format"; | ||
import { generator } from "./helpers"; | ||
import parseICU from "./icu"; | ||
import parseReact from "./react"; | ||
import { generator, assign, splitReplacements } from "./helpers"; | ||
import parseIcu from "./icu"; | ||
import parseXml from "./xml"; | ||
export const defaultLanguage = "en"; | ||
export class I18n { | ||
constructor(options = null) { | ||
constructor(options) { | ||
this.locale = "en"; | ||
this.messages = {}; | ||
this.idGenerator = generator.hyphens; | ||
this.setup(Object.assign({}, I18n.defaultSetup, options)); | ||
@@ -15,3 +18,4 @@ this.dateFormatter = createCachedFormatter(Intl.DateTimeFormat); | ||
const formatter = (type === "date") ? this.dateFormatter : this.numberFormatter; | ||
return formatter.call(this, locale, (options[formatStyle] || options.default)).format(value); | ||
const optionsForFormatStyle = formatStyle ? (options[formatStyle] || options.default) : options.default; | ||
return formatter.call(this, locale, optionsForFormatStyle).format(value); | ||
} | ||
@@ -27,3 +31,3 @@ getKey(key, locale = this.locale) { | ||
} | ||
return; | ||
return ""; | ||
} | ||
@@ -33,6 +37,6 @@ generateId(message) { | ||
} | ||
lookup(id, replacements = null, defaultMessage = null) { | ||
lookup(id, replacements = {}, defaultMessage = "") { | ||
const translation = this.getKey(id, this.locale) || defaultMessage || id; | ||
if (typeof translation === "string") { | ||
return parseICU(translation, replacements); | ||
return parseIcu(translation, replacements); | ||
} | ||
@@ -42,3 +46,3 @@ return translation(replacements); | ||
setup(options = {}) { | ||
const { locale, idGenerator, messages, compiler } = options; | ||
const { locale, idGenerator, messages } = options; | ||
if (idGenerator) | ||
@@ -63,3 +67,3 @@ this.idGenerator = idGenerator; | ||
function createT(context) { | ||
let T = function translate(message, replacements, id) { | ||
const T = (message, replacements, id) => { | ||
if (!id) | ||
@@ -69,13 +73,15 @@ id = context.generateId(message); | ||
}; | ||
T._i18nInstance = context; | ||
T.setup = context.setup.bind(T._i18nInstance); | ||
T.lookup = context.lookup.bind(T._i18nInstance); | ||
T.date = context.format.bind(T._i18nInstance, "date"); | ||
T.number = context.format.bind(T._i18nInstance, "number"); | ||
T.$ = function translateReact(message, replacements, id) { | ||
const translatedMessage = T.apply(this, arguments); | ||
const reactElements = parseReact(translatedMessage, replacements); | ||
return reactElements; | ||
const properties = { | ||
_i18nInstance: context, | ||
setup: context.setup.bind(context), | ||
lookup: context.lookup.bind(context), | ||
date: context.format.bind(context, "date"), | ||
number: context.format.bind(context, "number"), | ||
$: (message, replacements = {}, id) => { | ||
const [icu, xml] = splitReplacements(replacements); | ||
const translatedMessage = T(message, icu, id); | ||
return parseXml(translatedMessage, xml); | ||
}, | ||
}; | ||
return T; | ||
return assign(T, properties); | ||
} | ||
@@ -82,0 +88,0 @@ export function i18nNamespace() { |
@@ -1,3 +0,2 @@ | ||
/// <reference types="react" /> | ||
export declare type MFunc = (replacements?: Replacements) => string; | ||
export declare type MFunc = (replacements?: IcuReplacements) => string; | ||
export declare type Compiler = (message: string) => MFunc; | ||
@@ -15,8 +14,13 @@ export interface Messages { | ||
} | ||
export interface Replacements { | ||
[s: string]: string | number; | ||
export declare type Mutable<X> = { | ||
[P in keyof X]: X[P]; | ||
}; | ||
export interface IcuReplacements { | ||
readonly [s: string]: string | number; | ||
} | ||
export declare type ReactFactory = [React.Factory<any>, React.Props<any>]; | ||
export interface ReactReplacements { | ||
[s: string]: ReactFactory | React.ReactNode | JSX.Element | string | number; | ||
export interface XmlReplacements<X> { | ||
readonly [s: string]: (...children: (X | string)[]) => X; | ||
} | ||
export interface AnyReplacements<X> { | ||
readonly [s: string]: string | number | ((...children: (X | string)[]) => X); | ||
} |
@@ -0,1 +1,2 @@ | ||
import { AnyReplacements, IcuReplacements, XmlReplacements } from "./types"; | ||
export interface PluralOptions { | ||
@@ -11,1 +12,3 @@ other: string; | ||
export declare function Plural(pluralizeFor: string, options: PluralOptions): string; | ||
export declare const splitReplacements: <X>(replacements: AnyReplacements<X>) => [IcuReplacements, XmlReplacements<X>]; | ||
export declare const assign: <T, U>(target: T, source: U) => T & U; |
@@ -22,1 +22,26 @@ "use strict"; | ||
exports.Plural = Plural; | ||
exports.splitReplacements = function (replacements) { | ||
var icu = {}; | ||
var xml = {}; | ||
for (var key in replacements) { | ||
if (replacements.hasOwnProperty(key)) { | ||
var value = replacements[key]; | ||
if (typeof value === "function") { | ||
xml[key] = value; | ||
} | ||
else { | ||
icu[key] = value; | ||
} | ||
} | ||
} | ||
return [icu, xml]; | ||
}; | ||
exports.assign = function (target, source) { | ||
var to = Object(target); | ||
for (var nextKey in source) { | ||
if (Object.prototype.hasOwnProperty.call(source, nextKey)) { | ||
to[nextKey] = source[nextKey]; | ||
} | ||
} | ||
return to; | ||
}; |
@@ -1,2 +0,2 @@ | ||
import { Replacements, ReactReplacements } from "./types"; | ||
export default function parseICU(icuString: string, replacements: Replacements | ReactReplacements): string; | ||
import { IcuReplacements } from "./types"; | ||
export default function parseIcu(icuString: string, replacements: IcuReplacements): string; |
@@ -7,3 +7,3 @@ "use strict"; | ||
}; | ||
function parseICU(icuString, replacements) { | ||
function parseIcu(icuString, replacements) { | ||
if (!replacements) | ||
@@ -30,2 +30,2 @@ return icuString; | ||
} | ||
exports.default = parseICU; | ||
exports.default = parseIcu; |
@@ -1,11 +0,10 @@ | ||
/// <reference types="react" /> | ||
import { Replacements, Messages, MFunc, SetupOptions, ReactReplacements } from "./types"; | ||
import { IcuReplacements, Messages, MFunc, SetupOptions, AnyReplacements } from "./types"; | ||
import { CachedFormatter } from "./format"; | ||
export interface TFunc { | ||
(message: string, replacements?: Replacements, id?: string): string; | ||
lookup?: (id: string, replacements?: Replacements, defaultMessage?: string) => string; | ||
setup?: (options?: SetupOptions) => any; | ||
date?: (value: any, formatName?: string, locale?: string) => string; | ||
number?: (value: any, formatName?: string, locale?: string) => string; | ||
$?: (message: string, replacements?: ReactReplacements, id?: string) => React.ReactNode[]; | ||
(message: string, replacements?: IcuReplacements, id?: string): string; | ||
lookup: (id: string, replacements?: IcuReplacements, defaultMessage?: string) => string; | ||
setup: (options?: SetupOptions) => any; | ||
date: (value: any, formatName?: string, locale?: string) => string; | ||
number: (value: any, formatName?: string, locale?: string) => string; | ||
$: <X>(message: string, replacements?: AnyReplacements<X>, id?: string) => (X | string)[]; | ||
_i18nInstance?: I18n; | ||
@@ -17,3 +16,3 @@ } | ||
messages: Messages; | ||
idGenerator: (message: string) => any; | ||
idGenerator: (message: string) => string; | ||
dateFormatter: CachedFormatter; | ||
@@ -25,4 +24,4 @@ numberFormatter: CachedFormatter; | ||
getKey(key: string, locale?: string): MFunc | String; | ||
generateId(message: string): any; | ||
lookup(id: string, replacements?: Replacements, defaultMessage?: string): string; | ||
generateId(message: string): string; | ||
lookup(id: string, replacements?: IcuReplacements, defaultMessage?: string): string; | ||
setup(options?: SetupOptions): SetupOptions; | ||
@@ -29,0 +28,0 @@ } |
@@ -14,7 +14,9 @@ "use strict"; | ||
var icu_1 = require("./icu"); | ||
var react_1 = require("./react"); | ||
var xml_1 = require("./xml"); | ||
exports.defaultLanguage = "en"; | ||
var I18n = (function () { | ||
function I18n(options) { | ||
if (options === void 0) { options = null; } | ||
this.locale = "en"; | ||
this.messages = {}; | ||
this.idGenerator = helpers_1.generator.hyphens; | ||
this.setup(__assign({}, I18n.defaultSetup, options)); | ||
@@ -28,3 +30,4 @@ this.dateFormatter = format_1.default(Intl.DateTimeFormat); | ||
var formatter = (type === "date") ? this.dateFormatter : this.numberFormatter; | ||
return formatter.call(this, locale, (options[formatStyle] || options.default)).format(value); | ||
var optionsForFormatStyle = formatStyle ? (options[formatStyle] || options.default) : options.default; | ||
return formatter.call(this, locale, optionsForFormatStyle).format(value); | ||
}; | ||
@@ -41,3 +44,3 @@ I18n.prototype.getKey = function (key, locale) { | ||
} | ||
return; | ||
return ""; | ||
}; | ||
@@ -48,4 +51,4 @@ I18n.prototype.generateId = function (message) { | ||
I18n.prototype.lookup = function (id, replacements, defaultMessage) { | ||
if (replacements === void 0) { replacements = null; } | ||
if (defaultMessage === void 0) { defaultMessage = null; } | ||
if (replacements === void 0) { replacements = {}; } | ||
if (defaultMessage === void 0) { defaultMessage = ""; } | ||
var translation = this.getKey(id, this.locale) || defaultMessage || id; | ||
@@ -59,3 +62,3 @@ if (typeof translation === "string") { | ||
if (options === void 0) { options = {}; } | ||
var locale = options.locale, idGenerator = options.idGenerator, messages = options.messages, compiler = options.compiler; | ||
var locale = options.locale, idGenerator = options.idGenerator, messages = options.messages; | ||
if (idGenerator) | ||
@@ -82,3 +85,3 @@ this.idGenerator = idGenerator; | ||
function createT(context) { | ||
var T = function translate(message, replacements, id) { | ||
var T = function (message, replacements, id) { | ||
if (!id) | ||
@@ -88,13 +91,16 @@ id = context.generateId(message); | ||
}; | ||
T._i18nInstance = context; | ||
T.setup = context.setup.bind(T._i18nInstance); | ||
T.lookup = context.lookup.bind(T._i18nInstance); | ||
T.date = context.format.bind(T._i18nInstance, "date"); | ||
T.number = context.format.bind(T._i18nInstance, "number"); | ||
T.$ = function translateReact(message, replacements, id) { | ||
var translatedMessage = T.apply(this, arguments); | ||
var reactElements = react_1.default(translatedMessage, replacements); | ||
return reactElements; | ||
var properties = { | ||
_i18nInstance: context, | ||
setup: context.setup.bind(context), | ||
lookup: context.lookup.bind(context), | ||
date: context.format.bind(context, "date"), | ||
number: context.format.bind(context, "number"), | ||
$: function (message, replacements, id) { | ||
if (replacements === void 0) { replacements = {}; } | ||
var _a = helpers_1.splitReplacements(replacements), icu = _a[0], xml = _a[1]; | ||
var translatedMessage = T(message, icu, id); | ||
return xml_1.default(translatedMessage, xml); | ||
}, | ||
}; | ||
return T; | ||
return helpers_1.assign(T, properties); | ||
} | ||
@@ -101,0 +107,0 @@ function i18nNamespace() { |
@@ -1,3 +0,2 @@ | ||
/// <reference types="react" /> | ||
export declare type MFunc = (replacements?: Replacements) => string; | ||
export declare type MFunc = (replacements?: IcuReplacements) => string; | ||
export declare type Compiler = (message: string) => MFunc; | ||
@@ -15,8 +14,13 @@ export interface Messages { | ||
} | ||
export interface Replacements { | ||
[s: string]: string | number; | ||
export declare type Mutable<X> = { | ||
[P in keyof X]: X[P]; | ||
}; | ||
export interface IcuReplacements { | ||
readonly [s: string]: string | number; | ||
} | ||
export declare type ReactFactory = [React.Factory<any>, React.Props<any>]; | ||
export interface ReactReplacements { | ||
[s: string]: ReactFactory | React.ReactNode | JSX.Element | string | number; | ||
export interface XmlReplacements<X> { | ||
readonly [s: string]: (...children: (X | string)[]) => X; | ||
} | ||
export interface AnyReplacements<X> { | ||
readonly [s: string]: string | number | ((...children: (X | string)[]) => X); | ||
} |
{ | ||
"name": "t-i18n", | ||
"version": "0.3.0", | ||
"version": "0.4.0", | ||
"description": "Simple, standards-based localization", | ||
@@ -31,16 +31,14 @@ "author": "Mitch Cohen <mitch.cohen@me.com>", | ||
"@types/chai": "^4.0.4", | ||
"@types/mocha": "^2.2.42", | ||
"@types/mocha": "^2.2.48", | ||
"@types/node": "^8.0.24", | ||
"chai": "^4.1.1", | ||
"glob": "^7.1.2", | ||
"react": "^15.6.1", | ||
"react-dom-factories": "^1.0.1", | ||
"mocha": "^5.1.1", | ||
"ts-node": "^3.3.0", | ||
"typescript": "^2.5.2", | ||
"typescript": "^2.8.1", | ||
"xmldom": "^0.1.27" | ||
}, | ||
"dependencies": { | ||
"@types/react": "^16.0.8", | ||
"minimist": "^1.2.0" | ||
} | ||
} |
@@ -62,22 +62,33 @@ # T-i18n | ||
```js | ||
// "First name: Wendy | ||
// "First name: Wendy" | ||
T("First name: {userName}", { userName: "Wendy"}) | ||
``` | ||
So are React components. | ||
Non-string values (like React components) can be interpolated using an XML syntax. | ||
```jsx | ||
// T.$ Returns an array of React components | ||
T.$("There's a <myButton /> in my text!", { | ||
myButton: <button>button</button> | ||
}) | ||
// ["There's a ", <button>button</button>, " in my sentence!"] | ||
T.$( | ||
"There's a <myButton /> in my {text}!", | ||
{ | ||
myButton: () => <button>button</button>, | ||
text: "sentence", | ||
} | ||
) | ||
``` | ||
If your React components have string children, you can translate them inline. Pass in an array with a [React factory](https://facebook.github.io/react/docs/react-api.html#createfactory) and optional props. | ||
If your components have string children, you can translate them inline. | ||
```js | ||
T.$("<link>Visit your profile</link> to change your <strong>profile picture</strong>.", { | ||
link: [React.createFactory("a"), { href: "/user/" + user.uuid }], | ||
strong: [React.createFactory("strong")] | ||
}) | ||
```jsx | ||
// [ | ||
// <a href={"/user/" + user.uuid}>Visit your <strong>profile</strong></a>, | ||
// " to change your profile picture." | ||
// ] | ||
T.$( | ||
"<link>Visit your <strong>profile</strong></link> to change your profile picture.", | ||
{ | ||
link: (...children) => <a href={"/user/" + user.uuid}>{...children}</a>, | ||
strong: (...children) => <strong>{...children}</strong>, | ||
} | ||
) | ||
``` | ||
@@ -84,0 +95,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
36593
1
9
883
102
- Removed@types/react@^16.0.8
- Removed@types/prop-types@15.7.13(transitive)
- Removed@types/react@16.14.62(transitive)
- Removed@types/scheduler@0.16.8(transitive)
- Removedcsstype@3.1.3(transitive)