From a7ce70fc0fb680d82493416a5212d8549c9d782c Mon Sep 17 00:00:00 2001 From: Christian Kaisermann Date: Tue, 24 Aug 2021 09:08:37 -0300 Subject: [PATCH] refactor: some minor changes --- src/cli/extract.ts | 5 +++-- src/cli/includes/getObjFromExpression.ts | 8 +++----- src/cli/types/index.ts | 2 +- src/runtime/configs.ts | 9 ++------- src/runtime/includes/formatters.ts | 6 +++--- src/runtime/includes/loaderQueue.ts | 4 +++- src/runtime/stores/dictionary.ts | 1 - src/runtime/stores/formatters.ts | 17 +++++++++++------ src/runtime/stores/locale.ts | 11 +++++------ src/runtime/types/index.ts | 14 +++++++------- test/runtime/includes/utils.test.ts | 7 +++++-- test/runtime/stores/locale.test.ts | 1 - 12 files changed, 43 insertions(+), 42 deletions(-) diff --git a/src/cli/extract.ts b/src/cli/extract.ts index a5f537a..5efd9c2 100644 --- a/src/cli/extract.ts +++ b/src/cli/extract.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-non-null-assertion */ import type { Node, ObjectExpression, @@ -145,7 +146,7 @@ export function collectMessages(markup: string): Message[] { ...definitions.map((definition) => getObjFromExpression(definition)), ...calls.map((call) => { const [pathNode, options] = call.arguments; - let messageObj: Partial; + let messageObj: Message; if (pathNode.type === 'ObjectExpression') { // _({ ...opts }) @@ -168,7 +169,7 @@ export function collectMessages(markup: string): Message[] { return messageObj; }), - ].filter((Boolean as unknown) as (x: Message | null) => x is Message); + ].filter(Boolean) as Message[]; } export function extractMessages( diff --git a/src/cli/includes/getObjFromExpression.ts b/src/cli/includes/getObjFromExpression.ts index cd65b75..9098dbc 100644 --- a/src/cli/includes/getObjFromExpression.ts +++ b/src/cli/includes/getObjFromExpression.ts @@ -2,10 +2,8 @@ import type { ObjectExpression, Property, Identifier } from 'estree'; import type { Message } from '../types'; -export function getObjFromExpression( - exprNode: ObjectExpression, -): Partial { - return exprNode.properties.reduce>((acc, prop: Property) => { +export function getObjFromExpression(exprNode: ObjectExpression): Message { + return exprNode.properties.reduce((acc, prop: Property) => { // we only want primitives if ( prop.value.type === 'Literal' && @@ -17,5 +15,5 @@ export function getObjFromExpression( } return acc; - }, {}); + }, {} as Message); } diff --git a/src/cli/types/index.ts b/src/cli/types/index.ts index cdd0c04..6cf36d3 100644 --- a/src/cli/types/index.ts +++ b/src/cli/types/index.ts @@ -1,5 +1,5 @@ export interface Message { id: string; - default: string; + default?: string; [key: string]: any; } diff --git a/src/runtime/configs.ts b/src/runtime/configs.ts index b502ced..396884a 100644 --- a/src/runtime/configs.ts +++ b/src/runtime/configs.ts @@ -38,13 +38,8 @@ export const defaultFormats: Formats = { }, }; -export const defaultOptions: Omit< - ConfigureOptions, - 'fallbackLocale' | 'initialLocale' -> & - Record<'fallbackLocale' | 'initialLocale', null> = { - fallbackLocale: null, - initialLocale: null, +export const defaultOptions: ConfigureOptions = { + fallbackLocale: null as any, loadingDelay: 200, formats: defaultFormats, warnOnMissingMessages: true, diff --git a/src/runtime/includes/formatters.ts b/src/runtime/includes/formatters.ts index bb45eaa..eafc40e 100644 --- a/src/runtime/includes/formatters.ts +++ b/src/runtime/includes/formatters.ts @@ -1,4 +1,3 @@ -import type { Formats } from 'intl-messageformat'; import IntlMessageFormat from 'intl-messageformat'; import type { @@ -35,8 +34,8 @@ const getIntlFormatterOptions = ( ): any => { const { formats } = getOptions(); - if (type in formats && name in (formats as Formats)[type]) { - return (formats as Formats)[type][name]; + if (type in formats && name in formats[type]) { + return formats[type][name]; } throw new Error(`[svelte-i18n] Unknown "${name}" ${type} format.`); @@ -106,6 +105,7 @@ export const getTimeFormatter: MemoizedDateTimeFormatterFactoryOptional = ({ } = {}) => createTimeFormatter({ locale, ...args }); export const getMessageFormatter = monadicMemoize( + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion (message: string, locale: string = getCurrentLocale()!) => new IntlMessageFormat(message, locale, getOptions().formats, { ignoreTag: getOptions().ignoreTag, diff --git a/src/runtime/includes/loaderQueue.ts b/src/runtime/includes/loaderQueue.ts index 1a6b42b..23f966a 100644 --- a/src/runtime/includes/loaderQueue.ts +++ b/src/runtime/includes/loaderQueue.ts @@ -41,7 +41,9 @@ function getLocalesQueues(locale: string) { .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( (localeQueue) => getLocaleQueue(localeQueue)?.size, ); diff --git a/src/runtime/stores/dictionary.ts b/src/runtime/stores/dictionary.ts index bf7fa28..be4c37e 100644 --- a/src/runtime/stores/dictionary.ts +++ b/src/runtime/stores/dictionary.ts @@ -5,7 +5,6 @@ import type { LocaleDictionary, LocalesDictionary } from '../types/index'; import { getPossibleLocales } from './locale'; import { delve } from '../../shared/delve'; import { lookupCache } from '../includes/lookup'; -import { locales } from '..'; let dictionary: LocalesDictionary; const $dictionary = writable({}); diff --git a/src/runtime/stores/formatters.ts b/src/runtime/stores/formatters.ts index c34303c..b04b6a3 100644 --- a/src/runtime/stores/formatters.ts +++ b/src/runtime/stores/formatters.ts @@ -21,16 +21,18 @@ import { $dictionary } from './dictionary'; import { getCurrentLocale, getPossibleLocales, $locale } from './locale'; const formatMessage: MessageFormatter = (id, options = {}) => { + let messageObj = options as MessageObject; + if (typeof id === 'object') { - options = id as MessageObject; - id = options.id!; + messageObj = id as MessageObject; + id = messageObj.id; } const { values, locale = getCurrentLocale(), default: defaultValue, - } = options; + } = messageObj; if (locale == null) { throw new Error( @@ -47,7 +49,7 @@ const formatMessage: MessageFormatter = (id, options = {}) => { `[svelte-i18n] The message "${id}" was not found in "${getPossibleLocales( locale, ).join('", "')}".${ - hasLocaleQueue(getCurrentLocale()!) + hasLocaleQueue(getCurrentLocale()) ? `\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); }; -const getJSON: JSONGetter = (id: string, locale = getCurrentLocale()): any => { - return lookup(id, locale); +const getJSON: JSONGetter = ( + id: string, + locale = getCurrentLocale(), +) => { + return lookup(id, locale) as T; }; export const $format = derived([$locale, $dictionary], () => formatMessage); diff --git a/src/runtime/stores/locale.ts b/src/runtime/stores/locale.ts index 441784b..d843aa7 100644 --- a/src/runtime/stores/locale.ts +++ b/src/runtime/stores/locale.ts @@ -29,11 +29,11 @@ export function getPossibleLocales( } export function getCurrentLocale() { - return current; + return current ?? undefined; } internalLocale.subscribe((newLocale: string | null | undefined) => { - current = newLocale; + current = newLocale ?? undefined; if (typeof window !== 'undefined' && newLocale != null) { document.documentElement.setAttribute('lang', newLocale); @@ -42,9 +42,8 @@ internalLocale.subscribe((newLocale: string | null | undefined) => { const set = (newLocale: string | null | undefined): void | Promise => { if ( - ((getClosestAvailableLocale as unknown) as ( - refLocale: string | null | undefined, - ) => refLocale is string)(newLocale) && + newLocale && + getClosestAvailableLocale(newLocale) && hasLocaleQueue(newLocale) ) { const { loadingDelay } = getOptions(); @@ -66,7 +65,7 @@ const set = (newLocale: string | null | undefined): void | Promise => { $isLoading.set(true); } - return flush(newLocale) + return flush(newLocale as string) .then(() => { internalLocale.set(newLocale); }) diff --git a/src/runtime/types/index.ts b/src/runtime/types/index.ts index 17cb1d6..16ee4b3 100644 --- a/src/runtime/types/index.ts +++ b/src/runtime/types/index.ts @@ -26,8 +26,8 @@ export type InterpolationValues = | undefined; export interface MessageObject { - id?: string; - locale?: string | null; + id: string; + locale?: string; format?: string; default?: string; values?: InterpolationValues; @@ -35,7 +35,7 @@ export interface MessageObject { export type MessageFormatter = ( id: string | MessageObject, - options?: MessageObject, + options?: Omit, ) => string; export type TimeFormatter = ( @@ -53,11 +53,11 @@ export type NumberFormatter = ( options?: IntlFormatterOptions, ) => string; -export type JSONGetter = (id: string, locale?: string | null) => any; +export type JSONGetter = (id: string, locale?: string | null) => T; type IntlFormatterOptions = T & { format?: string; - locale?: string | null; + locale?: string; }; export interface MemoizedIntlFormatter { @@ -74,8 +74,8 @@ export interface MessagesLoader { export interface ConfigureOptions { fallbackLocale: string; - formats: Partial; - initialLocale: string; + initialLocale?: string | null; + formats: Formats; loadingDelay: number; warnOnMissingMessages: boolean; ignoreTag: boolean; diff --git a/test/runtime/includes/utils.test.ts b/test/runtime/includes/utils.test.ts index 46d4647..26a2f06 100644 --- a/test/runtime/includes/utils.test.ts +++ b/test/runtime/includes/utils.test.ts @@ -8,13 +8,16 @@ import { describe('getting client locale', () => { 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 = { pathname: '/', hostname: 'example.com', hash: '', search: '', - } as any; + }; }); it('gets the locale based on the passed hash parameter', () => { diff --git a/test/runtime/stores/locale.test.ts b/test/runtime/stores/locale.test.ts index e5b9547..996243f 100644 --- a/test/runtime/stores/locale.test.ts +++ b/test/runtime/stores/locale.test.ts @@ -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', () => { init({ fallbackLocale: 'en', - initialLocale: null as any, }); expect(get($locale)).toBe('en'); expect(getOptions().fallbackLocale).toBe('en');