@vocab/core 1.2.5 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/declarations/src/compile.d.ts +1 -1
- package/dist/declarations/src/config.d.ts +1 -1
- package/dist/declarations/src/generate-language.d.ts +1 -1
- package/dist/declarations/src/icu-handler.d.ts +1 -1
- package/dist/declarations/src/index.d.ts +1 -1
- package/dist/declarations/src/load-translations.d.ts +1 -1
- package/dist/declarations/src/runtime.d.ts +1 -1
- package/dist/declarations/src/translation-file.d.ts +1 -1
- package/dist/declarations/src/types.d.ts +115 -0
- package/dist/declarations/src/utils.d.ts +1 -1
- package/dist/declarations/src/validate/index.d.ts +1 -1
- package/dist/vocab-core.cjs.dev.js +22 -22
- package/dist/vocab-core.cjs.prod.js +22 -22
- package/dist/vocab-core.esm.js +22 -22
- package/package.json +1 -2
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { LoadedTranslation, UserConfig } from '
|
|
1
|
+
import { LoadedTranslation, UserConfig } from './types';
|
|
2
2
|
export declare function generateRuntime(loadedTranslation: LoadedTranslation): Promise<void>;
|
|
3
3
|
export declare function watch(config: UserConfig): () => Promise<void>;
|
|
4
4
|
export declare function compile({ watch: shouldWatch }: {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { UserConfig } from '
|
|
1
|
+
import type { UserConfig } from './types';
|
|
2
2
|
export declare function validateConfig(c: UserConfig): boolean;
|
|
3
3
|
export declare function resolveConfig(customConfigFilePath?: string): Promise<UserConfig | null>;
|
|
4
4
|
export declare function resolveConfigSync(customConfigFilePath?: string): UserConfig | null;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { MessageGenerator, TranslationsByKey } from '
|
|
1
|
+
import type { MessageGenerator, TranslationsByKey } from './types';
|
|
2
2
|
export declare function generateLanguageFromTranslations({ baseTranslations, generator, }: {
|
|
3
3
|
baseTranslations: TranslationsByKey<string>;
|
|
4
4
|
generator: MessageGenerator;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { ParsedICUMessages, TranslationMessagesByKey } from '
|
|
1
|
+
import type { ParsedICUMessages, TranslationMessagesByKey } from './types';
|
|
2
2
|
export declare const getParsedICUMessages: (m: TranslationMessagesByKey, locale: string) => ParsedICUMessages<any>;
|
|
@@ -3,4 +3,4 @@ export { validate } from './validate';
|
|
|
3
3
|
export { resolveConfig, resolveConfigSync, validateConfig } from './config';
|
|
4
4
|
export { getAltLanguages, getAltLanguageFilePath, getDevLanguageFileFromTsFile, } from './utils';
|
|
5
5
|
export { getUniqueKey, loadAllTranslations, loadTranslation, } from './load-translations';
|
|
6
|
-
export
|
|
6
|
+
export * from './types';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { TranslationsByKey, UserConfig, LoadedTranslation, LanguageTarget } from '
|
|
1
|
+
import type { TranslationsByKey, UserConfig, LoadedTranslation, LanguageTarget } from './types';
|
|
2
2
|
import { Fallback } from './utils';
|
|
3
3
|
export declare function getUniqueKey(key: string, namespace: string): string;
|
|
4
4
|
export declare function mergeWithDevLanguageTranslation({ translation, devTranslation, }: {
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { TranslationModule, TranslationMessagesByKey } from '
|
|
1
|
+
import type { TranslationModule, TranslationMessagesByKey } from './types';
|
|
2
2
|
export { createTranslationFile } from './translation-file';
|
|
3
3
|
export declare const createLanguage: (module: TranslationMessagesByKey) => TranslationModule<any>;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { TranslationModuleByLanguage, LanguageName, ParsedFormatFnByKey, TranslationFile } from '
|
|
1
|
+
import type { TranslationModuleByLanguage, LanguageName, ParsedFormatFnByKey, TranslationFile } from './types';
|
|
2
2
|
export declare function createTranslationFile<Language extends LanguageName, FormatFnByKey extends ParsedFormatFnByKey>(translationsByLanguage: TranslationModuleByLanguage<Language, FormatFnByKey>): TranslationFile<Language, FormatFnByKey>;
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
export type { FormatXMLElementFn } from 'intl-messageformat';
|
|
2
|
+
export type LanguageName = string;
|
|
3
|
+
export type TranslationKey = string;
|
|
4
|
+
export type TranslationMessage = string;
|
|
5
|
+
export type ParsedFormatFn = (parts: any) => any;
|
|
6
|
+
export type ParsedFormatFnByKey = Record<string, ParsedFormatFn>;
|
|
7
|
+
/**
|
|
8
|
+
* Equivalent to the `string` type, but tricks the language server into prodiving
|
|
9
|
+
* suggestions for string literals passed into the `Suggestions` generic parameter
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* Accept any string, but suggest specific animals
|
|
13
|
+
* ```
|
|
14
|
+
* type AnyAnimal = StringWithSuggestions<"cat" | "dog">;
|
|
15
|
+
* // Suggests cat and dog, but accepts any string
|
|
16
|
+
* const animal: AnyAnimal = "";
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export type StringWithSuggestions<Suggestions extends string> = Suggestions | Omit<string, Suggestions>;
|
|
20
|
+
/**
|
|
21
|
+
* ParsedICUMessage A strictly typed formatter from intl-messageformat
|
|
22
|
+
*/
|
|
23
|
+
interface ParsedICUMessage<FormatFn extends ParsedFormatFn> {
|
|
24
|
+
format: FormatFn;
|
|
25
|
+
}
|
|
26
|
+
export type ParsedICUMessages<FormatFnByKey extends ParsedFormatFnByKey> = {
|
|
27
|
+
[key in keyof FormatFnByKey]: ParsedICUMessage<FormatFnByKey[key]>;
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* TranslationModule is a wrapper around a potentially asynchronously loaded set of ParsedICUMessages
|
|
31
|
+
*/
|
|
32
|
+
export type TranslationModule<FormatFnByKey extends ParsedFormatFnByKey> = {
|
|
33
|
+
getValue: (locale: string) => ParsedICUMessages<FormatFnByKey> | undefined;
|
|
34
|
+
load: () => Promise<void>;
|
|
35
|
+
};
|
|
36
|
+
export type TranslationModuleByLanguage<Language extends LanguageName, FormatFnByKey extends ParsedFormatFnByKey> = Record<Language, TranslationModule<FormatFnByKey>>;
|
|
37
|
+
/**
|
|
38
|
+
* TranslationFile contains a record of TranslationModules per language, exposing a set of methods to load and return the module by language
|
|
39
|
+
*/
|
|
40
|
+
export type TranslationFile<Language extends LanguageName, FormatFnByKey extends ParsedFormatFnByKey> = {
|
|
41
|
+
/**
|
|
42
|
+
* Retrieve messages. If not loaded, will attempt to load messages and resolve once complete.
|
|
43
|
+
*/
|
|
44
|
+
getMessages: (language: Language, locale?: string) => Promise<ParsedICUMessages<FormatFnByKey>>;
|
|
45
|
+
/**
|
|
46
|
+
* Retrieve already loaded messages. Will return null if no messages have been loaded.
|
|
47
|
+
*/
|
|
48
|
+
getLoadedMessages: (language: Language, locale?: string) => ParsedICUMessages<FormatFnByKey> | null;
|
|
49
|
+
/**
|
|
50
|
+
* Load messages for the given language. Resolving once complete.
|
|
51
|
+
*/
|
|
52
|
+
load: (language: Language) => Promise<void>;
|
|
53
|
+
};
|
|
54
|
+
export interface LanguageTarget {
|
|
55
|
+
name: LanguageName;
|
|
56
|
+
extends?: LanguageName;
|
|
57
|
+
}
|
|
58
|
+
export interface MessageGenerator {
|
|
59
|
+
transformElement?: (element: string) => string;
|
|
60
|
+
transformMessage?: (message: string) => string;
|
|
61
|
+
}
|
|
62
|
+
export interface GeneratedLanguageTarget {
|
|
63
|
+
name: LanguageName;
|
|
64
|
+
extends?: LanguageName;
|
|
65
|
+
generator: MessageGenerator;
|
|
66
|
+
}
|
|
67
|
+
export interface UserConfig {
|
|
68
|
+
/**
|
|
69
|
+
* The root directory to compile and validate translations
|
|
70
|
+
*/
|
|
71
|
+
projectRoot?: string;
|
|
72
|
+
/**
|
|
73
|
+
* The language used in translations.json
|
|
74
|
+
*/
|
|
75
|
+
devLanguage: LanguageName;
|
|
76
|
+
/**
|
|
77
|
+
* An array of languages to build for
|
|
78
|
+
*/
|
|
79
|
+
languages: Array<LanguageTarget>;
|
|
80
|
+
/**
|
|
81
|
+
* An array of languages to generate from existing translations
|
|
82
|
+
*/
|
|
83
|
+
generatedLanguages?: Array<GeneratedLanguageTarget>;
|
|
84
|
+
/**
|
|
85
|
+
* A custom suffix to name vocab translation directories
|
|
86
|
+
*/
|
|
87
|
+
translationsDirectorySuffix?: string;
|
|
88
|
+
/**
|
|
89
|
+
* An array of glob paths to ignore from compilation and validation
|
|
90
|
+
*/
|
|
91
|
+
ignore?: Array<string>;
|
|
92
|
+
}
|
|
93
|
+
export type Tags = Array<string>;
|
|
94
|
+
export interface TranslationFileMetadata {
|
|
95
|
+
tags?: Tags;
|
|
96
|
+
}
|
|
97
|
+
export interface TranslationData {
|
|
98
|
+
message: TranslationMessage;
|
|
99
|
+
description?: string;
|
|
100
|
+
tags?: Tags;
|
|
101
|
+
}
|
|
102
|
+
export type TranslationsByKey<Key extends TranslationKey = string> = Record<Key, TranslationData>;
|
|
103
|
+
export type TranslationFileContents = TranslationsByKey & {
|
|
104
|
+
_meta?: TranslationFileMetadata;
|
|
105
|
+
};
|
|
106
|
+
export type TranslationMessagesByKey<Key extends TranslationKey = string> = Record<Key, TranslationMessage>;
|
|
107
|
+
export type TranslationsByLanguage<Key extends TranslationKey = string> = Record<LanguageName, TranslationsByKey<Key>>;
|
|
108
|
+
export type LoadedTranslation<Key extends TranslationKey = string> = {
|
|
109
|
+
namespace: string;
|
|
110
|
+
keys: Array<Key>;
|
|
111
|
+
filePath: string;
|
|
112
|
+
relativePath: string;
|
|
113
|
+
languages: TranslationsByLanguage<Key>;
|
|
114
|
+
metadata: TranslationFileMetadata;
|
|
115
|
+
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { LanguageName, LanguageTarget, TranslationsByKey, TranslationMessagesByKey, UserConfig } from '
|
|
1
|
+
import type { LanguageName, LanguageTarget, TranslationsByKey, TranslationMessagesByKey, UserConfig } from './types';
|
|
2
2
|
export declare const defaultTranslationDirSuffix = ".vocab";
|
|
3
3
|
export declare const devTranslationFileName = "translations.json";
|
|
4
4
|
export type Fallback = 'none' | 'valid' | 'all';
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { UserConfig, LoadedTranslation, LanguageName } from '
|
|
1
|
+
import { UserConfig, LoadedTranslation, LanguageName } from '../types';
|
|
2
2
|
export declare function findMissingKeys(loadedTranslation: LoadedTranslation, devLanguageName: LanguageName, altLanguages: Array<LanguageName>): readonly [boolean, Record<string, string[]>];
|
|
3
3
|
export declare function validate(config: UserConfig): Promise<boolean>;
|
|
@@ -438,8 +438,6 @@ async function loadAllTranslations({
|
|
|
438
438
|
return result;
|
|
439
439
|
}
|
|
440
440
|
|
|
441
|
-
const encodeWithinSingleQuotes = v => v.replace(/'/g, "\\'");
|
|
442
|
-
const encodeBackslash = v => v.replace(/\\/g, '\\\\');
|
|
443
441
|
function extractHasTags(ast) {
|
|
444
442
|
return ast.some(element => {
|
|
445
443
|
if (icuMessageformatParser.isSelectElement(element)) {
|
|
@@ -500,21 +498,16 @@ function extractParamTypes(ast, currentParams) {
|
|
|
500
498
|
function serialiseObjectToType(v) {
|
|
501
499
|
let result = '';
|
|
502
500
|
for (const [key, value] of Object.entries(v)) {
|
|
503
|
-
|
|
504
|
-
result += `'${encodeWithinSingleQuotes(key)}': ${serialiseObjectToType(value)},`;
|
|
505
|
-
} else {
|
|
506
|
-
result += `'${encodeWithinSingleQuotes(key)}': ${value},`;
|
|
507
|
-
}
|
|
501
|
+
result += `${JSON.stringify(key)}: ${value && typeof value === 'object' ? serialiseObjectToType(value) : value},`;
|
|
508
502
|
}
|
|
509
503
|
return `{ ${result} }`;
|
|
510
504
|
}
|
|
511
|
-
const
|
|
512
|
-
const serializeModuleImports = (imports, moduleName) => {
|
|
505
|
+
const serializeTypeImports = (imports, moduleName) => {
|
|
513
506
|
if (imports.size === 0) {
|
|
514
507
|
return '';
|
|
515
508
|
}
|
|
516
509
|
const importNames = Array.from(imports);
|
|
517
|
-
return `import { ${
|
|
510
|
+
return `import type { ${importNames.join(', ')} } from '${moduleName}';`;
|
|
518
511
|
};
|
|
519
512
|
function serialiseTranslationRuntime(value, imports, loadedTranslation) {
|
|
520
513
|
trace('Serialising translations:', loadedTranslation);
|
|
@@ -527,21 +520,30 @@ function serialiseTranslationRuntime(value, imports, loadedTranslation) {
|
|
|
527
520
|
let translationFunctionString = `() => ${message}`;
|
|
528
521
|
if (Object.keys(params).length > 0) {
|
|
529
522
|
const formatGeneric = hasTags ? '<T = string>' : '';
|
|
530
|
-
const formatReturn = hasTags
|
|
523
|
+
const formatReturn = hasTags && imports.has('FormatXMLElementFn') ? 'ReturnType<FormatXMLElementFn<T>>' : 'string';
|
|
531
524
|
translationFunctionString = `${formatGeneric}(values: ${serialiseObjectToType(params)}) => ${formatReturn}`;
|
|
532
525
|
}
|
|
533
|
-
translationsType[
|
|
526
|
+
translationsType[key] = translationFunctionString;
|
|
534
527
|
}
|
|
535
|
-
const content = Object.entries(loadedTranslation.languages).map(([languageName, translations]) => `'${encodeWithinSingleQuotes(languageName)}': createLanguage(${JSON.stringify(getTranslationMessages(translations))})`).join(',');
|
|
536
528
|
const languagesUnionAsString = Object.keys(loadedTranslation.languages).map(l => `'${l}'`).join(' | ');
|
|
537
|
-
|
|
529
|
+
const languageEntries = Object.entries(loadedTranslation.languages).map(([languageName, translations]) => `${JSON.stringify(languageName)}: createLanguage(${JSON.stringify(getTranslationMessages(translations))})`).join(',');
|
|
530
|
+
return (/* ts */`
|
|
531
|
+
// This file is automatically generated by Vocab.
|
|
532
|
+
// To make changes update translation.json files directly.
|
|
538
533
|
|
|
539
|
-
|
|
540
|
-
|
|
534
|
+
${serializeTypeImports(imports, '@vocab/core')}
|
|
535
|
+
import { createLanguage, createTranslationFile } from '@vocab/core/runtime';
|
|
541
536
|
|
|
542
|
-
|
|
537
|
+
const translations = createTranslationFile<
|
|
538
|
+
${languagesUnionAsString},
|
|
539
|
+
${serialiseObjectToType(translationsType)}
|
|
540
|
+
>({
|
|
541
|
+
${languageEntries}
|
|
542
|
+
});
|
|
543
543
|
|
|
544
|
-
|
|
544
|
+
export default translations;
|
|
545
|
+
`
|
|
546
|
+
);
|
|
545
547
|
}
|
|
546
548
|
async function generateRuntime(loadedTranslation) {
|
|
547
549
|
const {
|
|
@@ -562,15 +564,13 @@ async function generateRuntime(loadedTranslation) {
|
|
|
562
564
|
const [parsedParams, vocabTypesImports] = extractParamTypes(ast, params);
|
|
563
565
|
imports = new Set([...imports, ...vocabTypesImports]);
|
|
564
566
|
params = parsedParams;
|
|
565
|
-
messages.add(
|
|
567
|
+
messages.add(JSON.stringify(translatedLanguage[key].message));
|
|
566
568
|
}
|
|
567
569
|
}
|
|
568
|
-
const returnType = hasTags ? 'NonNullable<ReactNode>' : 'string';
|
|
569
570
|
translationTypes.set(key, {
|
|
570
571
|
params,
|
|
571
572
|
hasTags,
|
|
572
|
-
message: Array.from(messages).join(' | ')
|
|
573
|
-
returnType
|
|
573
|
+
message: Array.from(messages).join(' | ')
|
|
574
574
|
});
|
|
575
575
|
}
|
|
576
576
|
const prettierConfig = await prettier__default["default"].resolveConfig(filePath);
|
|
@@ -438,8 +438,6 @@ async function loadAllTranslations({
|
|
|
438
438
|
return result;
|
|
439
439
|
}
|
|
440
440
|
|
|
441
|
-
const encodeWithinSingleQuotes = v => v.replace(/'/g, "\\'");
|
|
442
|
-
const encodeBackslash = v => v.replace(/\\/g, '\\\\');
|
|
443
441
|
function extractHasTags(ast) {
|
|
444
442
|
return ast.some(element => {
|
|
445
443
|
if (icuMessageformatParser.isSelectElement(element)) {
|
|
@@ -500,21 +498,16 @@ function extractParamTypes(ast, currentParams) {
|
|
|
500
498
|
function serialiseObjectToType(v) {
|
|
501
499
|
let result = '';
|
|
502
500
|
for (const [key, value] of Object.entries(v)) {
|
|
503
|
-
|
|
504
|
-
result += `'${encodeWithinSingleQuotes(key)}': ${serialiseObjectToType(value)},`;
|
|
505
|
-
} else {
|
|
506
|
-
result += `'${encodeWithinSingleQuotes(key)}': ${value},`;
|
|
507
|
-
}
|
|
501
|
+
result += `${JSON.stringify(key)}: ${value && typeof value === 'object' ? serialiseObjectToType(value) : value},`;
|
|
508
502
|
}
|
|
509
503
|
return `{ ${result} }`;
|
|
510
504
|
}
|
|
511
|
-
const
|
|
512
|
-
const serializeModuleImports = (imports, moduleName) => {
|
|
505
|
+
const serializeTypeImports = (imports, moduleName) => {
|
|
513
506
|
if (imports.size === 0) {
|
|
514
507
|
return '';
|
|
515
508
|
}
|
|
516
509
|
const importNames = Array.from(imports);
|
|
517
|
-
return `import { ${
|
|
510
|
+
return `import type { ${importNames.join(', ')} } from '${moduleName}';`;
|
|
518
511
|
};
|
|
519
512
|
function serialiseTranslationRuntime(value, imports, loadedTranslation) {
|
|
520
513
|
trace('Serialising translations:', loadedTranslation);
|
|
@@ -527,21 +520,30 @@ function serialiseTranslationRuntime(value, imports, loadedTranslation) {
|
|
|
527
520
|
let translationFunctionString = `() => ${message}`;
|
|
528
521
|
if (Object.keys(params).length > 0) {
|
|
529
522
|
const formatGeneric = hasTags ? '<T = string>' : '';
|
|
530
|
-
const formatReturn = hasTags
|
|
523
|
+
const formatReturn = hasTags && imports.has('FormatXMLElementFn') ? 'ReturnType<FormatXMLElementFn<T>>' : 'string';
|
|
531
524
|
translationFunctionString = `${formatGeneric}(values: ${serialiseObjectToType(params)}) => ${formatReturn}`;
|
|
532
525
|
}
|
|
533
|
-
translationsType[
|
|
526
|
+
translationsType[key] = translationFunctionString;
|
|
534
527
|
}
|
|
535
|
-
const content = Object.entries(loadedTranslation.languages).map(([languageName, translations]) => `'${encodeWithinSingleQuotes(languageName)}': createLanguage(${JSON.stringify(getTranslationMessages(translations))})`).join(',');
|
|
536
528
|
const languagesUnionAsString = Object.keys(loadedTranslation.languages).map(l => `'${l}'`).join(' | ');
|
|
537
|
-
|
|
529
|
+
const languageEntries = Object.entries(loadedTranslation.languages).map(([languageName, translations]) => `${JSON.stringify(languageName)}: createLanguage(${JSON.stringify(getTranslationMessages(translations))})`).join(',');
|
|
530
|
+
return (/* ts */`
|
|
531
|
+
// This file is automatically generated by Vocab.
|
|
532
|
+
// To make changes update translation.json files directly.
|
|
538
533
|
|
|
539
|
-
|
|
540
|
-
|
|
534
|
+
${serializeTypeImports(imports, '@vocab/core')}
|
|
535
|
+
import { createLanguage, createTranslationFile } from '@vocab/core/runtime';
|
|
541
536
|
|
|
542
|
-
|
|
537
|
+
const translations = createTranslationFile<
|
|
538
|
+
${languagesUnionAsString},
|
|
539
|
+
${serialiseObjectToType(translationsType)}
|
|
540
|
+
>({
|
|
541
|
+
${languageEntries}
|
|
542
|
+
});
|
|
543
543
|
|
|
544
|
-
|
|
544
|
+
export default translations;
|
|
545
|
+
`
|
|
546
|
+
);
|
|
545
547
|
}
|
|
546
548
|
async function generateRuntime(loadedTranslation) {
|
|
547
549
|
const {
|
|
@@ -562,15 +564,13 @@ async function generateRuntime(loadedTranslation) {
|
|
|
562
564
|
const [parsedParams, vocabTypesImports] = extractParamTypes(ast, params);
|
|
563
565
|
imports = new Set([...imports, ...vocabTypesImports]);
|
|
564
566
|
params = parsedParams;
|
|
565
|
-
messages.add(
|
|
567
|
+
messages.add(JSON.stringify(translatedLanguage[key].message));
|
|
566
568
|
}
|
|
567
569
|
}
|
|
568
|
-
const returnType = hasTags ? 'NonNullable<ReactNode>' : 'string';
|
|
569
570
|
translationTypes.set(key, {
|
|
570
571
|
params,
|
|
571
572
|
hasTags,
|
|
572
|
-
message: Array.from(messages).join(' | ')
|
|
573
|
-
returnType
|
|
573
|
+
message: Array.from(messages).join(' | ')
|
|
574
574
|
});
|
|
575
575
|
}
|
|
576
576
|
const prettierConfig = await prettier__default["default"].resolveConfig(filePath);
|
package/dist/vocab-core.esm.js
CHANGED
|
@@ -422,8 +422,6 @@ async function loadAllTranslations({
|
|
|
422
422
|
return result;
|
|
423
423
|
}
|
|
424
424
|
|
|
425
|
-
const encodeWithinSingleQuotes = v => v.replace(/'/g, "\\'");
|
|
426
|
-
const encodeBackslash = v => v.replace(/\\/g, '\\\\');
|
|
427
425
|
function extractHasTags(ast) {
|
|
428
426
|
return ast.some(element => {
|
|
429
427
|
if (isSelectElement(element)) {
|
|
@@ -484,21 +482,16 @@ function extractParamTypes(ast, currentParams) {
|
|
|
484
482
|
function serialiseObjectToType(v) {
|
|
485
483
|
let result = '';
|
|
486
484
|
for (const [key, value] of Object.entries(v)) {
|
|
487
|
-
|
|
488
|
-
result += `'${encodeWithinSingleQuotes(key)}': ${serialiseObjectToType(value)},`;
|
|
489
|
-
} else {
|
|
490
|
-
result += `'${encodeWithinSingleQuotes(key)}': ${value},`;
|
|
491
|
-
}
|
|
485
|
+
result += `${JSON.stringify(key)}: ${value && typeof value === 'object' ? serialiseObjectToType(value) : value},`;
|
|
492
486
|
}
|
|
493
487
|
return `{ ${result} }`;
|
|
494
488
|
}
|
|
495
|
-
const
|
|
496
|
-
const serializeModuleImports = (imports, moduleName) => {
|
|
489
|
+
const serializeTypeImports = (imports, moduleName) => {
|
|
497
490
|
if (imports.size === 0) {
|
|
498
491
|
return '';
|
|
499
492
|
}
|
|
500
493
|
const importNames = Array.from(imports);
|
|
501
|
-
return `import { ${
|
|
494
|
+
return `import type { ${importNames.join(', ')} } from '${moduleName}';`;
|
|
502
495
|
};
|
|
503
496
|
function serialiseTranslationRuntime(value, imports, loadedTranslation) {
|
|
504
497
|
trace('Serialising translations:', loadedTranslation);
|
|
@@ -511,21 +504,30 @@ function serialiseTranslationRuntime(value, imports, loadedTranslation) {
|
|
|
511
504
|
let translationFunctionString = `() => ${message}`;
|
|
512
505
|
if (Object.keys(params).length > 0) {
|
|
513
506
|
const formatGeneric = hasTags ? '<T = string>' : '';
|
|
514
|
-
const formatReturn = hasTags
|
|
507
|
+
const formatReturn = hasTags && imports.has('FormatXMLElementFn') ? 'ReturnType<FormatXMLElementFn<T>>' : 'string';
|
|
515
508
|
translationFunctionString = `${formatGeneric}(values: ${serialiseObjectToType(params)}) => ${formatReturn}`;
|
|
516
509
|
}
|
|
517
|
-
translationsType[
|
|
510
|
+
translationsType[key] = translationFunctionString;
|
|
518
511
|
}
|
|
519
|
-
const content = Object.entries(loadedTranslation.languages).map(([languageName, translations]) => `'${encodeWithinSingleQuotes(languageName)}': createLanguage(${JSON.stringify(getTranslationMessages(translations))})`).join(',');
|
|
520
512
|
const languagesUnionAsString = Object.keys(loadedTranslation.languages).map(l => `'${l}'`).join(' | ');
|
|
521
|
-
|
|
513
|
+
const languageEntries = Object.entries(loadedTranslation.languages).map(([languageName, translations]) => `${JSON.stringify(languageName)}: createLanguage(${JSON.stringify(getTranslationMessages(translations))})`).join(',');
|
|
514
|
+
return (/* ts */`
|
|
515
|
+
// This file is automatically generated by Vocab.
|
|
516
|
+
// To make changes update translation.json files directly.
|
|
522
517
|
|
|
523
|
-
|
|
524
|
-
|
|
518
|
+
${serializeTypeImports(imports, '@vocab/core')}
|
|
519
|
+
import { createLanguage, createTranslationFile } from '@vocab/core/runtime';
|
|
525
520
|
|
|
526
|
-
|
|
521
|
+
const translations = createTranslationFile<
|
|
522
|
+
${languagesUnionAsString},
|
|
523
|
+
${serialiseObjectToType(translationsType)}
|
|
524
|
+
>({
|
|
525
|
+
${languageEntries}
|
|
526
|
+
});
|
|
527
527
|
|
|
528
|
-
|
|
528
|
+
export default translations;
|
|
529
|
+
`
|
|
530
|
+
);
|
|
529
531
|
}
|
|
530
532
|
async function generateRuntime(loadedTranslation) {
|
|
531
533
|
const {
|
|
@@ -546,15 +548,13 @@ async function generateRuntime(loadedTranslation) {
|
|
|
546
548
|
const [parsedParams, vocabTypesImports] = extractParamTypes(ast, params);
|
|
547
549
|
imports = new Set([...imports, ...vocabTypesImports]);
|
|
548
550
|
params = parsedParams;
|
|
549
|
-
messages.add(
|
|
551
|
+
messages.add(JSON.stringify(translatedLanguage[key].message));
|
|
550
552
|
}
|
|
551
553
|
}
|
|
552
|
-
const returnType = hasTags ? 'NonNullable<ReactNode>' : 'string';
|
|
553
554
|
translationTypes.set(key, {
|
|
554
555
|
params,
|
|
555
556
|
hasTags,
|
|
556
|
-
message: Array.from(messages).join(' | ')
|
|
557
|
-
returnType
|
|
557
|
+
message: Array.from(messages).join(' | ')
|
|
558
558
|
});
|
|
559
559
|
}
|
|
560
560
|
const prettierConfig = await prettier.resolveConfig(filePath);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vocab/core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"main": "dist/vocab-core.cjs.js",
|
|
5
5
|
"module": "dist/vocab-core.esm.js",
|
|
6
6
|
"exports": {
|
|
@@ -40,7 +40,6 @@
|
|
|
40
40
|
],
|
|
41
41
|
"dependencies": {
|
|
42
42
|
"@formatjs/icu-messageformat-parser": "^2.0.10",
|
|
43
|
-
"@vocab/types": "^1.2.0",
|
|
44
43
|
"chalk": "^4.1.0",
|
|
45
44
|
"chokidar": "^3.4.3",
|
|
46
45
|
"debug": "^4.3.1",
|