mirror of
https://github.com/Termix-SSH/Termix.git
synced 2026-10-10 22:02:55 +00:00
fix: crowdin sync and pretranslate for plugin locales, run plugin tests on release
This commit is contained in:
1 parent
1c4b057fd8
commit
f8edb5f299
5 files changed
+72
-30
No files matched your search
@@ -51,7 +51,7 @@ jobs:
|
||||
env:
|
||||
CROWDIN_API_TOKEN: ${{ secrets.CROWDIN_API_KEY }}
|
||||
|
||||
- name: Machine pre-translate untranslated strings
|
||||
- name: Pre-translate untranslated strings
|
||||
env:
|
||||
CROWDIN_API_KEY: ${{ secrets.CROWDIN_API_KEY }}
|
||||
run: node scripts/crowdin-pretranslate.cjs
|
||||
@@ -74,7 +74,7 @@ jobs:
|
||||
git config user.name "LukeGus"
|
||||
git config user.email "bugattiguy527@gmail.com"
|
||||
|
||||
git add src/ui/locales/translated
|
||||
git add src/ui/locales/translated plugins/*/locales/translated
|
||||
if git diff --cached --quiet; then
|
||||
echo "No translation changes to commit."
|
||||
exit 0
|
||||
|
||||
@@ -102,8 +102,9 @@ jobs:
|
||||
|
||||
- name: Lint and format
|
||||
run: |
|
||||
npm run lint:fix || true
|
||||
npm run lint:fix
|
||||
npm run format
|
||||
npm run lint
|
||||
|
||||
# The plugin boot tests load the built bundles.
|
||||
- name: Build plugins
|
||||
@@ -112,6 +113,9 @@ jobs:
|
||||
- name: Run unit tests
|
||||
run: npm run test
|
||||
|
||||
- name: Run plugin tests
|
||||
run: npm run test:plugins
|
||||
|
||||
- name: Sync version
|
||||
run: node scripts/sync-version.cjs --version "${{ needs.prep.outputs.version }}"
|
||||
|
||||
@@ -184,7 +188,7 @@ jobs:
|
||||
env:
|
||||
CROWDIN_API_TOKEN: ${{ secrets.CROWDIN_API_KEY }}
|
||||
|
||||
- name: Machine pre-translate untranslated strings
|
||||
- name: Pre-translate untranslated strings
|
||||
env:
|
||||
CROWDIN_API_KEY: ${{ secrets.CROWDIN_API_KEY }}
|
||||
run: node scripts/crowdin-pretranslate.cjs
|
||||
@@ -207,7 +211,7 @@ jobs:
|
||||
git config user.name "LukeGus"
|
||||
git config user.email "bugattiguy527@gmail.com"
|
||||
|
||||
git add src/ui/locales/translated
|
||||
git add src/ui/locales/translated plugins/*/locales/translated
|
||||
if git diff --cached --quiet; then
|
||||
echo "No translation changes to commit."
|
||||
exit 0
|
||||
|
||||
+4
-1
@@ -1,8 +1,11 @@
|
||||
project_id: "858252"
|
||||
api_token: "env:CROWDIN_API_TOKEN"
|
||||
preserve_hierarchy: true
|
||||
|
||||
files:
|
||||
# Core has always lived at /en.json in Crowdin; moving it would orphan its translations.
|
||||
- source: /src/ui/locales/en.json
|
||||
dest: /en.json
|
||||
translation: /src/ui/locales/translated/%locale_with_underscore%.json
|
||||
- source: /plugins/*/locales/en.json
|
||||
translation: /plugins/**/locales/translated/%locale_with_underscore%.json
|
||||
translation: /%original_path%/translated/%locale_with_underscore%.json
|
||||
@@ -52,14 +52,20 @@ async function resolveProjectId() {
|
||||
return { id: match.id, targetLanguageIds: match.targetLanguageIds || [] };
|
||||
}
|
||||
|
||||
async function resolveFileId(projectId) {
|
||||
const files = await paged(`/projects/${projectId}/files`);
|
||||
const match = files.find(
|
||||
(f) => f.name === SOURCE_FILE || f.path === `/${SOURCE_FILE}`,
|
||||
// Core is /en.json and each plugin is /plugins/<id>/locales/en.json.
|
||||
function isSourceFile(file) {
|
||||
return (
|
||||
file.path === `/${SOURCE_FILE}` ||
|
||||
/^\/plugins\/[^/]+\/locales\/en\.json$/.test(file.path || "")
|
||||
);
|
||||
if (!match)
|
||||
throw new Error(`source file "${SOURCE_FILE}" not found in project`);
|
||||
return match.id;
|
||||
}
|
||||
|
||||
async function resolveFileIds(projectId) {
|
||||
const files = await paged(`/projects/${projectId}/files`);
|
||||
const ids = files.filter(isSourceFile).map((f) => f.id);
|
||||
if (ids.length === 0)
|
||||
throw new Error(`no "${SOURCE_FILE}" source files found in project`);
|
||||
return ids;
|
||||
}
|
||||
|
||||
async function pollPreTranslation(projectId, preTranslationId) {
|
||||
@@ -84,31 +90,35 @@ async function main() {
|
||||
throw new Error("project has no target languages configured");
|
||||
}
|
||||
|
||||
const fileId = await resolveFileId(projectId);
|
||||
const fileIds = await resolveFileIds(projectId);
|
||||
|
||||
console.log(
|
||||
`Pre-translating project ${projectId}, file ${fileId}, ${targetLanguageIds.length} languages via MT engine ${ENGINE_ID}`,
|
||||
`Pre-translating project ${projectId}, ${fileIds.length} files, ${targetLanguageIds.length} languages`,
|
||||
);
|
||||
|
||||
const { data } = await request(
|
||||
"POST",
|
||||
`/projects/${projectId}/pre-translations`,
|
||||
{
|
||||
languageIds: targetLanguageIds,
|
||||
fileIds: [fileId],
|
||||
method: "mt",
|
||||
engineId: ENGINE_ID,
|
||||
scope: "untranslated",
|
||||
},
|
||||
);
|
||||
|
||||
const result = await pollPreTranslation(projectId, data.identifier);
|
||||
console.log(`Pre-translation finished (${result.progress}%)`);
|
||||
// Translation memory first so strings that moved between files keep their
|
||||
// existing translations, then machine translation for whatever is left.
|
||||
const passes = [
|
||||
{ method: "tm", translateUntranslatedOnly: true },
|
||||
{ method: "mt", engineId: ENGINE_ID, scope: "untranslated" },
|
||||
];
|
||||
for (const pass of passes) {
|
||||
const { data } = await request(
|
||||
"POST",
|
||||
`/projects/${projectId}/pre-translations`,
|
||||
{ languageIds: targetLanguageIds, fileIds, ...pass },
|
||||
);
|
||||
const result = await pollPreTranslation(projectId, data.identifier);
|
||||
console.log(
|
||||
`${pass.method} pre-translation finished (${result.progress}%)`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
resolveProjectId,
|
||||
resolveFileId,
|
||||
resolveFileIds,
|
||||
isSourceFile,
|
||||
pollPreTranslation,
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { createRequire } from "node:module";
|
||||
|
||||
const require = createRequire(import.meta.url);
|
||||
const { isSourceFile } = require("./crowdin-pretranslate.cjs") as {
|
||||
isSourceFile: (file: { path?: string }) => boolean;
|
||||
};
|
||||
|
||||
describe("isSourceFile", () => {
|
||||
it("matches the core and plugin source files", () => {
|
||||
expect(isSourceFile({ path: "/en.json" })).toBe(true);
|
||||
expect(isSourceFile({ path: "/plugins/acme-ssl/locales/en.json" })).toBe(
|
||||
true,
|
||||
);
|
||||
});
|
||||
|
||||
it("skips anything else", () => {
|
||||
expect(isSourceFile({ path: "/src/ui/locales/en.json" })).toBe(false);
|
||||
expect(isSourceFile({ path: "/plugins/a/b/locales/en.json" })).toBe(false);
|
||||
expect(isSourceFile({ path: "/plugins/acme-ssl/locales/de.json" })).toBe(
|
||||
false,
|
||||
);
|
||||
expect(isSourceFile({})).toBe(false);
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user