You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
231 lines
7.2 KiB
Python
231 lines
7.2 KiB
Python
#!/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 escape_new_lines(value):
|
|
"""
|
|
Escapes new lines, from "\n" to "\\n".
|
|
"""
|
|
return value.replace("\n", "\\n")
|
|
|
|
|
|
def extract_vars(text):
|
|
# Use a regular expression to find all strings inside curly braces
|
|
vars = re.findall(r'\{(.*?)\}', text)
|
|
return vars
|
|
|
|
|
|
def vars_to_record(vars):
|
|
arr = []
|
|
for var in vars:
|
|
to_append = '' + var + ': ' + ('"number"' if var == 'count' or var == 'found_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 args_to_type(args):
|
|
return args if args else 'undefined,'
|
|
|
|
|
|
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"
|
|
js_plural_object_container = "{\n"
|
|
plural_pattern = r"(zero|one|two|few|many|other)\s*\[([^\]]+)\]"
|
|
|
|
for key, value_en in locales['en'].items():
|
|
if value_en.startswith("{count, plural, "):
|
|
extracted_vars_en = extract_vars(replaced_en)
|
|
plurals_other = [[locale, replace_static_strings(data.get(key, ""))] for locale, data in locales.items()]
|
|
en_plurals_with_token = re.findall(plural_pattern, value_en.replace('#', '{count}'))
|
|
|
|
if not en_plurals_with_token:
|
|
raise ValueError("invalid plural string")
|
|
|
|
all_locales_plurals = []
|
|
|
|
extracted_vars = extract_vars(replace_static_strings(en_plurals_with_token[0][1]))
|
|
if('count' not in extracted_vars):
|
|
extracted_vars.append('count')
|
|
|
|
for plural in plurals_other:
|
|
js_plural_object = ""
|
|
|
|
locale_key = plural[0].replace("_","-") # 'lo', 'th', 'zh-CN', ....
|
|
plural_str = plural[1].replace('#', '{count}')
|
|
|
|
plurals_with_token = re.findall(plural_pattern, plural_str)
|
|
|
|
|
|
all_locales_strings = []
|
|
as_record_type_en = vars_to_record(extracted_vars)
|
|
|
|
for token, localized_string in plurals_with_token:
|
|
if localized_string:
|
|
to_append = ""
|
|
to_append += token
|
|
to_append += f": \"{escape_new_lines(localized_string)}\""
|
|
all_locales_strings.append(to_append)
|
|
|
|
# if that locale doesn't have translation in plurals, add the english hones
|
|
if not len(all_locales_strings):
|
|
for plural_en_token, plural_en_str in en_plurals_with_token:
|
|
all_locales_strings.append(f"{plural_en_token}: \"{escape_new_lines(plural_en_str)}\"")
|
|
js_plural_object += f" {wrapValue(locale_key)}:"
|
|
js_plural_object += "{\n "
|
|
js_plural_object += ",\n ".join(all_locales_strings)
|
|
js_plural_object += "\n },"
|
|
|
|
all_locales_plurals.append(js_plural_object)
|
|
js_plural_object_container += f' {wrapValue(key)}: {{\n{"\n".join(all_locales_plurals)}\n args: {args_to_type(as_record_type_en)}\n }},\n'
|
|
|
|
else:
|
|
replaced_en = replace_static_strings(value_en)
|
|
extracted_vars_en = extract_vars(replaced_en)
|
|
as_record_type_en = vars_to_record(extracted_vars_en)
|
|
other_locales_replaced_values = [[locale, replace_static_strings(data.get(key, ""))] for locale, data in locales.items()]
|
|
|
|
all_locales_strings = []
|
|
for locale, replaced_val in other_locales_replaced_values:
|
|
if replaced_val:
|
|
all_locales_strings.append(f'{wrapValue(locale.replace("_","-"))}: "{escape_new_lines(replaced_val)}"')
|
|
else:
|
|
all_locales_strings.append(f'{wrapValue(locale.replace("_","-"))}: "{escape_new_lines(replaced_en)}"')
|
|
|
|
# print('key',key, " other_locales_replaced_values:", other_locales_replaced_values)
|
|
js_object += f' {wrapValue(key)}: {{\n {",\n ".join(all_locales_strings)},\n args: {args_to_type(as_record_type_en)}\n }},\n'
|
|
|
|
js_object += "}"
|
|
js_plural_object_container += "}"
|
|
return js_object,js_plural_object_container
|
|
|
|
|
|
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}"
|
|
)
|
|
|
|
dicts = generate_type_object(locales)
|
|
|
|
dictVar = "simpleDictionary"
|
|
pluralDictVar = "pluralsDictionary"
|
|
|
|
|
|
ts_file.write(f"""
|
|
export const {dictVar} = {dicts[0]} as const;
|
|
|
|
export const {pluralDictVar} = {dicts[1]} as const;
|
|
""")
|
|
|
|
return f"Locales generated at: {OUTPUT_FILE}"
|
|
|