mirror of
https://github.com/cupcakearmy/svelte-i18n.git
synced 2024-11-16 18:10:43 +01:00
fix: enable typescript strictNullChecks
This commit is contained in:
parent
2537314af5
commit
bf4189a862
@ -23,7 +23,7 @@ const FORMAT_METHOD_NAMES = new Set(['format', '_', 't']);
|
|||||||
function isFormatCall(node: Node, imports: Set<string>) {
|
function isFormatCall(node: Node, imports: Set<string>) {
|
||||||
if (node.type !== 'CallExpression') return false;
|
if (node.type !== 'CallExpression') return false;
|
||||||
|
|
||||||
let identifier: Identifier;
|
let identifier: Identifier | undefined;
|
||||||
|
|
||||||
if (node.callee.type === 'Identifier') {
|
if (node.callee.type === 'Identifier') {
|
||||||
identifier = node.callee;
|
identifier = node.callee;
|
||||||
@ -125,7 +125,9 @@ export function collectMessageDefinitions(ast: Ast) {
|
|||||||
definitionDict.properties.map((propNode) => {
|
definitionDict.properties.map((propNode) => {
|
||||||
if (propNode.type !== 'Property') {
|
if (propNode.type !== 'Property') {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Found invalid '${propNode.type}' at L${propNode.loc.start.line}:${propNode.loc.start.column}`,
|
`Found invalid '${propNode.type}' at L${propNode.loc!.start.line}:${
|
||||||
|
propNode.loc!.start.column
|
||||||
|
}`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -143,7 +145,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;
|
let messageObj: Partial<Message>;
|
||||||
|
|
||||||
if (pathNode.type === 'ObjectExpression') {
|
if (pathNode.type === 'ObjectExpression') {
|
||||||
// _({ ...opts })
|
// _({ ...opts })
|
||||||
@ -166,7 +168,7 @@ export function collectMessages(markup: string): Message[] {
|
|||||||
|
|
||||||
return messageObj;
|
return messageObj;
|
||||||
}),
|
}),
|
||||||
].filter(Boolean);
|
].filter((Boolean as unknown) as (x: Message | null) => x is Message);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function extractMessages(
|
export function extractMessages(
|
||||||
|
@ -2,8 +2,10 @@ import type { ObjectExpression, Property, Identifier } from 'estree';
|
|||||||
|
|
||||||
import type { Message } from '../types';
|
import type { Message } from '../types';
|
||||||
|
|
||||||
export function getObjFromExpression(exprNode: ObjectExpression) {
|
export function getObjFromExpression(
|
||||||
return exprNode.properties.reduce<Message>((acc, prop: Property) => {
|
exprNode: ObjectExpression,
|
||||||
|
): 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' &&
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
export interface Message {
|
export interface Message {
|
||||||
id?: string;
|
id: string;
|
||||||
default?: string;
|
default: string;
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import type { ConfigureOptions } from './types';
|
import type { ConfigureOptions, ConfigureOptionsInit } from './types';
|
||||||
import { $locale } from './stores/locale';
|
import { $locale } from './stores/locale';
|
||||||
|
|
||||||
interface Formats {
|
interface Formats {
|
||||||
@ -47,13 +47,13 @@ export const defaultOptions: ConfigureOptions = {
|
|||||||
ignoreTag: true,
|
ignoreTag: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
const options: ConfigureOptions = defaultOptions;
|
const options: ConfigureOptions = defaultOptions as any;
|
||||||
|
|
||||||
export function getOptions() {
|
export function getOptions() {
|
||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function init(opts: ConfigureOptions) {
|
export function init(opts: ConfigureOptionsInit) {
|
||||||
const { formats, ...rest } = opts;
|
const { formats, ...rest } = opts;
|
||||||
const initialLocale = opts.initialLocale || opts.fallbackLocale;
|
const initialLocale = opts.initialLocale || opts.fallbackLocale;
|
||||||
|
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
import IntlMessageFormat from 'intl-messageformat';
|
import IntlMessageFormat from 'intl-messageformat';
|
||||||
|
|
||||||
import type { MemoizedIntlFormatter } from '../types';
|
import type {
|
||||||
|
MemoizedIntlFormatter,
|
||||||
|
MemoizedIntlFormatterOptional,
|
||||||
|
} from '../types';
|
||||||
import { getCurrentLocale } from '../stores/locale';
|
import { getCurrentLocale } from '../stores/locale';
|
||||||
import { getOptions } from '../configs';
|
import { getOptions } from '../configs';
|
||||||
import { monadicMemoize } from './memoize';
|
import { monadicMemoize } from './memoize';
|
||||||
@ -15,6 +18,16 @@ type MemoizedDateTimeFormatterFactory = MemoizedIntlFormatter<
|
|||||||
Intl.DateTimeFormatOptions
|
Intl.DateTimeFormatOptions
|
||||||
>;
|
>;
|
||||||
|
|
||||||
|
type MemoizedNumberFormatterFactoryOptional = MemoizedIntlFormatterOptional<
|
||||||
|
Intl.NumberFormat,
|
||||||
|
Intl.NumberFormatOptions
|
||||||
|
>;
|
||||||
|
|
||||||
|
type MemoizedDateTimeFormatterFactoryOptional = MemoizedIntlFormatterOptional<
|
||||||
|
Intl.DateTimeFormat,
|
||||||
|
Intl.DateTimeFormatOptions
|
||||||
|
>;
|
||||||
|
|
||||||
const getIntlFormatterOptions = (
|
const getIntlFormatterOptions = (
|
||||||
type: 'time' | 'number' | 'date',
|
type: 'time' | 'number' | 'date',
|
||||||
name: string,
|
name: string,
|
||||||
@ -76,17 +89,17 @@ const createTimeFormatter: MemoizedDateTimeFormatterFactory = monadicMemoize(
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
export const getNumberFormatter: MemoizedNumberFormatterFactory = ({
|
export const getNumberFormatter: MemoizedNumberFormatterFactoryOptional = ({
|
||||||
locale = getCurrentLocale(),
|
locale = getCurrentLocale(),
|
||||||
...args
|
...args
|
||||||
} = {}) => createNumberFormatter({ locale, ...args });
|
} = {}) => createNumberFormatter({ locale, ...args });
|
||||||
|
|
||||||
export const getDateFormatter: MemoizedDateTimeFormatterFactory = ({
|
export const getDateFormatter: MemoizedDateTimeFormatterFactoryOptional = ({
|
||||||
locale = getCurrentLocale(),
|
locale = getCurrentLocale(),
|
||||||
...args
|
...args
|
||||||
} = {}) => createDateFormatter({ locale, ...args });
|
} = {}) => createDateFormatter({ locale, ...args });
|
||||||
|
|
||||||
export const getTimeFormatter: MemoizedDateTimeFormatterFactory = ({
|
export const getTimeFormatter: MemoizedDateTimeFormatterFactoryOptional = ({
|
||||||
locale = getCurrentLocale(),
|
locale = getCurrentLocale(),
|
||||||
...args
|
...args
|
||||||
} = {}) => createTimeFormatter({ locale, ...args });
|
} = {}) => createTimeFormatter({ locale, ...args });
|
||||||
|
@ -62,7 +62,7 @@ function loadLocaleQueue(locale: string, localeQueue: MessagesLoader[]) {
|
|||||||
|
|
||||||
const activeFlushes: { [key: string]: Promise<void> } = {};
|
const activeFlushes: { [key: string]: Promise<void> } = {};
|
||||||
|
|
||||||
export function flush(locale: string): Promise<void> {
|
export async function flush(locale: string): Promise<void> {
|
||||||
if (!hasLocaleQueue(locale)) {
|
if (!hasLocaleQueue(locale)) {
|
||||||
if (locale in activeFlushes) {
|
if (locale in activeFlushes) {
|
||||||
return activeFlushes[locale];
|
return activeFlushes[locale];
|
||||||
|
@ -15,7 +15,7 @@ const addToCache = (path: string, locale: string, message: string) => {
|
|||||||
return message;
|
return message;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const lookup = (path: string, refLocale: string) => {
|
export const lookup = (path: string, refLocale: string | null | undefined) => {
|
||||||
if (refLocale == null) return undefined;
|
if (refLocale == null) return undefined;
|
||||||
|
|
||||||
if (refLocale in lookupCache && path in lookupCache[refLocale]) {
|
if (refLocale in lookupCache && path in lookupCache[refLocale]) {
|
||||||
|
@ -31,7 +31,7 @@ export function defineMessages(i: Record<string, MessageObject>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function waitLocale(locale?: string) {
|
export function waitLocale(locale?: string) {
|
||||||
return flush(locale || getCurrentLocale() || getOptions().initialLocale);
|
return flush(locale || getCurrentLocale() || getOptions().initialLocale!);
|
||||||
}
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
@ -34,7 +34,9 @@ export function getMessageFromDictionary(locale: string, id: string) {
|
|||||||
return match;
|
return match;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getClosestAvailableLocale(refLocale: string): string | null {
|
export function getClosestAvailableLocale(
|
||||||
|
refLocale: string,
|
||||||
|
): string | null | undefined {
|
||||||
if (refLocale == null) return undefined;
|
if (refLocale == null) return undefined;
|
||||||
|
|
||||||
const relatedLocales = getPossibleLocales(refLocale);
|
const relatedLocales = getPossibleLocales(refLocale);
|
||||||
|
@ -23,7 +23,7 @@ import { getCurrentLocale, getPossibleLocales, $locale } from './locale';
|
|||||||
const formatMessage: MessageFormatter = (id, options = {}) => {
|
const formatMessage: MessageFormatter = (id, options = {}) => {
|
||||||
if (typeof id === 'object') {
|
if (typeof id === 'object') {
|
||||||
options = id as MessageObject;
|
options = id as MessageObject;
|
||||||
id = options.id;
|
id = options.id!;
|
||||||
}
|
}
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@ -90,11 +90,8 @@ const formatNumber: NumberFormatter = (n, options) => {
|
|||||||
return getNumberFormatter(options).format(n);
|
return getNumberFormatter(options).format(n);
|
||||||
};
|
};
|
||||||
|
|
||||||
const getJSON: JSONGetter = <T = any>(
|
const getJSON: JSONGetter = (id: string, locale = getCurrentLocale()): any => {
|
||||||
id: string,
|
return lookup(id, locale);
|
||||||
locale = getCurrentLocale(),
|
|
||||||
) => {
|
|
||||||
return lookup(id, locale) as T;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const $format = derived([$locale, $dictionary], () => formatMessage);
|
export const $format = derived([$locale, $dictionary], () => formatMessage);
|
||||||
|
@ -6,7 +6,7 @@ import { getClosestAvailableLocale } from './dictionary';
|
|||||||
import { $isLoading } from './loading';
|
import { $isLoading } from './loading';
|
||||||
|
|
||||||
let current: string;
|
let current: string;
|
||||||
const $locale = writable(null);
|
const $locale = writable<string | null | undefined>(null);
|
||||||
|
|
||||||
function getSubLocales(refLocale: string) {
|
function getSubLocales(refLocale: string) {
|
||||||
return refLocale
|
return refLocale
|
||||||
@ -77,7 +77,8 @@ $locale.set = (newLocale: string): void | Promise<void> => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// istanbul ignore next
|
// istanbul ignore next
|
||||||
$locale.update = (fn: (locale: string) => void | Promise<void>) =>
|
$locale.update = (
|
||||||
localeSet(fn(current));
|
fn: (value: string | null | undefined) => string | null | undefined,
|
||||||
|
) => localeSet(fn(current));
|
||||||
|
|
||||||
export { $locale };
|
export { $locale };
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
import type { FormatXMLElementFn, Formats } from 'intl-messageformat';
|
import type { FormatXMLElementFn, Formats } from 'intl-messageformat';
|
||||||
|
|
||||||
export interface LocaleDictionary {
|
export interface LocaleDictionary {
|
||||||
[key: string]: LocaleDictionary | string | Array<string | LocaleDictionary>;
|
[key: string]:
|
||||||
|
| LocaleDictionary
|
||||||
|
| string
|
||||||
|
| Array<string | LocaleDictionary>
|
||||||
|
| null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type LocalesDictionary = {
|
export type LocalesDictionary = {
|
||||||
@ -49,7 +53,7 @@ export type NumberFormatter = (
|
|||||||
options?: IntlFormatterOptions<Intl.NumberFormatOptions>,
|
options?: IntlFormatterOptions<Intl.NumberFormatOptions>,
|
||||||
) => string;
|
) => string;
|
||||||
|
|
||||||
export type JSONGetter = <T>(id: string, locale?: string) => T;
|
export type JSONGetter = (id: string, locale?: string) => any;
|
||||||
|
|
||||||
type IntlFormatterOptions<T> = T & {
|
type IntlFormatterOptions<T> = T & {
|
||||||
format?: string;
|
format?: string;
|
||||||
@ -57,6 +61,10 @@ type IntlFormatterOptions<T> = T & {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export interface MemoizedIntlFormatter<T, U> {
|
export interface MemoizedIntlFormatter<T, U> {
|
||||||
|
(options: IntlFormatterOptions<U>): T;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MemoizedIntlFormatterOptional<T, U> {
|
||||||
(options?: IntlFormatterOptions<U>): T;
|
(options?: IntlFormatterOptions<U>): T;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,10 +73,14 @@ export interface MessagesLoader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface ConfigureOptions {
|
export interface ConfigureOptions {
|
||||||
fallbackLocale: string;
|
fallbackLocale: string | null | undefined;
|
||||||
formats?: Partial<Formats>;
|
formats: Formats;
|
||||||
initialLocale?: string;
|
initialLocale: string | null;
|
||||||
loadingDelay?: number;
|
loadingDelay: number;
|
||||||
warnOnMissingMessages?: boolean;
|
warnOnMissingMessages: boolean;
|
||||||
ignoreTag?: boolean;
|
ignoreTag: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type ConfigureOptionsInit = Pick<ConfigureOptions, 'fallbackLocale'> &
|
||||||
|
Partial<Record<'formats', Partial<ConfigureOptions['formats']>>> &
|
||||||
|
Partial<Omit<ConfigureOptions, 'fallbackLocale' | 'formats'>>;
|
||||||
|
@ -23,8 +23,8 @@ test('checks if exist queues of locale and its fallbacks', () => {
|
|||||||
expect(hasLocaleQueue('en-US')).toBe(true);
|
expect(hasLocaleQueue('en-US')).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("does nothing if there's no queue for a locale", () => {
|
test("does nothing if there's no queue for a locale", async () => {
|
||||||
expect(flush('foo')).toBeUndefined();
|
expect(await flush('foo')).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('flushes the queue of a locale and its fallbacks and merge the result with the dictionary', async () => {
|
test('flushes the queue of a locale and its fallbacks and merge the result with the dictionary', async () => {
|
||||||
|
@ -8,7 +8,7 @@ import {
|
|||||||
|
|
||||||
describe('getting client locale', () => {
|
describe('getting client locale', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
delete window.location;
|
delete (window as any).location;
|
||||||
window.location = {
|
window.location = {
|
||||||
pathname: '/',
|
pathname: '/',
|
||||||
hostname: 'example.com',
|
hostname: 'example.com',
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
|
"strictNullChecks": true,
|
||||||
"noImplicitAny": true,
|
"noImplicitAny": true,
|
||||||
"sourceMap": false,
|
"sourceMap": false,
|
||||||
"module": "esnext",
|
"module": "esnext",
|
||||||
"moduleResolution": "node",
|
"moduleResolution": "node",
|
||||||
|
"skipLibCheck": true,
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
"target": "es2017",
|
"target": "es2017",
|
||||||
|
@ -1263,9 +1263,9 @@
|
|||||||
integrity sha512-lg55ArB+ZiHHbBBttLpzD07akz0QPrZgUODNakeC09i62dnrywr9mFErHuaPlB6I7z+sEbK+IYmplahvplCj2g==
|
integrity sha512-lg55ArB+ZiHHbBBttLpzD07akz0QPrZgUODNakeC09i62dnrywr9mFErHuaPlB6I7z+sEbK+IYmplahvplCj2g==
|
||||||
|
|
||||||
"@types/node@^14.14.35":
|
"@types/node@^14.14.35":
|
||||||
version "14.14.35"
|
version "14.17.11"
|
||||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.35.tgz#42c953a4e2b18ab931f72477e7012172f4ffa313"
|
resolved "https://registry.yarnpkg.com/@types/node/-/node-14.17.11.tgz#82d266d657aec5ff01ca59f2ffaff1bb43f7bf0f"
|
||||||
integrity sha512-Lt+wj8NVPx0zUmUwumiVXapmaLUcAk3yPuHCFVXras9k5VT9TdhJqKqGVUQCD60OTMCl0qxJ57OiTL0Mic3Iag==
|
integrity sha512-n2OQ+0Bz6WEsUjrvcHD1xZ8K+Kgo4cn9/w94s1bJS690QMUWfJPW/m7CCb7gPkA1fcYwL2UpjXP/rq/Eo41m6w==
|
||||||
|
|
||||||
"@types/normalize-package-data@^2.4.0":
|
"@types/normalize-package-data@^2.4.0":
|
||||||
version "2.4.0"
|
version "2.4.0"
|
||||||
|
Loading…
Reference in New Issue
Block a user