mirror of
https://github.com/cupcakearmy/svelte-i18n.git
synced 2024-06-30 18:54:49 +02:00
refactor: some minor changes
This commit is contained in:
parent
8235f1e078
commit
a7ce70fc0f
|
@ -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(
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
export interface Message {
|
export interface Message {
|
||||||
id: string;
|
id: string;
|
||||||
default: string;
|
default?: string;
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
);
|
);
|
||||||
|
|
|
@ -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>({});
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
})
|
})
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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', () => {
|
||||||
|
|
|
@ -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');
|
||||||
|
|
Loading…
Reference in New Issue
Block a user