diff --git a/shared-helpers/package.json b/shared-helpers/package.json index f19dd8c701..79d3165ffa 100644 --- a/shared-helpers/package.json +++ b/shared-helpers/package.json @@ -38,6 +38,7 @@ "@types/react-transition-group": "^4.4.12", "@google-cloud/translate": "^9.2.0", "csv-parse": "^5.5.5", + "dotenv": "^17.2.3", "identity-obj-proxy": "^3.0.0", "jest": "^26.5.3", "next": "^15.5.7", diff --git a/shared-helpers/src/scripts/.env.template b/shared-helpers/src/scripts/.env.template new file mode 100644 index 0000000000..fb7edac6ef --- /dev/null +++ b/shared-helpers/src/scripts/.env.template @@ -0,0 +1,6 @@ +# google translate api email +GOOGLE_API_EMAIL= +# google translate api id +GOOGLE_API_ID= +# google translate api key +GOOGLE_API_KEY= \ No newline at end of file diff --git a/shared-helpers/src/scripts/get-machine-translations.ts b/shared-helpers/src/scripts/get-machine-translations.ts index 91b83f6236..fc311926bf 100644 --- a/shared-helpers/src/scripts/get-machine-translations.ts +++ b/shared-helpers/src/scripts/get-machine-translations.ts @@ -1,17 +1,13 @@ /* eslint-disable @typescript-eslint/no-var-requires, import/no-unresolved */ - -// Takes in a CSV file with two columns (t_key,t_value) with the key being the translation file key and the value being the associated English string, and prints out in the JSON translation file format the "key": "translated string" -// CSV format: -// t_key,t_value -// "key.here","Translation here" -// -// example from within this directory, first argument is one of LanguagesEnum and second argument is the formatted CSV filename with keys and english strings, piped to a new file: `ts-node get-machine-translations es english-keys.csv > any-filename-here.json` -import fs from "node:fs" -import { parse } from "csv-parse/sync" - +// Finds missing translations and automatically translates them using Google Translate API +// Prints out translations in the JSON translation file format: "key": "translated string" +// You will need to add the environment variables for Google Translate API access from the api env file into this env file +// Example: `ts-node get-machine-translations.ts > any-filename-here.json` import { Translate } from "@google-cloud/translate/build/src/v2" +import dotenv from "dotenv" +dotenv.config({ quiet: true }) -async function main(argv: string[]) { +async function main() { enum LanguagesEnum { "en" = "en", "es" = "es", @@ -22,9 +18,9 @@ async function main(argv: string[]) { "bn" = "bn", } - const GOOGLE_API_EMAIL = "SECRET_VALUE" - const GOOGLE_API_ID = "SECRET_VALUE" - const GOOGLE_API_KEY = "SECRET_VALUE" + const GOOGLE_API_EMAIL = process.env.GOOGLE_API_EMAIL || `` + const GOOGLE_API_ID = process.env.GOOGLE_API_ID || `` + const GOOGLE_API_KEY = process.env.GOOGLE_API_KEY || `` const makeTranslateService = () => { return new Translate({ @@ -40,26 +36,77 @@ async function main(argv: string[]) { return await makeTranslateService().translate(values, { from: LanguagesEnum.en, to: language, + format: "html", + }) + } + + type TranslationsType = { + [key: string]: string + } + + const findMissingStrings = ( + baseTranslations: TranslationsType, + checkedTranslations: TranslationsType + ) => { + const baseKeys = Object.keys(baseTranslations) + const checkedKeys = Object.keys(checkedTranslations) + const missingKeys: string[] = [] + baseKeys.forEach((key) => { + if (checkedKeys.indexOf(key) < 0) { + missingKeys.push(key) + } }) + return missingKeys } - const [language, englishStringsCsv] = argv.slice(2) + // Load translations + const englishTranslations = require("../locales/general.json") + const spanishTranslations = require("../locales/es.json") + const chineseTranslations = require("../locales/zh.json") + const vietnameseTranslations = require("../locales/vi.json") + const tagalogTranslations = require("../locales/tl.json") + const arabicTranslations = require("../locales/ar.json") + const bengaliTranslations = require("../locales/bn.json") + + const allTranslations = [ + { translationKeys: spanishTranslations, language: "Spanish", code: LanguagesEnum.es }, + { translationKeys: chineseTranslations, language: "Chinese", code: LanguagesEnum.zh }, + { translationKeys: vietnameseTranslations, language: "Vietnamese", code: LanguagesEnum.vi }, + { translationKeys: tagalogTranslations, language: "Tagalog", code: LanguagesEnum.tl }, + { translationKeys: arabicTranslations, language: "Arabic", code: LanguagesEnum.ar }, + { translationKeys: bengaliTranslations, language: "Bengali", code: LanguagesEnum.bn }, + ] + + console.log( + "Note that Google Translate does not preserve markdown well, and you may need to adjust some translations manually to add back in new lines and other missing formatting if there is any markdown.\n" + ) + console.log( + "You can paste these lines directly into each translation file, and then be sure to sort ascending! In VSCode, you can Command + Shift + P --> Sort Ascending.\n" + ) - const csvFile = fs.readFileSync(englishStringsCsv) + // Process each language + for (const foreignTranslations of allTranslations) { + console.log("\n--------------------") + console.log(`${foreignTranslations.language} Missing Translations:`) + console.log("--------------------") - const csvData = parse(csvFile, { - columns: true, - skip_empty_lines: true, - }) + const missingKeys = findMissingStrings(englishTranslations, foreignTranslations.translationKeys) - for (const row of csvData) { - const tKey = row["t_key"].trim() - const tValue = row["t_value"].trim() - const translatedValue = await fetch([tValue], language as LanguagesEnum) - console.log(`"${tKey}": "${translatedValue[0][0]}",`) + if (missingKeys.length === 0) { + console.log(`No missing translations for ${foreignTranslations.language}`) + continue + } + + const englishStrings = missingKeys.map((key) => englishTranslations[key]) + const translatedValues = await fetch(englishStrings, foreignTranslations.code) + + missingKeys.forEach((key, index) => { + const translatedString = translatedValues[0][index] + console.log(`"${key}": "${translatedString}",`) + }) } } -void main(process.argv) +void main() export {}