From 38960f42192e1ea94f4364b2dc8dbe833b9ad40f Mon Sep 17 00:00:00 2001 From: Anand Baburajan Date: Mon, 19 Jun 2023 18:19:07 +0530 Subject: [PATCH] feat: migrate translations command (#21362) * feat: migrate translations command * chore: formatting --- frappe/commands/translate.py | 18 ++++++++++++++ frappe/translate.py | 47 ++++++++++++++++++++++++++++++++++-- 2 files changed, 63 insertions(+), 2 deletions(-) diff --git a/frappe/commands/translate.py b/frappe/commands/translate.py index 69970d8d97..5042843405 100644 --- a/frappe/commands/translate.py +++ b/frappe/commands/translate.py @@ -102,10 +102,28 @@ def import_translations(context, lang, path): frappe.destroy() +@click.command("migrate-translations") +@click.argument("source-app") +@click.argument("target-app") +@pass_context +def migrate_translations(context, source_app, target_app): + "Migrate target-app-specific translations from source-app to target-app" + import frappe.translate + + site = get_site(context) + try: + frappe.init(site=site) + frappe.connect() + frappe.translate.migrate_translations(source_app, target_app) + finally: + frappe.destroy() + + commands = [ build_message_files, get_untranslated, import_translations, new_language, update_translations, + migrate_translations, ] diff --git a/frappe/translate.py b/frappe/translate.py index f35a4b7ec3..7ad5ac80f8 100644 --- a/frappe/translate.py +++ b/frappe/translate.py @@ -15,7 +15,7 @@ import operator import os import re from contextlib import contextmanager -from csv import reader +from csv import reader, writer from babel.messages.extract import extract_python from babel.messages.jslexer import Token, tokenize, unquote_string @@ -997,7 +997,6 @@ def write_csv_file(path, app_messages, lang_dict): :param lang_dict: Full translated dict. """ app_messages.sort(key=lambda x: x[1]) - from csv import writer with open(path, "w", newline="") as msgfile: w = writer(msgfile, lineterminator="\n") @@ -1118,6 +1117,50 @@ def import_translations(lang, path): write_translations_file(app, lang, full_dict) +def migrate_translations(source_app, target_app): + """Migrate target-app-specific translations from source-app to target-app""" + clear_cache() + strings_in_source_app = [m[1] for m in frappe.translate.get_messages_for_app(source_app)] + strings_in_target_app = [m[1] for m in frappe.translate.get_messages_for_app(target_app)] + + strings_in_target_app_but_not_in_source_app = list( + set(strings_in_target_app) - set(strings_in_source_app) + ) + + languages = frappe.translate.get_all_languages() + + source_app_translations_dir = os.path.join(frappe.get_pymodule_path(source_app), "translations") + target_app_translations_dir = os.path.join(frappe.get_pymodule_path(target_app), "translations") + + if not os.path.exists(target_app_translations_dir): + os.makedirs(target_app_translations_dir) + + for lang in languages: + source_csv = os.path.join(source_app_translations_dir, lang + ".csv") + + if not os.path.exists(source_csv): + continue + + target_csv = os.path.join(target_app_translations_dir, lang + ".csv") + temp_csv = os.path.join(source_app_translations_dir, "_temp.csv") + + with open(source_csv) as s, open(target_csv, "a+") as t, open(temp_csv, "a+") as temp: + source_reader = reader(s, lineterminator="\n") + target_writer = writer(t, lineterminator="\n") + temp_writer = writer(temp, lineterminator="\n") + + for row in source_reader: + if row[0] in strings_in_target_app_but_not_in_source_app: + target_writer.writerow(row) + else: + temp_writer.writerow(row) + + if not os.path.getsize(target_csv): + os.remove(target_csv) + os.remove(source_csv) + os.rename(temp_csv, source_csv) + + def rebuild_all_translation_files(): """Rebuild all translation files: `[app]/translations/[lang].csv`.""" for lang in get_all_languages():