-
Notifications
You must be signed in to change notification settings - Fork 41
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: openai translations #467
Conversation
WalkthroughWalkthroughThis update significantly enhances the application's localization support by adding user interface translations in multiple languages, including Catalan, German, Spanish, French, Hungarian, Italian, Japanese, Korean, Portuguese, Russian, and Chinese. It also integrates the OpenAI API into the translation script, streamlining the translation process for improved functionality. These changes aim to create a more inclusive and user-friendly experience for diverse demographics. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant App
participant OpenAI
User->>App: Request translation
App->>OpenAI: Send text for translation
OpenAI-->>App: Return translated text
App-->>User: Display translated text
Recent review detailsConfiguration used: CodeRabbit UI Files selected for processing (4)
Files skipped from review due to trivial changes (1)
Files skipped from review as they are similar to previous changes (2)
Additional context usedBiome
Additional comments not posted (7)
TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (invoked as PR comments)
Additionally, you can add CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 11
scripts/translate.js
Outdated
response && | ||
response.choices && |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use optional chaining for safer access.
Change to an optional chain for safer access to nested properties.
- response.choices &&
+ response?.choices &&
Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
response && | |
response.choices && | |
response?.choices && |
Tools
Biome
[error] 86-87: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
"card_header": "saldo de eCash", | ||
"sentence": "Denominado en Sats", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ensure consistency in capitalization.
The term "saldo de eCash" should be capitalized for consistency with other headers.
- "card_header": "saldo de eCash",
+ "card_header": "Saldo de eCash",
Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
"card_header": "saldo de eCash", | |
"sentence": "Denominado en Sats", | |
"card_header": "Saldo de eCash", | |
"sentence": "Denominado en Sats", |
"card_header": "saldo de eCash", | ||
"sentence": "Denominado en Sats", | ||
"your-balance": "Su saldo de eCash en esta federación:" | ||
"your-balance": "Tu saldo de eCash en esta federación:" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ensure consistency in capitalization.
The term "saldo de eCash" should be capitalized for consistency with other headers.
- "card_header": "saldo de eCash",
+ "card_header": "Saldo de eCash",
Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
"card_header": "saldo de eCash", | |
"sentence": "Denominado en Sats", | |
"your-balance": "Su saldo de eCash en esta federación:" | |
"your-balance": "Tu saldo de eCash en esta federación:" | |
"card_header": "Saldo de eCash", | |
"sentence": "Denominado en Sats", | |
"your-balance": "Tu saldo de eCash en esta federación:" |
"amount-label": "Montant (sats) :", | ||
"amount-placeholder": "Ingresa la cantidad en sats", | ||
"card-header": "Retirar Bitcoin", | ||
"close": "Закрыть", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Translation inconsistency: Close button
The translation for "close" is in Russian instead of Italian.
- "close": "Закрыть",
+ "close": "Chiudi",
Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
"close": "Закрыть", | |
"close": "Chiudi", |
@@ -0,0 +1,131 @@ | |||
{ | |||
"address-label": "Tu dirección:", | |||
"address-placeholder": "Введите ваш btc-адрес", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Translation inconsistency: Address placeholder
The placeholder text for the address is in Russian instead of Italian.
- "address-placeholder": "Введите ваш btc-адрес",
+ "address-placeholder": "Inserisci il tuo indirizzo BTC",
Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
"address-placeholder": "Введите ваш btc-адрес", | |
"address-placeholder": "Inserisci il tuo indirizzo BTC", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like this russitalian snuck through
"close": "Закрыть", | ||
"confirm-withdraw": "Confirmar Retiro", | ||
"error": "Errore", | ||
"error-address": "Die Menge oder die Adresse darf nicht leer sein", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Translation inconsistency: Error address
The translation for the error message is in German instead of Italian.
- "error-address": "Die Menge oder die Adresse darf nicht leer sein",
+ "error-address": "L'importo o l'indirizzo non possono essere vuoti",
Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
"error-address": "Die Menge oder die Adresse darf nicht leer sein", | |
"error-address": "L'importo o l'indirizzo non possono essere vuoti", |
"amount-label": "Montant (sats) :", | ||
"amount-placeholder": "Ingresa la cantidad en sats", | ||
"card-header": "Retirar Bitcoin", | ||
"close": "Закрыть", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Translation inconsistency: Close button
The translation for "close" is in Russian instead of Italian.
- "close": "Закрыть",
+ "close": "Chiudi",
Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
"close": "Закрыть", | |
"close": "Chiudi", |
"withdraw": "Retirar", | ||
"withdraw-all": "Retirar todo", | ||
"withdrawal-created": "Retiro creado.", | ||
"withdrawal-created-description": "Bitte überprüfen Sie Ihre Transaktionshistorie", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Translation inconsistency: Withdrawal created description
The translation for the withdrawal created description is in German instead of Italian.
- "withdrawal-created-description": "Bitte überprüfen Sie Ihre Transaktionshistorie",
+ "withdrawal-created-description": "Si prega di controllare la cronologia delle transazioni",
Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
"withdrawal-created-description": "Bitte überprüfen Sie Ihre Transaktionshistorie", | |
"withdrawal-created-description": "Si prega di controllare la cronologia delle transazioni", |
"connection-string-placeholder": "Colar código de convite da federação", | ||
"heading": "Conéctate a una federación usando un código de invitación", | ||
"information-bar-text": "El número de federaciones a las que puedes conectarte está limitado a una. La conexión a múltiples federaciones será compatible pronto.", | ||
"label": "Строка подключения:", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Translation inconsistency: Connection string label
The translation for the connection string label is in Russian instead of Italian.
- "label": "Строка подключения:",
+ "label": "Stringa di connessione:",
Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
"label": "Строка подключения:", | |
"label": "Stringa di connessione:", |
"close": "Закрыть", | ||
"confirm-withdraw": "Confirmar Retiro", | ||
"error": "Erro", | ||
"error-address": "Der Betrag oder die Adresse dürfen nicht leer sein", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Translation inconsistency: Error address
The translation for the error message is in German instead of Italian.
- "error-address": "Der Betrag oder die Adresse dürfen nicht leer sein",
+ "error-address": "L'importo o l'indirizzo non possono essere vuoti",
Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
"error-address": "Der Betrag oder die Adresse dürfen nicht leer sein", | |
"error-address": "L'importo o l'indirizzo non possono essere vuoti", |
package.json
Outdated
@@ -21,7 +21,8 @@ | |||
"husky": "^9.0.11", | |||
"prettier": "^2.5.1", | |||
"pretty-quick": "^3.1.3", | |||
"turbo": "^1.13.3" | |||
"turbo": "^1.13.3", | |||
"openai": "^4.1.0" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
since most folks won't need this, I think it would be better to make this an optionalDependency
. Then you can install it at runtime via:
(example is chatGPT generated)
const { execSync } = require('child_process');
function requireOrInstall(packageName) {
try {
// Try to require the package
return require(packageName);
} catch (e) {
if (e.code === 'MODULE_NOT_FOUND') {
// Package not found, install it
console.log(`${packageName} not found. Installing...`);
execSync(`npm install ${packageName}`, { stdio: 'inherit' });
// Require the package again after installation
return require(packageName);
} else {
throw e;
}
}
}
...
const { OpenAI } = requireOrInstall('openai');
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 5
const { OpenAI } = require('openai'); | ||
const openai = new OpenAI({ | ||
apiKey: process.env.OPENAI_API_KEY, | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Move OpenAI client initialization outside the try block.
The OpenAI client initialization should be moved outside the try block to ensure it is always executed, even if an error occurs later in the function.
async function translateAndFill() {
const { OpenAI } = require('openai');
const openai = new OpenAI({
apiKey: process.env.OPENAI_API_KEY,
});
try {
for (const srcPath of srcPaths) {
const srcFile = `${srcPath}/en.json`;
const srcData = JSON.parse(await fs.readFile(srcFile, 'utf8'));
Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
const { OpenAI } = require('openai'); | |
const openai = new OpenAI({ | |
apiKey: process.env.OPENAI_API_KEY, | |
}); | |
async function translateAndFill() { | |
const { OpenAI } = require('openai'); | |
const openai = new OpenAI({ | |
apiKey: process.env.OPENAI_API_KEY, | |
}); | |
try { | |
for (const srcPath of srcPaths) { | |
const srcFile = `${srcPath}/en.json`; | |
const srcData = JSON.parse(await fs.readFile(srcFile, 'utf8')); |
async function uninstallOpenAI() { | ||
console.log('Uninstalling OpenAI package...'); | ||
execSync('yarn remove openai', { stdio: 'inherit' }); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add error handling for package uninstallation.
The uninstallOpenAI
function should include error handling to manage potential issues during the package uninstallation process.
async function uninstallOpenAI() {
console.log('Uninstalling OpenAI package...');
- execSync('yarn remove openai', { stdio: 'inherit' });
+ try {
+ execSync('yarn remove openai', { stdio: 'inherit' });
+ } catch (error) {
+ console.error('Failed to uninstall OpenAI package:', error);
+ throw error;
+ }
}
Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
async function uninstallOpenAI() { | |
console.log('Uninstalling OpenAI package...'); | |
execSync('yarn remove openai', { stdio: 'inherit' }); | |
} | |
async function uninstallOpenAI() { | |
console.log('Uninstalling OpenAI package...'); | |
try { | |
execSync('yarn remove openai', { stdio: 'inherit' }); | |
} catch (error) { | |
console.error('Failed to uninstall OpenAI package:', error); | |
throw error; | |
} | |
} |
scripts/translate.js
Outdated
const prompt = `Translate the following text to ${targetLang}. Return only the translated string, without any additional text or explanations:\n\n${text}`; | ||
|
||
const response = await openai.chat.completions.create({ | ||
model: 'gpt-4o-mini', | ||
messages: [{ role: 'user', content: prompt }], | ||
temperature: 0.3, | ||
max_tokens: 150, | ||
stream: false, | ||
}); | ||
|
||
if ( | ||
response && | ||
response.choices && | ||
response.choices.length > 0 && | ||
response.choices[0].message | ||
) { | ||
return response.choices[0].message.content | ||
.trim() | ||
.replace(/^["']|["']$/g, ''); | ||
} else { | ||
throw new Error('Unexpected response format from OpenAI API'); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use optional chaining for safer access.
Change to an optional chain for safer access to nested properties.
if (
response &&
- response.choices &&
+ response?.choices &&
response.choices.length > 0 &&
response.choices[0].message
) {
return response.choices[0].message.content
.trim()
.replace(/^["']|["']$/g, '');
} else {
throw new Error('Unexpected response format from OpenAI API');
}
Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
const prompt = `Translate the following text to ${targetLang}. Return only the translated string, without any additional text or explanations:\n\n${text}`; | |
const response = await openai.chat.completions.create({ | |
model: 'gpt-4o-mini', | |
messages: [{ role: 'user', content: prompt }], | |
temperature: 0.3, | |
max_tokens: 150, | |
stream: false, | |
}); | |
if ( | |
response && | |
response.choices && | |
response.choices.length > 0 && | |
response.choices[0].message | |
) { | |
return response.choices[0].message.content | |
.trim() | |
.replace(/^["']|["']$/g, ''); | |
} else { | |
throw new Error('Unexpected response format from OpenAI API'); | |
} | |
const prompt = `Translate the following text to ${targetLang}. Return only the translated string, without any additional text or explanations:\n\n${text}`; | |
const response = await openai.chat.completions.create({ | |
model: 'gpt-4o-mini', | |
messages: [{ role: 'user', content: prompt }], | |
temperature: 0.3, | |
max_tokens: 150, | |
stream: false, | |
}); | |
if ( | |
response && | |
response?.choices && | |
response.choices.length > 0 && | |
response.choices[0].message | |
) { | |
return response.choices[0].message.content | |
.trim() | |
.replace(/^["']|["']$/g, ''); | |
} else { | |
throw new Error('Unexpected response format from OpenAI API'); | |
} |
Tools
Biome
[error] 97-98: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
async function installOpenAI() { | ||
console.log('Installing OpenAI package...'); | ||
execSync('yarn add openai', { stdio: 'inherit' }); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add error handling for package installation.
The installOpenAI
function should include error handling to manage potential issues during the package installation process.
async function installOpenAI() {
console.log('Installing OpenAI package...');
- execSync('yarn add openai', { stdio: 'inherit' });
+ try {
+ execSync('yarn add openai', { stdio: 'inherit' });
+ } catch (error) {
+ console.error('Failed to install OpenAI package:', error);
+ throw error;
+ }
}
Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
async function installOpenAI() { | |
console.log('Installing OpenAI package...'); | |
execSync('yarn add openai', { stdio: 'inherit' }); | |
} | |
async function installOpenAI() { | |
console.log('Installing OpenAI package...'); | |
try { | |
execSync('yarn add openai', { stdio: 'inherit' }); | |
} catch (error) { | |
console.error('Failed to install OpenAI package:', error); | |
throw error; | |
} | |
} |
async function fillMissingKeys(srcObj, targetObj, lang, path = '') { | ||
const updatedObj = { ...targetObj }; | ||
for (const key in srcObj) { | ||
const newPath = path ? `${path}.${key}` : key; | ||
|
||
if (typeof srcObj[key] === 'object' && srcObj[key] !== null) { | ||
targetObj[key] = targetObj[key] || {}; | ||
await fillMissingKeys( | ||
if (!updatedObj[key] || typeof updatedObj[key] !== 'object') { | ||
updatedObj[key] = {}; | ||
} | ||
updatedObj[key] = await fillMissingKeys( | ||
srcObj[key], | ||
targetObj[key], | ||
updatedObj[key], | ||
lang, | ||
newPath, | ||
targetFile | ||
newPath | ||
); | ||
} else if (targetObj[key] === undefined) { | ||
} else if (updatedObj[key] === undefined) { | ||
console.log(`Translating and adding missing key: ${newPath}`); | ||
try { | ||
const translation = await translate(srcObj[key], { to: lang }); | ||
targetObj[key] = translation.text; | ||
// Write the updated data back to the file after each translation | ||
await fs.writeFile( | ||
targetFile, | ||
JSON.stringify(targetObj, null, 2), | ||
'utf8' | ||
); | ||
// Introduce a delay between requests to avoid hitting the rate limit | ||
await delay(1000); | ||
} catch (error) { | ||
console.error(`Error translating key: ${newPath}`, error); | ||
if (error.message.includes('Too Many Requests')) { | ||
console.log('Hit rate limit, delaying further requests...'); | ||
await delay(3000); | ||
} | ||
await retryWithExponentialBackoff(async () => { | ||
const translation = await translateWithOpenAI(srcObj[key], lang); | ||
updatedObj[key] = translation; | ||
}); | ||
} else { | ||
console.log(`Skipping key: ${newPath}`); | ||
} | ||
} | ||
|
||
return updatedObj; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Optimize recursive call in fillMissingKeys
.
The recursive call to fillMissingKeys
can be optimized to avoid redundant object creation.
async function fillMissingKeys(srcObj, targetObj, lang, path = '') {
const updatedObj = { ...targetObj };
for (const key in srcObj) {
const newPath = path ? `${path}.${key}` : key;
if (typeof srcObj[key] === 'object' && srcObj[key] !== null) {
if (!updatedObj[key] || typeof updatedObj[key] !== 'object') {
updatedObj[key] = {};
}
- updatedObj[key] = await fillMissingKeys(
- srcObj[key],
- updatedObj[key],
- lang,
- newPath
- );
+ await fillMissingKeys(srcObj[key], updatedObj[key], lang, newPath);
} else if (updatedObj[key] === undefined) {
console.log(`Translating and adding missing key: ${newPath}`);
await retryWithExponentialBackoff(async () => {
const translation = await translateWithOpenAI(srcObj[key], lang);
updatedObj[key] = translation;
});
} else {
console.log(`Skipping key: ${newPath}`);
}
}
return updatedObj;
}
Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
async function fillMissingKeys(srcObj, targetObj, lang, path = '') { | |
const updatedObj = { ...targetObj }; | |
for (const key in srcObj) { | |
const newPath = path ? `${path}.${key}` : key; | |
if (typeof srcObj[key] === 'object' && srcObj[key] !== null) { | |
targetObj[key] = targetObj[key] || {}; | |
await fillMissingKeys( | |
if (!updatedObj[key] || typeof updatedObj[key] !== 'object') { | |
updatedObj[key] = {}; | |
} | |
updatedObj[key] = await fillMissingKeys( | |
srcObj[key], | |
targetObj[key], | |
updatedObj[key], | |
lang, | |
newPath, | |
targetFile | |
newPath | |
); | |
} else if (targetObj[key] === undefined) { | |
} else if (updatedObj[key] === undefined) { | |
console.log(`Translating and adding missing key: ${newPath}`); | |
try { | |
const translation = await translate(srcObj[key], { to: lang }); | |
targetObj[key] = translation.text; | |
// Write the updated data back to the file after each translation | |
await fs.writeFile( | |
targetFile, | |
JSON.stringify(targetObj, null, 2), | |
'utf8' | |
); | |
// Introduce a delay between requests to avoid hitting the rate limit | |
await delay(1000); | |
} catch (error) { | |
console.error(`Error translating key: ${newPath}`, error); | |
if (error.message.includes('Too Many Requests')) { | |
console.log('Hit rate limit, delaying further requests...'); | |
await delay(3000); | |
} | |
await retryWithExponentialBackoff(async () => { | |
const translation = await translateWithOpenAI(srcObj[key], lang); | |
updatedObj[key] = translation; | |
}); | |
} else { | |
console.log(`Skipping key: ${newPath}`); | |
} | |
} | |
return updatedObj; | |
} | |
async function fillMissingKeys(srcObj, targetObj, lang, path = '') { | |
const updatedObj = { ...targetObj }; | |
for (const key in srcObj) { | |
const newPath = path ? `${path}.${key}` : key; | |
if (typeof srcObj[key] === 'object' && srcObj[key] !== null) { | |
if (!updatedObj[key] || typeof updatedObj[key] !== 'object') { | |
updatedObj[key] = {}; | |
} | |
await fillMissingKeys(srcObj[key], updatedObj[key], lang, newPath); | |
} else if (updatedObj[key] === undefined) { | |
console.log(`Translating and adding missing key: ${newPath}`); | |
await retryWithExponentialBackoff(async () => { | |
const translation = await translateWithOpenAI(srcObj[key], lang); | |
updatedObj[key] = translation; | |
}); | |
} else { | |
console.log(`Skipping key: ${newPath}`); | |
} | |
} | |
return updatedObj; | |
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm
Used gpt-4o-mini for new translations
Summary by CodeRabbit
New Features
Bug Fixes
Chores