waha-shared 1.0.474 → 1.0.475
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.
|
@@ -45,9 +45,10 @@ interface UploadSourceParams {
|
|
|
45
45
|
/** The id of the project to upload to, from `crowdinProjectIds`. */
|
|
46
46
|
projectId: string;
|
|
47
47
|
/**
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
48
|
+
* Absolute path to the source file to upload, somewhere under a `crowdin/`
|
|
49
|
+
* directory (e.g. `/path/to/project/crowdin/eng/app_interface_text.json`,
|
|
50
|
+
* or `/path/to/project/crowdin/foo.md` for a project that keeps sources at
|
|
51
|
+
* the root). The path Crowdin sees is everything after `crowdin/`.
|
|
51
52
|
*/
|
|
52
53
|
source: string;
|
|
53
54
|
/** The Crowdin personal access token to use for authentication. */
|
|
@@ -21,13 +21,32 @@ exports.crowdinProjectIds = {
|
|
|
21
21
|
dmc: '663528',
|
|
22
22
|
emails: '929263',
|
|
23
23
|
};
|
|
24
|
-
const BASE_PATH = path_1.default.resolve(__dirname, '../../crowdin/eng');
|
|
25
24
|
/**
|
|
26
25
|
* Where a translated file lands, relative to the language folder. Every Waha
|
|
27
26
|
* project maps a language's Crowdin three-letter code onto its Waha id, which
|
|
28
27
|
* is why translations download straight into `crowdin/{wahaLanguageId}`.
|
|
29
28
|
*/
|
|
30
29
|
exports.CROWDIN_TRANSLATION_PATTERN = '%three_letters_code%/%original_file_name%';
|
|
30
|
+
/**
|
|
31
|
+
* Derives the Crowdin-relative path (what's shown in the dashboard, e.g.
|
|
32
|
+
* `eng/app_interface_text.json`) from an absolute filesystem path. Every
|
|
33
|
+
* Waha project keeps its Crowdin sources under a `crowdin/` directory, so
|
|
34
|
+
* that directory's name is the anchor: everything after the last `crowdin`
|
|
35
|
+
* segment is the path Crowdin knows about.
|
|
36
|
+
*
|
|
37
|
+
* This indirection exists because callers pass an absolute path rather than
|
|
38
|
+
* one relative to this file. `shared/` ships as a published npm package, so
|
|
39
|
+
* this file can end up executing from inside a consumer's `node_modules`,
|
|
40
|
+
* where a base path hardcoded relative to `__dirname` points nowhere useful.
|
|
41
|
+
*/
|
|
42
|
+
function crowdinRelativePath(absolutePath) {
|
|
43
|
+
const segments = absolutePath.split(path_1.default.sep);
|
|
44
|
+
const crowdinIndex = segments.lastIndexOf('crowdin');
|
|
45
|
+
if (crowdinIndex === -1) {
|
|
46
|
+
throw new Error(`Expected an absolute path under a "crowdin" directory, got "${absolutePath}".`);
|
|
47
|
+
}
|
|
48
|
+
return segments.slice(crowdinIndex + 1).join('/');
|
|
49
|
+
}
|
|
31
50
|
/**
|
|
32
51
|
* Downloads translations from Crowdin for a given project ID and source path.
|
|
33
52
|
*/
|
|
@@ -51,8 +70,9 @@ function downloadTranslations({ projectId, translationsFolder, token, sourcePatt
|
|
|
51
70
|
async function uploadSource({ projectId, source, token, label, fileSettings, }) {
|
|
52
71
|
const client = new crowdin_api_client_1.default({ token });
|
|
53
72
|
const id = Number(projectId);
|
|
54
|
-
const
|
|
55
|
-
const
|
|
73
|
+
const relativePath = crowdinRelativePath(source);
|
|
74
|
+
const fileName = relativePath.split('/').pop();
|
|
75
|
+
const contents = fs_1.default.readFileSync(source, 'utf8');
|
|
56
76
|
const storage = await client.uploadStorageApi.addStorage(fileName, contents);
|
|
57
77
|
/*
|
|
58
78
|
* Replacing a file needs its numeric id, and the API has no by-path
|
|
@@ -64,7 +84,7 @@ async function uploadSource({ projectId, source, token, label, fileSettings, })
|
|
|
64
84
|
filter: fileName,
|
|
65
85
|
limit: 500,
|
|
66
86
|
});
|
|
67
|
-
const existing = files.data.find((file) => file.data.path === `/${
|
|
87
|
+
const existing = files.data.find((file) => file.data.path === `/${relativePath}`);
|
|
68
88
|
const exportOptions = {
|
|
69
89
|
exportPattern: `/${exports.CROWDIN_TRANSLATION_PATTERN}`,
|
|
70
90
|
};
|
|
@@ -97,7 +117,7 @@ async function uploadSource({ projectId, source, token, label, fileSettings, })
|
|
|
97
117
|
exportOptions,
|
|
98
118
|
...fileSettings,
|
|
99
119
|
...(attachLabelIds && { attachLabelIds }),
|
|
100
|
-
...(await directoryId(client, id,
|
|
120
|
+
...(await directoryId(client, id, relativePath)),
|
|
101
121
|
};
|
|
102
122
|
await client.sourceFilesApi.createFile(id, request);
|
|
103
123
|
}
|
|
@@ -117,8 +137,8 @@ async function labelId(client, projectId, title) {
|
|
|
117
137
|
* misspelled path that gets created silently uploads to a new file and
|
|
118
138
|
* orphans every translation attached to the real one.
|
|
119
139
|
*/
|
|
120
|
-
async function directoryId(client, projectId,
|
|
121
|
-
const segments =
|
|
140
|
+
async function directoryId(client, projectId, relativePath) {
|
|
141
|
+
const segments = relativePath.split('/').slice(0, -1);
|
|
122
142
|
if (segments.length === 0)
|
|
123
143
|
return {};
|
|
124
144
|
const wanted = `/${segments.join('/')}`;
|