summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xbuild/mac/tweak_app_infoplist14
-rw-r--r--chrome/app/app-Info.plist50
-rw-r--r--chrome/app/breakpad_mac.mm3
-rw-r--r--chrome/app/chrome_dll_main.cc15
-rw-r--r--chrome/app/chromium_strings.grd11
-rw-r--r--chrome/app/google_chrome_strings.grd11
-rw-r--r--chrome/app/helper-Info.plist6
-rwxr-xr-xchrome/app/make_mac_app_symlinks9
-rwxr-xr-xchrome/app/nuke_mac_resources_link19
-rwxr-xr-xchrome/app/tweak_mac_lproj_folders11
-rw-r--r--chrome/chrome.gyp122
-rw-r--r--chrome/common/chrome_paths_internal.h9
-rw-r--r--chrome/common/chrome_paths_mac.mm27
-rw-r--r--chrome/tools/build/apply_locales.py27
-rw-r--r--chrome/tools/mac_helpers/infoplist_strings_util.mm296
15 files changed, 580 insertions, 50 deletions
diff --git a/build/mac/tweak_app_infoplist b/build/mac/tweak_app_infoplist
index 6af78e4..8110423 100755
--- a/build/mac/tweak_app_infoplist
+++ b/build/mac/tweak_app_infoplist
@@ -62,11 +62,9 @@ fi
TOP="${SRCROOT}/.."
BUILD_BRANDING=$1
-BRAND_SCRIPT="${TOP}/build/branding_value.sh"
set -x
-APP_NAME=$("${BRAND_SCRIPT}" "${BUILD_BRANDING}" PRODUCT_FULLNAME)
SRC_APP_PATH="${BUILT_PRODUCTS_DIR}/${WRAPPER_NAME}"
if [ "${USE_SVN}" = "1" ] ; then
@@ -103,14 +101,6 @@ fi
. "${TOP}/chrome/VERSION"
FULL_VERSION="${MAJOR}.${MINOR}.${BUILD}.${PATCH}"
-# Fetch the copyright.
-COPYRIGHT_STRING=$("${BRAND_SCRIPT}" "${BUILD_BRANDING}" COPYRIGHT)
-# Map (c) or (C) to the copyright symbol.
-COPYRIGHT_STRING=$(echo "${COPYRIGHT_STRING}" | sed -e $'s/([cC])/\302\251/g')
-
-# Build the full copyright string
-LONG_COPYRIGHT="${APP_NAME} ${FULL_VERSION}, ${COPYRIGHT_STRING}"
-
# I really hate how "defaults" doesn't take a real pathname but instead insists
# on appending ".plist" to everything.
INFO_PLIST_PATH="Contents/Info.plist"
@@ -134,8 +124,6 @@ fi
# Add public version info so "Get Info" works
defaults write "${TMP_INFO_PLIST_DEFAULTS}" \
- CFBundleGetInfoString -string "${LONG_COPYRIGHT}"
-defaults write "${TMP_INFO_PLIST_DEFAULTS}" \
CFBundleShortVersionString -string "${FULL_VERSION}"
# Honor the 429496.72.95 limit. The maximum comes from splitting 2^32 - 1 into
# 6, 2, 2 digits. The limitation was present in Tiger, but it could have been
@@ -146,8 +134,6 @@ defaults write "${TMP_INFO_PLIST_DEFAULTS}" \
# unique that meetings what LS wants.
defaults write "${TMP_INFO_PLIST_DEFAULTS}" \
CFBundleVersion -string "${BUILD}.${PATCH}"
-defaults write "${TMP_INFO_PLIST_DEFAULTS}" \
- NSHumanReadableCopyright -string "${COPYRIGHT_STRING}"
# Add or remove the Breakpad keys.
if [ "${USE_BREAKPAD}" = "1" ] ; then
diff --git a/chrome/app/app-Info.plist b/chrome/app/app-Info.plist
index 1341cdc..1e65fda 100644
--- a/chrome/app/app-Info.plist
+++ b/chrome/app/app-Info.plist
@@ -3,27 +3,9 @@
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
- <string>English</string>
- <key>UTExportedTypeDeclarations</key>
- <array>
- <dict>
- <key>UTTypeIdentifier</key>
- <string>org.chromium.extension</string>
- <key>UTTypeDescription</key>
- <string>Chromium Extra</string>
- <key>UTTypeConformsTo</key>
- <array>
- <string>public.data</string>
- </array>
- <key>UTTypeTagSpecification</key>
- <dict>
- <key>public.filename-extension</key>
- <array>
- <string>crx</string>
- </array>
- </dict>
- </dict>
- </array>
+ <string>en-US</string>
+ <key>CFBundleDisplayName</key>
+ <string>${EXECUTABLE_NAME}</string>
<key>CFBundleDocumentTypes</key>
<array>
<dict>
@@ -134,12 +116,12 @@
<string>Viewer</string>
</dict>
<dict>
+ <key>CFBundleTypeRole</key>
+ <string>Viewer</string>
<key>LSItemContentTypes</key>
<array>
<string>org.chromium.extension</string>
</array>
- <key>CFBundleTypeRole</key>
- <string>Viewer</string>
</dict>
</array>
<key>CFBundleExecutable</key>
@@ -188,11 +170,33 @@
<string>0.1</string>
<key>LSFileQuarantineEnabled</key>
<true/>
+ <key>LSHasLocalizedDisplayName</key>
+ <string>1</string>
<key>LSMinimumSystemVersion</key>
<string>10.5.0</string>
<key>NSMainNibFile</key>
<string>MainMenu</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
+ <key>UTExportedTypeDeclarations</key>
+ <array>
+ <dict>
+ <key>UTTypeConformsTo</key>
+ <array>
+ <string>public.data</string>
+ </array>
+ <key>UTTypeDescription</key>
+ <string>Chromium Extra</string>
+ <key>UTTypeIdentifier</key>
+ <string>org.chromium.extension</string>
+ <key>UTTypeTagSpecification</key>
+ <dict>
+ <key>public.filename-extension</key>
+ <array>
+ <string>crx</string>
+ </array>
+ </dict>
+ </dict>
+ </array>
</dict>
</plist>
diff --git a/chrome/app/breakpad_mac.mm b/chrome/app/breakpad_mac.mm
index 142a46e..6acb3f4 100644
--- a/chrome/app/breakpad_mac.mm
+++ b/chrome/app/breakpad_mac.mm
@@ -10,6 +10,7 @@
#import "base/basictypes.h"
#include "base/command_line.h"
#import "base/logging.h"
+#include "base/mac_util.h"
#import "base/scoped_nsautorelease_pool.h"
#include "base/sys_string_conversions.h"
#import "breakpad/src/client/mac/Framework/Breakpad.h"
@@ -44,7 +45,7 @@ void InitCrashReporter() {
// may not have access to the disk or to the same data as the browser
// process, so the browser passes the consent preference to them on the
// command line.
- NSBundle* main_bundle = [NSBundle mainBundle];
+ NSBundle* main_bundle = mac_util::MainAppBundle();
NSDictionary* info_dictionary = [main_bundle infoDictionary];
bool is_browser = [[info_dictionary objectForKey:@"LSUIElement"]
isEqualToString:@"1"] ? false : true;
diff --git a/chrome/app/chrome_dll_main.cc b/chrome/app/chrome_dll_main.cc
index d2af7a9..64f5ce53 100644
--- a/chrome/app/chrome_dll_main.cc
+++ b/chrome/app/chrome_dll_main.cc
@@ -49,6 +49,8 @@
#include "base/win_util.h"
#endif
#if defined(OS_MACOSX)
+#include "base/mac_util.h"
+#include "chrome/common/chrome_paths_internal.h"
#include "chrome/app/breakpad_mac.h"
#endif
#if defined(OS_LINUX)
@@ -335,6 +337,17 @@ int ChromeMain(int argc, const char** argv) {
#endif
const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess();
+ std::wstring process_type =
+ parsed_command_line.GetSwitchValue(switches::kProcessType);
+
+#if defined(OS_MACOSX)
+ // If process_type is not empty, this is the helper. Set the main app bundle
+ // so code can fetch Mac resources.
+ if (!process_type.empty()) {
+ FilePath main_path(chrome::GetBrowserBundlePath());
+ mac_util::SetOverrideAppBundlePath(main_path);
+ }
+#endif // OS_MACOSX
#if defined(OS_WIN)
// Must do this before any other usage of command line!
@@ -373,8 +386,6 @@ int ChromeMain(int argc, const char** argv) {
#endif // OS_POSIX
int browser_pid;
- std::wstring process_type =
- parsed_command_line.GetSwitchValue(switches::kProcessType);
if (process_type.empty()) {
browser_pid = base::GetCurrentProcId();
} else {
diff --git a/chrome/app/chromium_strings.grd b/chrome/app/chromium_strings.grd
index 2127282..b61d19a 100644
--- a/chrome/app/chromium_strings.grd
+++ b/chrome/app/chromium_strings.grd
@@ -349,6 +349,17 @@ be available for now. -->
<message name="IDS_DEFAULT_BROWSER_INFOBAR_SHORT_TEXT" desc="More compact text to show in the default browser query infobar.">
Chromium isn't your default browser.
</message>
+ <if expr="os == 'darwin'">
+ <message name="IDS_SHORT_PRODUCT_NAME" desc="The application's short name, used for the Mac's application menu, activity monitor, etc. This should be less than 16 characters. Example: Chrome, not Google Chrome.">
+ Chromium
+ </message>
+ <message name="IDS_HELPER_NAME" desc="The helper application's name. Should contain the Chrome application name (IDS_PRODUCT_NAME). Example: Google Chrome Helper.">
+ Chromium Helper
+ </message>
+ <message name="IDS_SHORT_HELPER_NAME" desc="The helper application's short name, used for the Mac's application menu, activity monitor, etc. Example: Chrome Helper, not Google Chrome Helper.">
+ Chromium Helper
+ </message>
+ </if>
</messages>
</release>
</grit>
diff --git a/chrome/app/google_chrome_strings.grd b/chrome/app/google_chrome_strings.grd
index bec59f6..5548e28 100644
--- a/chrome/app/google_chrome_strings.grd
+++ b/chrome/app/google_chrome_strings.grd
@@ -397,6 +397,17 @@ Chrome supports. -->
<message name="IDS_DEFAULT_BROWSER_INFOBAR_SHORT_TEXT" desc="More compact text to show in the default browser query infobar.">
Google Chrome isn't your default browser.
</message>
+ <if expr="os == 'darwin'">
+ <message name="IDS_SHORT_PRODUCT_NAME" desc="The application's short name, used for the Mac's application menu, activity monitor, etc. This should be less than 16 characters. Example: Chrome, not Google Chrome.">
+ Google Chrome
+ </message>
+ <message name="IDS_HELPER_NAME" desc="The helper application's name. Should contain the Chrome application name (IDS_PRODUCT_NAME). Example: Google Chrome Helper.">
+ Google Chrome Helper
+ </message>
+ <message name="IDS_SHORT_HELPER_NAME" desc="The helper application's short name, used for the Mac's application menu, activity monitor, etc. Example: Chrome Helper, not Google Chrome Helper.">
+ Chrome Helper
+ </message>
+ </if>
</messages>
</release>
</grit>
diff --git a/chrome/app/helper-Info.plist b/chrome/app/helper-Info.plist
index 9aeacff..72f92b7 100644
--- a/chrome/app/helper-Info.plist
+++ b/chrome/app/helper-Info.plist
@@ -3,7 +3,9 @@
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
- <string>English</string>
+ <string>en-US</string>
+ <key>CFBundleDisplayName</key>
+ <string>${EXECUTABLE_NAME}</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIdentifier</key>
@@ -20,6 +22,8 @@
<string>0.1</string>
<key>LSFileQuarantineEnabled</key>
<true/>
+ <key>LSHasLocalizedDisplayName</key>
+ <string>1</string>
<key>LSMinimumSystemVersion</key>
<string>10.5.0</string>
<key>LSUIElement</key>
diff --git a/chrome/app/make_mac_app_symlinks b/chrome/app/make_mac_app_symlinks
index 5f3c040..66353a95 100755
--- a/chrome/app/make_mac_app_symlinks
+++ b/chrome/app/make_mac_app_symlinks
@@ -5,14 +5,13 @@
# found in the LICENSE file.
# This script is intended to run from a "postbuild" action from within Xcode.
-# It sets up symbolic links for an app bundle's Resources and Frameworks
-# directories. This is intended to be used for app bundles that live within
-# the Resources directory of a larger app bundle, when the sub-app's
-# Resources and Frameworks directories should point to the enclosing app's.
+# It sets up symbolic links for an app bundle's Frameworks directory. This is
+# intended to be used for app bundles that live within the Resources directory
+# of a larger app bundle, when the sub-app's Frameworks directory should point
+# to the enclosing app's.
set -e
CONTENTS_PATH="${BUILT_PRODUCTS_DIR}/${WRAPPER_NAME}/Contents"
-ln -fhs ../.. "${CONTENTS_PATH}/Resources"
ln -fhs ../../../Frameworks "${CONTENTS_PATH}/Frameworks"
diff --git a/chrome/app/nuke_mac_resources_link b/chrome/app/nuke_mac_resources_link
new file mode 100755
index 0000000..98c5c75
--- /dev/null
+++ b/chrome/app/nuke_mac_resources_link
@@ -0,0 +1,19 @@
+#!/bin/sh
+
+# 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.
+
+# TODO: Remove this script and the action that invokes it after 09/01/09
+
+# The helper's Resources directory used to be a link, but now that we need
+# real resources, we have this script deletes the link as a stop gap for the
+# build bots and developers' builds.
+
+set -e
+
+RESOURCES_PATH="${BUILT_PRODUCTS_DIR}/${WRAPPER_NAME}/Contents/Resources"
+
+if [ -L "${RESOURCES_PATH}" ] ; then
+ rm -f "${RESOURCES_PATH}"
+fi
diff --git a/chrome/app/tweak_mac_lproj_folders b/chrome/app/tweak_mac_lproj_folders
index d15c858..78dba5b 100755
--- a/chrome/app/tweak_mac_lproj_folders
+++ b/chrome/app/tweak_mac_lproj_folders
@@ -19,4 +19,15 @@ cd "${BUILT_PRODUCTS_DIR}/${WRAPPER_NAME}/Contents/Resources"
rm -rf "zh.lproj" "en.lproj"
# Provide an link for en.lproj that points to en-US.lproj.
+
+# The standard OS language list includes English (en) and not a specific
+# "flavor" such as U.S. English (en-US). When checking for a language match,
+# the OS will remove subtags if no exact match is found, so that en will be
+# used if the user's preferred language list only contains British English
+# (en-GB) and no specific en-GB translation is available.
+#
+# To ensure that users with the default language list, which contains English
+# without any regional subtag, as well as users with a specific variant of
+# English with a regional subtag, will have access to an English-localized
+# application, a symbolic link from en.lproj to en-US.lproj is provided.
ln -fhs "en-US.lproj" "en.lproj"
diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp
index 69d534c..1b59fd8 100644
--- a/chrome/chrome.gyp
+++ b/chrome/chrome.gyp
@@ -3144,6 +3144,7 @@
# chrome/app/app-Info.plist has:
# CFBundleIdentifier of CHROMIUM_BUNDLE_ID
# CFBundleName of CHROMIUM_SHORT_NAME
+ # CFBundleSignature of CHROMIUM_CREATOR
# Xcode then replaces these values with the branded values we set
# as settings on the target.
'CHROMIUM_BUNDLE_ID': '<(mac_bundle_id)',
@@ -3155,6 +3156,7 @@
],
'dependencies': [
'helper_app',
+ 'infoplist_strings_tool',
# Bring in pdfsqueeze and run it on all pdfs
'../build/temp_gyp/pdfsqueeze.gyp:pdfsqueeze',
],
@@ -3172,6 +3174,51 @@
'message': 'Running pdfsqueeze on <(RULE_INPUT_PATH)',
},
],
+ 'actions': [
+ {
+ # Generate the InfoPlist.strings file
+ 'action_name': 'Generating InfoPlist.strings files',
+ 'variables': {
+ 'tool_path': '<(PRODUCT_DIR)/infoplist_strings_tool',
+ 'version_file_path': 'VERSION',
+ # Unique dir to write to so the [lang].lproj/InfoPlist.strings
+ # for the main app and the helper app don't name collide.
+ 'output_path': '<(INTERMEDIATE_DIR)/app_infoplist_strings',
+ },
+ 'conditions': [
+ [ 'branding == "Chrome"', {
+ 'variables': {
+ 'branding_name': 'google_chrome_strings',
+ },
+ }, { # else branding!="Chrome"
+ 'variables': {
+ 'branding_name': 'chromium_strings',
+ },
+ }],
+ ],
+ 'inputs': [
+ '<(tool_path)',
+ '<(version_file_path)',
+ # TODO: remove this helper when we have loops in GYP
+ '>!@(tools/build/apply_locales.py \'<(grit_out_dir)/<(branding_name)_ZZLOCALE.pak\' <(locales))',
+ ],
+ 'outputs': [
+ # TODO: remove this helper when we have loops in GYP
+ '>!@(tools/build/apply_locales.py \'<(output_path)/ZZLOCALE.lproj/InfoPlist.strings\' <(locales))',
+ ],
+ 'action': [
+ '<(tool_path)',
+ '-b', '<(branding_name)',
+ '-v', '<(version_file_path)',
+ '-g', '<(grit_out_dir)',
+ '-o', '<(output_path)',
+ '-t', 'main',
+ '<@(locales)',
+ ],
+ 'message': 'Generating the language InfoPlist.strings files',
+ 'process_outputs_as_mac_bundle_resources': 1,
+ },
+ ],
'copies': [
{
'destination': '<(PRODUCT_DIR)/<(mac_product_name).app/Contents/Frameworks',
@@ -4692,6 +4739,7 @@
'dependencies': [
'chrome_dll',
'interpose_dependency_shim',
+ 'infoplist_strings_tool',
],
'sources': [
# chrome_exe_main.mm's main() is the entry point for the "chrome"
@@ -4729,6 +4777,58 @@
],
},
],
+ 'actions': [
+ {
+ # TODO: remove this action and the script it runs after 09/01/09
+ 'action_name': 'Remove old resources symlink',
+ 'inputs': [],
+ 'outputs': [],
+ 'action': [ 'app/nuke_mac_resources_link' ],
+ },
+ {
+ # Generate the InfoPlist.strings file
+ 'action_name': 'Generating InfoPlist.strings files',
+ 'variables': {
+ 'tool_path': '<(PRODUCT_DIR)/infoplist_strings_tool',
+ 'version_file_path': 'VERSION',
+ # Unique dir to write to so the [lang].lproj/InfoPlist.strings
+ # for the main app and the helper app don't name collide.
+ 'output_path': '<(INTERMEDIATE_DIR)/helper_infoplist_strings',
+ },
+ 'conditions': [
+ [ 'branding == "Chrome"', {
+ 'variables': {
+ 'branding_name': 'google_chrome_strings',
+ },
+ }, { # else branding!="Chrome"
+ 'variables': {
+ 'branding_name': 'chromium_strings',
+ },
+ }],
+ ],
+ 'inputs': [
+ '<(tool_path)',
+ '<(version_file_path)',
+ # TODO: remove this helper when we have loops in GYP
+ '>!@(tools/build/apply_locales.py \'<(grit_out_dir)/<(branding_name)_ZZLOCALE.pak\' <(locales))',
+ ],
+ 'outputs': [
+ # TODO: remove this helper when we have loops in GYP
+ '>!@(tools/build/apply_locales.py \'<(output_path)/ZZLOCALE.lproj/InfoPlist.strings\' <(locales))',
+ ],
+ 'action': [
+ '<(tool_path)',
+ '-b', '<(branding_name)',
+ '-v', '<(version_file_path)',
+ '-g', '<(grit_out_dir)',
+ '-o', '<(output_path)',
+ '-t', 'helper',
+ '<@(locales)',
+ ],
+ 'message': 'Generating the language InfoPlist.strings files',
+ 'process_outputs_as_mac_bundle_resources': 1,
+ },
+ ],
'postbuilds': [
{
'postbuild_name': 'Make Symbolic Links',
@@ -4748,6 +4848,10 @@
'-s0',
'<(branding)'],
},
+ {
+ 'postbuild_name': 'Tweak Mac lproj folders',
+ 'action': ['app/tweak_mac_lproj_folders'],
+ },
],
'conditions': [
['mac_breakpad==1', {
@@ -4831,7 +4935,21 @@
'DYLIB_INSTALL_NAME_BASE': '@executable_path',
},
},
- ]
+ {
+ 'target_name': 'infoplist_strings_tool',
+ 'type': 'executable',
+ 'dependencies': [
+ 'chrome_strings',
+ '../base/base.gyp:base',
+ ],
+ 'include_dirs': [
+ '<(grit_out_dir)',
+ ],
+ 'sources': [
+ 'tools/mac_helpers/infoplist_strings_util.mm',
+ ],
+ },
+ ], # targets
}, { # else: OS != "mac"
'targets': [
{
@@ -5139,7 +5257,7 @@
}],
],
},
- ]
+ ],
}],
['OS=="win"',
{ 'targets': [
diff --git a/chrome/common/chrome_paths_internal.h b/chrome/common/chrome_paths_internal.h
index f1f0fa9..54b9870 100644
--- a/chrome/common/chrome_paths_internal.h
+++ b/chrome/common/chrome_paths_internal.h
@@ -7,7 +7,7 @@
#include "build/build_config.h"
-class FilePath;
+#include "base/file_path.h"
namespace chrome {
@@ -29,6 +29,13 @@ bool GetUserDownloadsDirectory(FilePath* result);
// The path to the user's desktop.
bool GetUserDesktop(FilePath* result);
+#if defined(OS_MACOSX)
+// Retrieves the browser bundle path. It is only valid to call this from a
+// helper process, as it makes assumptions about the location of the enclosing
+// bundle on disk.
+FilePath GetBrowserBundlePath();
+#endif // defined(OS_MACOSX)
+
} // namespace chrome
diff --git a/chrome/common/chrome_paths_mac.mm b/chrome/common/chrome_paths_mac.mm
index 618dd4f..82dbb3c 100644
--- a/chrome/common/chrome_paths_mac.mm
+++ b/chrome/common/chrome_paths_mac.mm
@@ -7,7 +7,6 @@
#import <Cocoa/Cocoa.h>
#import "base/base_paths.h"
-#import "base/file_path.h"
#import "base/logging.h"
#import "base/path_service.h"
@@ -72,4 +71,30 @@ bool GetUserDesktop(FilePath* result) {
return success;
}
+FilePath GetBrowserBundlePath() {
+ NSBundle* running_app_bundle = [NSBundle mainBundle];
+ NSString* running_app_bundle_path = [running_app_bundle bundlePath];
+ DCHECK(running_app_bundle_path) << "failed to get the main bundle path";
+
+ // Are we the helper or the browser (main bundle)?
+ if (![[[running_app_bundle infoDictionary]
+ objectForKey:@"LSUIElement"] boolValue]) {
+ // We aren't a LSUIElement, so this must be the browser, return it's path.
+ return FilePath([running_app_bundle_path fileSystemRepresentation]);
+ }
+
+ // Helper lives at ...app/Contents/Resources/...Helper.app
+ NSArray* components = [running_app_bundle_path pathComponents];
+ DCHECK_GE([components count], static_cast<NSUInteger>(4))
+ << "too few path components for this bundle to be within another bundle";
+ components =
+ [components subarrayWithRange:NSMakeRange(0, [components count] - 3)];
+
+ NSString* browser_path = [NSString pathWithComponents:components];
+ DCHECK([[browser_path pathExtension] isEqualToString:@"app"])
+ << "we weren't within another app?";
+
+ return FilePath([browser_path fileSystemRepresentation]);
+}
+
} // namespace chrome
diff --git a/chrome/tools/build/apply_locales.py b/chrome/tools/build/apply_locales.py
new file mode 100644
index 0000000..43d064a
--- /dev/null
+++ b/chrome/tools/build/apply_locales.py
@@ -0,0 +1,27 @@
+#!/usr/bin/env 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.
+
+# TODO: remove this script when GYP has for loops
+
+import sys
+
+def main(argv):
+ if len(argv) < 3:
+ print 'ERROR: need string and list of locales'
+ return 1
+
+ str_template = argv[1]
+ locales = argv[2:]
+
+ results = []
+ for locale in locales:
+ results.append(str_template.replace('ZZLOCALE', locale))
+
+ # Quote each element so filename spaces don't mess up GYP's attempt to parse
+ # it into a list.
+ print " ".join(['"%s"' % x for x in results])
+
+if __name__ == '__main__':
+ sys.exit(main(sys.argv))
diff --git a/chrome/tools/mac_helpers/infoplist_strings_util.mm b/chrome/tools/mac_helpers/infoplist_strings_util.mm
new file mode 100644
index 0000000..70fbca6
--- /dev/null
+++ b/chrome/tools/mac_helpers/infoplist_strings_util.mm
@@ -0,0 +1,296 @@
+// 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.
+
+// Helper tool that is built and run during a build to pull strings from
+// the GRD files and generate the InfoPlist.strings files needed for
+// Mac OS X app bundles.
+
+#import <Foundation/Foundation.h>
+
+#include <stdio.h>
+#include <unistd.h>
+
+#include "base/data_pack.h"
+#include "base/file_path.h"
+#include "base/scoped_nsautorelease_pool.h"
+#include "base/scoped_ptr.h"
+#include "base/string_piece.h"
+#include "base/string_util.h"
+#include "grit/chromium_strings.h"
+
+namespace {
+
+NSString* ApplicationVersionString(const char* version_file_path) {
+ NSError* error = nil;
+ NSString* path_string = [NSString stringWithUTF8String:version_file_path];
+ NSString* version_file =
+ [NSString stringWithContentsOfFile:path_string
+ encoding:NSUTF8StringEncoding
+ error:&error];
+ if (!version_file || error) {
+ fprintf(stderr, "Failed to load version file: %s\n",
+ [[error description] UTF8String]);
+ return nil;
+ }
+
+ int major = 0, minor = 0, build = 0, patch = 0;
+ NSScanner* scanner = [NSScanner scannerWithString:version_file];
+ if ([scanner scanString:@"MAJOR=" intoString:nil] &&
+ [scanner scanInt:&major] &&
+ [scanner scanString:@"MINOR=" intoString:nil] &&
+ [scanner scanInt:&minor] &&
+ [scanner scanString:@"BUILD=" intoString:nil] &&
+ [scanner scanInt:&build] &&
+ [scanner scanString:@"PATCH=" intoString:nil] &&
+ [scanner scanInt:&patch]) {
+ return [NSString stringWithFormat:@"%d.%d.%d.%d",
+ major, minor, build, patch];
+ }
+ fprintf(stderr, "Failed to parse version file\n");
+ return nil;
+}
+
+base::DataPack* LoadResourceDataPack(const char* dir_path,
+ const char* branding_strings_name,
+ const char* locale_name) {
+ base::DataPack* resource_pack = NULL;
+
+ NSString* resource_path = [NSString stringWithFormat:@"%s/%s_%s.pak",
+ dir_path, branding_strings_name, locale_name];
+ if (resource_path) {
+ FilePath resources_pak_path([resource_path fileSystemRepresentation]);
+ resource_pack = new base::DataPack;
+ bool success = resource_pack->Load(resources_pak_path);
+ if (!success) {
+ delete resource_pack;
+ resource_pack = NULL;
+ }
+ }
+
+ return resource_pack;
+}
+
+NSString* LoadStringFromDataPack(base::DataPack* data_pack,
+ const char* data_pack_lang,
+ uint32_t resource_id,
+ const char* resource_id_str) {
+ NSString* result = nil;
+ StringPiece data;
+ if (data_pack->Get(resource_id, &data)) {
+ // Data pack encodes strings as UTF16.
+ result =
+ [[[NSString alloc] initWithBytes:data.data()
+ length:data.length()
+ encoding:NSUTF16LittleEndianStringEncoding]
+ autorelease];
+ }
+ if (!result) {
+ fprintf(stderr, "ERROR: failed to load string %s for lang %s\n",
+ resource_id_str, data_pack_lang);
+ exit(1);
+ }
+ return result;
+}
+
+// Escape quotes, newlines, etc so there are no errors when the strings file
+// is parsed.
+NSString* EscapeForStringsFileValue(NSString* str) {
+ NSMutableString* worker = [NSMutableString stringWithString:str];
+
+ // Since this is a build tool, we don't really worry about making this
+ // the most efficient code.
+
+ // Backslash first since we need to do it before we put in all the others
+ [worker replaceOccurrencesOfString:@"\\"
+ withString:@"\\\\"
+ options:NSLiteralSearch
+ range:NSMakeRange(0, [worker length])];
+ // Now the rest of them.
+ [worker replaceOccurrencesOfString:@"\n"
+ withString:@"\\n"
+ options:NSLiteralSearch
+ range:NSMakeRange(0, [worker length])];
+ [worker replaceOccurrencesOfString:@"\r"
+ withString:@"\\r"
+ options:NSLiteralSearch
+ range:NSMakeRange(0, [worker length])];
+ [worker replaceOccurrencesOfString:@"\t"
+ withString:@"\\t"
+ options:NSLiteralSearch
+ range:NSMakeRange(0, [worker length])];
+ [worker replaceOccurrencesOfString:@"\""
+ withString:@"\\\""
+ options:NSLiteralSearch
+ range:NSMakeRange(0, [worker length])];
+
+ return [[worker copy] autorelease];
+}
+
+// The valid types for the -t arg
+const char* kAppType_Main = "main"; // Main app
+const char* kAppType_Helper = "helper"; // Helper app
+
+} // namespace
+
+int main(int argc, char* const argv[]) {
+ base::ScopedNSAutoreleasePool autorelease_pool;
+
+ const char* version_file_path = NULL;
+ const char* grit_output_dir = NULL;
+ const char* branding_strings_name = NULL;
+ const char* output_dir = NULL;
+ const char* app_type = kAppType_Main;
+
+ // Process the args
+ int ch;
+ while ((ch = getopt(argc, argv, "t:v:g:b:o:")) != -1) {
+ switch (ch) {
+ case 't':
+ app_type = optarg;
+ break;
+ case 'v':
+ version_file_path = optarg;
+ break;
+ case 'g':
+ grit_output_dir = optarg;
+ break;
+ case 'b':
+ branding_strings_name = optarg;
+ break;
+ case 'o':
+ output_dir = optarg;
+ break;
+ default:
+ fprintf(stderr, "ERROR: bad command line arg\n");
+ exit(1);
+ break;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+#define CHECK_ARG(a, b) \
+ do { \
+ if ((a)) { \
+ fprintf(stderr, "ERROR: " b "\n"); \
+ exit(1); \
+ } \
+ } while (false)
+
+ // Check our args
+ CHECK_ARG(!version_file_path, "Missing VERSION file path");
+ CHECK_ARG(!grit_output_dir, "Missing grit output dir path");
+ CHECK_ARG(!output_dir, "Missing path to write InfoPlist.strings files");
+ CHECK_ARG(!branding_strings_name, "Missing branding strings file name");
+ CHECK_ARG(argc == 0, "Missing language list");
+ CHECK_ARG((strcmp(app_type, kAppType_Main) != 0 &&
+ strcmp(app_type, kAppType_Helper) != 0),
+ "Unknown app type");
+
+ char* const* lang_list = argv;
+ int lang_list_count = argc;
+
+ // Parse the version file and build our string
+ NSString* version_string = ApplicationVersionString(version_file_path);
+ if (!version_string) {
+ fprintf(stderr, "ERROR: failed to get a version string");
+ exit(1);
+ }
+
+ NSFileManager* fm = [NSFileManager defaultManager];
+
+ for (int loop = 0; loop < lang_list_count; ++loop) {
+ const char* cur_lang = lang_list[loop];
+
+ // Open the branded string pak file
+ scoped_ptr<base::DataPack> branded_data_pack(
+ LoadResourceDataPack(grit_output_dir,
+ branding_strings_name,
+ cur_lang));
+ if (branded_data_pack.get() == NULL) {
+ fprintf(stderr, "ERROR: Failed to load branded pak for language: %s\n",
+ cur_lang);
+ exit(1);
+ }
+
+ uint32_t name_id = IDS_PRODUCT_NAME;
+ const char* name_id_str = "IDS_PRODUCT_NAME";
+ uint32_t short_name_id = IDS_SHORT_PRODUCT_NAME;
+ const char* short_name_id_str = "IDS_SHORT_PRODUCT_NAME";
+ if (strcmp(app_type, kAppType_Helper) == 0) {
+ name_id = IDS_HELPER_NAME;
+ name_id_str = "IDS_HELPER_NAME";
+ short_name_id = IDS_SHORT_HELPER_NAME;
+ short_name_id_str = "IDS_SHORT_HELPER_NAME";
+ }
+
+ // Fetch the strings
+ NSString* name =
+ LoadStringFromDataPack(branded_data_pack.get(), cur_lang,
+ name_id, name_id_str);
+ NSString* short_name =
+ LoadStringFromDataPack(branded_data_pack.get(), cur_lang,
+ short_name_id, short_name_id_str);
+ NSString* copyright =
+ LoadStringFromDataPack(branded_data_pack.get(), cur_lang,
+ IDS_ABOUT_VERSION_COPYRIGHT,
+ "IDS_ABOUT_VERSION_COPYRIGHT");
+
+ // For now, assume this is ok for all languages. If we need to, this could
+ // be moved into generated_resources.grd and fetched.
+ NSString *get_info = [NSString stringWithFormat:@"%@ %@, %@",
+ name, version_string, copyright];
+
+ // Generate the InfoPlist.strings file contents
+ NSString* strings_file_contents_string =
+ [NSString stringWithFormat:
+ @"CFBundleDisplayName = \"%@\";\n"
+ @"CFBundleGetInfoString = \"%@\";\n"
+ @"CFBundleName = \"%@\";\n"
+ @"NSHumanReadableCopyright = \"%@\";\n",
+ EscapeForStringsFileValue(name),
+ EscapeForStringsFileValue(get_info),
+ EscapeForStringsFileValue(short_name),
+ EscapeForStringsFileValue(copyright)];
+
+ // We set up Xcode projects expecting strings files to be UTF8, so make
+ // sure we write the data in that form. When Xcode copies them it will
+ // put them final runtime encoding.
+ NSData* strings_file_contents_utf8 =
+ [strings_file_contents_string dataUsingEncoding:NSUTF8StringEncoding];
+
+ if ([strings_file_contents_utf8 length] == 0) {
+ fprintf(stderr, "ERROR: failed to get the utf8 encoding of the strings "
+ "file for language: %s\n", cur_lang);
+ exit(1);
+ }
+
+ // Make sure the lproj we write to exists
+ NSString *output_path =
+ [[NSString stringWithUTF8String:output_dir]
+ stringByAppendingPathComponent:
+ [NSString stringWithFormat:@"%s.lproj", cur_lang]];
+ NSError* error = nil;
+ if (![fm fileExistsAtPath:output_path] &&
+ ![fm createDirectoryAtPath:output_path
+ withIntermediateDirectories:YES
+ attributes:nil
+ error:&error]) {
+ fprintf(stderr, "ERROR: '%s' didn't exist or we failed to create it\n",
+ [output_path UTF8String]);
+ exit(1);
+ }
+
+ // Write out the file
+ output_path =
+ [output_path stringByAppendingPathComponent:@"InfoPlist.strings"];
+ if (![strings_file_contents_utf8 writeToFile:output_path
+ atomically:YES]) {
+ fprintf(stderr, "ERROR: Failed to write out '%s'\n",
+ [output_path UTF8String]);
+ exit(1);
+ }
+ }
+ return 0;
+}