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

Side by Side Diff: remoting/tools/build/remoting_localize.py

Issue 18868009: Generate the lists of localization files instead of hardcoding them. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Updating DEPS and path to jinja2. Created 7 years, 5 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 | Annotate | Revision Log
« no previous file with comments | « remoting/tools/build/DEPS ('k') | remoting/tools/localize.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # Copyright 2013 The Chromium Authors. All rights reserved. 2 # Copyright 2013 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 """ 6 """
7 localize.py -- Generates an output file from the given template replacing 7 localize.py -- Generates an output file from the given template replacing
8 variables and localizing strings. 8 variables and localizing strings.
9 9
10 The script uses Jinja2 template processing library (src/third_party/jinja2). 10 The script uses Jinja2 template processing library (src/third_party/jinja2).
11 Variables available to the templates: 11 Variables available to the templates:
12 - |languages| - the list of languages passed on the command line. ('-l'). 12 - |languages| - the list of languages passed on the command line. ('-l').
13 - Each KEY=VALUE define ('-d') can be accesses as |KEY|. 13 - Each NAME=VALUE define ('-d') can be accesses as {{ NAME }}.
14 - |official_build| is set to '1' when CHROME_BUILD_TYPE environment variable 14 - |official_build| is set to '1' when CHROME_BUILD_TYPE environment variable
15 is set to "_official". 15 is set to "_official".
16 16
17 Filters: 17 Filters:
18 - GetCodepage - returns the code page for the given language. 18 - GetCodepage - returns the code page for the given language.
19 - GetCodepageDecimal same as GetCodepage, but returns a decimal value. 19 - GetCodepageDecimal same as GetCodepage, but returns a decimal value.
20 - GetLangId - returns Win32 LANGID. 20 - GetLangId - returns Win32 LANGID.
21 - GetPrimaryLanguage - returns a named Win32 constant specifing the primary 21 - GetPrimaryLanguage - returns a named Win32 constant specifing the primary
22 language ID. 22 language ID.
23 - GetSublanguage - returns a named Win32 constant specifing the sublanguage 23 - GetSublanguage - returns a named Win32 constant specifing the sublanguage
24 ID. 24 ID.
25 25
26 Globals: 26 Globals:
27 - IsRtlLanguage(language) - returns True if the language is right-to-left.
27 - SelectLanguage(language) - allows to select the language to the used by 28 - SelectLanguage(language) - allows to select the language to the used by
28 {% trans %}{% endtrans %} statements. 29 {% trans %}{% endtrans %} statements.
29 30
30 """ 31 """
31 32
32 import io 33 import io
33 import json 34 import json
34 from optparse import OptionParser 35 from optparse import OptionParser
35 import os 36 import os
36 import sys 37 import sys
38 from string import Template
39
37 40
38 # Win32 primary languages IDs. 41 # Win32 primary languages IDs.
39 _LANGUAGE_PRIMARY = { 42 _LANGUAGE_PRIMARY = {
40 'LANG_NEUTRAL' : 0x00, 43 'LANG_NEUTRAL' : 0x00,
41 'LANG_INVARIANT' : 0x7f, 44 'LANG_INVARIANT' : 0x7f,
42 'LANG_AFRIKAANS' : 0x36, 45 'LANG_AFRIKAANS' : 0x36,
43 'LANG_ALBANIAN' : 0x1c, 46 'LANG_ALBANIAN' : 0x1c,
44 'LANG_ALSATIAN' : 0x84, 47 'LANG_ALSATIAN' : 0x84,
45 'LANG_AMHARIC' : 0x5e, 48 'LANG_AMHARIC' : 0x5e,
46 'LANG_ARABIC' : 0x01, 49 'LANG_ARABIC' : 0x01,
(...skipping 488 matching lines...) Expand 10 before | Expand all | Expand 10 after
535 538
536 539
537 def IsRtlLanguage(language): 540 def IsRtlLanguage(language):
538 return language in _RTL_LANGUAGES; 541 return language in _RTL_LANGUAGES;
539 542
540 543
541 def NormalizeLanguageCode(language): 544 def NormalizeLanguageCode(language):
542 return language.replace('_', '-', 1) 545 return language.replace('_', '-', 1)
543 546
544 547
548 def GetDataPackageSuffix(language):
549 lang = NormalizeLanguageCode(language)
550 if lang == 'en':
551 lang = 'en-US'
552 return lang
553
554
555 def GetJsonSuffix(language):
556 return language.replace('-', '_', 1)
557
558
545 def ReadValuesFromFile(values_dict, file_name): 559 def ReadValuesFromFile(values_dict, file_name):
546 """ 560 """
547 Reads KEYWORD=VALUE settings from the specified file. 561 Reads NAME=VALUE settings from the specified file.
548 562
549 Everything to the left of the first '=' is the keyword, 563 Everything to the left of the first '=' is the keyword,
550 everything to the right is the value. No stripping of 564 everything to the right is the value. No stripping of
551 white space, so beware. 565 white space, so beware.
552 566
553 The file must exist, otherwise you get the Python exception from open(). 567 The file must exist, otherwise you get the Python exception from open().
554 """ 568 """
555 for line in open(file_name, 'r').readlines(): 569 for line in open(file_name, 'r').readlines():
556 key, val = line.rstrip('\r\n').split('=', 1) 570 key, val = line.rstrip('\r\n').split('=', 1)
557 values_dict[key] = val 571 values_dict[key] = val
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
589 else: 603 else:
590 if contents == old_contents: 604 if contents == old_contents:
591 return 605 return
592 target.close() 606 target.close()
593 os.unlink(file_name) 607 os.unlink(file_name)
594 io.open(file_name, 'w', encoding=encoding).write(contents) 608 io.open(file_name, 'w', encoding=encoding).write(contents)
595 609
596 610
597 class MessageMap: 611 class MessageMap:
598 """ Provides a dictionary of localized messages for each language.""" 612 """ Provides a dictionary of localized messages for each language."""
599 def __init__(self, languages, messages_path): 613 def __init__(self, languages, locale_dir):
600 self.language = None 614 self.language = None
601 self.message_map = {} 615 self.message_map = {}
602 616
603 # Populate the message map 617 # Populate the message map
604 if messages_path: 618 if locale_dir:
605 for language in languages: 619 for language in languages:
606 file_name = os.path.join(messages_path, 620 file_name = os.path.join(locale_dir,
607 language.replace('-', '_', 1), 621 GetJsonSuffix(language),
608 'messages.json') 622 'messages.json')
609 self.message_map[language] = ReadMessagesFromFile(file_name) 623 self.message_map[language] = ReadMessagesFromFile(file_name)
610 624
611 def GetText(self, message): 625 def GetText(self, message):
612 """ Returns a localized message for the current language. """ 626 """ Returns a localized message for the current language. """
613 return self.message_map[self.language][message] 627 return self.message_map[self.language][message]
614 628
615 def SelectLanguage(self, language): 629 def SelectLanguage(self, language):
616 """ Selects the language to be used when retrieving localized messages. """ 630 """ Selects the language to be used when retrieving localized messages. """
617 self.language = language 631 self.language = language
618 632
619 def MakeSelectLanguage(self): 633 def MakeSelectLanguage(self):
620 """ Returns a function that can be used to select the current language. """ 634 """ Returns a function that can be used to select the current language. """
621 return lambda language: self.SelectLanguage(language) 635 return lambda language: self.SelectLanguage(language)
622 636
623 def MakeGetText(self): 637 def MakeGetText(self):
624 """ Returns a function that can be used to retrieve a localized message. """ 638 """ Returns a function that can be used to retrieve a localized message. """
625 return lambda message: self.GetText(message) 639 return lambda message: self.GetText(message)
626 640
627 641
628 def Localize(source, target, options): 642 def Localize(source, locales, options):
629 # Load jinja2 library. 643 # Set the list of languages to use.
630 if options.jinja2: 644 languages = map(NormalizeLanguageCode, locales)
631 jinja2_path = os.path.normpath(options.jinja2) 645 context = { 'languages' : languages }
632 else:
633 jinja2_path = os.path.normpath(os.path.join(os.path.abspath(__file__),
634 '../../../third_party/jinja2'))
635 sys.path.append(os.path.split(jinja2_path)[0])
636 from jinja2 import Environment, FileSystemLoader
637 646
638 # Create jinja2 environment. 647 # Load the localized messages.
639 (template_path, template_name) = os.path.split(source) 648 message_map = MessageMap(languages, options.locale_dir)
640 env = Environment(loader=FileSystemLoader(template_path),
641 extensions=['jinja2.ext.do', 'jinja2.ext.i18n'])
642
643 # Register custom filters.
644 env.filters['GetCodepage'] = GetCodepage
645 env.filters['GetCodepageDecimal'] = GetCodepageDecimal
646 env.filters['GetLangId'] = GetLangId
647 env.filters['GetPrimaryLanguage'] = GetPrimaryLanguage
648 env.filters['GetSublanguage'] = GetSublanguage
649
650 # Set the list of languages to use
651 languages = map(NormalizeLanguageCode, options.languages)
652 context = { 'languages' : languages }
653 env.globals['IsRtlLanguage'] = IsRtlLanguage
654
655 # Load the localized messages and register the message map with jinja2.i18n
656 # extension.
657 message_map = MessageMap(languages, options.messages_path)
658 env.globals['SelectLanguage'] = message_map.MakeSelectLanguage()
659 env.install_gettext_callables(message_map.MakeGetText(),
660 message_map.MakeGetText());
661 649
662 # Add OFFICIAL_BUILD variable the same way chrome/tools/build/version.py 650 # Add OFFICIAL_BUILD variable the same way chrome/tools/build/version.py
663 # does. 651 # does.
664 if os.environ.get('CHROME_BUILD_TYPE') == '_official': 652 if os.environ.get('CHROME_BUILD_TYPE') == '_official':
665 context['official_build'] = '1' 653 context['official_build'] = '1'
666 else: 654 else:
667 context['official_build'] = '0' 655 context['official_build'] = '0'
668 656
669 # Add all variables defined in the command line. 657 # Add all variables defined in the command line.
670 if options.define: 658 if options.define:
671 for define in options.define: 659 for define in options.define:
672 context.update(dict([define.split('=', 1)])); 660 context.update(dict([define.split('=', 1)]));
673 661
674 # Read KEYWORD=VALUE variables from file. 662 # Read NAME=VALUE variables from file.
675 if options.input: 663 if options.variables:
676 for file_name in options.input: 664 for file_name in options.variables:
677 ReadValuesFromFile(context, file_name) 665 ReadValuesFromFile(context, file_name)
678 666
679 template = env.get_template(template_name) 667 env = None
680 WriteIfChanged(target, template.render(context), options.encoding); 668 template = None
681 return 0; 669
670 if source:
671 # Load jinja2 library.
672 if options.jinja2:
673 jinja2_path = os.path.normpath(options.jinja2)
674 else:
675 jinja2_path = os.path.normpath(
676 os.path.join(os.path.abspath(__file__),
677 '../../../../third_party/jinja2'))
678 sys.path.append(os.path.split(jinja2_path)[0])
679 from jinja2 import Environment, FileSystemLoader
680
681 # Create jinja2 environment.
682 (template_path, template_name) = os.path.split(source)
683 env = Environment(loader=FileSystemLoader(template_path),
684 extensions=['jinja2.ext.do', 'jinja2.ext.i18n'])
685
686 # Register custom filters.
687 env.filters['GetCodepage'] = GetCodepage
688 env.filters['GetCodepageDecimal'] = GetCodepageDecimal
689 env.filters['GetLangId'] = GetLangId
690 env.filters['GetPrimaryLanguage'] = GetPrimaryLanguage
691 env.filters['GetSublanguage'] = GetSublanguage
692
693 # Register the message map with jinja2.i18n extension.
694 env.globals['IsRtlLanguage'] = IsRtlLanguage
695 env.globals['SelectLanguage'] = message_map.MakeSelectLanguage()
696 env.install_gettext_callables(message_map.MakeGetText(),
697 message_map.MakeGetText());
698
699 template = env.get_template(template_name)
700
701 # Generate a separate file per each locale if requested.
702 outputs = []
703 if options.locale_output:
704 target = Template(options.locale_output)
705 for lang in languages:
706 context['languages'] = [ lang ]
707 context['language'] = lang
708 context['pak_suffix'] = GetDataPackageSuffix(lang)
709 context['json_suffix'] = GetJsonSuffix(lang)
710
711 template_file_name = target.safe_substitute(context)
712 outputs.append(template_file_name)
713 if not options.print_only:
714 WriteIfChanged(template_file_name, template.render(context),
715 options.encoding)
716 else:
717 outputs.append(options.output)
718 if not options.print_only:
719 WriteIfChanged(options.output, template.render(context), options.encoding)
720
721 if options.print_only:
722 # Quote each element so filename spaces don't mess up gyp's attempt to parse
723 # it into a list.
724 return " ".join(['"%s"' % x for x in outputs])
725
726 return
682 727
683 728
684 def main(): 729 def DoMain(argv):
685 usage = "Usage: localize [options] <input> <output>" 730 usage = "Usage: localize [options] locales"
686 parser = OptionParser(usage=usage) 731 parser = OptionParser(usage=usage)
687 parser.add_option( 732 parser.add_option(
688 '-d', '--define', dest='define', action='append', type='string', 733 '-d', '--define', dest='define', action='append', type='string',
689 help='define a variable (VAR=VALUE).') 734 help='define a variable (NAME=VALUE).')
690 parser.add_option(
691 '-i', '--input', dest='input', action='append', type='string',
692 help='read variables from INPUT.')
693 parser.add_option(
694 '-l', '--language', dest='languages', action='append', type='string',
695 help='add LANGUAGE to the list of languages to use.')
696 parser.add_option( 735 parser.add_option(
697 '--encoding', dest='encoding', type='string', default='utf-16', 736 '--encoding', dest='encoding', type='string', default='utf-16',
698 help="set the encoding of <output>. 'utf-16' is the default.") 737 help="set the encoding of <output>. 'utf-16' is the default.")
699 parser.add_option( 738 parser.add_option(
700 '--jinja2', dest='jinja2', type='string', 739 '--jinja2', dest='jinja2', type='string',
701 help="specifies path to the jinja2 library.") 740 help="specifies path to the jinja2 library.")
702 parser.add_option( 741 parser.add_option(
703 '--messages_path', dest='messages_path', type='string', 742 '--locale_dir', dest='locale_dir', type='string',
704 help="set path to localized messages.") 743 help="set path to localized message files.")
744 parser.add_option(
745 '--locale_output', dest='locale_output', type='string',
746 help='specify the per-locale output file name.')
747 parser.add_option(
748 '-o', '--output', dest='output', type='string',
749 help="specify the output file name.")
750 parser.add_option(
751 '--print_only', dest='print_only', action='store_true',
752 default=False, help='print the output file names only.')
753 parser.add_option(
754 '-t', '--template', dest='template', type='string',
755 help="specify the template file name.")
756 parser.add_option(
757 '--variables', dest='variables', action='append', type='string',
758 help='read variables (NAME=VALUE) from file.')
705 759
706 options, args = parser.parse_args() 760 options, locales = parser.parse_args(argv)
707 if len(args) != 2: 761 if not locales:
708 parser.error('Two positional arguments (<input> and <output>) are expected') 762 parser.error('At least one locale must be specified')
709 if not options.languages: 763 if bool(options.output) == bool(options.locale_output):
710 parser.error('At least one language must be specified') 764 parser.error(
711 if not options.messages_path: 765 'Either --output or --locale_output must be specified but not both')
712 parser.error('--messages_path is required') 766 if not options.template and not options.print_only:
767 parser.error('The template name is required unless --print_only is used')
713 768
714 return Localize(args[0], args[1], options) 769 return Localize(options.template, locales, options)
715 770
716 if __name__ == '__main__': 771 if __name__ == '__main__':
717 sys.exit(main()) 772 sys.exit(DoMain(sys.argv[1:]))
718 773
OLDNEW
« no previous file with comments | « remoting/tools/build/DEPS ('k') | remoting/tools/localize.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698