auto-gen-i18n.js 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. /* eslint-disable no-eval */
  2. const fs = require('node:fs')
  3. const path = require('node:path')
  4. const transpile = require('typescript').transpile
  5. const magicast = require('magicast')
  6. const { parseModule, generateCode, loadFile } = magicast
  7. const bingTranslate = require('bing-translate-api')
  8. const { translate } = bingTranslate
  9. const data = require('./languages.json')
  10. const targetLanguage = 'en-US'
  11. // https://github.com/plainheart/bing-translate-api/blob/master/src/met/lang.json
  12. const languageKeyMap = data.languages.reduce((map, language) => {
  13. if (language.supported) {
  14. if (language.value === 'zh-Hans' || language.value === 'zh-Hant')
  15. map[language.value] = language.value
  16. else
  17. map[language.value] = language.value.split('-')[0]
  18. }
  19. return map
  20. }, {})
  21. async function translateMissingKeyDeeply(sourceObj, targetObject, toLanguage) {
  22. await Promise.all(Object.keys(sourceObj).map(async (key) => {
  23. if (targetObject[key] === undefined) {
  24. if (typeof sourceObj[key] === 'object') {
  25. targetObject[key] = {}
  26. await translateMissingKeyDeeply(sourceObj[key], targetObject[key], toLanguage)
  27. }
  28. else {
  29. try {
  30. if (!sourceObj[key]) {
  31. targetObject[key] = ''
  32. return
  33. }
  34. const { translation } = await translate(sourceObj[key], null, languageKeyMap[toLanguage])
  35. targetObject[key] = translation
  36. }
  37. catch (e) {
  38. console.error(`Error translating ${sourceObj[key]}(${key}) to ${toLanguage}`)
  39. }
  40. }
  41. }
  42. else if (typeof sourceObj[key] === 'object') {
  43. targetObject[key] = targetObject[key] || {}
  44. await translateMissingKeyDeeply(sourceObj[key], targetObject[key], toLanguage)
  45. }
  46. }))
  47. }
  48. async function autoGenTrans(fileName, toGenLanguage) {
  49. const fullKeyFilePath = path.join(__dirname, targetLanguage, `${fileName}.ts`)
  50. const toGenLanguageFilePath = path.join(__dirname, toGenLanguage, `${fileName}.ts`)
  51. const fullKeyContent = eval(transpile(fs.readFileSync(fullKeyFilePath, 'utf8')))
  52. // To keep object format and format it for magicast to work: const translation = { ... } => export default {...}
  53. const readContent = await loadFile(toGenLanguageFilePath)
  54. const { code: toGenContent } = generateCode(readContent)
  55. const mod = await parseModule(`export default ${toGenContent.replace('export default translation', '').replace('const translation = ', '')}`)
  56. const toGenOutPut = mod.exports.default
  57. await translateMissingKeyDeeply(fullKeyContent, toGenOutPut, toGenLanguage)
  58. const { code } = generateCode(mod)
  59. const res = `const translation =${code.replace('export default', '')}
  60. export default translation
  61. `.replace(/,\n\n/g, ',\n').replace('};', '}')
  62. fs.writeFileSync(toGenLanguageFilePath, res)
  63. }
  64. async function main() {
  65. // const fileName = 'workflow'
  66. // Promise.all(Object.keys(languageKeyMap).map(async (toLanguage) => {
  67. // await autoGenTrans(fileName, toLanguage)
  68. // }))
  69. const files = fs
  70. .readdirSync(path.join(__dirname, targetLanguage))
  71. .map(file => file.replace(/\.ts/, ''))
  72. .filter(f => f !== 'app-debug') // ast parse error in app-debug
  73. await Promise.all(files.map(async (file) => {
  74. await Promise.all(Object.keys(languageKeyMap).map(async (language) => {
  75. await autoGenTrans(file, language)
  76. }))
  77. }))
  78. }
  79. main()