refactor: some minor changes

This commit is contained in:
Christian Kaisermann 2021-08-24 09:08:37 -03:00
parent 8235f1e078
commit a7ce70fc0f
12 changed files with 43 additions and 42 deletions

View File

@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-non-null-assertion */
import type { import type {
Node, Node,
ObjectExpression, ObjectExpression,
@ -145,7 +146,7 @@ export function collectMessages(markup: string): Message[] {
...definitions.map((definition) => getObjFromExpression(definition)), ...definitions.map((definition) => getObjFromExpression(definition)),
...calls.map((call) => { ...calls.map((call) => {
const [pathNode, options] = call.arguments; const [pathNode, options] = call.arguments;
let messageObj: Partial<Message>; let messageObj: Message;
if (pathNode.type === 'ObjectExpression') { if (pathNode.type === 'ObjectExpression') {
// _({ ...opts }) // _({ ...opts })
@ -168,7 +169,7 @@ export function collectMessages(markup: string): Message[] {
return messageObj; return messageObj;
}), }),
].filter((Boolean as unknown) as (x: Message | null) => x is Message); ].filter(Boolean) as Message[];
} }
export function extractMessages( export function extractMessages(

View File

@ -2,10 +2,8 @@ import type { ObjectExpression, Property, Identifier } from 'estree';
import type { Message } from '../types'; import type { Message } from '../types';
export function getObjFromExpression( export function getObjFromExpression(exprNode: ObjectExpression): Message {
exprNode: ObjectExpression, return exprNode.properties.reduce((acc, prop: Property) => {
): Partial<Message> {
return exprNode.properties.reduce<Partial<Message>>((acc, prop: Property) => {
// we only want primitives // we only want primitives
if ( if (
prop.value.type === 'Literal' && prop.value.type === 'Literal' &&
@ -17,5 +15,5 @@ export function getObjFromExpression(
} }
return acc; return acc;
}, {}); }, {} as Message);
} }

View File

@ -1,5 +1,5 @@
export interface Message { export interface Message {
id: string; id: string;
default: string; default?: string;
[key: string]: any; [key: string]: any;
} }

View File

@ -38,13 +38,8 @@ export const defaultFormats: Formats = {
}, },
}; };
export const defaultOptions: Omit< export const defaultOptions: ConfigureOptions = {
ConfigureOptions, fallbackLocale: null as any,
'fallbackLocale' | 'initialLocale'
> &
Record<'fallbackLocale' | 'initialLocale', null> = {
fallbackLocale: null,
initialLocale: null,
loadingDelay: 200, loadingDelay: 200,
formats: defaultFormats, formats: defaultFormats,
warnOnMissingMessages: true, warnOnMissingMessages: true,

View File

@ -1,4 +1,3 @@
import type { Formats } from 'intl-messageformat';
import IntlMessageFormat from 'intl-messageformat'; import IntlMessageFormat from 'intl-messageformat';
import type { import type {
@ -35,8 +34,8 @@ const getIntlFormatterOptions = (
): any => { ): any => {
const { formats } = getOptions(); const { formats } = getOptions();
if (type in formats && name in (formats as Formats)[type]) { if (type in formats && name in formats[type]) {
return (formats as Formats)[type][name]; return formats[type][name];
} }
throw new Error(`[svelte-i18n] Unknown "${name}" ${type} format.`); throw new Error(`[svelte-i18n] Unknown "${name}" ${type} format.`);
@ -106,6 +105,7 @@ export const getTimeFormatter: MemoizedDateTimeFormatterFactoryOptional = ({
} = {}) => createTimeFormatter({ locale, ...args }); } = {}) => createTimeFormatter({ locale, ...args });
export const getMessageFormatter = monadicMemoize( export const getMessageFormatter = monadicMemoize(
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
(message: string, locale: string = getCurrentLocale()!) => (message: string, locale: string = getCurrentLocale()!) =>
new IntlMessageFormat(message, locale, getOptions().formats, { new IntlMessageFormat(message, locale, getOptions().formats, {
ignoreTag: getOptions().ignoreTag, ignoreTag: getOptions().ignoreTag,

View File

@ -41,7 +41,9 @@ function getLocalesQueues(locale: string) {
.filter(([, localeQueue]) => localeQueue.length > 0); .filter(([, localeQueue]) => localeQueue.length > 0);
} }
export function hasLocaleQueue(locale: string) { export function hasLocaleQueue(locale?: string | null) {
if (locale == null) return false;
return getPossibleLocales(locale).some( return getPossibleLocales(locale).some(
(localeQueue) => getLocaleQueue(localeQueue)?.size, (localeQueue) => getLocaleQueue(localeQueue)?.size,
); );

View File

@ -5,7 +5,6 @@ import type { LocaleDictionary, LocalesDictionary } from '../types/index';
import { getPossibleLocales } from './locale'; import { getPossibleLocales } from './locale';
import { delve } from '../../shared/delve'; import { delve } from '../../shared/delve';
import { lookupCache } from '../includes/lookup'; import { lookupCache } from '../includes/lookup';
import { locales } from '..';
let dictionary: LocalesDictionary; let dictionary: LocalesDictionary;
const $dictionary = writable<LocalesDictionary>({}); const $dictionary = writable<LocalesDictionary>({});

View File

@ -21,16 +21,18 @@ import { $dictionary } from './dictionary';
import { getCurrentLocale, getPossibleLocales, $locale } from './locale'; import { getCurrentLocale, getPossibleLocales, $locale } from './locale';
const formatMessage: MessageFormatter = (id, options = {}) => { const formatMessage: MessageFormatter = (id, options = {}) => {
let messageObj = options as MessageObject;
if (typeof id === 'object') { if (typeof id === 'object') {
options = id as MessageObject; messageObj = id as MessageObject;
id = options.id!; id = messageObj.id;
} }
const { const {
values, values,
locale = getCurrentLocale(), locale = getCurrentLocale(),
default: defaultValue, default: defaultValue,
} = options; } = messageObj;
if (locale == null) { if (locale == null) {
throw new Error( throw new Error(
@ -47,7 +49,7 @@ const formatMessage: MessageFormatter = (id, options = {}) => {
`[svelte-i18n] The message "${id}" was not found in "${getPossibleLocales( `[svelte-i18n] The message "${id}" was not found in "${getPossibleLocales(
locale, locale,
).join('", "')}".${ ).join('", "')}".${
hasLocaleQueue(getCurrentLocale()!) hasLocaleQueue(getCurrentLocale())
? `\n\nNote: there are at least one loader still registered to this locale that wasn't executed.` ? `\n\nNote: there are at least one loader still registered to this locale that wasn't executed.`
: '' : ''
}`, }`,
@ -90,8 +92,11 @@ const formatNumber: NumberFormatter = (n, options) => {
return getNumberFormatter(options).format(n); return getNumberFormatter(options).format(n);
}; };
const getJSON: JSONGetter = (id: string, locale = getCurrentLocale()): any => { const getJSON: JSONGetter = <T = any>(
return lookup(id, locale); id: string,
locale = getCurrentLocale(),
) => {
return lookup(id, locale) as T;
}; };
export const $format = derived([$locale, $dictionary], () => formatMessage); export const $format = derived([$locale, $dictionary], () => formatMessage);

View File

@ -29,11 +29,11 @@ export function getPossibleLocales(
} }
export function getCurrentLocale() { export function getCurrentLocale() {
return current; return current ?? undefined;
} }
internalLocale.subscribe((newLocale: string | null | undefined) => { internalLocale.subscribe((newLocale: string | null | undefined) => {
current = newLocale; current = newLocale ?? undefined;
if (typeof window !== 'undefined' && newLocale != null) { if (typeof window !== 'undefined' && newLocale != null) {
document.documentElement.setAttribute('lang', newLocale); document.documentElement.setAttribute('lang', newLocale);
@ -42,9 +42,8 @@ internalLocale.subscribe((newLocale: string | null | undefined) => {
const set = (newLocale: string | null | undefined): void | Promise<void> => { const set = (newLocale: string | null | undefined): void | Promise<void> => {
if ( if (
((getClosestAvailableLocale as unknown) as ( newLocale &&
refLocale: string | null | undefined, getClosestAvailableLocale(newLocale) &&
) => refLocale is string)(newLocale) &&
hasLocaleQueue(newLocale) hasLocaleQueue(newLocale)
) { ) {
const { loadingDelay } = getOptions(); const { loadingDelay } = getOptions();
@ -66,7 +65,7 @@ const set = (newLocale: string | null | undefined): void | Promise<void> => {
$isLoading.set(true); $isLoading.set(true);
} }
return flush(newLocale) return flush(newLocale as string)
.then(() => { .then(() => {
internalLocale.set(newLocale); internalLocale.set(newLocale);
}) })

View File

@ -26,8 +26,8 @@ export type InterpolationValues =
| undefined; | undefined;
export interface MessageObject { export interface MessageObject {
id?: string; id: string;
locale?: string | null; locale?: string;
format?: string; format?: string;
default?: string; default?: string;
values?: InterpolationValues; values?: InterpolationValues;
@ -35,7 +35,7 @@ export interface MessageObject {
export type MessageFormatter = ( export type MessageFormatter = (
id: string | MessageObject, id: string | MessageObject,
options?: MessageObject, options?: Omit<MessageObject, 'id'>,
) => string; ) => string;
export type TimeFormatter = ( export type TimeFormatter = (
@ -53,11 +53,11 @@ export type NumberFormatter = (
options?: IntlFormatterOptions<Intl.NumberFormatOptions>, options?: IntlFormatterOptions<Intl.NumberFormatOptions>,
) => string; ) => string;
export type JSONGetter = (id: string, locale?: string | null) => any; export type JSONGetter = <T>(id: string, locale?: string | null) => T;
type IntlFormatterOptions<T> = T & { type IntlFormatterOptions<T> = T & {
format?: string; format?: string;
locale?: string | null; locale?: string;
}; };
export interface MemoizedIntlFormatter<T, U> { export interface MemoizedIntlFormatter<T, U> {
@ -74,8 +74,8 @@ export interface MessagesLoader {
export interface ConfigureOptions { export interface ConfigureOptions {
fallbackLocale: string; fallbackLocale: string;
formats: Partial<Formats>; initialLocale?: string | null;
initialLocale: string; formats: Formats;
loadingDelay: number; loadingDelay: number;
warnOnMissingMessages: boolean; warnOnMissingMessages: boolean;
ignoreTag: boolean; ignoreTag: boolean;

View File

@ -8,13 +8,16 @@ import {
describe('getting client locale', () => { describe('getting client locale', () => {
beforeEach(() => { beforeEach(() => {
delete (window as any).location; // @ts-expect-error - TS doesn't know this is a fake window object
delete window.location;
// @ts-expect-error - TS doesn't know this is a fake window object
window.location = { window.location = {
pathname: '/', pathname: '/',
hostname: 'example.com', hostname: 'example.com',
hash: '', hash: '',
search: '', search: '',
} as any; };
}); });
it('gets the locale based on the passed hash parameter', () => { it('gets the locale based on the passed hash parameter', () => {

View File

@ -90,7 +90,6 @@ test('if no initial locale is set, set the locale to the fallback', () => {
test('if no initial locale was found, set to the fallback locale', () => { test('if no initial locale was found, set to the fallback locale', () => {
init({ init({
fallbackLocale: 'en', fallbackLocale: 'en',
initialLocale: null as any,
}); });
expect(get($locale)).toBe('en'); expect(get($locale)).toBe('en');
expect(getOptions().fallbackLocale).toBe('en'); expect(getOptions().fallbackLocale).toBe('en');