You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

auto-gen-i18n.js 3.8KB

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