Skip to content

Commit

Permalink
feat(i18n): add i18n-import
Browse files Browse the repository at this point in the history
  • Loading branch information
zyf722 committed Jun 27, 2024
1 parent e66fd1d commit 83a040a
Show file tree
Hide file tree
Showing 7 changed files with 2,315 additions and 12 deletions.
6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,9 @@
"prepush": "run-s fix build test",
"start-release": "node ./scripts/start-release.mjs",
"vscode-intellisense": "node ./scripts/vscode-intellisense.js",
"i18n-export": "node ./scripts/i18n-export.js"
"i18n-export": "node ./scripts/i18n-export.js",
"i18n-update-push": "node ./scripts/i18n-upload.mjs",
"i18n-update-pull": "node ./scripts/i18n-import.mjs"
},
"dependencies": {
"@codemirror/autocomplete": "6.3.0",
Expand Down Expand Up @@ -197,4 +199,4 @@
"lcov"
]
}
}
}
2 changes: 1 addition & 1 deletion scripts/i18n-export.js
Original file line number Diff line number Diff line change
Expand Up @@ -379,7 +379,7 @@ const generateTranslation = async () => {
}
};

module.exports = { generateTranslation };
module.exports = { generateTranslation, sortedJSONify, prettierConfig };

if (require.main === module) {
generateTranslation();
Expand Down
114 changes: 114 additions & 0 deletions scripts/i18n-import.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import { LokaliseApi } from '@lokalise/node-api';
import path from 'path';
import fs from 'fs';
import { execSync } from 'child_process';
import { sortedJSONify, prettierConfig } from './i18n-export.js';
import prettier from 'prettier';

const outDir = path.resolve('src/livecodes/i18n/locales');
const api = new LokaliseApi({ apiKey: process.env.LOKALISE_API_TOKEN });
const projectID = process.env.LOKALISE_PROJECT_ID;

/**
* Expand the flattened translation object (KV pairs) to a nested object.
* @param {string} source Path to the source file.
* @returns object
*/
const generateTranslationObject = (source) => {
const translations = JSON.parse(fs.readFileSync(source, 'utf-8'));
const translationObject = {};
for (const key in translations) {
const keys = key.split('.');
const lastKey = keys.pop();
let currentObject = translationObject;
keys.forEach((k) => {
if (!currentObject[k]) {
currentObject[k] = {};
}
currentObject = currentObject[k];
});
currentObject[lastKey] = translations[key];
}
return translationObject;
};

const importFromLokalise = async () => {
const branchName = process.argv[2];

console.log('Fetching translations from Lokalise...');

// Make a tmp directory to store the downloaded files
const tmpDir = path.resolve('tmp');
fs.mkdirSync(tmpDir, { recursive: true });

const response = await api.files().download(`${projectID}:${branchName}`, {
format: 'json',
original_filenames: true,
});
console.log(`Downloading zip file from ${response.bundle_url}`);

const zipPath = path.join(tmpDir, 'locales.zip');
const zipFile = await fetch(response.bundle_url);
fs.writeFileSync(zipPath, Buffer.from(await zipFile.arrayBuffer()));

console.log(`Extracting zip file to ${tmpDir}...`);
execSync(`unzip -o ${zipPath} -d ${tmpDir}`);
fs.unlinkSync(zipPath);

fs.readdir(tmpDir, (err, languages) => {
if (err) {
console.error(err);
return;
}

console.log(
`Extracted languages to tmp directory, ${languages.length} languages (including English) found.`,
);

languages.forEach((language) => {
const languagePath = path.join(tmpDir, language);
if (!fs.statSync(languagePath).isDirectory() || language === 'en') {
return;
}

fs.readdir(languagePath, (err, files) => {
if (err) {
console.error(err);
return;
}

language = language.replace('_', '-');
const outLanguagePath = path.join(outDir, language);
console.log(`Importing language ${language}...`);

fs.mkdirSync(outLanguagePath, { recursive: true });

files.forEach(async (file) => {
const source = path.join(languagePath, file);
const target = path.join(outLanguagePath, file.replace('.lokalise.json', '.ts'));

const namespace = file.split('.')[0];
const name = namespace === 'translation' ? 'translation' : 'languageInfo';
const type = namespace === 'translation' ? 'I18nTranslation' : 'I18nLangInfoTranslation';

const translationObject = generateTranslationObject(source);
const code = `import type { ${type} } from '../models';
const ${name}: ${type} = ${sortedJSONify(translationObject)};
export default ${name};
`;

const translationContent = await prettier.format(code, {
parser: 'typescript',
...prettierConfig,
});

fs.writeFileSync(target, translationContent);
});
});
});
});
};

importFromLokalise();
Loading

0 comments on commit 83a040a

Please sign in to comment.