15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#!/usr/bin/python
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Copyright (c) 2009 The Chromium Authors. All rights reserved.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# found in the LICENSE file.
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Usage: generate_localizer [xib_path] [output_dot_h_path] [output_dot_mm_path]
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Extracts all the localizable strings that start with "^IDS" from the given
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# xib file, and then generates a localizer to process those strings.
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import os
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import plistlib
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import subprocess
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import sys
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)generate_localizer = "me"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)localizer_template_h = \
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)'''//          ---------- WARNING ----------
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// THIS IS A GENERATED FILE, DO NOT EDIT IT DIRECTLY!
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This header includes the table used by ui_localizer.mm.  Nothing else should
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// be including this file.
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Generated by %(generate_localizer)s.
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Generated from:
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//     %(xib_files)s
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef UI_LOCALIZER_TABLE_H_
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define UI_LOCALIZER_TABLE_H_
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const UILocalizerResourceMap kUIResources[] = {
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)%(resource_map_list)s  };
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const size_t kUIResourcesSize = arraysize(kUIResources);
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif  // UI_LOCALIZER_TABLE_H_
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)'''
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def xib_localizable_strings(xib_path):
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Runs ibtool to extract the localizable strings data from the xib."""
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tools_dir = os.environ.get('DEVELOPER_BIN_DIR', '/usr/bin')
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tool_path = os.path.join(tools_dir, 'ibtool')
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # Take SDKROOT out of the environment passed to ibtool. ibtool itself has
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # no need for it, but when ibtool runs via xcrun and Xcode isn't aware of
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # the SDK in use, its presence causes an error.
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if 'SDKROOT' in os.environ:
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ibtool_env = os.environ.copy()
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    del ibtool_env['SDKROOT']
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else:
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ibtool_env = os.environ
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ibtool_cmd = subprocess.Popen([tool_path, '--localizable-strings', xib_path],
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                stdout=subprocess.PIPE, stderr=subprocess.PIPE,
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                env=ibtool_env)
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  (cmd_out, cmd_err) = ibtool_cmd.communicate()
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if ibtool_cmd.returncode:
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sys.stderr.write('%s:0: error: ibtool on "%s" failed (%d):\n%s\n' %
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     (generate_localizer, xib_path, ibtool_cmd.returncode,
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      cmd_err))
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return None
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return cmd_out
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def extract_resource_constants(plist_localizable_strings_dict, xib_path):
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Extracts all the values that start with ^IDS from the localizable
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  strings plist entry."""
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  constants_list = []
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for item_dict in plist_localizable_strings_dict.itervalues():
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for item_value in item_dict.itervalues():
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if item_value.startswith('^IDS'):
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        constants_list.append(item_value)
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      elif item_value.startswith('IDS'):
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        sys.stderr.write(
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            '%s:0: warning: %s found a string with questionable prefix, "%s"\n'
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            % (xib_path, generate_localizer, item_value));
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return constants_list
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def generate_file_contents(constants_list, xib_paths):
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Generates the header listing the constants."""
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # Bounce through a set to uniq the strings, sort the list, then build the
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # values we need from it.
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  constants_list = sorted(set(constants_list))
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  constant_list_str = ''
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for item in constants_list:
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    parts = item.split('$', 1)
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    label_id = parts[0]
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if len(parts) == 2:
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      label_arg_id = parts[1]
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      label_arg_id = '0'
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    constant_list_str += '    { "%s", %s, %s },\n' % \
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ( item, label_id[1:], label_arg_id)
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # Assemble the contents from the templates.
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  values_dict = {
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    'resource_map_list': constant_list_str,
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    'generate_localizer': generate_localizer,
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    'xib_files': "\n//     ".join(xib_paths),
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  h_file = localizer_template_h % values_dict
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return h_file
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def Main(argv=None):
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  global generate_localizer
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  generate_localizer = os.path.basename(argv[0])
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # Args
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if len(argv) < 3:
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sys.stderr.write('%s:0: error: Expected output file and then xibs\n' %
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     generate_localizer);
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 1
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  output_path = argv[1];
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  xib_paths = argv[2:]
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  full_constants_list = []
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for xib_path in xib_paths:
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Run ibtool and convert to something Python can deal with
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    plist_string = xib_localizable_strings(xib_path)
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if not plist_string:
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return 2
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    plist = plistlib.readPlistFromString(plist_string)
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Extract the resource constant strings
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    localizable_strings = plist['com.apple.ibtool.document.localizable-strings']
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    constants_list = extract_resource_constants(localizable_strings, xib_path)
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if not constants_list:
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sys.stderr.write("%s:0: warning: %s didn't find any resource strings\n" %
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       (xib_path, generate_localizer));
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    full_constants_list.extend(constants_list)
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # Generate our file contents
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  h_file_content = \
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      generate_file_contents(full_constants_list, xib_paths)
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # Write out the file
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  file_fd = open(output_path, 'w')
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  file_fd.write(h_file_content)
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  file_fd.close()
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return 0
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)if __name__ == '__main__':
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sys.exit(Main(sys.argv))
146