3
3
import xml .etree .ElementTree as ET
4
4
import sys
5
5
import argparse
6
- import html
7
6
from pathlib import Path
8
- from colorama import Fore , Style , init
7
+ from colorama import Fore , Style
8
+ from generate_shared import clean_string , load_glossary_dict
9
9
10
10
# Customizable mapping for output folder hierarchy
11
11
# Add entries here to customize the output path for specific locales
37
37
TRANSLATIONS_OUTPUT_DIRECTORY = args .translations_output_directory
38
38
NON_TRANSLATABLE_STRINGS_OUTPUT_PATH = args .non_translatable_strings_output_path
39
39
40
+ clean_string_extra_dict = {'{count}' : '#' }
41
+
40
42
def parse_xliff (file_path ):
41
43
tree = ET .parse (file_path )
42
44
root = tree .getroot ()
@@ -69,26 +71,20 @@ def parse_xliff(file_path):
69
71
70
72
return translations
71
73
72
- def clean_string (text ):
73
- # Note: any changes done for all platforms needs most likely to be done on crowdin side.
74
- # So we don't want to replace -> with → for instance, we want the crowdin strings to not have those at all.
75
- text = html .unescape (text ) # Unescape any HTML escaping
76
- return text .strip () # Strip whitespace
77
74
78
- def generate_icu_pattern (target ):
75
+ def generate_icu_pattern (target , glossary_dict ):
79
76
if isinstance (target , dict ): # It's a plural group
80
77
pattern_parts = []
81
78
for form , value in target .items ():
82
79
if form in ['zero' , 'one' , 'two' , 'few' , 'many' , 'other' , 'exact' , 'fractional' ]:
83
- # Replace {count} with #
84
- value = clean_string (value .replace ('{count}' , '#' ))
80
+ value = clean_string (value , False , glossary_dict , clean_string_extra_dict )
85
81
pattern_parts .append (f"{ form } [{ value } ]" )
86
82
87
83
return "{{count, plural, {0}}}" .format (" " .join (pattern_parts ))
88
84
else : # It's a regular string
89
- return clean_string (target )
85
+ return clean_string (target , False , glossary_dict , clean_string_extra_dict )
90
86
91
- def convert_xliff_to_json (input_file , output_dir , locale , locale_two_letter_code ):
87
+ def convert_xliff_to_json (input_file , output_dir , locale , locale_two_letter_code , glossary_dict ):
92
88
if not os .path .exists (input_file ):
93
89
raise FileNotFoundError (f"Could not find '{ input_file } ' in raw translations directory" )
94
90
@@ -97,8 +93,9 @@ def convert_xliff_to_json(input_file, output_dir, locale, locale_two_letter_code
97
93
sorted_translations = sorted (translations .items ())
98
94
converted_translations = {}
99
95
96
+
100
97
for resname , target in sorted_translations :
101
- converted_translations [resname ] = generate_icu_pattern (target )
98
+ converted_translations [resname ] = generate_icu_pattern (target , glossary_dict )
102
99
103
100
# Generate output files
104
101
output_locale = LOCALE_PATH_MAPPING .get (locale , LOCALE_PATH_MAPPING .get (locale_two_letter_code , locale_two_letter_code ))
@@ -112,16 +109,10 @@ def convert_xliff_to_json(input_file, output_dir, locale, locale_two_letter_code
112
109
file .write ('\n ' )
113
110
return output_locale
114
111
115
- def convert_non_translatable_strings_to_type_script (input_file , output_path , exported_locales , rtl_languages ):
116
- if not os .path .exists (input_file ):
117
- raise FileNotFoundError (f"Could not find '{ input_file } ' in raw translations directory" )
118
112
119
- # Process the non-translatable string input
120
- non_translatable_strings_data = {}
121
- with open (input_file , 'r' , encoding = "utf-8" ) as file :
122
- non_translatable_strings_data = json .load (file )
123
113
124
- entries = non_translatable_strings_data ['data' ]
114
+ def convert_non_translatable_strings_to_type_script (input_file , output_path , exported_locales , rtl_languages ):
115
+ glossary_dict = load_glossary_dict (input_file )
125
116
rtl_locales = sorted ([lang ["twoLettersCode" ] for lang in rtl_languages ])
126
117
127
118
# Output the file in the desired format
@@ -132,9 +123,8 @@ def convert_non_translatable_strings_to_type_script(input_file, output_path, exp
132
123
133
124
with open (output_path , 'w' , encoding = 'utf-8' ) as file :
134
125
file .write ('export enum LOCALE_DEFAULTS {\n ' )
135
- for entry in entries :
136
- key = entry ['data' ]['note' ]
137
- text = entry ['data' ]['text' ]
126
+ for key in glossary_dict :
127
+ text = glossary_dict [key ]
138
128
file .write (f" { key } = '{ text } ',\n " )
139
129
140
130
file .write ('}\n ' )
@@ -143,7 +133,7 @@ def convert_non_translatable_strings_to_type_script(input_file, output_path, exp
143
133
file .write ('\n ' )
144
134
file .write (f"export const crowdinLocales = [{ joined_exported_locales } ,\n ] as const;\n " )
145
135
file .write ('\n ' )
146
- file .write (f "export type CrowdinLocale = (typeof crowdinLocales)[number];\n " )
136
+ file .write ("export type CrowdinLocale = (typeof crowdinLocales)[number];\n " )
147
137
file .write ('\n ' )
148
138
149
139
@@ -158,6 +148,8 @@ def convert_all_files(input_directory):
158
148
with open (project_info_file , 'r' , encoding = "utf-8" ) as file :
159
149
project_details = json .load (file )
160
150
151
+ non_translatable_strings_file = os .path .join (input_directory , "_non_translatable_strings.json" )
152
+
161
153
# Extract the language info and sort the target languages alphabetically by locale
162
154
source_language = project_details ['data' ]['sourceLanguage' ]
163
155
target_languages = project_details ['data' ]['targetLanguages' ]
@@ -168,18 +160,20 @@ def convert_all_files(input_directory):
168
160
# Convert the XLIFF data to the desired format
169
161
print (f"\033 [2K{ Fore .WHITE } ⏳ Converting translations to target format...{ Style .RESET_ALL } " , end = '\r ' )
170
162
exported_locales = []
163
+ glossary_dict = load_glossary_dict (non_translatable_strings_file )
164
+
171
165
for language in [source_language ] + target_languages :
172
166
lang_locale = language ['locale' ]
173
167
lang_two_letter_code = language ['twoLettersCode' ]
174
168
print (f"\033 [2K{ Fore .WHITE } ⏳ Converting translations for { lang_locale } to target format...{ Style .RESET_ALL } " , end = '\r ' )
175
169
input_file = os .path .join (input_directory , f"{ lang_locale } .xliff" )
176
- exported_as = convert_xliff_to_json (input_file , TRANSLATIONS_OUTPUT_DIRECTORY , lang_locale , lang_two_letter_code )
170
+ exported_as = convert_xliff_to_json (input_file , TRANSLATIONS_OUTPUT_DIRECTORY , lang_locale , lang_two_letter_code , glossary_dict )
177
171
exported_locales .append (exported_as )
178
172
print (f"\033 [2K{ Fore .GREEN } ✅ All conversions complete{ Style .RESET_ALL } " )
179
173
180
174
# Convert the non-translatable strings to the desired format
181
175
print (f"\033 [2K{ Fore .WHITE } ⏳ Generating static strings file...{ Style .RESET_ALL } " , end = '\r ' )
182
- non_translatable_strings_file = os . path . join ( input_directory , "_non_translatable_strings.json" )
176
+
183
177
rtl_languages = [lang for lang in target_languages if lang ["textDirection" ] == "rtl" ]
184
178
convert_non_translatable_strings_to_type_script (non_translatable_strings_file , NON_TRANSLATABLE_STRINGS_OUTPUT_PATH , exported_locales , rtl_languages )
185
179
print (f"\033 [2K{ Fore .GREEN } ✅ Static string generation complete{ Style .RESET_ALL } " )
0 commit comments