Installing AppleGlot on macOS Catalina and Big Sur

TL;DR, I’ve published a script to automate the installation here.


I recently wanted to use AppleGlot, a developer tool from Apple that facilitates the automatic translation of strings from Apple’s published string glossaries from macOS and iOS. A good demonstration of its functionality is available here.

However, the latest version of AppleGlot available from developer.apple.com at time of writing is 4.0 (v161.6), which has the following issues on macOS Catalina and Big Sur:

The signing certificate is invalid (FB8770951) and the installer hasn’t been updated to work on macOS Catalina’s Read-Only System Volume (FB8773764).



I inspected the package file with Suspicious Package, which reveals that the appleglot binary is installed to /usr/local/bin/appleglot, whilst several related frameworks attempt to be installed to /System/Library/PrivateFrameworks – which is no longer possible as of macOS Catalina.

Inspecting the appleglot package

By exporting the appleglot binary from the package and running otool -l on the binary (-l is used to “print the load commands”), we can see that appleglot attempts to load the dynamically-linked AppleGlot.framework library from the aforementioned /System/Library/PrivateFrameworks/:

otool -l appleglot

...

Load command 11
          cmd LC_LOAD_DYLIB
      cmdsize 56
         name /usr/lib/libobjc.A.dylib (offset 24)
   time stamp 2 Thu Jan  1 10:00:02 1970
      current version 228.0.0
compatibility version 1.0.0
Load command 12
          cmd LC_LOAD_DYLIB
      cmdsize 104
         name /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation (offset 24)
   time stamp 2 Thu Jan  1 10:00:02 1970
      current version 635.0.0
compatibility version 150.0.0
Load command 13
          cmd LC_LOAD_DYLIB
      cmdsize 88
         name /System/Library/Frameworks/Cocoa.framework/Versions/A/Cocoa (offset 24)
   time stamp 2 Thu Jan  1 10:00:02 1970
      current version 17.0.0
compatibility version 1.0.0
Load command 14
          cmd LC_LOAD_DYLIB
      cmdsize 104
         name /System/Library/PrivateFrameworks/AppleGlot.framework/Versions/A/AppleGlot (offset 24)
   time stamp 2 Thu Jan  1 10:00:02 1970
      current version 161.6.3
compatibility version 1.0.0

To fix this, we can use install_name_tool to modify the appleglot binary to load this framework from another file path. install_name_tool, which is located at /usr/bin/install_name_tool, is used to “change dynamic shared library install names”.




💡 Fun fact

The install_name_tool binary, as with other binaries from Xcode.app is a stub that calls the install_name_tool binary located in the current Xcode toolchain with /usr/lib/libxcselect.dylib. We can see this with the full disassembly of the binary below:

otool -tV /usr/bin/install_name_tool 


/usr/bin/install_name_tool:
(__TEXT,__text) section
_main:
0000000100000f6b        pushq        %rbp
0000000100000f6c        movq        %rsp, %rbp
0000000100000f6f        leal        -0x1(%rdi), %eax
0000000100000f72        leaq        0x8(%rsi), %rdx
0000000100000f76        leaq        0x29(%rip), %rdi ## literal pool for: "install_name_tool"
0000000100000f7d        movl        %eax, %esi
0000000100000f7f        xorl        %ecx, %ecx
0000000100000f81        callq        0x100000f86 ## symbol stub for: _xcselect_invoke_xcrun




Anyway, back to appleglot. Let’s copy the frameworks into a path that is not limited by System Integrity Protection – I’ve chosen /Library/Frameworks. Then, we can copy the appleglot binary and man page into their directories in /usr, and the Appleglot plugins to /Library/Application Support/AppleGlot. These items in the installer package can be they can be coped from Suspicious Package, or from the output of pkgutil --expand AppleGlot.pkg <folder>

Then, we can use install_name_tool to change where the appleglot binary loads its frameworks:

install_name_tool \
    ./usr/local/bin/appleglot \
    -change \
    "/System/Library/PrivateFrameworks/AppleGlot.framework/Versions/A/AppleGlot" \
    "/Library/Frameworks/AppleGlot.framework/Versions/A/AppleGlot" \

We also need to update the load paths for each of the AppleGlot Frameworks’s plugins (I’m not sure what the plugins in the “PlugIns Disabled” are for, but in my basic usage of appleglot they haven’t appeared to be used).

for filename in /Library/Frameworks/AppleGlot.framework/PlugIns/*; do
    BUNDLE_NAME="$(basename $filename)"
    BINARY_NAME="${BUNDLE_NAME%.*}"

    install_name_tool \
        "$filename/Contents/MacOS/$BINARY_NAME" \
        -change \
        "/System/Library/PrivateFrameworks/AppleGlot.framework/Versions/A/AppleGlot" \
        "/Library/Frameworks/AppleGlot.framework/Versions/A/AppleGlot"

    install_name_tool \
        "$filename/Contents/MacOS/$BINARY_NAME" \
        -change \
        "/System/Library/PrivateFrameworks/MonteLib.framework/Versions/A/MonteLib" \
        "/Library/Frameworks/MonteLib.framework/Versions/A/MonteLib"
done

And then it works!

appleglot -h

Usage: appleglot [options] command [arguments]
appleglot commands are:
    list           print list of components in NewBase
    getlangs       get the current base language and target language
    setlangs       set the current base language and target language
    populate       create NewLoc, using OldLoc if available
    update         update NewLoc from Glossaries
    finalize       remove temporary working files
    create         create empty environment
'appleglot -h command_name' prints the description of 'command_name'.

Options:
    -a                     Set append mode for log files.
    -f                     Force update mode (disable clean population logic).
    -b path_to_budnle      Specify the bundle path for nibtool/ibtool.
    -d path_to_AG_env      Specify the path for the AppleGlot environment.
                           Default is the current directory.
    -n path_to_nibtool     Specify the path for nibtool.
    -F paths_to_frameworks Specify custom framework paths (colon separated) for nibtool.
    -L paths_to_libraries  Specify custom library paths (colon separated) for nibtool.
    -p path_to_palette     Specify the path for IB palette for nibtool.
    -P path_to_directory   Specify the path for IB palette directory for nibtool.
    -g path_to_plugin      Specify the path for IB plugin for ibtool.
    -G path_to_directory   Specify the path for IB plugin directory for ibtool.
    -w                     Use AD/WG for glossary files.
    -y                     Use XLIFF for glossary files.


Thanks for reading, and feel free to use the bash script to automate this install process. Hopefully this blog post can be deprecated soon 🤞

← Previous Post: TodayFlights – Notification Center Flight Tracking