lingui-po-translate 1.0.0 → 1.0.1
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/core/core-definitions.js +21 -0
- package/dist/core/core-util.js +65 -0
- package/dist/core/invoke-translation-service.js +82 -0
- package/dist/core/translate-cli.js +113 -0
- package/dist/core/translate-core.js +230 -0
- package/dist/core/tset-ops.js +110 -0
- package/dist/file-formats/common/format-cache.js +72 -0
- package/dist/file-formats/common/managed-json.js +37 -0
- package/dist/file-formats/common/managed-utf8.js +69 -0
- package/dist/file-formats/common/parse-utils.js +14 -0
- package/dist/file-formats/csv/csv.js +64 -0
- package/dist/file-formats/file-format-definitions.js +43 -0
- package/dist/file-formats/flat-json/flat-json.js +29 -0
- package/dist/file-formats/flutter-arb/flutter-arb.js +62 -0
- package/dist/file-formats/ios-strings/ios-read.js +72 -0
- package/dist/file-formats/ios-strings/ios-strings.js +22 -0
- package/dist/file-formats/ios-strings/ios-write.js +37 -0
- package/dist/file-formats/nested-json/nested-json.js +66 -0
- package/dist/file-formats/po/comment-parser.js +68 -0
- package/dist/file-formats/po/po-files.js +78 -0
- package/dist/file-formats/po/po-ops.js +111 -0
- package/dist/file-formats/xml/xml-generic.js +81 -0
- package/dist/file-formats/xml/xml-read.js +66 -0
- package/dist/file-formats/xml/xml-traverse.js +160 -0
- package/dist/file-formats/xml/xml-write.js +62 -0
- package/dist/file-formats/yaml/yaml-generic.js +113 -0
- package/dist/file-formats/yaml/yaml-manipulation.js +132 -0
- package/dist/file-formats/yaml/yaml-parse.js +38 -0
- package/dist/index.js +66 -0
- package/dist/matchers/i18next.js +11 -0
- package/dist/matchers/icu.js +23 -0
- package/dist/matchers/matcher-definitions.js +46 -0
- package/dist/matchers/sprintf.js +11 -0
- package/dist/services/azure-translator.js +52 -0
- package/dist/services/google-translate.js +55 -0
- package/dist/services/key-as-translation.js +18 -0
- package/dist/services/manual.js +29 -0
- package/dist/services/openai-translate.js +91 -0
- package/dist/services/service-definitions.js +57 -0
- package/dist/services/sync-without-translate.js +18 -0
- package/dist/services/typechat.js +214 -0
- package/dist/util/extract-version.js +20 -0
- package/dist/util/flatten.js +40 -0
- package/dist/util/util.js +87 -0
- package/package.json +2 -2
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TypeChatTranslate = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const axios_1 = (0, tslib_1.__importDefault)(require("axios"));
|
|
6
|
+
const clipboardy_1 = (0, tslib_1.__importDefault)(require("clipboardy"));
|
|
7
|
+
const inquirer_1 = (0, tslib_1.__importDefault)(require("inquirer"));
|
|
8
|
+
const lodash_1 = require("lodash");
|
|
9
|
+
const typechat_1 = require("typechat");
|
|
10
|
+
const util_1 = require("../util/util");
|
|
11
|
+
const MINUTE_MS = 60 * 1000;
|
|
12
|
+
function generateSchema(batch, name, comment) {
|
|
13
|
+
const properties = batch
|
|
14
|
+
.map((tString) => {
|
|
15
|
+
return ` '${tString.key}': string;`;
|
|
16
|
+
})
|
|
17
|
+
.join("\n");
|
|
18
|
+
const schema = `export interface ${name} {\n${properties}\n}\n`;
|
|
19
|
+
return comment ? `// ${comment} \n\n${schema}` : schema;
|
|
20
|
+
}
|
|
21
|
+
function generatePrompt(batch, args) {
|
|
22
|
+
const entries = batch.reduce((entries, tString) => {
|
|
23
|
+
entries[tString.key] = tString.value;
|
|
24
|
+
return entries;
|
|
25
|
+
}, {});
|
|
26
|
+
// Build context info for entries that have context
|
|
27
|
+
const contextInfo = batch
|
|
28
|
+
.filter((tString) => tString.context)
|
|
29
|
+
.map((tString) => `- "${tString.key}": ${tString.context}`)
|
|
30
|
+
.join("\n");
|
|
31
|
+
const basePrompt = `Translate the following JSON object from ${args.srcLng} into ${args.targetLng}:\n`;
|
|
32
|
+
const customPrompt = args.prompt
|
|
33
|
+
? `\nAdditional instructions: ${args.prompt}\n\n`
|
|
34
|
+
: "\n";
|
|
35
|
+
const contextPrompt = contextInfo
|
|
36
|
+
? `\nContext for specific keys:\n${contextInfo}\n\n`
|
|
37
|
+
: "";
|
|
38
|
+
return basePrompt + customPrompt + contextPrompt + JSON.stringify(entries, null, 2);
|
|
39
|
+
}
|
|
40
|
+
function parseResponse(batch, data) {
|
|
41
|
+
return batch.map((tString) => {
|
|
42
|
+
var _a;
|
|
43
|
+
const result = {
|
|
44
|
+
key: tString.key,
|
|
45
|
+
translated: (_a = data[tString.key]) !== null && _a !== void 0 ? _a : "",
|
|
46
|
+
};
|
|
47
|
+
return result;
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
async function translateBatch(model, batch, args, env) {
|
|
51
|
+
var _a;
|
|
52
|
+
console.log("Translate a batch of " + batch.length + " strings with TypeChat...");
|
|
53
|
+
const schemaName = (_a = env.TYPECHAT_SCHEMA_NAME) !== null && _a !== void 0 ? _a : "AppLocalizations";
|
|
54
|
+
const schemaComment = env.TYPECHAT_SCHEMA_COMMENT;
|
|
55
|
+
const translator = (0, typechat_1.createJsonTranslator)(model, generateSchema(batch, schemaName, schemaComment), schemaName);
|
|
56
|
+
const response = await translator.translate(generatePrompt(batch, args));
|
|
57
|
+
if (!response.success) {
|
|
58
|
+
(0, util_1.logFatal)(response.message);
|
|
59
|
+
}
|
|
60
|
+
return parseResponse(batch, response.data);
|
|
61
|
+
}
|
|
62
|
+
function createLanguageModel(env) {
|
|
63
|
+
var _a, _b, _c;
|
|
64
|
+
const apiKey = (_a = env.OPENAI_API_KEY) !== null && _a !== void 0 ? _a : missingEnvironmentVariable("OPENAI_API_KEY");
|
|
65
|
+
const model = (_b = env.OPENAI_MODEL) !== null && _b !== void 0 ? _b : "gpt-4o-mini-2024-07-18";
|
|
66
|
+
const url = (_c = env.OPENAI_ENDPOINT) !== null && _c !== void 0 ? _c : "https://api.openai.com/v1/chat/completions";
|
|
67
|
+
return createAxiosLanguageModel(url, {
|
|
68
|
+
headers: {
|
|
69
|
+
Authorization: `Bearer ${apiKey}`,
|
|
70
|
+
},
|
|
71
|
+
}, { model });
|
|
72
|
+
}
|
|
73
|
+
function createManualModel() {
|
|
74
|
+
const model = {
|
|
75
|
+
complete,
|
|
76
|
+
};
|
|
77
|
+
return model;
|
|
78
|
+
async function complete(prompt) {
|
|
79
|
+
await clipboardy_1.default.write(prompt);
|
|
80
|
+
console.log(`Prompt copied to clipboard`);
|
|
81
|
+
await inquirer_1.default.prompt([
|
|
82
|
+
{
|
|
83
|
+
name: "Enter",
|
|
84
|
+
message: "Press enter after you copied the response.",
|
|
85
|
+
type: "input",
|
|
86
|
+
},
|
|
87
|
+
]);
|
|
88
|
+
const result = await clipboardy_1.default.read();
|
|
89
|
+
return (0, typechat_1.success)(result);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
function sanitize_keys(target, propertyKey, descriptor) {
|
|
93
|
+
const originalMethod = descriptor.value;
|
|
94
|
+
descriptor.value = async function (args) {
|
|
95
|
+
const sanitizedKeys = args.strings.map(({ key }) => {
|
|
96
|
+
return {
|
|
97
|
+
new: key.replace(/[^a-zA-Z0-9_]+/g, "_"),
|
|
98
|
+
old: key,
|
|
99
|
+
};
|
|
100
|
+
});
|
|
101
|
+
// Replace keys with sanitized versions
|
|
102
|
+
for (let i = 0; i < sanitizedKeys.length; i++) {
|
|
103
|
+
args.strings[i].key = sanitizedKeys[i].new;
|
|
104
|
+
}
|
|
105
|
+
// Call the original method
|
|
106
|
+
const results = await originalMethod.apply(this, [args]);
|
|
107
|
+
// Restore original keys in the results
|
|
108
|
+
for (let i = 0; i < sanitizedKeys.length; i++) {
|
|
109
|
+
results[i].key = sanitizedKeys[i].old;
|
|
110
|
+
}
|
|
111
|
+
return results;
|
|
112
|
+
};
|
|
113
|
+
return descriptor;
|
|
114
|
+
}
|
|
115
|
+
class TypeChatTranslate {
|
|
116
|
+
constructor(manual) {
|
|
117
|
+
this.manual = manual !== null && manual !== void 0 ? manual : false;
|
|
118
|
+
}
|
|
119
|
+
async translateStrings(args) {
|
|
120
|
+
var _a, _b;
|
|
121
|
+
const rpm = parseInt((_a = process.env.TYPECHAT_RPM) !== null && _a !== void 0 ? _a : "");
|
|
122
|
+
const batchSize = parseInt((_b = process.env.OPEN_AI_BATCH_SIZE) !== null && _b !== void 0 ? _b : "");
|
|
123
|
+
const batches = (0, lodash_1.chunk)(args.strings, isNaN(batchSize) ? 10 : batchSize);
|
|
124
|
+
const results = [];
|
|
125
|
+
const model = this.manual
|
|
126
|
+
? createManualModel()
|
|
127
|
+
: createLanguageModel(process.env);
|
|
128
|
+
for (var i = 0; i < batches.length; i++) {
|
|
129
|
+
const batch = batches[i];
|
|
130
|
+
const start = new Date();
|
|
131
|
+
const result = await translateBatch(model, batch, args, process.env);
|
|
132
|
+
results.push(result);
|
|
133
|
+
// Sleep to not exceeded the specified requests per minute (RPM)
|
|
134
|
+
if (!this.manual && !isNaN(rpm) && rpm > 0 && i < batches.length - 1) {
|
|
135
|
+
const requestDuration = new Date().getTime() - start.getTime();
|
|
136
|
+
const sleepDuration = (MINUTE_MS / rpm) - requestDuration;
|
|
137
|
+
console.log(`Going to sleep for ${sleepDuration} ms`);
|
|
138
|
+
await sleep(sleepDuration);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return (0, lodash_1.flatten)(results);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
(0, tslib_1.__decorate)([
|
|
145
|
+
sanitize_keys
|
|
146
|
+
], TypeChatTranslate.prototype, "translateStrings", null);
|
|
147
|
+
exports.TypeChatTranslate = TypeChatTranslate;
|
|
148
|
+
// The following code is from TypeChat
|
|
149
|
+
// https://github.com/microsoft/TypeChat/blob/e8395ef2e4688ec7b94a7612046aeaec0af93046/src/model.ts#L65
|
|
150
|
+
// MIT License - https://github.com/microsoft/TypeChat/blob/main/LICENSE
|
|
151
|
+
// Copyright (c) Microsoft Corporation.
|
|
152
|
+
/**
|
|
153
|
+
* Common implementation of language model encapsulation of an OpenAI REST API endpoint.
|
|
154
|
+
*/
|
|
155
|
+
function createAxiosLanguageModel(url, config, defaultParams) {
|
|
156
|
+
const client = axios_1.default.create(config);
|
|
157
|
+
const model = {
|
|
158
|
+
complete,
|
|
159
|
+
};
|
|
160
|
+
return model;
|
|
161
|
+
async function complete(prompt) {
|
|
162
|
+
var _a, _b, _c, _d;
|
|
163
|
+
let retryCount = 0;
|
|
164
|
+
const retryMaxAttempts = (_a = model.retryMaxAttempts) !== null && _a !== void 0 ? _a : 3;
|
|
165
|
+
const retryPauseMs = (_b = model.retryPauseMs) !== null && _b !== void 0 ? _b : 1000;
|
|
166
|
+
while (true) {
|
|
167
|
+
const params = {
|
|
168
|
+
max_tokens: 2048,
|
|
169
|
+
temperature: 0,
|
|
170
|
+
...defaultParams,
|
|
171
|
+
messages: [{ role: "user", content: prompt }],
|
|
172
|
+
n: 1,
|
|
173
|
+
};
|
|
174
|
+
const result = await client.post(url, params, {
|
|
175
|
+
validateStatus: (status) => true,
|
|
176
|
+
});
|
|
177
|
+
if (result.status === 200) {
|
|
178
|
+
return (0, typechat_1.success)((_d = (_c = result.data.choices[0].message) === null || _c === void 0 ? void 0 : _c.content) !== null && _d !== void 0 ? _d : "");
|
|
179
|
+
}
|
|
180
|
+
if (result.status === 401) {
|
|
181
|
+
return (0, typechat_1.error)(`REST API error ${result.status}: ${result.statusText}`);
|
|
182
|
+
}
|
|
183
|
+
if (!isTransientHttpError(result.status) ||
|
|
184
|
+
retryCount >= retryMaxAttempts) {
|
|
185
|
+
return (0, typechat_1.error)(`REST API error ${result.status}: ${result.statusText}`);
|
|
186
|
+
}
|
|
187
|
+
await sleep(retryPauseMs);
|
|
188
|
+
retryCount++;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Returns true of the given HTTP status code represents a transient error.
|
|
194
|
+
*/
|
|
195
|
+
function isTransientHttpError(code) {
|
|
196
|
+
switch (code) {
|
|
197
|
+
case 429: // TooManyRequests
|
|
198
|
+
case 500: // InternalServerError
|
|
199
|
+
case 502: // BadGateway
|
|
200
|
+
case 503: // ServiceUnavailable
|
|
201
|
+
case 504: // GatewayTimeout
|
|
202
|
+
return true;
|
|
203
|
+
}
|
|
204
|
+
return false;
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Sleeps for the given number of milliseconds.
|
|
208
|
+
*/
|
|
209
|
+
function sleep(ms) {
|
|
210
|
+
return new Promise((resolve) => setTimeout(resolve, ms > 0 ? ms : 0));
|
|
211
|
+
}
|
|
212
|
+
function missingEnvironmentVariable(name) {
|
|
213
|
+
(0, util_1.logFatal)(`Missing environment variable: ${name}`);
|
|
214
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.extractVersion = void 0;
|
|
4
|
+
const path_1 = require("path");
|
|
5
|
+
const fs_1 = require("fs");
|
|
6
|
+
function extractVersion(args) {
|
|
7
|
+
const rootDir = (0, path_1.resolve)((0, path_1.join)(args.cliBinDir, ".."));
|
|
8
|
+
try {
|
|
9
|
+
const jsonStr = (0, fs_1.readFileSync)((0, path_1.join)(rootDir, "package.json"), {
|
|
10
|
+
encoding: "utf8",
|
|
11
|
+
flag: "r",
|
|
12
|
+
});
|
|
13
|
+
const packageJson = JSON.parse(jsonStr);
|
|
14
|
+
return packageJson.version;
|
|
15
|
+
}
|
|
16
|
+
catch (e) {
|
|
17
|
+
return e.toString() + "\nFailed to retrieve the version";
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
exports.extractVersion = extractVersion;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.unflatten = exports.NESTED_JSON_SEPARATOR = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const lodash_1 = (0, tslib_1.__importDefault)(require("lodash"));
|
|
6
|
+
exports.NESTED_JSON_SEPARATOR = ".";
|
|
7
|
+
function replaceAll(string, search, replace) {
|
|
8
|
+
return string.split(search).join(replace);
|
|
9
|
+
}
|
|
10
|
+
const escapeRules = {
|
|
11
|
+
".": "\\\\|",
|
|
12
|
+
"[": "\\\\(",
|
|
13
|
+
"]": "\\\\)",
|
|
14
|
+
};
|
|
15
|
+
function unescapeKey(str) {
|
|
16
|
+
let targetStr = str;
|
|
17
|
+
for (const replace of Object.keys(escapeRules)) {
|
|
18
|
+
const search = escapeRules[replace];
|
|
19
|
+
targetStr = replaceAll(targetStr, search, replace);
|
|
20
|
+
}
|
|
21
|
+
return targetStr;
|
|
22
|
+
}
|
|
23
|
+
function unescapeObject(obj) {
|
|
24
|
+
const targetObj = {};
|
|
25
|
+
for (const key of Object.keys(obj)) {
|
|
26
|
+
let value = obj[key];
|
|
27
|
+
if (typeof value === "object" && value !== null) {
|
|
28
|
+
value = unescapeObject(value);
|
|
29
|
+
}
|
|
30
|
+
targetObj[unescapeKey(key)] = value;
|
|
31
|
+
}
|
|
32
|
+
return targetObj;
|
|
33
|
+
}
|
|
34
|
+
function unflatten(params) {
|
|
35
|
+
const rawUnflattened = lodash_1.default.reduce(params, function (result, value, key) {
|
|
36
|
+
return lodash_1.default.set(result, key, value);
|
|
37
|
+
}, {});
|
|
38
|
+
return unescapeObject(rawUnflattened);
|
|
39
|
+
}
|
|
40
|
+
exports.unflatten = unflatten;
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.nodeVersionSatisfies = exports.runCommandOrDie = exports.writeUtf8File = exports.readUtf8File = exports.deleteFile = exports.logFatal = exports.getDebugPath = exports.checkNotDir = exports.checkDir = exports.joinDirWithFileName = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const child_process_1 = require("child_process");
|
|
6
|
+
const fs_1 = require("fs");
|
|
7
|
+
const path_1 = require("path");
|
|
8
|
+
const semver_1 = (0, tslib_1.__importDefault)(require("semver"));
|
|
9
|
+
function joinDirWithFileName(dir, fileName) {
|
|
10
|
+
checkDir(dir);
|
|
11
|
+
return (0, path_1.join)((0, path_1.resolve)(dir), fileName);
|
|
12
|
+
}
|
|
13
|
+
exports.joinDirWithFileName = joinDirWithFileName;
|
|
14
|
+
function isDirectory(path) {
|
|
15
|
+
try {
|
|
16
|
+
const stat = (0, fs_1.lstatSync)(path);
|
|
17
|
+
return stat.isDirectory();
|
|
18
|
+
}
|
|
19
|
+
catch (e) {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
function extractHint(hint) {
|
|
24
|
+
if (!hint) {
|
|
25
|
+
return "";
|
|
26
|
+
}
|
|
27
|
+
return hint.errorHint + " ";
|
|
28
|
+
}
|
|
29
|
+
function checkDir(dir, hint) {
|
|
30
|
+
checkExists(dir, hint);
|
|
31
|
+
if (!isDirectory(dir)) {
|
|
32
|
+
logFatal(`${extractHint(hint)}${getDebugPath(dir)} is not a directory.`);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
exports.checkDir = checkDir;
|
|
36
|
+
function checkNotDir(path, hint) {
|
|
37
|
+
checkExists(path, hint);
|
|
38
|
+
if (isDirectory(path)) {
|
|
39
|
+
logFatal(`${extractHint(hint)}${getDebugPath(path)} is a directory.`);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
exports.checkNotDir = checkNotDir;
|
|
43
|
+
function checkExists(path, hint) {
|
|
44
|
+
if (!(0, fs_1.existsSync)(path)) {
|
|
45
|
+
logFatal(`${extractHint(hint)}${getDebugPath(path)} does not exist.`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
function getDebugPath(path) {
|
|
49
|
+
return `\'${(0, path_1.resolve)(path)}\'`; // Show an absolute path to users in case of errors.
|
|
50
|
+
}
|
|
51
|
+
exports.getDebugPath = getDebugPath;
|
|
52
|
+
function logFatal(msg) {
|
|
53
|
+
console.error(`error: ${msg}`);
|
|
54
|
+
return process.exit(1);
|
|
55
|
+
}
|
|
56
|
+
exports.logFatal = logFatal;
|
|
57
|
+
function deleteFile(path) {
|
|
58
|
+
checkExists(path);
|
|
59
|
+
(0, fs_1.unlinkSync)(path);
|
|
60
|
+
console.info(`Deleted ${getDebugPath(path)}`);
|
|
61
|
+
}
|
|
62
|
+
exports.deleteFile = deleteFile;
|
|
63
|
+
function readUtf8File(path) {
|
|
64
|
+
checkNotDir(path);
|
|
65
|
+
return (0, fs_1.readFileSync)(path, { encoding: "utf8", flag: "r" });
|
|
66
|
+
}
|
|
67
|
+
exports.readUtf8File = readUtf8File;
|
|
68
|
+
function writeUtf8File(path, content) {
|
|
69
|
+
(0, fs_1.writeFileSync)(path, content, { encoding: "utf8" });
|
|
70
|
+
}
|
|
71
|
+
exports.writeUtf8File = writeUtf8File;
|
|
72
|
+
function runCommandOrDie(command) {
|
|
73
|
+
try {
|
|
74
|
+
return (0, child_process_1.execSync)(command).toString();
|
|
75
|
+
}
|
|
76
|
+
catch (e) {
|
|
77
|
+
//console.error(e.stderr.toString());
|
|
78
|
+
logFatal(`Failed to run \'${command}\' in current directory \'${process.cwd()}\'.`);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
exports.runCommandOrDie = runCommandOrDie;
|
|
82
|
+
function nodeVersionSatisfies(feature, range) {
|
|
83
|
+
if (!semver_1.default.satisfies(process.version, range)) {
|
|
84
|
+
logFatal(`${feature} requires node ${range}`);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
exports.nodeVersionSatisfies = nodeVersionSatisfies;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lingui-po-translate",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "AI-powered translation tool for Lingui PO files with context-aware translations",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"test": "jest --testTimeout=10000",
|
|
36
36
|
"test:windows": "npm run test -- --config=test/windows.jest.config.js",
|
|
37
37
|
"test:generate_refs": "GENERATE_REFS=True npm run test",
|
|
38
|
-
"prepublishOnly": "git diff --exit-code"
|
|
38
|
+
"prepublishOnly": "rm -rf ./dist && tsc && git diff --exit-code"
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
41
|
"@google-cloud/translate": "^8.3.0",
|