class Fame::XliffImport

Handles import and export of .xliff files

Handles import and export of .xliff files

Constants

ACCEPTED_FILE_TYPES

All accepted XLIFF file types

REQUIRED_LOCALIZATION_FILES

All required localization files If these files are not present in their respective .lproj folder the ‘xcodebuild -importLocalizations` command will fail

Public Class Methods

new(xcode_proj_path) click to toggle source

Initializer @param xcode_proj_path A path to a .xcodeproj file whose contents should be localized.

# File lib/fame/xliff_import.rb, line 14
def initialize(xcode_proj_path)
  @xcode_proj = XcodeProject.new(xcode_proj_path)
end

Public Instance Methods

create_missing_strings_files() click to toggle source

Import of .xliff files using ‘xcodebuild` may fail in case the appropriate .strings file do not already exist. “` xcodebuild: error: Importing localizations from en.xliff will make changes to Example. Import with xcodebuild can only modify existing strings files. Please import with Xcode instead of xcodebuild to make the changes to Example. “`

This method creates the missing localization .strings files in order to silence this error.

# File lib/fame/xliff_import_old.rb, line 50
def create_missing_strings_files
  # search for Base.lproj folder in project
  project_root = File.expand_path("..", @xcode_proj.xcode_proj_path)
  base_lproj = Dir.glob(project_root + "/**/*{Base.lproj}").first # TODO: ask if multiple...
  raise "There is no Base.lproj folder, please make sure to have a base localization" unless base_lproj
  lproj_root = File.expand_path("..", base_lproj)

  # collect all names of files that need to be generated in each <language>.lproj folder
  # TODO: not sure if we should determine the project_root like this or kust use an input param from the cli?
  ib_file_names = InterfaceBuilder.determine_ib_files!(project_root)
    .map { |f| File.basename(f, ".*") }
    .map { |f| "#{f}.strings"}
  required_files = REQUIRED_LOCALIZATION_FILES + ib_file_names

  # Create <language>.lproj files for all languages
  @xcode_proj.all_languages.each do |language|
    # create .lproj folder
    lproj_folder_path = File.join(lproj_root, "#{language}.lproj")
    Dir.mkdir(lproj_folder_path) unless File.exists?(lproj_folder_path)
    puts "Checking for missing .strings files for #{lproj_folder_path}".blue

    required_files.each do |file_name|
      path = File.join(lproj_folder_path, file_name)
      exists = File.exists?(path)
      File.write(path, "") unless exists

      puts "#{file_name}".colorize(exists ? :yellow : :green) + " at #{path}".light_black
    end
  end

  # <ib_file>.strings
  # Localizable.strings
  # InfoPlist.strings

  # search for Base.lproj
  # create .lproj folders if needed
  # create files for each `string_files` entry
end
import(path) click to toggle source

Imports all .xliff files at the given path into the current Xcode project @param path A folder of .xliff files that should be imported into the current Xcode project.

# File lib/fame/xliff_import.rb, line 22
def import(path)
  xliffs = determine_xliff_files!(path)
  puts "Found #{xliffs.count} xliff file(s) -> #{xliffs.map { |x| File.basename(x, '.*') }}".light_black

  errors = []
  xliffs.each_with_index do |xliff, index|
    language =  File.basename(xliff, '.*')
    puts "(#{index+1}/#{xliffs.count}) [#{language}] Importing #{xliff}".blue

    # may result in the following error:
    # xcodebuild: error: Importing localizations from en.xliff will make changes to Example. Import with xcodebuild can only modify existing strings files.
    output = `xcodebuild -importLocalizations -localizationPath #{xliff} -project #{@xcode_proj.xcode_proj_path} 2>&1`
    error = output.split("\n").grep(/^xcodebuild: error: Importing localizations/i)
    errors << error
  end

  report_result(errors)
end

Private Instance Methods

determine_xliff_files!(path) click to toggle source

Searches the given path for .xliff files and returns their paths. @param path The path that should be searched for .xliff files. @return [Array<String>] An array of paths to .xliff files.

# File lib/fame/xliff_import.rb, line 48
def determine_xliff_files!(path)
  raise "[XliffImport] The provided file or folder does not exist" unless File.exist? path

  if File.directory?(path)
    files = Dir.glob(path + "/**/*{#{ACCEPTED_FILE_TYPES.join(',')}}")
    raise "[XliffImport] The provided folder did not contain any XLIFF files (#{ACCEPTED_FILE_TYPES.join(', ')})" unless files.count > 0
    return files
  else
    raise "[XliffImport] The provided file is not an XLIFF (#{ACCEPTED_FILE_TYPES.join(', ')})" unless ACCEPTED_FILE_TYPES.include? File.extname(path)
    return [path]
  end
end
report_result(errors) click to toggle source

Prints the result of the import

# File lib/fame/xliff_import.rb, line 64
def report_result(errors)
  # handle errors
  if errors.count > 0
    puts "\n✘ XLIFF import failed (#{errors.count} error(s))\n".red
    puts errors
    help = "\nOoops! xcodebuild cannot import one or more of the provided .xliff file(s) because the necessary .strings files do not exist yet.\n\n" +
          "Here's how to fix it:\n" +
          "  1. Open Xcode, select the project root (blue icon)\n" +
          "  2. Choose Editor > Import Localizations...\n" +
          "  3. Repeat steps 1 and 2 for every localization\n\n" +
          "Don't worry, you only have to do this manually once.\n" +
          "After the initial Xcode import, this command will be able to import your xliff files."
    puts help.blue
  else
    puts "\n✔︎ Done importing XLIFFs\n".green
  end
end