summaryrefslogtreecommitdiffstats
path: root/build/mac/generate_localizer
blob: c9d49f959b44c7ef12f47aa14159ccbd916eabe7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
#!/usr/bin/python

# Copyright (c) 2009 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

# Usage: generate_localizer [xib_path] [output_dot_h_path] [output_dot_mm_path]
#
# Extracts all the localizable strings that start with "^IDS" from the given
# xib file, and then generates a localizer to process those strings.

import os.path
import plistlib
import subprocess
import sys

generate_localizer = "me"

localizer_template_h = \
'''//          ---------- WARNING ----------
// THIS IS A GENERATED FILE, DO NOT EDIT IT DIRECTLY!
//
// Generated by %(generate_localizer)s.
// Generated from %(xib_file)s.
//

#ifndef %(class_name)s_LOCALIZER_H_
#define %(class_name)s_LOCALIZER_H_

#import "chrome/browser/cocoa/ui_localizer.h"

// A subclass of ChromeUILocalizer that handles localization based on resource
// constants.

@interface %(class_name)sLocalizer : ChromeUILocalizer
@end

#endif  // %(class_name)s_LOCALIZER_H_
'''

localizer_template_mm = \
'''//          ---------- WARNING ----------
// THIS IS A GENERATED FILE, DO NOT EDIT IT DIRECTLY!
//
// Generated by '%(generate_localizer)s'.
// Generated from '%(xib_file)s'.
//

#import "%(header_name)s"

#include "grit/app_strings.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"

@implementation %(class_name)sLocalizer

- (NSString *)localizedStringForString:(NSString *)string {

  static const ui_localizer::ResourceMap kUIResources[] = {
%(resource_map_list)s  };
  static const size_t kUIResourcesSize = arraysize(kUIResources);

  return ui_localizer::LocalizedStringForKeyFromMapList(string,
                                                        kUIResources,
                                                        kUIResourcesSize);
}

@end
'''

def xib_localizable_strings(xib_path):
  """Runs ibtool to extract the localizable strings data from the xib."""
  ibtool_cmd = subprocess.Popen(['/usr/bin/ibtool', '--localizable-strings',
                                 xib_path],
                                stdout=subprocess.PIPE, stderr=subprocess.PIPE)
  (cmd_out, cmd_err) = ibtool_cmd.communicate()
  if ibtool_cmd.returncode:
    sys.stderr.write('%s:0: error: ibtool on "%s" failed (%d):\n%s\n' %
                     (generate_localizer, xib_path, ibtool_cmd.returncode,
                      cmd_err))
    return None
  return cmd_out

def extract_resource_constants(plist_localizable_strings_dict, xib_path):
  """Extracts all the values that start with ^IDS from the localizable
  strings plist entry."""
  constants_list = []
  for item_dict in plist_localizable_strings_dict.itervalues():
    for item_value in item_dict.itervalues():
      if item_value.startswith('^IDS'):
        constants_list.append(item_value)
      elif item_value.startswith('IDS'):
        sys.stderr.write(
            '%s:0: warning: %s found a string with questionable prefix, "%s"\n'
            % (xib_path, generate_localizer, item_value));
  return constants_list

def generate_files_contents(class_name, constants_list, header_name, xib_path):
  """Generates a localizer files contents from the list of constants."""
  # Bounce through a set to uniq the strings, sort the list, then build the
  # values we need from it.
  constants_list = sorted(set(constants_list))
  constant_list_str = ''
  for item in constants_list:
    parts = item.split('$', 1)
    label_id = parts[0]
    if len(parts) == 2:
      label_arg_id = parts[1]
    else:
      label_arg_id = '0'
    constant_list_str += '    { "%s", %s, %s },\n' % \
        ( item, label_id[1:], label_arg_id)
  # Assemble the contents from the templates.
  values_dict = {
    'class_name': class_name,
    'header_name': header_name,
    'resource_map_list': constant_list_str,
    'generate_localizer': generate_localizer,
    'xib_file': xib_path,
  }
  h_file = localizer_template_h % values_dict
  mm_file = localizer_template_mm % values_dict
  return (h_file, mm_file)


def Main(argv=None):
  global generate_localizer
  generate_localizer = os.path.basename(argv[0])

  # Args
  if len(argv) != 4:
    sys.stderr.write('%s:0: error: Expected xib and output file arguments\n' %
                     generate_localizer);
    return 1
  xib_path, output_h_path, output_mm_path = argv[1:]

  # Run ibtool and convert to something Python can deal with
  plist_string = xib_localizable_strings(xib_path)
  if not plist_string:
    return 2
  plist = plistlib.readPlistFromString(plist_string)

  # Extract the resource constant strings
  localizable_strings = plist['com.apple.ibtool.document.localizable-strings']
  constants_list = extract_resource_constants(localizable_strings, xib_path)
  if not constants_list:
    sys.stderr.write("%s:0: warning: %s didn't find any resource strings\n" %
                     (xib_path, generate_localizer));
    # Seed constant_list with an entry so things will compile even though the
    # array sould really be empty (array_size in the generated file doesn't
    # like an empty array).
    constants_list.append('^0');

  # Name the class based on the output file
  class_name = os.path.splitext(os.path.basename(output_h_path))[0]
  suffix = '_localizer'
  if class_name.endswith(suffix):
    class_name = class_name[:-len(suffix)];
  class_name = class_name.replace('_', ' ').title().replace(' ', '');

  # Generate our file contents
  (h_file_content, mm_file_content) = \
      generate_files_contents(class_name, constants_list,
                              os.path.basename(output_h_path),
                              xib_path)

  # Write out the files
  file_fd = open(output_h_path, 'w')
  file_fd.write(h_file_content)
  file_fd.close()
  file_fd = open(output_mm_path, 'w')
  file_fd.write(mm_file_content)
  file_fd.close()

  return 0

if __name__ == '__main__':
  sys.exit(Main(sys.argv))