Skip to content

Commit 30420e6

Browse files
committed
feat(i18n): add local translation command
Add npm run translateLocal to run the existing Phoenix and Markdown viewer translation passes against http://localhost:4310/translate. Make the URL configurable through CORE_AI_TRANSLATE_URL while preserving the hosted default, and send Basic authorization only when a key is configured. Propagate translation failures through the Gulp task instead of leaving async Promise wrappers unresolved. Document local and hosted usage. Validation: syntax, ESLint, whitespace and npm task discovery pass. Isolated smoke checks cover endpoint routing, authorization, payloads, failures and both translation passes. No live translation batch or locale writes.
1 parent 3a6f742 commit 30420e6

4 files changed

Lines changed: 52 additions & 32 deletions

File tree

‎docs/02-Adding-Translations.md‎

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,25 @@ Each `src/nls/<locale>` folder contains similar files, plus a few additional one
3535
## Autogenerated and Manual translations
3636
When any string changes are made to `src/nls/root/strings.js` , it will automatically be scanned by GitHub Actions and the corresponding translations will be generated. A pull request will be raised with the new translations.
3737

38-
You can also run the translation command locally if you have the AWS/GCP keys with the command. This is mostly FYI for phoenix internal devs.
38+
Internal developers can run both the Phoenix and Markdown viewer translation passes using the
39+
hosted core.ai service. Set `CORE_AI_TRANSLATE_API_KEY`, then run:
40+
3941
```bash
4042
npm run _translateStrings
4143
```
4244

45+
To use a local translation service running at `http://localhost:4310/translate`, run:
46+
47+
```bash
48+
npm run translateLocal
49+
```
50+
51+
The local service must accept the same request/response format as the hosted service. Both commands
52+
update the existing locale files and translation metadata. `CORE_AI_TRANSLATE_API_KEY` is sent as
53+
Basic authorization when set; an unauthenticated local service does not need it. The local command
54+
works on Windows, macOS and Linux using the existing `cross-env` dependency. Other endpoints can
55+
be selected by setting `CORE_AI_TRANSLATE_URL` when running `npm run _translateStrings`.
56+
4357
### Skipping auto translate
4458
For some strings we may not want to translate them. For Example, for the keyboard shortcut string key `"KEYBOARD_CTRL": "Ctrl"`
4559
we don't want it translated to any language. Just add another key appending `_DO_NOT_TRANSLATE` to the key to disable automatic translations Eg. `"KEYBOARD_CTRL_DO_NOT_TRANSLATE": "true"` just below the original key.

‎gulpfile.js/index.js‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -430,12 +430,12 @@ function releaseProd() {
430430
});
431431
}
432432

433-
function translateStrings() {
434-
return new Promise(async (resolve)=>{ // eslint-disable-line
435-
await Translate.translate();
436-
await Translate.translateMdviewer();
437-
resolve();
438-
});
433+
/** Translate both Phoenix and Markdown viewer locales using the configured service.
434+
* @return {Promise<void>} Rejects if either translation pass fails.
435+
*/
436+
async function translateStrings() {
437+
await Translate.translate();
438+
await Translate.translateMdviewer();
439439
}
440440

441441
function _listFilesInDir(dir) {

‎gulpfile.js/translateStrings.js‎

Lines changed: 30 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
const fs = require('fs');
2323
const path = require('path');
2424
const CORE_AI_TRANSLATE_API_KEY = process.env.CORE_AI_TRANSLATE_API_KEY;
25+
const CORE_AI_TRANSLATE_URL = process.env.CORE_AI_TRANSLATE_URL || "https://translate.core.ai/translate";
2526

2627
// A global accumulator object initialized to zero
2728
const globalUtilizationMetrics = {
@@ -102,20 +103,20 @@ function getTranslationrequest(stringsToTranslate, lang) {
102103
}
103104

104105
/**
105-
* Sends translation payload to the specified API and returns the result.
106+
* Send the translation payload to the configured service, with credentials when supplied.
106107
*
107108
* @param {object} apiInput - The translation payload object.
108109
* @returns {Promise<any>} The JSON-parsed response from the API.
109110
*/
110111
async function getTranslation(apiInput) {
111-
const url = "https://translate.core.ai/translate";
112+
const headers = { "Content-Type": "application/json" };
113+
if (CORE_AI_TRANSLATE_API_KEY) {
114+
headers.authorization = `Basic ${CORE_AI_TRANSLATE_API_KEY}`;
115+
}
112116
try {
113-
const response = await fetch(url, {
117+
const response = await fetch(CORE_AI_TRANSLATE_URL, {
114118
method: "POST",
115-
headers: {
116-
"Content-Type": "application/json",
117-
"authorization": `Basic ${CORE_AI_TRANSLATE_API_KEY}`
118-
},
119+
headers: headers,
119120
body: JSON.stringify(apiInput)
120121
});
121122

@@ -378,23 +379,23 @@ async function _processLang(lang, config) {
378379

379380
// ---- Phoenix NLS translation ----
380381

382+
/** Translate Phoenix locales through the configured service, propagating request failures to Gulp.
383+
* @return {Promise<void>} Resolves when all Phoenix locales have been processed.
384+
*/
381385
async function translate() {
382-
console.log("please make sure that core.ai lang translation service credentials are available as env vars.");
383-
return new Promise(async (resolve)=>{
384-
const nlsDir = 'src/nls';
385-
let langs = _getAllNLSFolders(nlsDir);
386-
console.log(langs);
387-
const config = {
388-
nlsDir,
389-
sourceStrings: rootStrings,
390-
format: 'js',
391-
errorsFile: 'src/nls/errors.txt'
392-
};
393-
for(let lang of langs){
394-
await _processLang(lang, config);
395-
}
396-
resolve();
397-
});
386+
console.log("Using translation service:", CORE_AI_TRANSLATE_URL);
387+
const nlsDir = 'src/nls';
388+
const langs = _getAllNLSFolders(nlsDir);
389+
console.log(langs);
390+
const config = {
391+
nlsDir,
392+
sourceStrings: rootStrings,
393+
format: 'js',
394+
errorsFile: 'src/nls/errors.txt'
395+
};
396+
for (const lang of langs) {
397+
await _processLang(lang, config);
398+
}
398399
}
399400

400401
// ---- mdviewer translation ----
@@ -476,9 +477,13 @@ async function translateMdviewer() {
476477
// Copy translated flat JSON → nested locale files for mdviewer runtime
477478
console.log("[mdviewer] Copying translations to locales folder...");
478479
for (let lang of langs) {
479-
if (lang === 'root') continue;
480+
if (lang === 'root') {
481+
continue;
482+
}
480483
const flatStrings = _getJson(path.join(mdNlsDir, lang, 'strings.json'));
481-
if (!Object.keys(flatStrings).length) continue;
484+
if (!Object.keys(flatStrings).length) {
485+
continue;
486+
}
482487
const nested = _unflattenObject(flatStrings);
483488
fs.writeFileSync(
484489
path.join(localesDir, `${lang}.json`),

‎package.json‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@
8484
"serveExternal": "npm install --prefix src-node && node serve-proxy.js . -p 8000 -a 0.0.0.0 --log-ip -c-1",
8585
"createJSDocs": "node build/api-docs-generator.js && git add docs",
8686
"_translateStrings": "gulp translateStrings",
87+
"translateLocal": "cross-env CORE_AI_TRANSLATE_URL=http://localhost:4310/translate gulp translateStrings",
8788
"_minify": "r.js -o require.min.config.js && echo this is untested see https://stackoverflow.com/questions/14337970/minifying-requirejs-javascript-codebase-to-a-single-file"
8889
},
8990
"licenses": [

0 commit comments

Comments
 (0)