11#!/bin/python3
22import re
3- from typing import List , Tuple
43
54OUTPUT_FILE = "./ts/localization/locales.ts"
65
76
7+ # Define the mapping of special fields to their types and corresponding "WithX"
8+ with_map = {
9+ ("name" , "string" ): "WithName" ,
10+ ("group_name" , "string" ): "WithGroupName" ,
11+ ("community_name" , "string" ): "WithCommunityName" ,
12+ ("other_name" , "string" ): "WithOtherName" ,
13+ ("author" , "string" ): "WithAuthor" ,
14+ ("emoji" , "string" ): "WithEmoji" ,
15+ ("emoji_name" , "string" ): "WithEmojiName" ,
16+ ("admin_name" , "string" ): "WithAdminName" ,
17+ ("time" , "string" ): "WithTime" ,
18+ ("time_large" , "string" ): "WithTimeLarge" ,
19+ ("time_small" , "string" ): "WithTimeSmall" ,
20+ ("disappearing_messages_type" , "string" ): "WithDisappearingMessagesType" ,
21+ ("conversation_name" , "string" ): "WithConversationName" ,
22+ ("file_type" , "string" ): "WithFileType" ,
23+ ("date" , "string" ): "WithDate" ,
24+ ("date_time" , "string" ): "WithDateTime" ,
25+ ("message_snippet" , "string" ): "WithMessageSnippet" ,
26+ ("query" , "string" ): "WithQuery" ,
27+ ("version" , "string" ): "WithVersion" ,
28+ ("information" , "string" ): "WithInformation" ,
29+ ("device" , "string" ): "WithDevice" ,
30+ ("percent_loader" , "string" ): "WithPercentLoader" ,
31+ ("message_count" , "string" ): "WithMessageCount" ,
32+ ("conversation_count" , "string" ): "WithConversationCount" ,
33+ ("found_count" , "number" ): "WithFoundCount" ,
34+ ("hash" , "string" ): "WithHash" ,
35+ ("url" , "string" ): "WithUrl" ,
36+ ("account_id" , "string" ): "WithAccountId" ,
37+ ("count" , "number" ): "WithCount" ,
38+ ("service_node_id" , "string" ): "WithServiceNodeId" ,
39+ ("limit" , "string" ): "WithLimit" ,
40+ ("relative_time" , "string" ): "WithRelativeTime" ,
41+ ("icon" , "string" ): "WithIcon" ,
42+ ("storevariant" , "string" ): "WithStoreVariant" ,
43+ ("min" , "string" ): "WithMin" ,
44+ ("max" , "string" ): "WithMax" ,
45+ }
46+
47+
848def wrapValue (value ):
949 """
1050 Wraps the given value in single quotes if it contains any characters other than letters, digits, or underscores.
@@ -62,14 +102,26 @@ def extract_vars(text):
62102 return vars
63103
64104
105+
106+ def vars_to_record_ts (vars ):
107+ arr = []
108+ for var in vars :
109+ to_append = [var , 'number' if var == 'count' or var == 'found_count' else 'string' ]
110+ if to_append not in arr :
111+ arr .append (to_append )
112+
113+ return arr
114+
115+
116+
117+
65118def vars_to_record (vars ):
66119 arr = []
67120 for var in vars :
68121 to_append = '' + var + ': ' + ('"number"' if var == 'count' or var == 'found_count' else '"string"' )
69122 if to_append not in arr :
70123 arr .append (to_append )
71124
72- # print(arr)
73125 if not arr :
74126 return ''
75127 return "{" + ', ' .join (arr ) + "}"
@@ -90,10 +142,15 @@ def generate_type_object(locales):
90142 Returns:
91143 str: A string representation of the JavaScript object.
92144 """
93- js_object = "{\n "
94- js_plural_object_container = "{\n "
145+ js_object_no_args = "{\n "
146+ js_object_with_args = "{\n "
147+ js_plural_object_container_with_args = "{\n "
95148 plural_pattern = r"(zero|one|two|few|many|other)\s*\[([^\]]+)\]"
96149
150+ tokens_simple_no_args = []
151+ tokens_simple_with_args = {}
152+ tokens_plurals_with_args = {}
153+
97154 for key , value_en in locales ['en' ].items ():
98155 if value_en .startswith ("{count, plural, " ):
99156 extracted_vars_en = extract_vars (value_en )
@@ -119,7 +176,6 @@ def generate_type_object(locales):
119176
120177
121178 all_locales_strings = []
122- as_record_type_en = vars_to_record (extracted_vars )
123179
124180 for token , localized_string in plurals_with_token :
125181 if localized_string :
@@ -138,11 +194,11 @@ def generate_type_object(locales):
138194 js_plural_object += "\n },"
139195
140196 all_locales_plurals .append (js_plural_object )
141- js_plural_object_container += f' { wrapValue (key )} : {{\n { "\n " .join (all_locales_plurals )} \n args: { args_to_type (as_record_type_en )} \n }},\n '
197+ js_plural_object_container_with_args += f' { wrapValue (key )} : {{\n { "\n " .join (all_locales_plurals )} \n }},\n '
198+ tokens_plurals_with_args [key ] = vars_to_record_ts (extracted_vars )
142199
143200 else :
144201 extracted_vars_en = extract_vars (value_en )
145- as_record_type_en = vars_to_record (extracted_vars_en )
146202 other_locales_replaced_values = [[locale , data .get (key , "" )] for locale , data in locales .items ()]
147203
148204 all_locales_strings = []
@@ -152,12 +208,28 @@ def generate_type_object(locales):
152208 else :
153209 all_locales_strings .append (f'{ wrapValue (locale .replace ("_" ,"-" ))} : "{ escape_str (value_en )} "' )
154210
155- # print('key',key, " other_locales_replaced_values:", other_locales_replaced_values)
156- js_object += f' { wrapValue (key )} : {{\n { ",\n " .join (all_locales_strings )} ,\n args: { args_to_type (as_record_type_en )} \n }},\n '
211+ if extracted_vars_en :
212+ js_object_with_args += f' { wrapValue (key )} : {{\n { ",\n " .join (all_locales_strings )} ,\n }},\n '
213+ tokens_simple_with_args [key ] = vars_to_record_ts (extracted_vars_en )
214+ else :
215+ js_object_no_args += f' { wrapValue (key )} : {{\n { ",\n " .join (all_locales_strings )} ,\n }},\n '
216+ tokens_simple_no_args .append (key )
157217
158- js_object += "}"
159- js_plural_object_container += "}"
160- return js_object ,js_plural_object_container
218+ tokens_simple_no_args_str = "\n '" + "' |\n '" .join (tokens_simple_no_args ) + "'"
219+
220+ js_object_no_args += "}"
221+ js_object_with_args += "}"
222+ js_plural_object_container_with_args += "}"
223+
224+ dicts = {
225+ "simple_no_args" : js_object_no_args ,
226+ "simple_with_args" : js_object_with_args ,
227+ "plurals_with_args" : js_plural_object_container_with_args ,
228+ "tokens_simple_no_args_str" : tokens_simple_no_args_str ,
229+ "tokens_simple_with_args" : tokens_simple_with_args ,
230+ "tokens_plural_with_args" : tokens_plurals_with_args ,
231+ }
232+ return dicts
161233
162234
163235DISCLAIMER = """
@@ -190,6 +262,40 @@ def generateLocalesType(locale, data):
190262 return f"Locales generated at: { OUTPUT_FILE } "
191263
192264
265+ def format_tokens_with_named_args (token_args_dict ):
266+ result = []
267+
268+ for token , args in token_args_dict .items ():
269+ extras = []
270+ with_types = []
271+
272+ for arg_name , arg_type in args :
273+ key = (arg_name , arg_type )
274+ if key in with_map :
275+ with_types .append (with_map [key ])
276+ else :
277+ extras .append (f"{ arg_name } : { arg_type } " )
278+
279+ # Join parts
280+ joined = " & " .join (with_types )
281+ if extras :
282+ extras_str = "{ " + ", " .join (extras ) + " }"
283+ joined = f"{ joined } & { extras_str } " if joined else extras_str
284+
285+ result .append (f" { token } : { joined } " )
286+
287+ return "{\n " + ",\n " .join (result ) + "\n }"
288+
289+
290+ def generate_with_types (with_map ):
291+ lines = []
292+ for (arg_name , arg_type ), type_name in with_map .items ():
293+ lines .append (f"type { type_name } = {{{ arg_name } : { arg_type } }};" )
294+ return "\n " .join (lines )
295+
296+
297+
298+
193299def generateLocalesMergedType (locales ):
194300 """
195301 Generate the locales type and write it to a file.
@@ -204,17 +310,45 @@ def generateLocalesMergedType(locales):
204310 f"{ DISCLAIMER } "
205311 )
206312
313+ ts_file .write ("import type { CrowdinLocale } from './constants';\n " )
314+
207315 dicts = generate_type_object (locales )
208316
209- dictVar = "simpleDictionary"
210- pluralDictVar = "pluralsDictionary"
317+ tokens_simple_with_args = dicts ['tokens_simple_with_args' ]
318+ tokens_plural_with_args = dicts ['tokens_plural_with_args' ]
319+
320+ tokens_union_simple_args = format_tokens_with_named_args (tokens_simple_with_args )
321+ tokens_union_plural_args = format_tokens_with_named_args (tokens_plural_with_args )
211322
212323
213324 ts_file .write (f"""
214- export const { dictVar } = { dicts [0 ]} as const;
325+ { generate_with_types (with_map )}
326+
327+ export type TokenSimpleNoArgs = { dicts ['tokens_simple_no_args_str' ]} ;
328+
329+ export type TokensSimpleAndArgs = { tokens_union_simple_args } ;
330+
331+ export type TokensPluralAndArgs = { tokens_union_plural_args } ;
332+
333+ export type TokenSimpleWithArgs = { "\n '" + "' |\n '" .join (list (tokens_simple_with_args .keys ())) + "'" }
334+
335+ export type TokenPluralWithArgs = { "\n '" + "' |\n '" .join (list (tokens_plural_with_args .keys ())) + "'" }
336+
337+ export const simpleDictionaryNoArgs: Record<
338+ TokenSimpleNoArgs,
339+ Record<CrowdinLocale, string>
340+ > = { dicts ['simple_no_args' ]} as const;
341+
342+
343+ export const simpleDictionaryWithArgs: Record<
344+ TokenSimpleWithArgs,
345+ Record<CrowdinLocale, string>
346+ > = { dicts ['simple_with_args' ]} as const;
347+
348+ export const pluralsDictionaryWithArgs = { dicts ['plurals_with_args' ]} as const;
215349
216- export const { pluralDictVar } = { dicts [1 ]} as const;
217350""" )
218351
352+
219353 return f"Locales generated at: { OUTPUT_FILE } "
220354
0 commit comments