Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(137)

Side by Side Diff: chrome/installer/util/prebuild/create_string_rc.py

Issue 2834973002: Revert of Enable side-by-side beta and dev channels. (Closed)
Patch Set: Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be 3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file. 4 # found in the LICENSE file.
5 5
6 """Generates .h and .rc files for installer strings. Run "python 6 """Generates .h and .rc files for installer strings. Run "python
7 create_string_rc.py" for usage details. 7 create_string_rc.py" for usage details.
8 8
9 This script generates an rc file and header (NAME.{rc,h}) to be included in 9 This script generates an rc file and header (NAME.{rc,h}) to be included in
10 setup.exe. The rc file includes translations for strings pulled from the given 10 setup.exe. The rc file includes translations for strings pulled from the given
(...skipping 26 matching lines...) Expand all
37 import sys 37 import sys
38 from xml import sax 38 from xml import sax
39 39
40 BASEDIR = os.path.dirname(os.path.abspath(__file__)) 40 BASEDIR = os.path.dirname(os.path.abspath(__file__))
41 sys.path.append(os.path.join(BASEDIR, '../../../../tools/grit')) 41 sys.path.append(os.path.join(BASEDIR, '../../../../tools/grit'))
42 sys.path.append(os.path.join(BASEDIR, '../../../../tools/python')) 42 sys.path.append(os.path.join(BASEDIR, '../../../../tools/python'))
43 43
44 from grit.extern import tclib 44 from grit.extern import tclib
45 45
46 # The IDs of strings we want to import from the .grd files and include in 46 # The IDs of strings we want to import from the .grd files and include in
47 # setup.exe's resources. These strings are universal for all brands. 47 # setup.exe's resources.
48 STRING_IDS = [ 48 STRING_IDS = [
49 'IDS_ABOUT_VERSION_COMPANY_NAME', 49 'IDS_ABOUT_VERSION_COMPANY_NAME',
50 'IDS_APP_SHORTCUTS_SUBDIR_NAME', 50 'IDS_APP_SHORTCUTS_SUBDIR_NAME',
51 'IDS_APP_SHORTCUTS_SUBDIR_NAME_CANARY',
51 'IDS_INBOUND_MDNS_RULE_DESCRIPTION', 52 'IDS_INBOUND_MDNS_RULE_DESCRIPTION',
53 'IDS_INBOUND_MDNS_RULE_DESCRIPTION_CANARY',
52 'IDS_INBOUND_MDNS_RULE_NAME', 54 'IDS_INBOUND_MDNS_RULE_NAME',
55 'IDS_INBOUND_MDNS_RULE_NAME_CANARY',
53 'IDS_INSTALL_EXISTING_VERSION_LAUNCHED', 56 'IDS_INSTALL_EXISTING_VERSION_LAUNCHED',
54 'IDS_INSTALL_FAILED', 57 'IDS_INSTALL_FAILED',
55 'IDS_INSTALL_HIGHER_VERSION', 58 'IDS_INSTALL_HIGHER_VERSION',
56 'IDS_INSTALL_INSUFFICIENT_RIGHTS', 59 'IDS_INSTALL_INSUFFICIENT_RIGHTS',
57 'IDS_INSTALL_INVALID_ARCHIVE', 60 'IDS_INSTALL_INVALID_ARCHIVE',
58 'IDS_INSTALL_OS_ERROR', 61 'IDS_INSTALL_OS_ERROR',
59 'IDS_INSTALL_OS_NOT_SUPPORTED', 62 'IDS_INSTALL_OS_NOT_SUPPORTED',
60 'IDS_INSTALL_SINGLETON_ACQUISITION_FAILED', 63 'IDS_INSTALL_SINGLETON_ACQUISITION_FAILED',
61 'IDS_INSTALL_TEMP_DIR_FAILED', 64 'IDS_INSTALL_TEMP_DIR_FAILED',
62 'IDS_INSTALL_UNCOMPRESSION_FAILED', 65 'IDS_INSTALL_UNCOMPRESSION_FAILED',
63 'IDS_PRODUCT_DESCRIPTION', 66 'IDS_PRODUCT_DESCRIPTION',
64 'IDS_PRODUCT_NAME', 67 'IDS_PRODUCT_NAME',
65 'IDS_SAME_VERSION_REPAIR_FAILED', 68 'IDS_SAME_VERSION_REPAIR_FAILED',
66 'IDS_SETUP_PATCH_FAILED', 69 'IDS_SETUP_PATCH_FAILED',
67 'IDS_SHORTCUT_NEW_WINDOW', 70 'IDS_SHORTCUT_NEW_WINDOW',
68 'IDS_SHORTCUT_TOOLTIP', 71 'IDS_SHORTCUT_TOOLTIP',
72 'IDS_SXS_SHORTCUT_NAME',
69 ] 73 ]
70 74
71 # Certain strings are conditional on a brand's install mode (see 75 # Certain strings are conditional on a brand's install mode (see
72 # chrome/install_static/install_modes.h for details). This allows 76 # chrome/install_static/install_modes.h for details). This allows
73 # installer::GetLocalizedString to return a resource specific to the current 77 # installer::GetLocalizedString to return a resource specific to the current
74 # install mode at runtime (e.g., "Google Chrome SxS" as IDS_SHORTCUT_NAME for 78 # install mode at runtime (e.g., "Google Chrome SxS" as IDS_SHORTCUT_NAME for
75 # the localized shortcut name for Google Chrome's canary channel). 79 # the localized shortcut name for Google Chrome's canary channel).
76 # l10n_util::GetStringUTF16 (used within the rest of Chrome) is unaffected, and 80 # l10n_util::GetStringUTF16 (used within the rest of Chrome) is unaffected, and
77 # will always return the requested string. 81 # will always return the requested string.
78 # 82 #
(...skipping 16 matching lines...) Expand all
95 # 'resource_id_1' names an existing string ID. All calls to 99 # 'resource_id_1' names an existing string ID. All calls to
96 # installer::GetLocalizedString with this string ID will map to the 100 # installer::GetLocalizedString with this string ID will map to the
97 # mode-specific string. 101 # mode-specific string.
98 # 102 #
99 # Note: Update the test expectations in GetBaseMessageIdForMode.GoogleStringIds 103 # Note: Update the test expectations in GetBaseMessageIdForMode.GoogleStringIds
100 # when adding to/modifying this structure. 104 # when adding to/modifying this structure.
101 MODE_SPECIFIC_STRINGS = { 105 MODE_SPECIFIC_STRINGS = {
102 'IDS_APP_SHORTCUTS_SUBDIR_NAME': { 106 'IDS_APP_SHORTCUTS_SUBDIR_NAME': {
103 'google_chrome': [ 107 'google_chrome': [
104 'IDS_APP_SHORTCUTS_SUBDIR_NAME', 108 'IDS_APP_SHORTCUTS_SUBDIR_NAME',
105 'IDS_APP_SHORTCUTS_SUBDIR_NAME_BETA',
106 'IDS_APP_SHORTCUTS_SUBDIR_NAME_DEV',
107 'IDS_APP_SHORTCUTS_SUBDIR_NAME_CANARY', 109 'IDS_APP_SHORTCUTS_SUBDIR_NAME_CANARY',
108 ], 110 ],
109 'chromium': [ 111 'chromium': [
110 'IDS_APP_SHORTCUTS_SUBDIR_NAME', 112 'IDS_APP_SHORTCUTS_SUBDIR_NAME',
111 ], 113 ],
112 }, 114 },
113 'IDS_INBOUND_MDNS_RULE_DESCRIPTION': { 115 'IDS_INBOUND_MDNS_RULE_DESCRIPTION': {
114 'google_chrome': [ 116 'google_chrome': [
115 'IDS_INBOUND_MDNS_RULE_DESCRIPTION', 117 'IDS_INBOUND_MDNS_RULE_DESCRIPTION',
116 'IDS_INBOUND_MDNS_RULE_DESCRIPTION_BETA',
117 'IDS_INBOUND_MDNS_RULE_DESCRIPTION_DEV',
118 'IDS_INBOUND_MDNS_RULE_DESCRIPTION_CANARY', 118 'IDS_INBOUND_MDNS_RULE_DESCRIPTION_CANARY',
119 ], 119 ],
120 'chromium': [ 120 'chromium': [
121 'IDS_INBOUND_MDNS_RULE_DESCRIPTION', 121 'IDS_INBOUND_MDNS_RULE_DESCRIPTION',
122 ], 122 ],
123 }, 123 },
124 'IDS_INBOUND_MDNS_RULE_NAME': { 124 'IDS_INBOUND_MDNS_RULE_NAME': {
125 'google_chrome': [ 125 'google_chrome': [
126 'IDS_INBOUND_MDNS_RULE_NAME', 126 'IDS_INBOUND_MDNS_RULE_NAME',
127 'IDS_INBOUND_MDNS_RULE_NAME_BETA',
128 'IDS_INBOUND_MDNS_RULE_NAME_DEV',
129 'IDS_INBOUND_MDNS_RULE_NAME_CANARY', 127 'IDS_INBOUND_MDNS_RULE_NAME_CANARY',
130 ], 128 ],
131 'chromium': [ 129 'chromium': [
132 'IDS_INBOUND_MDNS_RULE_NAME', 130 'IDS_INBOUND_MDNS_RULE_NAME',
133 ], 131 ],
134 }, 132 },
135 # In contrast to the strings above, this one (IDS_PRODUCT_NAME) is used 133 # In contrast to the strings above, this one (IDS_PRODUCT_NAME) is used
136 # throughout Chrome in mode-independent contexts. Within the installer (the 134 # throughout Chrome in mode-independent contexts. Within the installer (the
137 # place where this mapping matters), it is only used for mode-specific strings 135 # place where this mapping matters), it is only used for mode-specific strings
138 # such as the name of Chrome's shortcut. 136 # such as the name of Chrome's shortcut.
139 'IDS_PRODUCT_NAME': { 137 'IDS_PRODUCT_NAME': {
140 'google_chrome': [ 138 'google_chrome': [
141 'IDS_PRODUCT_NAME', 139 'IDS_PRODUCT_NAME',
142 'IDS_SHORTCUT_NAME_BETA',
143 'IDS_SHORTCUT_NAME_DEV',
144 'IDS_SXS_SHORTCUT_NAME', 140 'IDS_SXS_SHORTCUT_NAME',
145 ], 141 ],
146 'chromium': [ 142 'chromium': [
147 'IDS_PRODUCT_NAME', 143 'IDS_PRODUCT_NAME',
148 ], 144 ],
149 }, 145 },
150 } 146 }
151 # Note: Update the test expectations in GetBaseMessageIdForMode.GoogleStringIds 147 # Note: Update the test expectations in GetBaseMessageIdForMode.GoogleStringIds
152 # when adding to/modifying the above structure. 148 # when adding to/modifying the above structure.
153 149
154 # The ID of the first resource string. 150 # The ID of the first resource string.
155 FIRST_RESOURCE_ID = 1600 151 FIRST_RESOURCE_ID = 1600
156 152
157 153
158 class GrdHandler(sax.handler.ContentHandler): 154 class GrdHandler(sax.handler.ContentHandler):
159 """Extracts selected strings from a .grd file. 155 """Extracts selected strings from a .grd file.
160 156
161 Attributes: 157 Attributes:
162 messages: A dict mapping string identifiers to their corresponding messages. 158 messages: A dict mapping string identifiers to their corresponding messages.
163 """ 159 """
164 def __init__(self, string_id_set): 160 def __init__(self, string_ids):
165 """Constructs a handler that reads selected strings from a .grd file. 161 """Constructs a handler that reads selected strings from a .grd file.
166 162
167 The dict attribute |messages| is populated with the strings that are read. 163 The dict attribute |messages| is populated with the strings that are read.
168 164
169 Args: 165 Args:
170 string_id_set: A set of message identifiers to extract. 166 string_ids: A list of message identifiers to extract.
171 """ 167 """
172 sax.handler.ContentHandler.__init__(self) 168 sax.handler.ContentHandler.__init__(self)
173 self.messages = {} 169 self.messages = {}
174 self.__id_set = string_id_set 170 self.__id_set = set(string_ids)
175 self.__message_name = None 171 self.__message_name = None
176 self.__element_stack = [] 172 self.__element_stack = []
177 self.__text_scraps = [] 173 self.__text_scraps = []
178 self.__characters_callback = None 174 self.__characters_callback = None
179 175
180 def startElement(self, name, attrs): 176 def startElement(self, name, attrs):
181 self.__element_stack.append(name) 177 self.__element_stack.append(name)
182 if name == 'message': 178 if name == 'message':
183 self.__OnOpenMessage(attrs.getValue('name')) 179 self.__OnOpenMessage(attrs.getValue('name'))
184 180
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after
303 'installer_util_strings'). 299 'installer_util_strings').
304 inputs: A list of (grd_file, xtb_dir) pairs containing the source data. 300 inputs: A list of (grd_file, xtb_dir) pairs containing the source data.
305 outdir: The directory into which the files will be generated. 301 outdir: The directory into which the files will be generated.
306 """ 302 """
307 self.name = name 303 self.name = name
308 self.inputs = inputs 304 self.inputs = inputs
309 self.outdir = outdir 305 self.outdir = outdir
310 self.brand = brand 306 self.brand = brand
311 307
312 def MakeFiles(self): 308 def MakeFiles(self):
313 string_id_set = self.__BuildStringIds() 309 translated_strings = self.__ReadSourceAndTranslatedStrings()
314 translated_strings = self.__ReadSourceAndTranslatedStrings(string_id_set)
315 self.__WriteRCFile(translated_strings) 310 self.__WriteRCFile(translated_strings)
316 self.__WriteHeaderFile(string_id_set, translated_strings) 311 self.__WriteHeaderFile(translated_strings)
317 312
318 class __TranslationData(object): 313 class __TranslationData(object):
319 """A container of information about a single translation.""" 314 """A container of information about a single translation."""
320 def __init__(self, resource_id_str, language, translation): 315 def __init__(self, resource_id_str, language, translation):
321 self.resource_id_str = resource_id_str 316 self.resource_id_str = resource_id_str
322 self.language = language 317 self.language = language
323 self.translation = translation 318 self.translation = translation
324 319
325 def __cmp__(self, other): 320 def __cmp__(self, other):
326 """Allow __TranslationDatas to be sorted by id then by language.""" 321 """Allow __TranslationDatas to be sorted by id then by language."""
327 id_result = cmp(self.resource_id_str, other.resource_id_str) 322 id_result = cmp(self.resource_id_str, other.resource_id_str)
328 return cmp(self.language, other.language) if id_result == 0 else id_result 323 return cmp(self.language, other.language) if id_result == 0 else id_result
329 324
330 def __BuildStringIds(self): 325 def __ReadSourceAndTranslatedStrings(self):
331 """Returns the set of string IDs to extract from the grd and xtb files."""
332 # Start with the strings that apply to all brands.
333 string_id_set = set(STRING_IDS)
334 # Add in the strings for the current brand.
335 for string_id, brands in MODE_SPECIFIC_STRINGS.iteritems():
336 brand_strings = brands.get(self.brand)
337 if not brand_strings:
338 raise exceptions.RuntimeError(
339 'No strings declared for brand \'%s\' in MODE_SPECIFIC_STRINGS for '
340 'message %s' % (self.brand, string_id))
341 string_id_set.update(brand_strings)
342 return string_id_set
343
344 def __ReadSourceAndTranslatedStrings(self, string_id_set):
345 """Reads the source strings and translations from all inputs.""" 326 """Reads the source strings and translations from all inputs."""
346 translated_strings = [] 327 translated_strings = []
347 for grd_file, xtb_dir in self.inputs: 328 for grd_file, xtb_dir in self.inputs:
348 # Get the name of the grd file sans extension. 329 # Get the name of the grd file sans extension.
349 source_name = os.path.splitext(os.path.basename(grd_file))[0] 330 source_name = os.path.splitext(os.path.basename(grd_file))[0]
350 # Compute a glob for the translation files. 331 # Compute a glob for the translation files.
351 xtb_pattern = os.path.join(os.path.dirname(grd_file), xtb_dir, 332 xtb_pattern = os.path.join(os.path.dirname(grd_file), xtb_dir,
352 '%s*.xtb' % source_name) 333 '%s*.xtb' % source_name)
353 translated_strings.extend( 334 translated_strings.extend(
354 self.__ReadSourceAndTranslationsFrom(string_id_set, grd_file, 335 self.__ReadSourceAndTranslationsFrom(grd_file, glob.glob(xtb_pattern)))
355 glob.glob(xtb_pattern)))
356 translated_strings.sort() 336 translated_strings.sort()
357 return translated_strings 337 return translated_strings
358 338
359 def __ReadSourceAndTranslationsFrom(self, string_id_set, grd_file, xtb_files): 339 def __ReadSourceAndTranslationsFrom(self, grd_file, xtb_files):
360 """Reads source strings and translations for a .grd file. 340 """Reads source strings and translations for a .grd file.
361 341
362 Reads the source strings and all available translations for the messages 342 Reads the source strings and all available translations for the messages
363 identified by string_id_set. The source string is used where translations 343 identified by STRING_IDS. The source string is used where translations are
364 are missing. 344 missing.
365 345
366 Args: 346 Args:
367 string_id_set: The identifiers of the strings to read.
368 grd_file: Path to a .grd file. 347 grd_file: Path to a .grd file.
369 xtb_files: List of paths to .xtb files. 348 xtb_files: List of paths to .xtb files.
370 349
371 Returns: 350 Returns:
372 An unsorted list of __TranslationData instances. 351 An unsorted list of __TranslationData instances.
373 """ 352 """
374 sax_parser = sax.make_parser() 353 sax_parser = sax.make_parser()
375 354
376 # Read the source (en-US) string from the .grd file. 355 # Read the source (en-US) string from the .grd file.
377 grd_handler = GrdHandler(string_id_set) 356 grd_handler = GrdHandler(STRING_IDS)
378 sax_parser.setContentHandler(grd_handler) 357 sax_parser.setContentHandler(grd_handler)
379 sax_parser.parse(grd_file) 358 sax_parser.parse(grd_file)
380 source_strings = grd_handler.messages 359 source_strings = grd_handler.messages
381 360
382 # Manually put the source strings as en-US in the list of translated 361 # Manually put the source strings as en-US in the list of translated
383 # strings. 362 # strings.
384 translated_strings = [] 363 translated_strings = []
385 for string_id, message_text in source_strings.iteritems(): 364 for string_id, message_text in source_strings.iteritems():
386 translated_strings.append(self.__TranslationData(string_id, 365 translated_strings.append(self.__TranslationData(string_id,
387 'EN_US', 366 'EN_US',
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
431 for translation in translated_strings: 410 for translation in translated_strings:
432 # Escape special characters for the rc file. 411 # Escape special characters for the rc file.
433 escaped_text = (translation.translation.replace('"', '""') 412 escaped_text = (translation.translation.replace('"', '""')
434 .replace('\t', '\\t') 413 .replace('\t', '\\t')
435 .replace('\n', '\\n')) 414 .replace('\n', '\\n'))
436 outfile.write(u' %s "%s"\n' % 415 outfile.write(u' %s "%s"\n' %
437 (translation.resource_id_str + '_' + translation.language, 416 (translation.resource_id_str + '_' + translation.language,
438 escaped_text)) 417 escaped_text))
439 outfile.write(FOOTER_TEXT) 418 outfile.write(FOOTER_TEXT)
440 419
441 def __WriteHeaderFile(self, string_id_set, translated_strings): 420 def __WriteHeaderFile(self, translated_strings):
442 """Writes a .h file with resource ids.""" 421 """Writes a .h file with resource ids."""
443 # TODO(grt): Stream the lines to the file rather than building this giant 422 # TODO(grt): Stream the lines to the file rather than building this giant
444 # list of lines first. 423 # list of lines first.
445 lines = [] 424 lines = []
446 do_languages_lines = ['\n#define DO_LANGUAGES'] 425 do_languages_lines = ['\n#define DO_LANGUAGES']
447 installer_string_mapping_lines = ['\n#define DO_INSTALLER_STRING_MAPPING'] 426 installer_string_mapping_lines = ['\n#define DO_INSTALLER_STRING_MAPPING']
448 do_mode_strings_lines = ['\n#define DO_MODE_STRINGS'] 427 do_mode_strings_lines = ['\n#define DO_MODE_STRINGS']
449 428
450 # Write the values for how the languages ids are offset. 429 # Write the values for how the languages ids are offset.
451 seen_languages = set() 430 seen_languages = set()
(...skipping 23 matching lines...) Expand all
475 brand_strings = brands.get(self.brand) 454 brand_strings = brands.get(self.brand)
476 if not brand_strings: 455 if not brand_strings:
477 raise exceptions.RuntimeError( 456 raise exceptions.RuntimeError(
478 'No strings declared for brand \'%s\' in MODE_SPECIFIC_STRINGS for ' 457 'No strings declared for brand \'%s\' in MODE_SPECIFIC_STRINGS for '
479 'message %s' % (self.brand, string_id)) 458 'message %s' % (self.brand, string_id))
480 do_mode_strings_lines.append( 459 do_mode_strings_lines.append(
481 ' HANDLE_MODE_STRING(%s_BASE, %s)' 460 ' HANDLE_MODE_STRING(%s_BASE, %s)'
482 % (string_id, ', '.join([ ('%s_BASE' % s) for s in brand_strings]))) 461 % (string_id, ', '.join([ ('%s_BASE' % s) for s in brand_strings])))
483 462
484 # Write out base ID values. 463 # Write out base ID values.
485 for string_id in sorted(string_id_set): 464 for string_id in STRING_IDS:
486 lines.append('#define %s_BASE %s_%s' % (string_id, 465 lines.append('#define %s_BASE %s_%s' % (string_id,
487 string_id, 466 string_id,
488 translated_strings[0].language)) 467 translated_strings[0].language))
489 installer_string_mapping_lines.append(' HANDLE_STRING(%s_BASE, %s)' 468 installer_string_mapping_lines.append(' HANDLE_STRING(%s_BASE, %s)'
490 % (string_id, string_id)) 469 % (string_id, string_id))
491 470
492 with open(os.path.join(self.outdir, self.name + '.h'), 'wb') as outfile: 471 with open(os.path.join(self.outdir, self.name + '.h'), 'wb') as outfile:
493 outfile.write('\n'.join(lines)) 472 outfile.write('\n'.join(lines))
494 outfile.write('\n#ifndef RC_INVOKED') 473 outfile.write('\n#ifndef RC_INVOKED')
495 outfile.write(' \\\n'.join(do_languages_lines)) 474 outfile.write(' \\\n'.join(do_languages_lines))
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
534 513
535 514
536 def main(): 515 def main():
537 args = ParseCommandLine() 516 args = ParseCommandLine()
538 StringRcMaker(args.name, args.inputs, args.outdir, args.brand).MakeFiles() 517 StringRcMaker(args.name, args.inputs, args.outdir, args.brand).MakeFiles()
539 return 0 518 return 0
540 519
541 520
542 if '__main__' == __name__: 521 if '__main__' == __name__:
543 sys.exit(main()) 522 sys.exit(main())
OLDNEW
« no previous file with comments | « chrome/installer/util/l10n_string_util_unittest.cc ('k') | chrome/test/mini_installer/config/chrome_beta_installed.prop » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698