stream-chat-react-native-core
Version:
The official React Native and Expo components for Stream Chat, a service for building chat applications
298 lines (262 loc) • 11.2 kB
text/typescript
import { default as Dayjs } from 'dayjs';
import 'dayjs/locale/nl';
import localeData from 'dayjs/plugin/localeData';
import moment, { type Moment } from 'moment-timezone';
import frTranslations from '../../i18n/fr.json';
import nlTranslations from '../../i18n/nl.json';
import { Streami18n } from '../i18n/Streami18n';
Dayjs.extend(localeData);
const customDayjsLocaleConfig = {
months:
'januar_februar_mars_apríl_mai_juni_juli_august_september_oktober_november_desember'.split('_'),
monthsShort: 'jan_feb_mar_apr_mai_jun_jul_aug_sep_okt_nov_des'.split('_'),
ordinal: '%d.',
weekdays: 'sunnudagur_mánadagur_týsdagur_mikudagur_hósdagur_fríggjadagur_leygardagur'.split('_'),
weekdaysMin: 'su_má_tý_mi_hó_fr_le'.split('_'),
weekdaysShort: 'sun_mán_týs_mik_hós_frí_ley'.split('_'),
};
describe('Jest Timezone', () => {
it('global config should set the timezone to UTC', () => {
expect(new Date().getTimezoneOffset()).toBe(0);
});
});
describe('Streami18n instance - default', () => {
const streami18nOptions = { logger: () => {} };
const streami18n = new Streami18n(streami18nOptions);
it('should provide default english translator', async () => {
const { t: _t } = await streami18n.getTranslators();
const text = Date.now().toString();
expect(_t(text)).toBe(text);
});
it('should provide dayjs with default en locale', async () => {
const { tDateTimeParser } = await streami18n.getTranslators();
expect(tDateTimeParser() instanceof Dayjs).toBe(true);
expect((tDateTimeParser() as Dayjs.Dayjs).locale()).toBe('en');
});
});
describe('Streami18n instance - with built-in language', () => {
describe('datetime translations enabled', () => {
const streami18nOptions = { language: 'nl' };
const streami18n = new Streami18n(streami18nOptions);
it('should provide dutch translator', async () => {
const { t: _t } = await streami18n.getTranslators();
for (const key in nlTranslations) {
const value = nlTranslations[key as keyof typeof nlTranslations];
const hasTemplateInKey = key.indexOf('{{') > -1 && key.indexOf('}}') > -1;
const hasTemplateInValue =
typeof value === 'string' && value.indexOf('{{') > -1 && value.indexOf('}}') > -1;
if (hasTemplateInKey || hasTemplateInValue || key.indexOf('duration/') > -1) {
continue;
}
expect(_t(key)).toBe(nlTranslations[key as keyof typeof nlTranslations]);
}
});
it('should provide dayjs with `nl` locale', async () => {
const { tDateTimeParser } = await streami18n.getTranslators();
expect(tDateTimeParser() instanceof Dayjs).toBe(true);
expect((tDateTimeParser() as Dayjs.Dayjs).locale()).toBe('nl');
});
});
describe('datetime translations disabled', () => {
const streami18nOptions = {
disableDateTimeTranslations: true,
language: 'nl',
};
const streami18n = new Streami18n(streami18nOptions);
it('should provide dutch translator', async () => {
const { t: _t } = await streami18n.getTranslators();
for (const key in nlTranslations) {
const value = nlTranslations[key as keyof typeof nlTranslations];
const hasTemplateInKey = key.indexOf('{{') > -1 && key.indexOf('}}') > -1;
const hasTemplateInValue =
typeof value === 'string' && value.indexOf('{{') > -1 && value.indexOf('}}') > -1;
if (hasTemplateInKey || hasTemplateInValue || key.indexOf('duration/') > -1) {
continue;
}
expect(_t(key)).toBe(nlTranslations[key as keyof typeof nlTranslations]);
}
});
it('should provide dayjs with default `en` locale', async () => {
const { tDateTimeParser } = await streami18n.getTranslators();
expect(tDateTimeParser() instanceof Dayjs).toBe(true);
expect((tDateTimeParser() as Dayjs.Dayjs).locale()).toBe('en');
});
});
describe('custom dayjs locale config', () => {
const streami18nOptions = {
dayjsLocaleConfigForLanguage: customDayjsLocaleConfig,
language: 'nl',
};
const streami18n = new Streami18n(
streami18nOptions as unknown as ConstructorParameters<typeof Streami18n>[0],
);
it('should provide dayjs with given custom locale config', async () => {
const { tDateTimeParser } = await streami18n.getTranslators();
expect(tDateTimeParser() instanceof Dayjs).toBe(true);
const localeConfig = (tDateTimeParser() as Dayjs.Dayjs).localeData() as unknown as Record<
string,
unknown
>;
for (const key in streami18nOptions.dayjsLocaleConfigForLanguage) {
if (typeof localeConfig[key] === 'function') {
expect((localeConfig[key] as () => unknown)()).toStrictEqual(
customDayjsLocaleConfig[key as keyof typeof customDayjsLocaleConfig],
);
} else {
expect(localeConfig[key]).toStrictEqual(
customDayjsLocaleConfig[key as keyof typeof customDayjsLocaleConfig],
);
}
}
});
});
});
describe('Streami18n instance - with custom translations', () => {
describe('datetime translations enabled', () => {
const textKey1 = 'this is text one';
const textValue1 = '这是文字一';
const textKey2 = 'this is text two';
const textValue2 = '这是文字二';
const translations = {
[textKey1]: textValue1,
[textKey2]: textValue2,
};
const streami18nOptions = {
language: 'zh',
translationsForLanguage: translations,
};
const streami18n = new Streami18n(
streami18nOptions as unknown as ConstructorParameters<typeof Streami18n>[0],
);
it('should provide given (chinese in this case) translator', async () => {
const { t: _t } = await streami18n.getTranslators();
expect(_t(textKey1)).toBe(textValue1);
expect(_t(textKey2)).toBe(textValue2);
});
it('should provide dayjs with default `en` locale', async () => {
const { tDateTimeParser } = await streami18n.getTranslators();
expect(tDateTimeParser() instanceof Dayjs).toBe(true);
expect((tDateTimeParser() as Dayjs.Dayjs).locale()).toBe('en');
});
});
});
describe('registerTranslation - register new language `mr` (Marathi)', () => {
const streami18nOptions = {
disableDateTimeTranslations: false,
language: 'en',
};
const streami18n = new Streami18n(streami18nOptions);
const languageCode = 'mr';
const translations = {
text1: 'अनुवादित मजकूर 1',
text2: 'अनुवादित मजकूर 2',
};
streami18n.registerTranslation(
languageCode,
translations as unknown as Parameters<typeof streami18n.registerTranslation>[1],
customDayjsLocaleConfig as unknown as Parameters<typeof streami18n.registerTranslation>[2],
);
streami18n.setLanguage('mr');
it('should add Marathi translations object to list of translations', () => {
expect(streami18n.getTranslations()).toHaveProperty(languageCode, {
translation: translations,
});
});
it('should register dayjs locale config for Marathi translations', async () => {
const { tDateTimeParser } = await streami18n.getTranslators();
expect(tDateTimeParser() instanceof Dayjs).toBe(true);
const localeConfig = (tDateTimeParser() as Dayjs.Dayjs).localeData() as unknown as Record<
string,
unknown
>;
for (const key in customDayjsLocaleConfig) {
if (typeof localeConfig[key] === 'function') {
expect((localeConfig[key] as () => unknown)()).toStrictEqual(
customDayjsLocaleConfig[key as keyof typeof customDayjsLocaleConfig],
);
} else {
expect(localeConfig[key]).toStrictEqual(
customDayjsLocaleConfig[key as keyof typeof customDayjsLocaleConfig],
);
}
}
});
});
describe('setLanguage - switch to french', () => {
const streami18nOptions = {};
const streami18n = new Streami18n(streami18nOptions);
it('should provide french translator', async () => {
await streami18n.setLanguage('fr');
const { t: _t } = await streami18n.getTranslators();
for (const key in frTranslations) {
// Skip keys with template strings or duration keys
const value = frTranslations[key as keyof typeof frTranslations];
const hasTemplateInKey = key.indexOf('{{') > -1 && key.indexOf('}}') > -1;
const hasTemplateInValue =
typeof value === 'string' && value.indexOf('{{') > -1 && value.indexOf('}}') > -1;
if (hasTemplateInKey || hasTemplateInValue || key.indexOf('duration/') > -1) {
continue;
}
expect(_t(key)).toBe(frTranslations[key as keyof typeof frTranslations]);
}
});
});
describe('Streami18n timezone', () => {
describe.each([['moment', moment]])('%s', (moduleName, module) => {
it('is by default the local timezone', () => {
const streamI18n = new Streami18n({ DateTimeParser: module });
const date = new Date();
expect((streamI18n.tDateTimeParser(date) as Moment).format('H')).toBe(
date.getHours().toString(),
);
});
it('can be set to different timezone on init', () => {
const streamI18n = new Streami18n({ DateTimeParser: module, timezone: 'Europe/Prague' });
const date = new Date();
expect((streamI18n.tDateTimeParser(date) as Moment).format('H')).not.toBe(
date.getHours().toString(),
);
expect((streamI18n.tDateTimeParser(date) as Moment).format('H')).not.toBe(
(date.getUTCHours() - 2).toString(),
);
});
it('is ignored if datetime parser does not support timezones', () => {
const mutableModule = module as unknown as { tz: unknown };
const tz = mutableModule.tz;
delete (mutableModule as { tz?: unknown }).tz;
const streamI18n = new Streami18n({ DateTimeParser: module, timezone: 'Europe/Prague' });
const date = new Date();
expect((streamI18n.tDateTimeParser(date) as Moment).format('H')).toBe(
date.getHours().toString(),
);
mutableModule.tz = tz;
});
describe('formatters property', () => {
it('contains the default timestampFormatter', () => {
expect(new Streami18n().formatters.timestampFormatter).toBeDefined();
});
it('allows to override the default timestampFormatter', async () => {
const i18n = new Streami18n({
formatters: { timestampFormatter: () => () => 'custom' },
translationsForLanguage: { abc: '{{ value | timestampFormatter }}' } as Record<
string,
string
>,
});
await (i18n as unknown as { init: () => Promise<void> }).init();
expect(i18n.t('abc')).toBe('custom');
});
it('allows to add new custom formatter', async () => {
const i18n = new Streami18n({
formatters: { customFormatter: () => () => 'custom' },
translationsForLanguage: { abc: '{{ value | customFormatter }}' } as Record<
string,
string
>,
});
await (i18n as unknown as { init: () => Promise<void> }).init();
expect(i18n.t('abc')).toBe('custom');
});
});
});
});