2020
2121/* eslint-env node */
2222const fs = require ( 'fs' ) ;
23- const projectId = process . env . GCP_PROJECT_ID ;
24- const API_KEY = process . env . GCP_API_KEY ;
23+ const CORE_AI_TRANSLATE_API_KEY = process . env . CORE_AI_TRANSLATE_API_KEY ;
24+
25+ // A global accumulator object initialized to zero
26+ const globalUtilizationMetrics = {
27+ tokens : {
28+ prompt : 0 ,
29+ candidates : 0 ,
30+ cachedContent : 0 ,
31+ total : 0
32+ } ,
33+ characters : {
34+ input : 0 ,
35+ output : 0
36+ } ,
37+ costs : {
38+ input : 0 ,
39+ output : 0 ,
40+ total : 0 ,
41+ currency : "USD" // or set once, if you always expect the same currency
42+ }
43+ } ;
44+
45+ /**
46+ * Aggregate the utilization metrics from a single object into a global accumulator.
47+ * @param {object } obj - An object with `utilizationMetrics` (tokens, characters, costs).
48+ * @returns {object } The updated global utilization metrics.
49+ */
50+ function aggregateUtilizationMetrics ( obj ) {
51+ if ( ! obj || ! obj . utilizationMetrics ) {
52+ console . warn ( "Object missing 'utilizationMetrics' field, nothing to aggregate." ) ;
53+ return globalUtilizationMetrics ;
54+ }
55+
56+ const { tokens, characters, costs } = obj . utilizationMetrics ;
57+
58+ // Safely add tokens
59+ if ( tokens ) {
60+ globalUtilizationMetrics . tokens . prompt += tokens . prompt || 0 ;
61+ globalUtilizationMetrics . tokens . candidates += tokens . candidates || 0 ;
62+ globalUtilizationMetrics . tokens . cachedContent += tokens . cachedContent || 0 ;
63+ globalUtilizationMetrics . tokens . total += tokens . total || 0 ;
64+ }
65+
66+ // Safely add characters
67+ if ( characters ) {
68+ globalUtilizationMetrics . characters . input += characters . input || 0 ;
69+ globalUtilizationMetrics . characters . output += characters . output || 0 ;
70+ }
71+
72+ // Safely add costs
73+ if ( costs ) {
74+ globalUtilizationMetrics . costs . input += costs . input || 0 ;
75+ globalUtilizationMetrics . costs . output += costs . output || 0 ;
76+ globalUtilizationMetrics . costs . total += costs . total || 0 ;
77+ // currency is assumed to remain consistent; you could also check or update it if needed
78+ }
79+
80+ return globalUtilizationMetrics ;
81+ }
82+
83+ function getTranslationrequest ( stringsToTranslate , lang ) {
84+ return {
85+ translationContext : "This is a bunch of strings extracted from a JavaScript file used to develop our product with is a text editor. Some strings may have HTML or templates(mustache library used). Please translate these strings accurately." ,
86+ "source" : stringsToTranslate ,
87+ "provider" : "vertex" ,
88+ "sourceContext" : {
89+ // this is currently unused. you can provide context specific to the key in the source to give the AI
90+ // additional context about the key for translation.
91+ } ,
92+ translationTargets : [ lang ] // multiple langs can be given here to translate at a time, for now using only one
93+ } ;
94+ }
95+
96+ /**
97+ * Sends translation payload to the specified API and returns the result.
98+ *
99+ * @param {object } apiInput - The translation payload object.
100+ * @returns {Promise<any> } The JSON-parsed response from the API.
101+ */
102+ async function getTranslation ( apiInput ) {
103+ const url = "https://translate.core.ai/translate" ;
104+ try {
105+ const response = await fetch ( url , {
106+ method : "POST" ,
107+ headers : {
108+ "Content-Type" : "application/json" ,
109+ "authorization" : `Basic ${ CORE_AI_TRANSLATE_API_KEY } `
110+ } ,
111+ body : JSON . stringify ( apiInput )
112+ } ) ;
113+
114+ if ( ! response . ok ) {
115+ throw new Error ( `Request failed with status ${ response . status } ` ) ;
116+ }
117+
118+ // Parse and return the JSON response
119+ const data = await response . json ( ) ;
120+ return data ;
121+ } catch ( error ) {
122+ console . error ( "Error translating:" , error ) ;
123+ throw error ;
124+ }
125+ }
25126
26127function _getAllNLSFolders ( ) {
27128 let names = fs . readdirSync ( 'src/nls' ) ;
@@ -84,8 +185,11 @@ function _isTranslatableKey(key) {
84185}
85186
86187async function coreAiTranslate ( stringsToTranslate , lang ) {
87- const translations = _getJson ( "/home/home/Downloads/full_transalation_phoenix.json" , 'utf8' ) ;
88- // console.log("Translation output: ", JSON.stringify(translations, null, 4)); todo uncomment
188+ const translationRequest = getTranslationrequest ( stringsToTranslate , lang ) ;
189+ const translations = await getTranslation ( translationRequest ) ;
190+ aggregateUtilizationMetrics ( translations ) ;
191+ console . log ( "Translation output: " , JSON . stringify ( translations , null , 4 ) ) ;
192+ console . log ( "Aggregate utilization metrics: " , JSON . stringify ( globalUtilizationMetrics , null , 4 ) ) ;
89193 if ( translations . failedLanguages . length ) {
90194 const errorStr = `Error translating ${ lang } . it has failures ` ;
91195 console . error ( errorStr ) ;
@@ -147,7 +251,14 @@ async function _processLang(lang) {
147251 // we have already translated this in the last pass.
148252 // Load expert translation if there is one else we don't need to translate, use existing translation as is.
149253 translations [ rootKey ] = expertTranslations [ englishStringToTranslate ] || localeStringsJS [ rootKey ] ;
150- updatedLastTranslatedJSON [ rootKey ] = englishStringToTranslate ;
254+ if ( translations [ rootKey ] ) {
255+ updatedLastTranslatedJSON [ rootKey ] = englishStringToTranslate ;
256+ } else {
257+ // we dont have a last local translation in locale strings.js file to use. this cannot happen
258+ // except in a translation reset pass where we delete all translations and restart like when we moved
259+ // to core.ai auto translate.
260+ pendingTranslate [ rootKey ] = englishStringToTranslate ;
261+ }
151262 } else {
152263 // this is a new english string or there is a string change.
153264 if ( expertTranslations [ englishStringToTranslate ] ) {
@@ -173,11 +284,13 @@ async function _processLang(lang) {
173284 }
174285 let englishStringToTranslate = rootStrings [ rootKey ] ;
175286 const translatedText = aiTranslations [ rootKey ] ;
176- translations [ rootKey ] = translatedText ;
177- updatedLastTranslatedJSON [ rootKey ] = englishStringToTranslate ;
287+ if ( translatedText ) {
288+ translations [ rootKey ] = translatedText ;
289+ updatedLastTranslatedJSON [ rootKey ] = englishStringToTranslate ;
290+ }
178291 }
179292 // now detect any keys that has not yet been translated
180- const allKeys = Object . keys ( rootStrings ) ;
293+ const allKeys = Object . keys ( rootStrings ) . filter ( _isTranslatableKey ) ;
181294 const translatedKeys = Object . keys ( translations ) ;
182295 const notTranslated = allKeys . filter ( key => ! translatedKeys . includes ( key ) ) ;
183296 if ( notTranslated . length ) {
@@ -193,12 +306,12 @@ async function _processLang(lang) {
193306}
194307
195308async function translate ( ) {
196- console . log ( "please make sure that AWS/Google credentials are available as env vars." ) ;
309+ console . log ( "please make sure that core.ai lang translation service credentials are available as env vars." ) ;
197310 return new Promise ( async ( resolve ) => {
198311 let langs = _getAllNLSFolders ( ) ;
199312 console . log ( langs ) ;
200313 for ( let lang of langs ) {
201- _processLang ( lang ) ;
314+ await _processLang ( lang ) ;
202315 }
203316 resolve ( ) ;
204317 } ) ;
0 commit comments