Class: Fastlane::Helper::Ios::L10nHelper
- Inherits:
-
Object
- Object
- Fastlane::Helper::Ios::L10nHelper
- Defined in:
- lib/fastlane/plugin/wpmreleasetoolkit/helper/ios/ios_l10n_helper.rb
Class Method Summary collapse
-
.download_glotpress_export_file(project_url:, locale:, filters:, destination:) ⇒ Object
Downloads the export from GlotPress for a given locale and given filters.
-
.generate_strings_file_from_hash(translations:, output_path:) ⇒ Object
Generate a ‘.strings` file from a dictionary of string translations.
-
.merge_strings(paths:, output_path:) ⇒ Array<String>
Merge the content of multiple ‘.strings` files into a new `.strings` text file.
-
.read_strings_file_as_hash(path:) ⇒ Hash<String,String>
Return the list of translations in a ‘.strings` file.
-
.strings_file_type(path:) ⇒ Symbol
Returns the type of a ‘.strings` file (XML, binary or ASCII).
Class Method Details
.download_glotpress_export_file(project_url:, locale:, filters:, destination:) ⇒ Object
Downloads the export from GlotPress for a given locale and given filters.
144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 |
# File 'lib/fastlane/plugin/wpmreleasetoolkit/helper/ios/ios_l10n_helper.rb', line 144 def self.download_glotpress_export_file(project_url:, locale:, filters:, destination:) query_params = (filters || {}).transform_keys { |k| "filters[#{k}]" }.merge(format: 'strings') uri = URI.parse("#{project_url.chomp('/')}/#{locale}/default/export-translations/?#{URI.encode_www_form(query_params)}") # Set an unambiguous User Agent so GlotPress won't rate-limit us = { 'User-Agent' => Wpmreleasetoolkit::USER_AGENT } begin IO.copy_stream(uri.open(), destination) rescue StandardError => e UI.error "Error downloading locale `#{locale}` — #{e.} (#{uri})" retry if e.is_a?(OpenURI::HTTPError) && UI.confirm("Retry downloading `#{locale}`?") return nil end end |
.generate_strings_file_from_hash(translations:, output_path:) ⇒ Object
The generated file will be in XML-plist format since ASCII plist is deprecated as an output format by every Apple tool so there’s no safe way to generate ASCII format.
Generate a ‘.strings` file from a dictionary of string translations.
Especially useful to generate ‘.strings` files not from code, but from keys extracted from another source (like a JSON file export from GlotPress, or subset of keys extracted from the main `Localizable.strings` to generate an `InfoPlist.strings`)
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
# File 'lib/fastlane/plugin/wpmreleasetoolkit/helper/ios/ios_l10n_helper.rb', line 116 def self.generate_strings_file_from_hash(translations:, output_path:) builder = Nokogiri::XML::Builder.new(encoding: 'UTF-8') do |xml| xml.doc.create_internal_subset( 'plist', '-//Apple//DTD PLIST 1.0//EN', 'http://www.apple.com/DTDs/PropertyList-1.0.dtd' ) xml.comment('Warning: Auto-generated file, do not edit.') xml.plist(version: '1.0') do xml.dict do translations.sort.each do |k, v| # NOTE: use `sort` just in order to be deterministic over various runs xml.key(k.to_s) xml.string(v.to_s) end end end end File.write(output_path, builder.to_xml) end |
.merge_strings(paths:, output_path:) ⇒ Array<String>
For now, this method only supports merging ‘.strings` file in `:text` format and basically concatenates the files (+ checking for duplicates in the process)
The method is able to handle input files which are using different encodings, guessing the encoding of each input file using the BOM (and defaulting to UTF8). The generated file will always be in utf-8, by convention.
Merge the content of multiple ‘.strings` files into a new `.strings` text file.
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
# File 'lib/fastlane/plugin/wpmreleasetoolkit/helper/ios/ios_l10n_helper.rb', line 53 def self.merge_strings(paths:, output_path:) duplicates = [] Tempfile.create('wpmrt-l10n-merge-', encoding: 'utf-8') do |tmp_file| all_keys_found = [] tmp_file.write("/* Generated File. Do not edit. */\n\n") paths.each do |input_file, prefix| next if File.empty?(input_file) # Skip existing but totally empty files, to avoid adding useless `MARK:` comment for them fmt = strings_file_type(path: input_file) raise "The file `#{input_file}` does not exist or is of unknown format." if fmt.nil? raise "The file `#{input_file}` is in #{fmt} format but we currently only support merging `.strings` files in text format." unless fmt == :text string_keys = read_strings_file_as_hash(path: input_file).keys.map { |k| "#{prefix}#{k}" } duplicates += (string_keys & all_keys_found) # Find duplicates using Array intersection, and add those to duplicates list all_keys_found += string_keys tmp_file.write("/* MARK: - #{File.basename(input_file)} */\n\n") # Read line-by-line to reduce memory footprint during content copy; Be sure to guess file encoding using the Byte-Order-Mark. File.readlines(input_file, mode: 'rb:BOM|UTF-8').each do |line| unless prefix.nil? || prefix.empty? # We need to ensure the line and RegExp are using the same encoding, so we transcode everything to UTF-8. line.encode!(Encoding::UTF_8) # The `/u` modifier on the RegExps is to make them UTF-8 line.gsub!(/^(\s*")/u, "\\1#{prefix}") # Lines starting with a quote are considered to be start of a key; add prefix right after the quote line.gsub!(/^(\s*)([A-Z0-9_]+)(\s*=\s*")/ui, "\\1\"#{prefix}\\2\"\\3") # Lines starting with an identifier followed by a '=' are considered to be an unquoted key (typical in InfoPlist.strings files for example) end tmp_file.write(line) end tmp_file.write("\n") end tmp_file.close # ensure we flush the content to disk FileUtils.cp(tmp_file.path, output_path) end duplicates end |
.read_strings_file_as_hash(path:) ⇒ Hash<String,String>
Return the list of translations in a ‘.strings` file.
96 97 98 99 100 101 102 103 |
# File 'lib/fastlane/plugin/wpmreleasetoolkit/helper/ios/ios_l10n_helper.rb', line 96 def self.read_strings_file_as_hash(path:) return {} if File.empty?(path) # Return empty hash if completely empty file output, status = Open3.capture2e('/usr/bin/plutil', '-convert', 'json', '-o', '-', path) raise output unless status.success? JSON.parse(output) end |
.strings_file_type(path:) ⇒ Symbol
Returns the type of a ‘.strings` file (XML, binary or ASCII)
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
# File 'lib/fastlane/plugin/wpmreleasetoolkit/helper/ios/ios_l10n_helper.rb', line 21 def self.strings_file_type(path:) return :text if File.empty?(path) # If completely empty file, consider it as a valid `.strings` files in textual format # Start by checking it seems like a valid property-list file (and not e.g. an image or plain text file) _, status = Open3.capture2('/usr/bin/plutil', '-lint', path) return nil unless status.success? # If it is a valid property-list file, determine the actual format used format_desc, status = Open3.capture2('/usr/bin/file', path) return nil unless status.success? case format_desc when /Apple binary property list/ then return :binary when /XML/ then return :xml when /text/ then return :text end end |