mirror of
https://github.com/elyby/accounts-frontend.git
synced 2024-11-16 21:22:59 +05:30
Reimplement scripts with TS
This commit is contained in:
parent
649e7b8e23
commit
10e8b77acf
102
@types/cwordin-api.d.ts
vendored
Normal file
102
@types/cwordin-api.d.ts
vendored
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
declare module 'crowdin-api' {
|
||||||
|
export interface ProjectInfoFile {
|
||||||
|
node_type: 'file';
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
created: string;
|
||||||
|
last_updated: string;
|
||||||
|
last_accessed: string;
|
||||||
|
last_revision: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ProjectInfoDirectory {
|
||||||
|
node_type: 'directory';
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
files: Array<ProjectInfoFile | ProjectInfoDirectory>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ProjectInfoResponse {
|
||||||
|
details: {
|
||||||
|
source_language: {
|
||||||
|
name: string;
|
||||||
|
code: string;
|
||||||
|
};
|
||||||
|
name: string;
|
||||||
|
identifier: string;
|
||||||
|
created: string;
|
||||||
|
description: string;
|
||||||
|
join_policy: string;
|
||||||
|
last_build: string | null;
|
||||||
|
last_activity: string;
|
||||||
|
participants_count: string; // it's number, but string in the response
|
||||||
|
logo_url: string | null;
|
||||||
|
total_strings_count: string; // it's number, but string in the response
|
||||||
|
total_words_count: string; // it's number, but string in the response
|
||||||
|
duplicate_strings_count: number;
|
||||||
|
duplicate_words_count: number;
|
||||||
|
invite_url: {
|
||||||
|
translator: string;
|
||||||
|
proofreader: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
languages: Array<{
|
||||||
|
name: string; // English language name
|
||||||
|
code: string;
|
||||||
|
can_translate: 0 | 1;
|
||||||
|
can_approve: 0 | 1;
|
||||||
|
}>;
|
||||||
|
files: Array<ProjectInfoFile | ProjectInfoDirectory>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LanguageStatusNode {
|
||||||
|
node_type: 'directory' | 'file';
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
phrases: number;
|
||||||
|
translated: number;
|
||||||
|
approved: number;
|
||||||
|
words: number;
|
||||||
|
words_translated: number;
|
||||||
|
words_approved: number;
|
||||||
|
files: Array<LanguageStatusNode>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LanguageStatusResponse {
|
||||||
|
files: Array<LanguageStatusNode>;
|
||||||
|
}
|
||||||
|
|
||||||
|
type FilesList = Record<string, string | ReadableStream>;
|
||||||
|
|
||||||
|
export default class CrowdinApi {
|
||||||
|
constructor(params: {
|
||||||
|
apiKey: string;
|
||||||
|
projectName: string;
|
||||||
|
baseUrl?: string;
|
||||||
|
});
|
||||||
|
projectInfo(): Promise<ProjectInfoResponse>;
|
||||||
|
languageStatus(language: string): Promise<LanguageStatusResponse>;
|
||||||
|
exportFile(
|
||||||
|
file: string,
|
||||||
|
language: string,
|
||||||
|
params?: {
|
||||||
|
branch?: string;
|
||||||
|
format?: 'xliff';
|
||||||
|
export_translated_only?: boolean;
|
||||||
|
export_approved_only?: boolean;
|
||||||
|
},
|
||||||
|
): Promise<string>; // TODO: not sure about Promise return type
|
||||||
|
updateFile(
|
||||||
|
files: FilesList,
|
||||||
|
params: {
|
||||||
|
titles?: Record<string, string>;
|
||||||
|
export_patterns?: Record<string, string>;
|
||||||
|
new_names?: Record<string, string>;
|
||||||
|
first_line_contains_header?: string;
|
||||||
|
scheme?: string;
|
||||||
|
update_option?: 'update_as_unapproved' | 'update_without_changes';
|
||||||
|
branch?: string;
|
||||||
|
},
|
||||||
|
): Promise<void>;
|
||||||
|
}
|
||||||
|
}
|
13
@types/multi-progress.d.ts
vendored
Normal file
13
@types/multi-progress.d.ts
vendored
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
declare module 'multi-progress' {
|
||||||
|
export default class MultiProgress {
|
||||||
|
constructor(stream?: string);
|
||||||
|
newBar(
|
||||||
|
schema: string,
|
||||||
|
options: ProgressBar.ProgressBarOptions,
|
||||||
|
): ProgressBar;
|
||||||
|
terminate(): void;
|
||||||
|
move(index: number): void;
|
||||||
|
tick(index: number, value?: number, options?: any): void;
|
||||||
|
update(index: number, value?: number, options?: any): void;
|
||||||
|
}
|
||||||
|
}
|
66
@types/prompt.d.ts
vendored
Normal file
66
@types/prompt.d.ts
vendored
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
// Type definitions for Prompt.js 1.0.0
|
||||||
|
// Project: https://github.com/flatiron/prompt
|
||||||
|
|
||||||
|
declare module 'prompt' {
|
||||||
|
type PropertiesType =
|
||||||
|
| Array<string>
|
||||||
|
| prompt.PromptSchema
|
||||||
|
| Array<prompt.PromptPropertyOptions>;
|
||||||
|
|
||||||
|
namespace prompt {
|
||||||
|
interface PromptSchema {
|
||||||
|
properties: PromptProperties;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface PromptProperties {
|
||||||
|
[propName: string]: PromptPropertyOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface PromptPropertyOptions {
|
||||||
|
name?: string;
|
||||||
|
pattern?: RegExp;
|
||||||
|
message?: string;
|
||||||
|
required?: boolean;
|
||||||
|
hidden?: boolean;
|
||||||
|
description?: string;
|
||||||
|
type?: string;
|
||||||
|
default?: string;
|
||||||
|
before?: (value: any) => any;
|
||||||
|
conform?: (result: any) => boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function start(): void;
|
||||||
|
|
||||||
|
export function get<T extends PropertiesType>(
|
||||||
|
properties: T,
|
||||||
|
callback: (
|
||||||
|
err: Error,
|
||||||
|
result: T extends Array<string>
|
||||||
|
? Record<T[number], string>
|
||||||
|
: T extends PromptSchema
|
||||||
|
? Record<keyof T['properties'], string>
|
||||||
|
: T extends Array<PromptPropertyOptions>
|
||||||
|
? Record<
|
||||||
|
T[number]['name'] extends string ? T[number]['name'] : number,
|
||||||
|
string
|
||||||
|
>
|
||||||
|
: never,
|
||||||
|
) => void,
|
||||||
|
): void;
|
||||||
|
|
||||||
|
export function addProperties(
|
||||||
|
obj: any,
|
||||||
|
properties: PropertiesType,
|
||||||
|
callback: (err: Error) => void,
|
||||||
|
): void;
|
||||||
|
|
||||||
|
export function history(propertyName: string): any;
|
||||||
|
|
||||||
|
export let override: any;
|
||||||
|
export let colors: boolean;
|
||||||
|
export let message: string;
|
||||||
|
export let delimiter: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export = prompt;
|
||||||
|
}
|
@ -35,9 +35,9 @@
|
|||||||
"ts:check": "tsc",
|
"ts:check": "tsc",
|
||||||
"ci:check": "yarn lint:check && yarn ts:check && yarn test",
|
"ci:check": "yarn lint:check && yarn ts:check && yarn test",
|
||||||
"analyze": "yarn run clean && yarn run build:webpack --analyze",
|
"analyze": "yarn run clean && yarn run build:webpack --analyze",
|
||||||
"i18n:collect": "babel-node ./packages/scripts/i18n-collect.js",
|
"i18n:collect": "babel-node --extensions \".ts\" ./packages/scripts/i18n-collect.ts",
|
||||||
"i18n:push": "babel-node ./packages/scripts/i18n-crowdin.js push",
|
"i18n:push": "babel-node --extensions \".ts\" ./packages/scripts/i18n-crowdin.ts push",
|
||||||
"i18n:pull": "babel-node ./packages/scripts/i18n-crowdin.js pull",
|
"i18n:pull": "babel-node --extensions \".ts\" ./packages/scripts/i18n-crowdin.ts pull",
|
||||||
"build": "yarn run clean && yarn run build:webpack",
|
"build": "yarn run clean && yarn run build:webpack",
|
||||||
"build:install": "yarn install",
|
"build:install": "yarn install",
|
||||||
"build:webpack": "NODE_ENV=production webpack --colors -p --bail",
|
"build:webpack": "NODE_ENV=production webpack --colors -p --bail",
|
||||||
|
@ -35,6 +35,9 @@
|
|||||||
"whatwg-fetch": "^3.0.0"
|
"whatwg-fetch": "^3.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/debounce": "^1.2.0",
|
||||||
|
"@types/intl": "^1.2.0",
|
||||||
|
"@types/raf": "^3.4.0",
|
||||||
"@types/react-helmet": "^5.0.15",
|
"@types/react-helmet": "^5.0.15",
|
||||||
"@types/webpack-env": "^1.15.0",
|
"@types/webpack-env": "^1.15.0",
|
||||||
"enzyme": "^3.8.0",
|
"enzyme": "^3.8.0",
|
||||||
|
@ -3,7 +3,7 @@ import options from 'app/services/api/options';
|
|||||||
|
|
||||||
let readyPromise: Promise<void>;
|
let readyPromise: Promise<void>;
|
||||||
let lang = 'en';
|
let lang = 'en';
|
||||||
let sitekey;
|
let sitekey: string;
|
||||||
|
|
||||||
export type CaptchaID = string;
|
export type CaptchaID = string;
|
||||||
|
|
||||||
|
@ -17,16 +17,17 @@ export function hasStorage() {
|
|||||||
return _hasStorage;
|
return _hasStorage;
|
||||||
}
|
}
|
||||||
|
|
||||||
class DummyStorage {
|
// TODO: work on
|
||||||
getItem(key) {
|
class DummyStorage implements Storage {
|
||||||
|
getItem(key: string): string | null {
|
||||||
return this[key] || null;
|
return this[key] || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
setItem(key, value) {
|
setItem(key: string, value: string): void {
|
||||||
this[key] = value;
|
this[key] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
removeItem(key) {
|
removeItem(key: string): void {
|
||||||
Reflect.deleteProperty(this, key);
|
Reflect.deleteProperty(this, key);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -12,19 +12,27 @@ const LANG_DIR = `${__dirname}/../app/i18n`;
|
|||||||
const DEFAULT_LOCALE = 'en';
|
const DEFAULT_LOCALE = 'en';
|
||||||
const SUPPORTED_LANGS = [DEFAULT_LOCALE, ...Object.keys(localesMap)];
|
const SUPPORTED_LANGS = [DEFAULT_LOCALE, ...Object.keys(localesMap)];
|
||||||
|
|
||||||
|
interface MessageDescriptor {
|
||||||
|
id: string | number;
|
||||||
|
defaultMessage: string;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Aggregates the default messages that were extracted from the app's
|
* Aggregates the default messages that were extracted from the app's
|
||||||
* React components via the React Intl Babel plugin. An error will be thrown if
|
* React components via the React Intl Babel plugin. An error will be thrown if
|
||||||
* there are messages in different components that use the same `id`. The result
|
* there are messages in different components that use the same `id`. The result
|
||||||
* is a flat collection of `id: message` pairs for the app's default locale.
|
* is a flat collection of `id: message` pairs for the app's default locale.
|
||||||
*/
|
*/
|
||||||
let idToFileMap: { [key: string]: string[] } = {};
|
let idToFileMap: Record<string, Array<string>> = {};
|
||||||
let duplicateIds: string[] = [];
|
let duplicateIds: Array<string | number> = [];
|
||||||
const collectedMessages = globSync(MESSAGES_PATTERN)
|
const collectedMessages = globSync(MESSAGES_PATTERN)
|
||||||
.map(filename => [filename, JSON.parse(fs.readFileSync(filename, 'utf8'))])
|
.map<[string, Array<MessageDescriptor>]>(filename => [
|
||||||
.reduce((collection, [file, descriptors]) => {
|
filename,
|
||||||
|
JSON.parse(fs.readFileSync(filename, 'utf8')),
|
||||||
|
])
|
||||||
|
.reduce<Record<string, string>>((collection, [file, descriptors]) => {
|
||||||
descriptors.forEach(({ id, defaultMessage }) => {
|
descriptors.forEach(({ id, defaultMessage }) => {
|
||||||
if (collection.hasOwnProperty(id)) {
|
if (collection[id]) {
|
||||||
duplicateIds.push(id);
|
duplicateIds.push(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,13 +60,9 @@ idToFileMap = {};
|
|||||||
* Making a diff with the previous DEFAULT_LOCALE version
|
* Making a diff with the previous DEFAULT_LOCALE version
|
||||||
*/
|
*/
|
||||||
const defaultMessagesPath = `${LANG_DIR}/${DEFAULT_LOCALE}.json`;
|
const defaultMessagesPath = `${LANG_DIR}/${DEFAULT_LOCALE}.json`;
|
||||||
let keysToUpdate: string[] = [];
|
|
||||||
let keysToAdd: string[] = [];
|
|
||||||
let keysToRemove: string[] = [];
|
|
||||||
const keysToRename: Array<[string, string]> = [];
|
|
||||||
const isNotMarked = (value: string) => value.slice(0, 2) !== '--';
|
const isNotMarked = (value: string) => value.slice(0, 2) !== '--';
|
||||||
|
|
||||||
const prevMessages: { [key: string]: string } = readJSON(defaultMessagesPath);
|
const prevMessages = readJSON<Record<string, string>>(defaultMessagesPath);
|
||||||
const prevMessagesMap = Object.entries(prevMessages).reduce(
|
const prevMessagesMap = Object.entries(prevMessages).reduce(
|
||||||
(acc, [key, value]) => {
|
(acc, [key, value]) => {
|
||||||
if (acc[value]) {
|
if (acc[value]) {
|
||||||
@ -69,21 +73,24 @@ const prevMessagesMap = Object.entries(prevMessages).reduce(
|
|||||||
|
|
||||||
return acc;
|
return acc;
|
||||||
},
|
},
|
||||||
{} as { [key: string]: string[] },
|
{} as Record<string, Array<string>>,
|
||||||
);
|
);
|
||||||
|
|
||||||
keysToAdd = Object.keys(collectedMessages).filter(key => !prevMessages[key]);
|
const keysToAdd = Object.keys(collectedMessages).filter(
|
||||||
keysToRemove = Object.keys(prevMessages)
|
key => !prevMessages[key],
|
||||||
|
);
|
||||||
|
const keysToRemove: Array<string> = Object.keys(prevMessages)
|
||||||
.filter(key => !collectedMessages[key])
|
.filter(key => !collectedMessages[key])
|
||||||
.filter(isNotMarked);
|
.filter(isNotMarked);
|
||||||
keysToUpdate = Object.entries(prevMessages).reduce(
|
const keysToUpdate: Array<string> = Object.entries(prevMessages).reduce(
|
||||||
(acc, [key, message]) =>
|
(acc, [key, message]) =>
|
||||||
acc.concat(
|
acc.concat(
|
||||||
collectedMessages[key] && collectedMessages[key] !== message ? key : [],
|
collectedMessages[key] && collectedMessages[key] !== message ? key : [],
|
||||||
),
|
),
|
||||||
[] as string[],
|
[] as Array<string>,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const keysToRename: Array<[string, string]> = [];
|
||||||
// detect keys to rename, mutating keysToAdd and keysToRemove
|
// detect keys to rename, mutating keysToAdd and keysToRemove
|
||||||
[...keysToAdd].forEach(toKey => {
|
[...keysToAdd].forEach(toKey => {
|
||||||
const keys = prevMessagesMap[collectedMessages[toKey]] || [];
|
const keys = prevMessagesMap[collectedMessages[toKey]] || [];
|
||||||
@ -91,7 +98,6 @@ keysToUpdate = Object.entries(prevMessages).reduce(
|
|||||||
|
|
||||||
if (fromKey) {
|
if (fromKey) {
|
||||||
keysToRename.push([fromKey, toKey]);
|
keysToRename.push([fromKey, toKey]);
|
||||||
|
|
||||||
keysToRemove.splice(keysToRemove.indexOf(fromKey), 1);
|
keysToRemove.splice(keysToRemove.indexOf(fromKey), 1);
|
||||||
keysToAdd.splice(keysToAdd.indexOf(toKey), 1);
|
keysToAdd.splice(keysToAdd.indexOf(toKey), 1);
|
||||||
}
|
}
|
||||||
@ -178,7 +184,7 @@ function buildLocales() {
|
|||||||
|
|
||||||
SUPPORTED_LANGS.map(lang => {
|
SUPPORTED_LANGS.map(lang => {
|
||||||
const destPath = `${LANG_DIR}/${lang}.json`;
|
const destPath = `${LANG_DIR}/${lang}.json`;
|
||||||
const newMessages = readJSON(destPath);
|
const newMessages = readJSON<Record<string, string>>(destPath);
|
||||||
|
|
||||||
keysToRename.forEach(([fromKey, toKey]) => {
|
keysToRename.forEach(([fromKey, toKey]) => {
|
||||||
newMessages[toKey] = newMessages[fromKey];
|
newMessages[toKey] = newMessages[fromKey];
|
||||||
@ -195,18 +201,23 @@ function buildLocales() {
|
|||||||
newMessages[key] = collectedMessages[key];
|
newMessages[key] = collectedMessages[key];
|
||||||
});
|
});
|
||||||
|
|
||||||
const sortedKeys = Object.keys(newMessages).sort((key1, key2) => {
|
const sortedKeys: Array<string> = Object.keys(newMessages).sort(
|
||||||
key1 = key1.replace(/^-+/, '');
|
(key1, key2) => {
|
||||||
key2 = key2.replace(/^-+/, '');
|
key1 = key1.replace(/^-+/, '');
|
||||||
|
key2 = key2.replace(/^-+/, '');
|
||||||
|
|
||||||
return key1 < key2 || !isNotMarked(key1) ? -1 : 1;
|
return key1 < key2 || !isNotMarked(key1) ? -1 : 1;
|
||||||
});
|
},
|
||||||
|
);
|
||||||
|
|
||||||
const sortedNewMessages = sortedKeys.reduce((acc, key) => {
|
const sortedNewMessages = sortedKeys.reduce<typeof newMessages>(
|
||||||
acc[key] = newMessages[key];
|
(acc, key) => {
|
||||||
|
acc[key] = newMessages[key];
|
||||||
|
|
||||||
return acc;
|
return acc;
|
||||||
}, {});
|
},
|
||||||
|
{},
|
||||||
|
);
|
||||||
|
|
||||||
fs.writeFileSync(
|
fs.writeFileSync(
|
||||||
destPath,
|
destPath,
|
||||||
@ -215,15 +226,15 @@ function buildLocales() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function readJSON(destPath) {
|
function readJSON<T extends {}>(destPath: string): T {
|
||||||
try {
|
try {
|
||||||
return JSON.parse(fs.readFileSync(destPath, 'utf8'));
|
return JSON.parse(fs.readFileSync(destPath, 'utf8'));
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(
|
console.log(
|
||||||
chalk.yellow(`Can not read ${destPath}. The new file will be created.`),
|
chalk.yellow(`Can't read ${destPath}. The new file will be created.`),
|
||||||
`(${err.message})`,
|
`(${err.message})`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return {};
|
return {} as T;
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,16 @@
|
|||||||
/* eslint-env node */
|
/* eslint-env node */
|
||||||
/* eslint-disable no-console */
|
/* eslint-disable */
|
||||||
|
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import CrowdinApi from 'crowdin-api';
|
import CrowdinApi, { LanguageStatusNode, LanguageStatusResponse, ProjectInfoResponse } from 'crowdin-api';
|
||||||
import MultiProgress from 'multi-progress';
|
import MultiProgress from 'multi-progress';
|
||||||
import ch from 'chalk';
|
import ch from 'chalk';
|
||||||
import iso639 from 'iso-639-1';
|
import iso639 from 'iso-639-1';
|
||||||
import prompt from 'prompt';
|
import prompt from 'prompt';
|
||||||
|
|
||||||
|
import { ValuesType } from 'utility-types';
|
||||||
|
|
||||||
import config from '../../config';
|
import config from '../../config';
|
||||||
|
|
||||||
if (!config.crowdinApiKey) {
|
if (!config.crowdinApiKey) {
|
||||||
@ -24,18 +26,21 @@ const LANG_DIR = path.resolve(`${__dirname}/../app/i18n`);
|
|||||||
const INDEX_FILE_NAME = 'index.js';
|
const INDEX_FILE_NAME = 'index.js';
|
||||||
const MIN_RELEASE_PROGRESS = 80; // Minimal ready percent before translation can be published
|
const MIN_RELEASE_PROGRESS = 80; // Minimal ready percent before translation can be published
|
||||||
|
|
||||||
const crowdin = new CrowdinApi({ apiKey: PROJECT_KEY });
|
const crowdin = new CrowdinApi({
|
||||||
|
apiKey: PROJECT_KEY,
|
||||||
|
projectName: PROJECT_ID,
|
||||||
|
});
|
||||||
const progressBar = new MultiProgress();
|
const progressBar = new MultiProgress();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Locales that has been verified by core team members
|
* Locales that has been verified by core team members
|
||||||
*/
|
*/
|
||||||
const RELEASED_LOCALES = ['be', 'fr', 'id', 'pt', 'ru', 'uk', 'vi', 'zh'];
|
const RELEASED_LOCALES: Array<string> = ['be', 'fr', 'id', 'pt', 'ru', 'uk', 'vi', 'zh'];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Array of Crowdin locales to our internal locales representation
|
* Array of Crowdin locales to our internal locales representation
|
||||||
*/
|
*/
|
||||||
const LOCALES_MAP = {
|
const LOCALES_MAP: Record<string, string> = {
|
||||||
'pt-BR': 'pt',
|
'pt-BR': 'pt',
|
||||||
'zh-CN': 'zh',
|
'zh-CN': 'zh',
|
||||||
};
|
};
|
||||||
@ -43,7 +48,7 @@ const LOCALES_MAP = {
|
|||||||
/**
|
/**
|
||||||
* This array allows us to customise native languages names, because ISO-639-1 sometimes is strange
|
* This array allows us to customise native languages names, because ISO-639-1 sometimes is strange
|
||||||
*/
|
*/
|
||||||
const NATIVE_NAMES_MAP = {
|
const NATIVE_NAMES_MAP: Record<string, string> = {
|
||||||
be: 'Беларуская',
|
be: 'Беларуская',
|
||||||
id: 'Bahasa Indonesia',
|
id: 'Bahasa Indonesia',
|
||||||
lt: 'Lietuvių',
|
lt: 'Lietuvių',
|
||||||
@ -57,7 +62,7 @@ const NATIVE_NAMES_MAP = {
|
|||||||
/**
|
/**
|
||||||
* This arrays allows us to override Crowdin English languages names
|
* This arrays allows us to override Crowdin English languages names
|
||||||
*/
|
*/
|
||||||
const ENGLISH_NAMES_MAP = {
|
const ENGLISH_NAMES_MAP: Record<string, string> = {
|
||||||
pt: 'Portuguese, Brazilian',
|
pt: 'Portuguese, Brazilian',
|
||||||
sr: 'Serbian',
|
sr: 'Serbian',
|
||||||
zh: 'Simplified Chinese',
|
zh: 'Simplified Chinese',
|
||||||
@ -65,9 +70,6 @@ const ENGLISH_NAMES_MAP = {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts Crowdin's language code to our internal value
|
* Converts Crowdin's language code to our internal value
|
||||||
*
|
|
||||||
* @param {string} code
|
|
||||||
* @returns {string}
|
|
||||||
*/
|
*/
|
||||||
function toInternalLocale(code: string): string {
|
function toInternalLocale(code: string): string {
|
||||||
return LOCALES_MAP[code] || code;
|
return LOCALES_MAP[code] || code;
|
||||||
@ -76,108 +78,33 @@ function toInternalLocale(code: string): string {
|
|||||||
/**
|
/**
|
||||||
* Форматирует входящий объект с переводами в итоговую строку в том формате, в каком они
|
* Форматирует входящий объект с переводами в итоговую строку в том формате, в каком они
|
||||||
* хранятся в самом приложении
|
* хранятся в самом приложении
|
||||||
*
|
|
||||||
* @param {object} translates
|
|
||||||
* @returns {string}
|
|
||||||
*/
|
*/
|
||||||
function serializeToFormattedJson(
|
function serializeToModule(translates: Record<string, any>): string {
|
||||||
translates: { [key: string]: any },
|
|
||||||
{ asModule = false }: { asModule?: boolean } = {},
|
|
||||||
): string {
|
|
||||||
const src = JSON.stringify(sortByKeys(translates), null, 2);
|
const src = JSON.stringify(sortByKeys(translates), null, 2);
|
||||||
|
|
||||||
return asModule ? `module.exports = ${src};\n` : `${src}\n`;
|
return `module.exports = ${src};\n`;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// http://stackoverflow.com/a/29622653/5184751
|
||||||
* http://stackoverflow.com/a/29622653/5184751
|
function sortByKeys<T extends Record<string, any>>(object: T): T {
|
||||||
*
|
|
||||||
* @param {object} object
|
|
||||||
* @returns {object}
|
|
||||||
*/
|
|
||||||
function sortByKeys(object: { [key: string]: any }): { [key: string]: any } {
|
|
||||||
return Object.keys(object)
|
return Object.keys(object)
|
||||||
.sort()
|
.sort()
|
||||||
.reduce((result, key) => {
|
.reduce((result, key) => {
|
||||||
|
// @ts-ignore
|
||||||
result[key] = object[key];
|
result[key] = object[key];
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}, {});
|
}, {} as T);
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ProjectInfoFile {
|
async function pullLocales(): Promise<ProjectInfoResponse['languages']> {
|
||||||
node_type: 'file';
|
const { languages } = await crowdin.projectInfo();
|
||||||
id: number;
|
|
||||||
name: string;
|
|
||||||
created: string;
|
|
||||||
last_updated: string;
|
|
||||||
last_accessed: string;
|
|
||||||
last_revision: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ProjectInfoDirectory {
|
|
||||||
node_type: 'directory';
|
|
||||||
id: number;
|
|
||||||
name: string;
|
|
||||||
files: Array<ProjectInfoFile | ProjectInfoDirectory>;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ProjectInfoResponse {
|
|
||||||
details: {
|
|
||||||
source_language: {
|
|
||||||
name: string;
|
|
||||||
code: string;
|
|
||||||
};
|
|
||||||
name: string;
|
|
||||||
identifier: string;
|
|
||||||
created: string;
|
|
||||||
description: string;
|
|
||||||
join_policy: string;
|
|
||||||
last_build: string | null;
|
|
||||||
last_activity: string;
|
|
||||||
participants_count: string; // it's number, but string in the response
|
|
||||||
logo_url: string | null;
|
|
||||||
total_strings_count: string; // it's number, but string in the response
|
|
||||||
total_words_count: string; // it's number, but string in the response
|
|
||||||
duplicate_strings_count: number;
|
|
||||||
duplicate_words_count: number;
|
|
||||||
invite_url: {
|
|
||||||
translator: string;
|
|
||||||
proofreader: string;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
languages: Array<{
|
|
||||||
name: string; // English language name
|
|
||||||
code: string;
|
|
||||||
can_translate: 0 | 1;
|
|
||||||
can_approve: 0 | 1;
|
|
||||||
}>;
|
|
||||||
files: Array<ProjectInfoFile | ProjectInfoDirectory>;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function pullLocales() {
|
|
||||||
const { languages }: ProjectInfoResponse = await crowdin.projectInfo(
|
|
||||||
PROJECT_ID,
|
|
||||||
);
|
|
||||||
|
|
||||||
return languages;
|
return languages;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface LanguageStatusNode {
|
|
||||||
node_type: 'directory' | 'file';
|
|
||||||
id: number;
|
|
||||||
name: string;
|
|
||||||
phrases: number;
|
|
||||||
translated: number;
|
|
||||||
approved: number;
|
|
||||||
words: number;
|
|
||||||
words_translated: number;
|
|
||||||
words_approved: number;
|
|
||||||
files: Array<LanguageStatusNode>;
|
|
||||||
}
|
|
||||||
|
|
||||||
function findFile(
|
function findFile(
|
||||||
root: Array<LanguageStatusNode>,
|
root: LanguageStatusResponse['files'],
|
||||||
path: string,
|
path: string,
|
||||||
): LanguageStatusNode | null {
|
): LanguageStatusNode | null {
|
||||||
const [nodeToSearch, ...rest] = path.split('/');
|
const [nodeToSearch, ...rest] = path.split('/');
|
||||||
@ -229,14 +156,18 @@ async function pull() {
|
|||||||
);
|
);
|
||||||
let downloadingTotal = 0;
|
let downloadingTotal = 0;
|
||||||
let downloadingReady = 0;
|
let downloadingReady = 0;
|
||||||
|
|
||||||
|
interface Result {
|
||||||
|
locale: ValuesType<typeof locales>,
|
||||||
|
progress: number,
|
||||||
|
translatesFilePath: string,
|
||||||
|
}
|
||||||
|
|
||||||
const results = await Promise.all(
|
const results = await Promise.all(
|
||||||
locales.map(async locale => {
|
// TODO: there is should be some way to reimplement this
|
||||||
const {
|
// with reduce to avoid null values
|
||||||
files,
|
locales.map(async (locale): Promise<Result | null> => {
|
||||||
}: { files: Array<LanguageStatusNode> } = await crowdin.languageStatus(
|
const { files } = await crowdin.languageStatus(locale.code);
|
||||||
PROJECT_ID,
|
|
||||||
locale.code,
|
|
||||||
);
|
|
||||||
checkingProgressBar.tick();
|
checkingProgressBar.tick();
|
||||||
const fileInfo = findFile(files, CROWDIN_FILE_PATH);
|
const fileInfo = findFile(files, CROWDIN_FILE_PATH);
|
||||||
|
|
||||||
@ -261,7 +192,6 @@ async function pull() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const translatesFilePath = await crowdin.exportFile(
|
const translatesFilePath = await crowdin.exportFile(
|
||||||
PROJECT_ID,
|
|
||||||
CROWDIN_FILE_PATH,
|
CROWDIN_FILE_PATH,
|
||||||
locale.code,
|
locale.code,
|
||||||
);
|
);
|
||||||
@ -291,47 +221,40 @@ async function pull() {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
results.map(
|
results
|
||||||
result =>
|
.filter((result): result is Result => result !== null)
|
||||||
new Promise((resolve, reject) => {
|
.map(result => new Promise((resolve, reject) => {
|
||||||
if (result === null) {
|
const {
|
||||||
resolve();
|
locale: { code, name },
|
||||||
|
progress,
|
||||||
|
translatesFilePath,
|
||||||
|
} = result;
|
||||||
|
const ourCode = toInternalLocale(code);
|
||||||
|
|
||||||
return;
|
indexFileEntries[ourCode] = {
|
||||||
}
|
code: ourCode,
|
||||||
|
name: NATIVE_NAMES_MAP[ourCode] || iso639.getNativeName(ourCode),
|
||||||
|
englishName: ENGLISH_NAMES_MAP[ourCode] || name,
|
||||||
|
progress: parseFloat(progress.toFixed(1)),
|
||||||
|
isReleased: RELEASED_LOCALES.includes(ourCode),
|
||||||
|
};
|
||||||
|
|
||||||
const {
|
fs.copyFile(
|
||||||
locale: { code, name },
|
translatesFilePath,
|
||||||
progress,
|
path.join(LANG_DIR, `${ourCode}.json`),
|
||||||
translatesFilePath,
|
0,
|
||||||
} = result;
|
err => {
|
||||||
const ourCode = toInternalLocale(code);
|
err ? reject(err) : resolve();
|
||||||
|
},
|
||||||
indexFileEntries[ourCode] = {
|
);
|
||||||
code: ourCode,
|
})),
|
||||||
name: NATIVE_NAMES_MAP[ourCode] || iso639.getNativeName(ourCode),
|
|
||||||
englishName: ENGLISH_NAMES_MAP[ourCode] || name,
|
|
||||||
progress: parseFloat(progress.toFixed(1)),
|
|
||||||
isReleased: RELEASED_LOCALES.includes(ourCode),
|
|
||||||
};
|
|
||||||
|
|
||||||
fs.copyFile(
|
|
||||||
translatesFilePath,
|
|
||||||
path.join(LANG_DIR, `${ourCode}.json`),
|
|
||||||
0,
|
|
||||||
err => {
|
|
||||||
err ? reject(err) : resolve();
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
console.log('Writing an index file.');
|
console.log('Writing an index file.');
|
||||||
|
|
||||||
fs.writeFileSync(
|
fs.writeFileSync(
|
||||||
path.join(LANG_DIR, INDEX_FILE_NAME),
|
path.join(LANG_DIR, INDEX_FILE_NAME),
|
||||||
serializeToFormattedJson(indexFileEntries, { asModule: true }),
|
serializeToModule(indexFileEntries),
|
||||||
);
|
);
|
||||||
|
|
||||||
console.log(ch.green('The index file was successfully written'));
|
console.log(ch.green('The index file was successfully written'));
|
||||||
@ -362,12 +285,10 @@ function push() {
|
|||||||
console.log(`Publishing ${ch.bold(SOURCE_LANG)} translates file...`);
|
console.log(`Publishing ${ch.bold(SOURCE_LANG)} translates file...`);
|
||||||
|
|
||||||
await crowdin.updateFile(
|
await crowdin.updateFile(
|
||||||
PROJECT_ID,
|
|
||||||
{
|
{
|
||||||
[CROWDIN_FILE_PATH]: path.join(LANG_DIR, `${SOURCE_LANG}.json`),
|
[CROWDIN_FILE_PATH]: path.join(LANG_DIR, `${SOURCE_LANG}.json`),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// eslint-disable-next-line @typescript-eslint/camelcase
|
|
||||||
update_option: disapprove
|
update_option: disapprove
|
||||||
? 'update_as_unapproved'
|
? 'update_as_unapproved'
|
||||||
: 'update_without_changes',
|
: 'update_without_changes',
|
||||||
|
@ -11,12 +11,15 @@
|
|||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/node": "^7.8.3",
|
"@babel/node": "^7.8.3",
|
||||||
|
"@types/mkdirp": "^0.5.2",
|
||||||
|
"@types/progress": "^2.0.3",
|
||||||
"chalk": "^3.0.0",
|
"chalk": "^3.0.0",
|
||||||
"crowdin-api": "erickskrauch/crowdin-api#add_missed_methods_and_fix_files_uploading",
|
"crowdin-api": "^4.0.0",
|
||||||
"glob": "^7.1.6",
|
"glob": "^7.1.6",
|
||||||
"iso-639-1": "^2.1.0",
|
"iso-639-1": "^2.1.0",
|
||||||
"mkdirp": "^0.5.1",
|
"mkdirp": "^0.5.1",
|
||||||
"multi-progress": "^2.0.0",
|
"multi-progress": "^2.0.0",
|
||||||
"prompt": "^1.0.0"
|
"prompt": "^1.0.0",
|
||||||
|
"utility-types": "^3.10.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
59
yarn.lock
59
yarn.lock
@ -2787,6 +2787,11 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0"
|
resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0"
|
||||||
integrity sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==
|
integrity sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==
|
||||||
|
|
||||||
|
"@types/debounce@^1.2.0":
|
||||||
|
version "1.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/debounce/-/debounce-1.2.0.tgz#9ee99259f41018c640b3929e1bb32c3dcecdb192"
|
||||||
|
integrity sha512-bWG5wapaWgbss9E238T0R6bfo5Fh3OkeoSt245CM7JJwVwpw6MEBCbIxLq5z8KzsE3uJhzcIuQkyiZmzV3M/Dw==
|
||||||
|
|
||||||
"@types/eslint-visitor-keys@^1.0.0":
|
"@types/eslint-visitor-keys@^1.0.0":
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#1ee30d79544ca84d68d4b3cdb0af4f205663dd2d"
|
resolved "https://registry.yarnpkg.com/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#1ee30d79544ca84d68d4b3cdb0af4f205663dd2d"
|
||||||
@ -2819,6 +2824,11 @@
|
|||||||
"@types/react" "*"
|
"@types/react" "*"
|
||||||
hoist-non-react-statics "^3.3.0"
|
hoist-non-react-statics "^3.3.0"
|
||||||
|
|
||||||
|
"@types/intl@^1.2.0":
|
||||||
|
version "1.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/intl/-/intl-1.2.0.tgz#1245511f13064402087979f498764611a3c758fc"
|
||||||
|
integrity sha512-BP+KwmOvD9AR5aoxnbyyPr3fAtpjEI/bVImHsotmpuC43+z0NAmjJ9cQbX7vPCq8XcvCeAVc8E3KSQPYNaPsUQ==
|
||||||
|
|
||||||
"@types/invariant@^2.2.31":
|
"@types/invariant@^2.2.31":
|
||||||
version "2.2.31"
|
version "2.2.31"
|
||||||
resolved "https://registry.yarnpkg.com/@types/invariant/-/invariant-2.2.31.tgz#4444c03004f215289dbca3856538434317dd28b2"
|
resolved "https://registry.yarnpkg.com/@types/invariant/-/invariant-2.2.31.tgz#4444c03004f215289dbca3856538434317dd28b2"
|
||||||
@ -2866,6 +2876,13 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d"
|
resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d"
|
||||||
integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==
|
integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==
|
||||||
|
|
||||||
|
"@types/mkdirp@^0.5.2":
|
||||||
|
version "0.5.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/mkdirp/-/mkdirp-0.5.2.tgz#503aacfe5cc2703d5484326b1b27efa67a339c1f"
|
||||||
|
integrity sha512-U5icWpv7YnZYGsN4/cmh3WD2onMY0aJIiTE6+51TwJCttdHvtCYmkBNOobHlXwrJRL0nkH9jH4kD+1FAdMN4Tg==
|
||||||
|
dependencies:
|
||||||
|
"@types/node" "*"
|
||||||
|
|
||||||
"@types/node@*", "@types/node@^12.0.0":
|
"@types/node@*", "@types/node@^12.0.0":
|
||||||
version "12.12.24"
|
version "12.12.24"
|
||||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-12.12.24.tgz#d4606afd8cf6c609036b854360367d1b2c78931f"
|
resolved "https://registry.yarnpkg.com/@types/node/-/node-12.12.24.tgz#d4606afd8cf6c609036b854360367d1b2c78931f"
|
||||||
@ -2876,6 +2893,13 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0"
|
resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0"
|
||||||
integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==
|
integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==
|
||||||
|
|
||||||
|
"@types/progress@^2.0.3":
|
||||||
|
version "2.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/progress/-/progress-2.0.3.tgz#7ccbd9c6d4d601319126c469e73b5bb90dfc8ccc"
|
||||||
|
integrity sha512-bPOsfCZ4tsTlKiBjBhKnM8jpY5nmIll166IPD58D92hR7G7kZDfx5iB9wGF4NfZrdKolebjeAr3GouYkSGoJ/A==
|
||||||
|
dependencies:
|
||||||
|
"@types/node" "*"
|
||||||
|
|
||||||
"@types/prop-types@*":
|
"@types/prop-types@*":
|
||||||
version "15.7.3"
|
version "15.7.3"
|
||||||
resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.3.tgz#2ab0d5da2e5815f94b0b9d4b95d1e5f243ab2ca7"
|
resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.3.tgz#2ab0d5da2e5815f94b0b9d4b95d1e5f243ab2ca7"
|
||||||
@ -2886,6 +2910,11 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.2.tgz#690a1475b84f2a884fd07cd797c00f5f31356ea8"
|
resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.2.tgz#690a1475b84f2a884fd07cd797c00f5f31356ea8"
|
||||||
integrity sha512-ce5d3q03Ex0sy4R14722Rmt6MT07Ua+k4FwDfdcToYJcMKNtRVQvJ6JCAPdAmAnbRb6CsX6aYb9m96NGod9uTw==
|
integrity sha512-ce5d3q03Ex0sy4R14722Rmt6MT07Ua+k4FwDfdcToYJcMKNtRVQvJ6JCAPdAmAnbRb6CsX6aYb9m96NGod9uTw==
|
||||||
|
|
||||||
|
"@types/raf@^3.4.0":
|
||||||
|
version "3.4.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/raf/-/raf-3.4.0.tgz#2b72cbd55405e071f1c4d29992638e022b20acc2"
|
||||||
|
integrity sha512-taW5/WYqo36N7V39oYyHP9Ipfd5pNFvGTIQsNGj86xV88YQ7GnI30/yMfKDF7Zgin0m3e+ikX88FvImnK4RjGw==
|
||||||
|
|
||||||
"@types/reach__router@^1.2.3":
|
"@types/reach__router@^1.2.3":
|
||||||
version "1.2.6"
|
version "1.2.6"
|
||||||
resolved "https://registry.yarnpkg.com/@types/reach__router/-/reach__router-1.2.6.tgz#b14cf1adbd1a365d204bbf6605cd9dd7b8816c87"
|
resolved "https://registry.yarnpkg.com/@types/reach__router/-/reach__router-1.2.6.tgz#b14cf1adbd1a365d204bbf6605cd9dd7b8816c87"
|
||||||
@ -4156,7 +4185,7 @@ bluebird@3.7.1:
|
|||||||
resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.1.tgz#df70e302b471d7473489acf26a93d63b53f874de"
|
resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.1.tgz#df70e302b471d7473489acf26a93d63b53f874de"
|
||||||
integrity sha512-DdmyoGCleJnkbp3nkbxTLJ18rjDsE4yCggEwKNXkeV123sPNfOCYeDoeuOY+F2FrSjO1YXcTU+dsy96KMy+gcg==
|
integrity sha512-DdmyoGCleJnkbp3nkbxTLJ18rjDsE4yCggEwKNXkeV123sPNfOCYeDoeuOY+F2FrSjO1YXcTU+dsy96KMy+gcg==
|
||||||
|
|
||||||
bluebird@^3.3.5, bluebird@^3.5.0, bluebird@^3.5.1, bluebird@^3.5.5:
|
bluebird@^3.3.5, bluebird@^3.5.0, bluebird@^3.5.3, bluebird@^3.5.5:
|
||||||
version "3.7.2"
|
version "3.7.2"
|
||||||
resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f"
|
resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f"
|
||||||
integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==
|
integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==
|
||||||
@ -5252,14 +5281,15 @@ cross-spawn@^7.0.0:
|
|||||||
shebang-command "^2.0.0"
|
shebang-command "^2.0.0"
|
||||||
which "^2.0.1"
|
which "^2.0.1"
|
||||||
|
|
||||||
crowdin-api@erickskrauch/crowdin-api#add_missed_methods_and_fix_files_uploading:
|
crowdin-api@^4.0.0:
|
||||||
version "2.0.3"
|
version "4.0.0"
|
||||||
resolved "https://codeload.github.com/erickskrauch/crowdin-api/tar.gz/acf088542aff16e903290ebf43866494fa07e58d"
|
resolved "https://registry.yarnpkg.com/crowdin-api/-/crowdin-api-4.0.0.tgz#faa1d0af62e97fcbdf94d7a0830db5f5ddbdb0e6"
|
||||||
|
integrity sha512-NEUMrtEvxhNjiBp68EEm0t4PGQaBxxUlKSQHy3GlgjepQffd2bxnBTx2+8LkB9wzClu2+euVV/MStQG7++tkVw==
|
||||||
dependencies:
|
dependencies:
|
||||||
bluebird "^3.5.1"
|
bluebird "^3.5.3"
|
||||||
request "^2.88.0"
|
request "^2.88.0"
|
||||||
request-promise "^4.2.2"
|
request-promise "^4.2.4"
|
||||||
temp "^0.8.3"
|
temp "^0.9.0"
|
||||||
|
|
||||||
crypto-browserify@^3.11.0:
|
crypto-browserify@^3.11.0:
|
||||||
version "3.12.0"
|
version "3.12.0"
|
||||||
@ -12661,7 +12691,7 @@ request-promise-native@^1.0.5:
|
|||||||
stealthy-require "^1.1.1"
|
stealthy-require "^1.1.1"
|
||||||
tough-cookie "^2.3.3"
|
tough-cookie "^2.3.3"
|
||||||
|
|
||||||
request-promise@^4.2.2:
|
request-promise@^4.2.4:
|
||||||
version "4.2.5"
|
version "4.2.5"
|
||||||
resolved "https://registry.yarnpkg.com/request-promise/-/request-promise-4.2.5.tgz#186222c59ae512f3497dfe4d75a9c8461bd0053c"
|
resolved "https://registry.yarnpkg.com/request-promise/-/request-promise-4.2.5.tgz#186222c59ae512f3497dfe4d75a9c8461bd0053c"
|
||||||
integrity sha512-ZgnepCykFdmpq86fKGwqntyTiUrHycALuGggpyCZwMvGaZWgxW6yagT0FHkgo5LzYvOaCNvxYwWYIjevSH1EDg==
|
integrity sha512-ZgnepCykFdmpq86fKGwqntyTiUrHycALuGggpyCZwMvGaZWgxW6yagT0FHkgo5LzYvOaCNvxYwWYIjevSH1EDg==
|
||||||
@ -14083,10 +14113,10 @@ telejson@^3.2.0:
|
|||||||
lodash "^4.17.15"
|
lodash "^4.17.15"
|
||||||
memoizerific "^1.11.3"
|
memoizerific "^1.11.3"
|
||||||
|
|
||||||
temp@^0.8.3:
|
temp@^0.9.0:
|
||||||
version "0.8.4"
|
version "0.9.1"
|
||||||
resolved "https://registry.yarnpkg.com/temp/-/temp-0.8.4.tgz#8c97a33a4770072e0a05f919396c7665a7dd59f2"
|
resolved "https://registry.yarnpkg.com/temp/-/temp-0.9.1.tgz#2d666114fafa26966cd4065996d7ceedd4dd4697"
|
||||||
integrity sha512-s0ZZzd0BzYv5tLSptZooSjK8oj6C+c19p7Vqta9+6NPOf7r+fxq0cJe6/oN4LTC79sy5NY8ucOJNgwsKCSbfqg==
|
integrity sha512-WMuOgiua1xb5R56lE0eH6ivpVmg/lq2OHm4+LtT/xtEtPQ+sz6N3bBM6WZ5FvO1lO4IKIOb43qnhoc4qxP5OeA==
|
||||||
dependencies:
|
dependencies:
|
||||||
rimraf "~2.6.2"
|
rimraf "~2.6.2"
|
||||||
|
|
||||||
@ -14721,6 +14751,11 @@ utile@0.3.x:
|
|||||||
ncp "1.0.x"
|
ncp "1.0.x"
|
||||||
rimraf "2.x.x"
|
rimraf "2.x.x"
|
||||||
|
|
||||||
|
utility-types@^3.10.0:
|
||||||
|
version "3.10.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/utility-types/-/utility-types-3.10.0.tgz#ea4148f9a741015f05ed74fd615e1d20e6bed82b"
|
||||||
|
integrity sha512-O11mqxmi7wMKCo6HKFt5AhO4BwY3VV68YU07tgxfz8zJTIxr4BpsezN49Ffwy9j3ZpwwJp4fkRwjRzq3uWE6Rg==
|
||||||
|
|
||||||
utils-merge@1.0.1:
|
utils-merge@1.0.1:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
|
resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
|
||||||
|
Loading…
Reference in New Issue
Block a user