defmodule Mix.Tasks.Expo.Msguniq do @shortdoc "Unifies duplicate translations in message catalog" @moduledoc """ Unifies duplicate translations in the given PO file. By default, this task outputs the file on standard output. If you want to *overwrite* the given PO file, pass in the `--output` flag. *This task is available since v0.5.0.* ## Usage mix expo.msguniq PO_FILE [--output-file=OUTPUT_FILE] ## Options * `--output-file` (`-o`) - File to store the output in. `-` for standard output. Defaults to `-`. """ @moduledoc since: "0.5.0" use Mix.Task alias Expo.Message alias Expo.Messages alias Expo.PO alias Expo.PO.DuplicateMessagesError @switches [output_file: :string] @aliases [o: :output_file] @default_options [output_file: "-"] @impl Mix.Task def run(args) do {:ok, _} = Application.ensure_all_started(:expo) {opts, argv} = OptionParser.parse!(args, strict: @switches, aliases: @aliases) opts = Keyword.merge(@default_options, opts) output = case opts[:output_file] do "-" -> IO.stream(:stdio, :line) file -> File.stream!(file) end file = case argv do [] -> Mix.raise(""" mix expo.msguniq failed due to missing po file path argument """) [_file_one, _file_two | _other_files] -> Mix.raise(""" mix expo.msguniq failed due to multiple po file path arguments Only one is currently supported """) [file] -> file end case PO.parse_file(file) do {:ok, _messages} -> :ok {:error, %DuplicateMessagesError{duplicates: duplicates, catalogue: catalogue}} -> po = duplicates |> Enum.reduce(catalogue, &merge_duplicate/2) |> PO.compose() |> Enum.map(&List.wrap/1) _output = Enum.into(po, output) IO.puts(:stderr, IO.ANSI.format("Merged #{length(duplicates)} translations")) {:error, error} -> raise error end end defp merge_duplicate( {duplicate, _error_message, _line, _original_line}, %Messages{messages: messages} = po ) do %Messages{ po | messages: Enum.map(messages, fn message -> if Message.key(message) == Message.key(duplicate) do Message.merge(message, duplicate) else message end end) } end end