zammad/zammad

View on GitHub
lib/generators/zammad/translation_catalog/writer/pot.rb

Summary

Maintainability
A
0 mins
Test Coverage
# Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/

class Zammad::TranslationCatalog::Writer::Pot < Zammad::TranslationCatalog::Writer::Base

  optional false

  def write(extracted_strings)

    pot = build_pot_content(extracted_strings)

    target_filename = "#{target_path}.pot"

    # rubocop:disable Rails/Output
    if options['check']
      original_file_content = File.read(target_filename)
      if original_file_content.eql? pot
        puts "File #{target_filename} is up-to-date."
        return
      else
        puts "File #{target_filename} is not up-to-date, please run 'rails generate zammad:translation_catalog' to update it."
        exit! # rubocop:disable Rails/Exit
      end
    end
    # rubocop:enable Rails/Output

    create_or_update_file(target_filename, pot)
  end

  private

  DATE_FORMAT_LEGEND = <<~LEGEND.chomp
    #. These placeholders are supported:
    #. - 'dd' - 2-digit day
    #. - 'd' - day
    #. - 'mm' - 2-digit month
    #. - 'm' - month
    #. - 'yyyy' - year
    #. - 'yy' - last 2 digits of year
    #. - 'SS' - 2-digit second
    #. - 'MM' - 2-digit minute
    #. - 'HH' - 2-digit hour (24h)
    #. - 'l' - hour (12h)
    #. - 'P' - Meridian indicator ('am' or 'pm')
  LEGEND

  def build_pot_content(extracted_strings)
    # Don't set a POT-Creation-Date to avoid unneccessary changes in Git.
    pot = <<~POT_HEADER
      msgid ""
      msgstr ""
      "Project-Id-Version: #{product_name}\\n"
      "POT-Creation-Date: \\n"
      "PO-Revision-Date: \\n"
      "Last-Translator: \\n"
      "Language-Team: \\n"
      "Language: en_US\\n"
      "MIME-Version: 1.0\\n"
      "Content-Type: text/plain; charset=UTF-8\\n"
      "Content-Transfer-Encoding: 8bit\\n"

    POT_HEADER

    # Add the default date/time format strings for 'en_US' as translations to
    #   the source catalog file. They will be read into the Translation model
    #   and can be customized via the translations admin GUI.
    pot += <<~FORMAT_STRINGS if !options['addon_path']
      #. Default date format to use for the current locale.
      #{DATE_FORMAT_LEGEND}
      msgid "FORMAT_DATE"
      msgstr "mm/dd/yyyy"

      #. Default date/time format to use for the current locale.
      #{DATE_FORMAT_LEGEND}
      msgid "FORMAT_DATETIME"
      msgstr "mm/dd/yyyy l:MM P"

    FORMAT_STRINGS

    extracted_strings.sorted_values.each { |s| pot += string_to_pot(s) }

    pot
  end

  def string_to_pot(string)
    pot = ''
    pot += string.comment.lines.map { |l| "#. #{l}" }.join if string.comment
    string.references.to_a.sort.each do |ref|
      pot += "#: #{ref}\n"
    end
    pot += <<~POT_ENTRY
      msgid "#{escape_for_po(string.string)}"
      msgstr ""

    POT_ENTRY
  end

  # Escape: \ -> \\, " -> \" and newline -> literal \n
  def escape_for_po(str)
    # Not sure why, but six backslashes are needed here to produce two in the result.
    str.gsub(%r{\\}, '\\\\\\').gsub(%r{"}, '\\"').gsub(%r{\n}, '\\n')
  end
end