Skip to content

Instantly share code, notes, and snippets.

@kjrocker
Last active July 13, 2018 19:49
Show Gist options
  • Save kjrocker/cab7dfba2ef43ec8fa4c0e96bd7258d5 to your computer and use it in GitHub Desktop.
Save kjrocker/cab7dfba2ef43ec8fa4c0e96bd7258d5 to your computer and use it in GitHub Desktop.
React Localization Boilerplate
import * as i18n from 'i18next';
import * as detector from 'i18next-browser-languagedetector';
import * as backend from 'i18next-xhr-backend';
const instance = i18n
.createInstance()
.use(backend)
.use(detector)
.init({
debug: true,
fallbackLng: 'en',
interpolation: {
escapeValue: false // not needed for react!!
},
ns: ['common'],
defaultNS: 'common',
// backend specific options
backend: {
loadPath: '/locales/{{lng}}/{{ns}}.json'
},
// detector specific options
detection: {},
// react i18next special options (optional)
react: {
wait: true
}
});
export default instance;
import { mount } from 'enzyme';
import * as i18n from 'i18next';
import { TranslationFunction } from 'i18next';
import * as React from 'react';
import withText from './withText';
const i18nInstance = i18n
.createInstance({
fallbackLng: 'en',
debug: true,
interpolation: {
escapeValue: false // not needed for react!!
},
ns: ['common'],
defaultNS: 'common'
})
.init();
i18nInstance.addResourceBundle('en', 'common', { example1: 'Example Key', example2: 'Why' });
const DumbSpan = (props: any) => <span>{props.content}</span>;
const mapText = (t: TranslationFunction, ownProps: object) => {
return { content: t('example1') };
};
describe('withText', () => {
it('still passes `t` and `i18next` props', () => {
const Component = withText(mapText, { i18n: i18nInstance })(DumbSpan);
const Wrapper = mount(<Component />);
expect(Wrapper.find(DumbSpan).prop('i18n')).toEqual(i18nInstance);
expect(Wrapper.find(DumbSpan).prop('t')).toBeInstanceOf(Function);
Wrapper.unmount();
});
});
describe('withText', () => {
it('passes props from mapText', (done) => {
const Component = withText(mapText, { i18n: i18nInstance })(DumbSpan);
const Wrapper = mount(<Component />);
setTimeout(() => {
expect(Wrapper.find(DumbSpan).prop('content')).toEqual('Example Key');
Wrapper.unmount();
done();
}, 1000);
});
});
import { i18n as i18nInterface, TranslationFunction } from 'i18next';
import * as React from 'react';
import { I18n } from 'react-i18next';
import { i18nProps } from 'react-i18next/src/I18n';
const defaultOptions = {};
type Omit<T, K> = Pick<T, Exclude<keyof T, K>>;
export interface WithTextProps {
i18n: i18nInterface;
t: TranslationFunction;
ready: boolean;
}
const withText = (fn: (t: TranslationFunction, props?: object) => object, args?: Partial<i18nProps>) => {
const extraProps = Object.assign({}, defaultOptions, args);
return <P extends object>(BaseComponent: React.ComponentType<P>) => {
return (props: Omit<P, keyof WithTextProps>) => {
return (
<I18n {...extraProps}>
{(t, other) => {
const tProps = fn(t, props);
return <BaseComponent {...other} {...tProps} {...props} />;
}}
</I18n>
);
};
};
};
export default withText;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment