#!/bin/python3 import re from typing import List, Tuple OUTPUT_FILE = "./ts/localization/locales.ts" def wrapValue(value): """ Wraps the given value in single quotes if it contains any characters other than letters, digits, or underscores. Args: value (str): The value to be wrapped. Returns: str: The wrapped value if it contains any special characters, otherwise the original value. """ if re.search(r"[^a-zA-Z0-9_]", value): return f"'{value}'" return value def parseValue(value): """ Parses the given value by replacing single quotes with escaped single quotes. Args: value (str): The value to be parsed. Returns: str: The parsed value with escaped single quotes. """ return value.replace("'", "\\'") def generate_js_object(data): """ Generate a JavaScript object from a dictionary. Args: data (dict): The dictionary containing key-value pairs. Returns: str: A string representation of the JavaScript object. """ js_object = "{\n" for key, value in data.items(): js_object += f" {wrapValue(key)}: '{parseValue(value)}',\n" js_object += "}" return js_object def extract_vars(text): # Use a regular expression to find all strings inside curly braces vars = re.findall(r'\{(.*?)\}', text) return vars def extract_plurals(text: str) -> List[Tuple[str, str]]: pattern = r'(\b\w+\b)\s*(\[[^\]]+\])' matches = re.findall(pattern, text) return matches def vars_to_record(vars): arr = [] for var in vars: to_append = '"' + var + '": ' + ('number' if var == 'count' else 'string') if to_append not in arr: arr.append(to_append) # print(arr) if not arr: return '' return "{" + ', '.join(arr) + "}" def replace_static_strings(str): # todo make those come from the glossary replaced = str.replace("{app_name}", "Session")\ .replace("{session_download_url}", "https://getsession.org/download")\ .replace("{session_download_url}", "GIF")\ .replace("{oxen_foundation}", "Oxen Foundation")\ .replace("\"", "\\\"") return replaced def generate_type_object(locales): """ Generate a JavaScript type from a dictionary. Args: data (dict): The dictionary containing key-value pairs. Returns: str: A string representation of the JavaScript object. """ js_object = "{\n" for key, value_en in locales['en'].items(): # print('value',value) if value_en.startswith("{count, plural, "): continue # plurals = extract_plurals(value) # print(plurals) # js_plural_object = "{\n" # for plural in plurals: # plural_token = plural[0] # plural_str = plural[1].replace('#', '{count}') # extracted_vars = extract_vars(replace_static_strings(plural_str)) # if('count' not in extracted_vars): # extracted_vars.append('count') # print('extracted_vars',extracted_vars) # as_record_type = vars_to_record(extracted_vars) # js_plural_object += f" {wrapValue(plural_token)}: {as_record_type},\n" # js_plural_object += " }" # js_object += f" {wrapValue(key)}: {js_plural_object},\n" else: replaced_en = replace_static_strings(value_en) extracted_vars = extract_vars(replaced_en) as_record_type = vars_to_record(extracted_vars) other_locales_replaced_values = [[locale, replace_static_strings(data.get(key, ""))] for locale, data in locales.items()] filtered_values = [] # filter out strings that matches the english one (i.e. untranslated strings) for locale, replaced_val in other_locales_replaced_values: if replaced_val == replaced_en and not locale == 'en': # print(f"{locale}: ${key} saved content is the same as english saved.") filtered_values.append(f"{locale}: undefined") else: filtered_values.append(f"{locale}: \"{replaced_val}\"") # print('key',key, " other_locales_replaced_values:", other_locales_replaced_values) js_object += f" {wrapValue(key)}:{{\n {",\n ".join(filtered_values)},\n args: {as_record_type if as_record_type else 'undefined'}\n }},\n" js_object += "}" return js_object DISCLAIMER = """ // This file was generated by a script. Do not modify this file manually. // To make changes, modify the corresponding JSON file and re-run the script. """ def generateLocalesType(locale, data): """ Generate the locales type and write it to a file. Args: locale: The locale dictionary containing the localization data. """ # write the locale_dict to a file with open(OUTPUT_FILE, "w", encoding='utf-8') as ts_file: ts_file.write( f"{DISCLAIMER}" ) ts_file.write( f"export const {locale} = {generate_js_object(data)} as const;\n" ) ts_file.write( f"\nexport type Dictionary = typeof en;\n" ) return f"Locales generated at: {OUTPUT_FILE}" def generateLocalesMergedType(locales): """ Generate the locales type and write it to a file. Args: locale: The locale dictionary containing the localization data. """ # write the locale_dict to a file with open(OUTPUT_FILE, "w", encoding='utf-8') as ts_file: ts_file.write( f"{DISCLAIMER}" ) ts_file.write( f"export const plop = {generate_type_object(locales)};\n" ) return f"Locales generated at: {OUTPUT_FILE}"