fill the void

Posted
10 August 2009 @ 11pm

Tagged
development

8 Comments

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

8 Comments

Posted by
andy
1 October 2009 @ 5pm

Is it possible to both have a localized .xib file as well as a Localizable.strings file that NSLocalizedString can use? The reason I ask is that my app has text not associated with UI elements.


Posted by
bdunagan
1 October 2009 @ 8pm

Absolutely. There are many cases where you should use NSLocalizedString(), like dynamic localized text such as a status, in addition to localizing UI elements. In fact, you can localize a UI element in a XIB, then populate its value with NSLocalizedString() when necessary.


Posted by
anu
23 October 2009 @ 5pm

Does incremental localization work only when adding new UI elements or when you modify existing ones? I have a xib that was translated earlier. I now changed the label of an element in my interface and am using ibtool to update the new translation for the text in all other language xibs. it does not seem to work.

On running this ibtool command, it seems to preserve the element sizing for the translated xibs and display the correct translations for the un-modified elements, but the modified string label is displayed in English in all the other xibs.


Posted by
bdunagan
5 November 2009 @ 8pm

[Man, I'm a slacker replying to comments. Sorry.] The key is the element’s ID. Replacing an element with an identical copy still removes the original element, along with its ID, and adds the new element, with a new ID. You can modify the existing element, like moving or resizing it, and ibtool will still work fine. And, you can always see the element IDs by generating a strings file for the XIB. Not sure if this is your problem, @anu.


Posted by
anu
11 November 2009 @ 11am

I modified the string of the label in the new English.xib. The strings file generated seems to have the same key such as “508.title”, only the value for that key has changed. If I feed in the old English.xib, the updated English.xib with the new string for that textfield, the old Danish.xib, the newly generated Danish.xib seems to have all the other translations in place except this modified string which comes up in English( the way it was specified in the new English.xib).

The ibtool for some reason does not seem to be pulling out the correct the translation from the intermediate Danish.strings file for that label alone.


Posted by
bdunagan
11 November 2009 @ 1pm

@anu, I just tried what you describe on a new project, and it worked for me. There could be a punctuation error in your Danish.strings file that’s preventing the problem string from being read. I have a ruby script in my Google Code repository to validate .strings files better than ibtool.

Also, try generating .strings files for both the old and new Danish.xibs and diff’ing them, just to make sure that string is the only string failing. I do that before every commit.

If you’re still having issues, feel free to email me the problem files, and I’ll take a look at them.


Posted by
anu
12 November 2009 @ 10pm

works!!! seems like my new English nib had been messed up for some reason. the right translations got pulled out and the resizing of elements were retained as well.


[...] week, I ran one of my ibtool ruby scripts to localize an app. During the process, it generated the following [...]


Leave a Comment