New json format: JSON_ANGULAR
Is your feature request related to a problem? Please describe. Modern Angular has very specific json format for translated files:
{
"locale": "ru",
"translations": {
"system.request_timeout": "Превышено время отправки запроса"
}
}
it is possible to download "almost" angular-like json with current config:
{
"$schema": "https://docs.tolgee.io/cli-schema.json",
"format": "JSON_ICU",
"push": {
"removeOtherKeys": true,
"forceMode": "OVERRIDE",
"namespaces": [
"frontend"
],
"filesTemplate": "./{namespace}.{languageTag}.json",
"languages": [
"ru"
]
},
"pull": {
"namespaces": [
"frontend"
],
"path": "./apps/frontend/src/locale",
"fileStructureTemplate": "messages.{languageTag}.{extension}",
"supportArrays": false,
"delimiter": null
}
}
which downloads in this format:
{
"locale": "ru",
"translations.system.request_timeout": "Превышено время отправки запроса"
}
then, it should be processed via hack-ish script to match Angular's format
Describe the solution you'd like Add native JSON_ANGULAR format
Describe alternatives you've considered
Script, which i use as a workaround (maybe it can help someone):
#!/usr/bin/env node
const fs = require('fs');
const path = require('path');
const { execSync } = require('child_process');
const readline = require('readline');
// Create readline interface for user input
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
// Function to prompt user for input
function prompt(question) {
return new Promise((resolve) => {
rl.question(question, (answer) => {
resolve(answer);
});
});
}
// Main function
async function main() {
try {
console.log('Checking environment variables...');
// Check for required environment variables
let projectId = process.env.PROJECT_ID;
let apiKey = process.env.API_KEY;
let apiUrl = process.env.API_URL;
// Prompt for missing variables
if (!projectId) {
projectId = await prompt('PROJECT_ID not found. Please enter PROJECT_ID: ');
}
if (!apiKey) {
apiKey = await prompt('API_KEY not found. Please enter API_KEY: ');
}
if (!apiUrl) {
apiUrl = await prompt('API_URL not found. Please enter API_URL: ');
}
console.log('Running tolgee pull command...');
// Execute tolgee pull command
const command = `npx tolgee pull --project-id=${projectId} --api-url=${apiUrl} --api-key=${apiKey}`;
execSync(command, { stdio: 'inherit' });
console.log('Tolgee pull completed successfully.');
// Read .tolgeerc.json to get the path to downloaded translations
const tolgeeConfigPath = path.resolve(process.cwd(), '.tolgeerc.json');
const tolgeeConfig = JSON.parse(fs.readFileSync(tolgeeConfigPath, 'utf8'));
if (!tolgeeConfig.pull || !tolgeeConfig.pull.path) {
throw new Error('Could not find pull.path in .tolgeerc.json');
}
const translationsPath = path.resolve(process.cwd(), tolgeeConfig.pull.path);
console.log(`Processing translation files in ${translationsPath}...`);
// Get all JSON files in the translations directory
const files = fs.readdirSync(translationsPath)
.filter(file => file.startsWith('messages.') && file.endsWith('.json'));
if (files.length === 0) {
console.log('No translation files found.');
rl.close();
return;
}
// Process each translation file
for (const file of files) {
const filePath = path.join(translationsPath, file);
console.log(`Processing ${filePath}...`);
const content = JSON.parse(fs.readFileSync(filePath, 'utf8'));
const locale = content.locale;
// Create a new object with the transformed structure
const transformedContent = {
locale: locale,
translations: {}
};
// Process each key in the original content
for (const [key, value] of Object.entries(content)) {
if (key === 'locale') continue;
// Extract the part after "translations." prefix
if (key.startsWith('translations.')) {
const newKey = key.substring('translations.'.length);
transformedContent.translations[newKey] = value;
}
}
// Write the transformed content back to the file
fs.writeFileSync(filePath, JSON.stringify(transformedContent, null, 4), 'utf8');
console.log(`Transformed ${filePath} successfully.`);
}
console.log('All translation files processed successfully.');
rl.close();
} catch (error) {
console.error('Error:', error.message);
rl.close();
process.exit(1);
}
}
// Run the main function
main();
Additional context
Hi! Thanks for the report! I'm sorry for the delay. It looks like no one has addressed your issue yet.
Our team doesn't have any Angular experts, but it would be great to have proper support for it. If anyone wants to implement this format, please feel free to do so. We will gladly accept PRs.