class Fastlane::Actions::LokaliseMetadataAction

Public Class Methods

authors() click to toggle source
# File Lanes/actions/lokalise_metadata.rb, line 615
def self.authors
  ["Fedya-L"]
end
available_options() click to toggle source
# File Lanes/actions/lokalise_metadata.rb, line 563
def self.available_options
  [
    FastlaneCore::ConfigItem.new(key: :api_token,
                                 env_name: "LOKALISE_API_TOKEN",
                                 description: "API Token for Lokalise",
                                 verify_block: proc do |value|
                                    UI.user_error! "No API token for Lokalise given, pass using `api_token: 'token'`" unless (value and not value.empty?)
                                 end),
    FastlaneCore::ConfigItem.new(key: :project_identifier,
                                 env_name: "LOKALISE_PROJECT_ID",
                                 description: "Lokalise Project ID",
                                 verify_block: proc do |value|
                                    UI.user_error! "No Project Identifier for Lokalise given, pass using `project_identifier: 'identifier'`" unless (value and not value.empty?)
                                 end),
    FastlaneCore::ConfigItem.new(key: :add_languages,
                                 description: "Add missing languages in lokalise",
                                 optional: true,
                                 is_string: false,
                                 default_value: false,
                                 verify_block: proc do |value|
                                   UI.user_error! "Add languages should be true or false" unless [true, false].include? value
                                 end),
    FastlaneCore::ConfigItem.new(key: :override_translation,
                                 description: "Override translations in lokalise",
                                 optional: true,
                                 is_string: false,
                                 default_value: false,
                                 verify_block: proc do |value|
                                   UI.user_error! "Override translation should be true or false" unless [true, false].include? value
                                 end),
    FastlaneCore::ConfigItem.new(key: :action,
                                 description: "Action to perform (can be update_lokalise_itunes or update_lokalise_googleplay or update_itunes or update_googleplay)",
                                 optional: false,
                                 is_string: true,
                                 verify_block: proc do |value|
                                   UI.user_error! "Action should be update_lokalise_googleplay or update_lokalise_itunes or update_itunes or update_googleplay" unless ["update_lokalise_itunes", "update_lokalise_googleplay", "update_itunes", "update_googleplay"].include? value
                                 end),
    FastlaneCore::ConfigItem.new(key: :release_number,
                                description: "Release number is required to update google play",
                                optional: true,
                                is_string: false),
    FastlaneCore::ConfigItem.new(key: :validate_only,
                                description: "Only validate the metadata (works with only update_googleplay action)",
                                optional: true,
                                is_string: false,
                                default_value: false,
                                verify_block: proc do |value|
                                  UI.user_error! "Validate only should be true or false" unless [true, false].include? value
                                end),
  ]
end
create_languages(languages, for_itunes) click to toggle source
# File Lanes/actions/lokalise_metadata.rb, line 53
def self.create_languages(languages, for_itunes)
  data = {
    iso: languages.map { |language| fix_language_name(language, for_itunes, true) } .to_json
  }
  make_request("language/add", data)
end
description() click to toggle source

@!group Documentation

# File Lanes/actions/lokalise_metadata.rb, line 555
def self.description
  "Upload metadata to lokalise."
end
details() click to toggle source
# File Lanes/actions/lokalise_metadata.rb, line 559
def self.details
  "This action scans fastlane/metadata folder and uploads metadata to lokalise.com"
end
filter_metadata(metadata, other_metadata) click to toggle source
# File Lanes/actions/lokalise_metadata.rb, line 60
def self.filter_metadata(metadata, other_metadata)
  filtered_metadata = {}
  metadata.each { |language, translations|
    other_translations = other_metadata[language]
    filtered_translations = {}
    
    if other_translations != nil && other_translations.empty? == false
      translations.each { |key, value|
        other_value = other_translations[key]
        filtered_translations[key] = value unless other_value != nil && other_value.empty? == false
      }
    else 
      filtered_translations = translations
    end

    filtered_metadata[language] = filtered_translations unless filtered_translations.empty?
  }
  return filtered_metadata
end
fix_language_name(name, for_itunes, for_lokalise = false) click to toggle source
# File Lanes/actions/lokalise_metadata.rb, line 484
def self.fix_language_name(name, for_itunes, for_lokalise = false)
  if for_itunes
    if for_lokalise
      name =  name.gsub("-","_")
      name = "en" if name == "en_US"
      name = "de" if name == "de_DE"
      name = "es" if name == "es_ES"
      name = "fr" if name == "fr_FR"
    else 
      name = name.gsub("_","-")
      name = "en-US" if name == "en"
      name = "de-DE" if name == "de"
      name = "es-ES" if name == "es"
      name = "fr-FR" if name == "fr"
    end
  else
    if for_lokalise
      name =  name.gsub("-","_")
      name = "tr" if name == "tr_TR"
      name = "hy" if name == "hy_AM"
      name = "my" if name == "my_MM"
      name = "ms" if name == "ms_MY"
      name = "cs" if name == "cs_CZ"
      name = "da" if name == "da_DK"
      name = "et_EE" if name == "et"
      name = "fi" if name == "fi_FI"
      name = "he" if name == "iw_IL"
      name = "hu" if name == "hu_HU"
      name = "ja" if name == "ja_JP"
      name = "ko" if name == "ko_KR"
      name = "ky" if name == "ky_KG"
      name = "lo" if name == "lo_LA"
      name = "lv_LV" if name == "lv"
      name = "lt_LT" if name == "lt"
      name = "mr" if name == "mr_IN"
      name = "no" if name == "no_NO"
      name = "pl" if name == "pl_PL"
      name = "si" if name == "si_LK"
      name = "sl_SI" if name == "sl"
    else 
      name = name.gsub("_","-")
      name = "tr-TR" if name == "tr"
      name = "hy-AM" if name == "hy"
      name = "my-MM" if name == "my"
      name = "ms-MY" if name == "ms"
      name = "cs-CZ" if name == "cs"
      name = "da-DK" if name == "da"
      name = "et" if name == "et-EE"
      name = "fi-FI" if name == "fi"
      name = "iw-IL" if name == "he"
      name = "hu-HU" if name == "hu"
      name = "ja-JP" if name == "ja"
      name = "ko-KR" if name == "ko"
      name = "ky-KG" if name == "ky"
      name = "lo-LA" if name == "lo"
      name = "lv" if name == "lv-LV"
      name = "lt" if name == "lt-LT"
      name = "mr-IN" if name == "mr"
      name = "no-NO" if name == "no"
      name = "pl-PL" if name == "pl"
      name = "si-LK" if name == "si"
      name = "sl" if name == "sl-SI"
    end
  end
  return name
end
get_metadata(available_languages, folder, for_itunes) click to toggle source
# File Lanes/actions/lokalise_metadata.rb, line 239
def self.get_metadata(available_languages, folder, for_itunes)
  complete_metadata = {}

  available_languages.each { |iso_code|
    language_directory = "#{folder}#{iso_code}"
    if Dir.exist? language_directory
      language_metadata = {}
      if for_itunes
        metadata_key_file_itunes().each { |key, file|
          populate_hash_key_from_file(language_metadata, key, language_directory + "/#{file}.txt")
        }
      else 
        metadata_key_file_googleplay().each { |key, file|
          if file == "changelogs"
            changelog_directory = "#{folder}#{iso_code}/changelogs"
            files = Dir.entries("#{changelog_directory}")
            collectedFiles = files.collect { |s| s.partition(".").first.to_i }
            sortedFiles = collectedFiles.sort
            populate_hash_key_from_file(language_metadata, key, language_directory + "/changelogs/#{sortedFiles.last}.txt")
          else 
            populate_hash_key_from_file(language_metadata, key, language_directory + "/#{file}.txt")
          end
        }
      end
      complete_metadata[iso_code] = language_metadata
    end
  }

  return complete_metadata
end
get_metadata_from_lokalise(valid_keys, for_itunes) click to toggle source
# File Lanes/actions/lokalise_metadata.rb, line 270
def self.get_metadata_from_lokalise(valid_keys, for_itunes)

  data = {
    platform_mask: 16,
    keys: valid_keys.to_json,
  }

  response = make_request("string/list", data)

  if for_itunes
    valid_languages = itunes_connect_languages_in_lokalise() 
  else
    valid_languages = google_play_languages_in_lokalise()        
  end
  metadata = {}

  response["strings"].each { |lang, translation_objects|
    if valid_languages.include?(lang)
      translations = {}
      translation_objects.each { |object|
        key = object["key"]
        translation = object["translation"]
        if valid_keys.include?(key) && translation != nil && translation.empty? == false 
          translations[key] = translation
        end
      }
      if translations.empty? == false
        metadata[fix_language_name(lang, for_itunes)] = translations
      end
    end
  }
  return metadata

end
get_metadata_from_lokalise_googleplay() click to toggle source
# File Lanes/actions/lokalise_metadata.rb, line 312
def self.get_metadata_from_lokalise_googleplay()

  valid_keys = metadata_keys_googleplay()
  return get_metadata_from_lokalise(valid_keys, false)

end
get_metadata_from_lokalise_itunes() click to toggle source
# File Lanes/actions/lokalise_metadata.rb, line 305
def self.get_metadata_from_lokalise_itunes()

  valid_keys = metadata_keys_itunes()
  return get_metadata_from_lokalise(valid_keys, true)

end
get_metadata_google_play() click to toggle source
# File Lanes/actions/lokalise_metadata.rb, line 229
def self.get_metadata_google_play()
  available_languages = google_play_languages
  return get_metadata(available_languages, "fastlane/metadata/android/", false)
end
get_metadata_itunes_connect() click to toggle source
# File Lanes/actions/lokalise_metadata.rb, line 234
def self.get_metadata_itunes_connect()
  available_languages = itunes_connect_languages
  return get_metadata(available_languages, "fastlane/metadata/", true)
end
google_play_languages() click to toggle source
# File Lanes/actions/lokalise_metadata.rb, line 402
def self.google_play_languages()
  return [
    'af',
    'am',
    'ar',
    'hy',
    'az-AZ',
    'eu-ES',
    'be',
    'bn-BD',
    'bg',
    'my',
    'ca',
    'zh-CN',
    'zh-TW',
    'zh-HK',
    'hr',
    'cs',
    'da',
    'nl-NL',
    'en-AU',
    'en-CA',
    'en-IN',
    'en-SG',
    'en-ZA',
    'en-GB',
    'en-US',
    'et-EE',
    'fil',
    'fi',
    'fr-CA',
    'fr-FR',
    'gl-ES',
    'ka-GE',
    'de-DE',
    'el-GR',
    'he',
    'hi-IN',
    'hu',
    'is-IS',
    'id',
    'it-IT',
    'ja',
    'kn-IN',
    'km-KH',
    'ko',
    'ky',
    'lo',
    'lv-LV',
    'lt-LT',
    'mk-MK',
    'ms',
    'ml-IN',
    'mr',
    'mn-MN',
    'ne-NP',
    'no',
    'fa',
    'pl',
    'pt-BR',
    'pt-PT',
    'ro',
    'ru-RU',
    'sr',
    'si',
    'sk',
    'sl-SI',
    'es-419',
    'es-ES',
    'es-US',
    'sw',
    'sv-SE',
    'ta-IN',
    'te-IN',
    'th',
    'tr',
    'uk',
    'vi',
    'zu'
  ]
end
google_play_languages_in_lokalise() click to toggle source
# File Lanes/actions/lokalise_metadata.rb, line 363
def self.google_play_languages_in_lokalise()
  return google_play_languages().map { |lang| 
    fix_language_name(lang, false, true) 
  }
end
is_supported?(platform) click to toggle source
# File Lanes/actions/lokalise_metadata.rb, line 619
def self.is_supported?(platform)
  platform == :ios
end
itunes_connect_languages() click to toggle source
# File Lanes/actions/lokalise_metadata.rb, line 369
def self.itunes_connect_languages()
  return [
    "en-US",
    "zh-Hans",
    "zh-Hant",
    "da",
    "nl-NL",
    "en-AU",
    "en-CA",
    "en-GB",
    "fi",
    "fr-FR",
    "fr-CA",
    "de-DE",
    "el",
    "id",
    "it",
    "ja",
    "ko",
    "ms",
    "no",
    "pt-BR",
    "pt-PT",
    "ru",
    "es-MX",
    "es-ES",
    "sv",
    "th",
    "tr",
    "vi"
  ]
end
itunes_connect_languages_in_lokalise() click to toggle source
# File Lanes/actions/lokalise_metadata.rb, line 357
def self.itunes_connect_languages_in_lokalise()
  return itunes_connect_languages().map { |lang| 
    fix_language_name(lang, true, true) 
  }
end
make_key_object_from_metadata(key, metadata, for_itunes) click to toggle source
# File Lanes/actions/lokalise_metadata.rb, line 210
def self.make_key_object_from_metadata(key, metadata, for_itunes)
  key_data = {
    "key" => key,
    "platform_mask" => 16,
    "translations" => {}
  }
  metadata.each { |iso_code, data|
    translation = data[key]
    unless translation == nil || translation.empty?
      key_data["translations"][fix_language_name(iso_code, for_itunes, true)] = translation
    end
  }
  unless key_data["translations"].empty? 
    return key_data
  else
    return nil
  end
end
make_request(path, data) click to toggle source
# File Lanes/actions/lokalise_metadata.rb, line 154
def self.make_request(path, data)
  require 'net/http'

  request_data = {
    api_token: @params[:api_token],
    id: @params[:project_identifier]
  }.merge(data)

  uri = URI("https://api.lokalise.com/api/#{path}")
  request = Net::HTTP::Post.new(uri)
  request.set_form_data(request_data)
  
  http = Net::HTTP.new(uri.host, uri.port)
  http.use_ssl = true
  response = http.request(request)

  jsonResponse = JSON.parse(response.body)
  raise "Bad response 🉐\n#{response.body}" unless jsonResponse.kind_of? Hash
  if jsonResponse["response"]["status"] == "success"  then
    UI.success "Response #{jsonResponse} 🚀"
  elsif jsonResponse["response"]["status"] == "error"
    code = jsonResponse["response"]["code"]
    message = jsonResponse["response"]["message"]
    raise "Response error code #{code} (#{message}) 📟"
  else
    raise "Bad response 🉐\n#{jsonResponse}"
  end
  return jsonResponse
end
metadata_key_file_googleplay() click to toggle source
# File Lanes/actions/lokalise_metadata.rb, line 348
def self.metadata_key_file_googleplay()
  return {
    "googleplay.app.title" => "title",
    "googleplay.app.full_description" => "full_description",
    "googleplay.app.short_description" => "short_description",
    "googleplay.app.changelogs" => "changelogs",
  }
end
metadata_key_file_itunes() click to toggle source
# File Lanes/actions/lokalise_metadata.rb, line 337
def self.metadata_key_file_itunes()
  return {
    "appstore.app.name" => "name",
    "appstore.app.description" => "description",
    "appstore.app.keywords" => "keywords",
    "appstore.app.promotional_text" => "promotional_text",
    "appstore.app.release_notes" => "release_notes",
    "appstore.app.subtitle" => "subtitle",
  }
end
metadata_keys_googleplay() click to toggle source
# File Lanes/actions/lokalise_metadata.rb, line 333
def self.metadata_keys_googleplay()
  return metadata_key_file_googleplay().keys
end
metadata_keys_itunes() click to toggle source
# File Lanes/actions/lokalise_metadata.rb, line 329
def self.metadata_keys_itunes()
  return metadata_key_file_itunes().keys
end
populate_hash_key_from_file(hash, key, filepath) click to toggle source
# File Lanes/actions/lokalise_metadata.rb, line 319
def self.populate_hash_key_from_file(hash, key, filepath)
  begin
    text = File.read filepath
    text.chomp!
    hash[key] = text unless text.empty?
  rescue => exception
    raise exception
  end        
end
run(params) click to toggle source
# File Lanes/actions/lokalise_metadata.rb, line 6
def self.run(params)
  @params = params
  action = params[:action]

  case action
  when "update_itunes"
    key_file = metadata_key_file_itunes()
    metadata = get_metadata_from_lokalise_itunes()
    run_deliver_action(metadata)
  when "update_googleplay"
    release_number = params[:release_number]
    UI.user_error! "Release number is required when using `update_googleplay` action (should be an integer and greater that 0)" unless (release_number and release_number.is_a?(Integer) and release_number > 0)
    key_file = metadata_key_file_googleplay
    metadata = get_metadata_from_lokalise_googleplay()
    save_metadata_to_files(metadata, release_number)
    run_supply_action(params[:validate_only])
  when "update_lokalise_itunes"
    metadata = get_metadata_itunes_connect()
    add_languages = params[:add_languages]
    override_translation = params[:override_translation]
    if add_languages == true 
      create_languages(metadata.keys, true)
    end
    if override_translation == true
      upload_metadata_itunes(metadata) unless metadata.empty?
    else
      lokalise_metadata = get_metadata_from_lokalise_itunes()
      filtered_metadata = filter_metadata(metadata, lokalise_metadata)
      upload_metadata_itunes(filtered_metadata) unless filtered_metadata.empty?
    end
  when "update_lokalise_googleplay"
    metadata = get_metadata_google_play()
    add_languages = params[:add_languages]
    override_translation = params[:override_translation]
    if add_languages == true 
      create_languages(metadata.keys, false)
    end
    if override_translation == true
      upload_metadata_google_play(metadata) unless metadata.empty?
    else
      lokalise_metadata = get_metadata_from_lokalise_googleplay()
      filtered_metadata = filter_metadata(metadata, lokalise_metadata)
      upload_metadata_google_play(filtered_metadata) unless filtered_metadata.empty?
    end
  end
end
run_deliver_action(metadata) click to toggle source
# File Lanes/actions/lokalise_metadata.rb, line 81
def self.run_deliver_action(metadata)
  config = FastlaneCore::Configuration.create(Actions::DeliverAction.available_options, {})
  config.load_configuration_file("Deliverfile")
  config[:metadata_path] = "./fastlane/no_metadata"
  config[:screenshots_path] = "./fastlane/no_screenshot"
  config[:skip_screenshots] = true
  config[:run_precheck_before_submit] = false
  config[:skip_binary_upload] = true
  config[:skip_app_version_update] = true
  config[:force] = true

  metadata_key_file_itunes().each { |key, parameter|
    final_translations = {}

    metadata.each { |lang, translations|
      if translations.empty? == false
        translation = translations[key]
        final_translations[lang] = translation if translation != nil && translation.empty? == false
      end 
    }

    config[parameter.to_sym] = final_translations
  }

  Actions::DeliverAction.run(config)
end
run_supply_action(validate_only) click to toggle source
# File Lanes/actions/lokalise_metadata.rb, line 108
def self.run_supply_action(validate_only)
  config = FastlaneCore::Configuration.create(Actions::SupplyAction.available_options, {})
  config[:skip_upload_apk] = true
  config[:skip_upload_aab] = true
  config[:skip_upload_screenshots] = true
  config[:skip_upload_images] = true
  config[:validate_only] = validate_only

  Actions::SupplyAction.run(config)
end
save_metadata_to_files(metadata, release_number) click to toggle source
# File Lanes/actions/lokalise_metadata.rb, line 119
def self.save_metadata_to_files(metadata, release_number)

  translations = {}

  metadata_key_file_googleplay().each { |key, parameter|
    final_translations = {}

    metadata.each { |lang, translations|
      if translations.empty? == false
        translation = translations[key]
        final_translations[lang] = translation if translation != nil && translation.empty? == false
      end 
    }

    translations[parameter.to_sym] = final_translations
  }

  FileUtils.rm_rf(Dir['fastlane/metadata/android/*'])

  translations.each { |key, parameter|
    parameter.each { |lang, text|
      path = "fastlane/metadata/android/#{lang}/#{key}.txt"
      if "#{key}" ==  "changelogs"
        path = "fastlane/metadata/android/#{lang}/changelogs/#{release_number}.txt"
      end
      dirname = File.dirname(path)
      unless File.directory?(dirname)
        FileUtils.mkdir_p(dirname)
      end
      File.write(path, text)
    }
  }

end
upload_metadata(metadata_keys, for_itunes, metadata) click to toggle source
# File Lanes/actions/lokalise_metadata.rb, line 184
def self.upload_metadata(metadata_keys, for_itunes, metadata)
  
  keys = []

  metadata_keys.each do |key, value|
    key = make_key_object_from_metadata(key, metadata, for_itunes)
    if key 
      keys << key
    end
  end

  data = {
    data: keys.to_json
  }

  make_request("string/set", data)
end
upload_metadata_google_play(metadata) click to toggle source
# File Lanes/actions/lokalise_metadata.rb, line 206
def self.upload_metadata_google_play(metadata)
  upload_metadata(metadata_key_file_googleplay, false, metadata)
end
upload_metadata_itunes(metadata) click to toggle source
# File Lanes/actions/lokalise_metadata.rb, line 202
def self.upload_metadata_itunes(metadata)
  upload_metadata(metadata_key_file_itunes, true, metadata)
end