bdunagan

Brian Dunagan

August 10 2009
ibtool scripts on Google Code

I added the four localization scripts from previous posts to Google Code. In addition, I added a readme to document how to use them, as they do require some setup to work smoothly. Below is the readme and the script for incremental localization.

readme

=Localization Readme=
This readme covers four scripts I wrote to utilize ibtool. They're all available on Google Code with MIT license.
- Brian (brian@bdunagan.com)


These first two scripts don't require a complicated environment, just a directory with the applicable contents.

====generate_xib_strings.rb====
http://www.bdunagan.com/2009/03/15/ibtool-localization-made-easy/
Usage: ruby generate_xib_strings.rb path_to_lproj
Point the script at the folder containing the XIBs and it will generate .strings files for each of them, titled xib_name.strings.

====validate_strings_files.rb====
http://www.bdunagan.com/2009/06/27/ibtool-caveats/
Usage: ruby validate_strings_files.rb path_to_strings
Point the script at the folder containing the .strings and it will validate them, beyond what ibtool (build 677, v3.1.2) catches. (ibtool silently fails on many characters.)


These second two scripts do require a complicated environment. They both take localized .strings files and incorporate them into localized .lproj folders, either by clobbering or updating. Both scripts expect the .strings to be laid out like below. Both scripts depend on the .strings folders to match the .lproj folder names.

+ strings_folder/
--+ DE/
----+ AnotherWindow.strings
----+ Localizable.strings
----+ MainWindow.strings
--+ ES/
----+ AnotherWindow.strings
----+ Localizable.strings
----+ MainWindow.strings
--+ FR/
----+ AnotherWindow.strings
----+ Localizable.strings
----+ MainWindow.strings

====localize_xibs.rb====
http://www.bdunagan.com/2009/03/15/ibtool-localization-made-easy/
Usage: ruby localize_xibs.rb path_to_project path_to_strings
Creating a localized XIB is remarkably easy. A simple call to ibtool handles it, given a localized .strings file and an English version of the XIB. Keep in mind this script will clobber the existing set of localized XIBs.

====localize_xibs_incremental.rb====
http://www.bdunagan.com/2009/04/15/ibtool-localization-made-easier/
Usage: ruby localize_xibs_incremental.rb path_to_project path_to_strings
This is the most complicated script, but it shows how powerful ibtool is. It incrementally updates localized XIBs. Apple goes into great detail on its documentation: http://developer.apple.com/documentation/developertools/conceptual/IB_UserGuide/LocalizingNibFiles/LocalizingNibFiles.html#//apple_ref/doc/uid/TP40005344-CH13-SW8. Essentially, ibtool will diff v1 and v2 of English.lproj/MainWindow.xib and stick those changes along with new localized strings into v2 of fr.lproj/MainWindow.xib while preserving changes from v1 of fr.lproj/MainWindow.xib. Resizing UI elements is a perfect example of changes that are preserved in incremental updates. It does require even more preprocessing as a setup. In addition to the strings folder directory structure, all the relevant .lproj folders need to be laid out in a specific manner.

+ English.lproj/
--+ AnotherWindow.new.xib
--+ AnotherWindow.old.xib
--+ Localizable.strings
--+ MainWindow.new.xib
--+ MainWindow.old.xib

+ fr.lproj/
--+ AnotherWindow.old.xib
--+ Localizable.strings
--+ MainWindow.old.xib

I wrote the script in terms of xib_name.old.xib and xib_name.new.xib. The old version of the localized XIB is simply the existing version, as I want to create the new version. I do name the new version xib_name.xib intentionally so that it's ready to be committed to the source code repository, presumably where it already exists. The new version of the English XIB is the latest version also, but the old version of the English XIB is the checkpoint in the revision history where I last updated the localized XIB.

Finally, the last part of the script's workflow actually generates .strings files for the old and new versions of the localized XIB. I always diff this pair of files to ensure the update process went smoothly.

localize_xibs_incremental.rb

#!/usr/bin/ruby
# MIT license

# localize_xibs_incremental.rb
# This script takes a set of localized strings, a set of old and new English XIBs, and a set of current 
# localized XIBs and incrementally localizes the localized XIBs with the localized strings and the diff between 
# the old English XIBs and the new English XIBs.

# ibtool
#   --previous-file English.lproj/MainWindow.old.xib
#   --incremental-file fr.lproj/MainWindow.old.xib
#   --strings-file path_to_strings/fr/MainWindow.strings
#   --localize-incremental
#   --write fr.lproj/MainWindow.xib
#   English.lproj/MainWindow.new.xib

# More info: http://developer.apple.com/documentation/developertools/conceptual/IB_UserGuide/LocalizingNibFiles/LocalizingNibFiles.html

require 'FileUtils'

# Check for arguments.
if ARGV.length != 2
  puts "Usage: ruby localize_xibs_incremental.rb path_to_project path_to_strings"
  exit
end

# Get path arguments and 'cd' to that project path.
SOURCE_XIB_FOLDER = "English.lproj"
PROJECT_PATH = ARGV[0]
STRINGS_PATH = ARGV[1]
FileUtils.cd(PROJECT_PATH)
FILES_TO_IGNORE = [".svn", "." ,"..", ".DS_Store"]
NON_XIB_LOCALIZED_FILES = ["InfoPlist.strings","Localizable.strings"]

# Iterate through the current directory.
Dir.entries(STRINGS_PATH).each do |localized_folder|
  if (!FILES_TO_IGNORE.include?(localized_folder))
    puts "Generating localizations for #{localized_folder}"
    # Iterate over the .strings language folders.
    Dir.entries(STRINGS_PATH + "/" + localized_folder).each do |strings_file|
      strings_path = STRINGS_PATH + "/" + localized_folder + "/" + strings_file
      if (NON_XIB_LOCALIZED_FILES.include?(strings_file))
        %x[cp \"#{strings_path}\" \"#{localized_folder}.lproj/#{strings_file}\"]
        puts "COPIED #{strings_file} to #{localized_folder}"
      elsif (!FILES_TO_IGNORE.include?(strings_file))
        filename = strings_file.slice(0,strings_file.length-8)
        source_xib = SOURCE_XIB_FOLDER + "/" + filename

        # Create a new localized XIB based on older localized version and two English versions.
        command = "ibtool --previous-file \"#{source_xib}.old.xib\" " + 
                         "--incremental-file \"#{localized_folder}.lproj/#{filename}.old.xib\" " + 
                         "--strings-file \"#{strings_path}\" " + 
                         "--localize-incremental " + 
                         "--write \"#{localized_folder}.lproj/#{filename}.xib\" " + 
                         "\"#{source_xib}.new.xib\""
        results = %x[#{command}]
        if results.length > 0
          puts "FAILURE: #{command}:\n#{results}"
        else
          puts "SUCCESS: #{localized_folder}.lproj/#{filename}.xib"
        end

        # Generate .strings files for both localized versions to easily compare. Erase after.
        command = "ibtool --generate-strings-file \"#{localized_folder}.lproj/#{filename}.old.strings\" \"#{localized_folder}.lproj/#{filename}.old.xib\""
        results = %x[#{command}]
        command = "ibtool --generate-strings-file \"#{localized_folder}.lproj/#{filename}.new.strings\" \"#{localized_folder}.lproj/#{filename}.xib\""
        results = %x[#{command}]
      end
    end
  end
end
Custom UITableViewCell from a XIB in Interface Builder Icons, Iterated
LinkedIn GitHub Email