Na minha busca contínua para colocar arquivos .po sob controle de versão do git, escrevi este script para uso em diff e filter-clean:
msgcat --no-location --no-wrap --sort-output - | msgattrib --no-obsolete - | grep -Ev '^"POT-Creation-Date|^"PO-Revision-Date|^"Last-Translator|^"X-Generator'
As entradas .gitconfig para chamar este script se parecem com isto:
[diff "podiff"]
textconv = cat "$1" | "$(git rev-parse --show-toplevel)"/podiff
cachetextconv = true
[filter "pocomments"]
clean = "$(git rev-parse --show-toplevel)"/podiff
smudge = cat "$1" # NOP; enable the other one temporarily to affect files on checkout, restore, etc., but please do not commit it -Zsar 2024-06-10
# smudge = "$(git rev-parse --show-toplevel)"/podiff
required
Cada uma das etapas realiza uma função crucial:
- Refactors e alterações de código não relacionadas fazem com que a localização da fonte e a ordem de entrada mudem incessantemente. Esta invocação msgcat normaliza essas, então os arquivos commit-tet não têm essas alterações.
- Entradas obsoletas dobram o tamanho dos conjuntos de alterações sempre que um msgid muda. Temos controle de versão -> esta invocação msgattrib os remove.
- Esses campos na entrada de metadados de um arquivo .po mudam toda vez que alguém o edita com uma ferramenta dedicada - temos controle de versão -> esta invocação do grep os remove.
Agora surgiu outro obstáculo. Percebeu isso --no-wrap
na frente? Não funciona.
Além disso, o encapsulamento não é estável: a cada commit estranho, alguém tem uma palavra invertida entre as linhas sem alterações humanas .
Além disso, a ferramenta relacionada Poedit também tem uma configuração "Wrap at", desabilitar o que também não funciona. (Porque ele delega para as ferramentas gettext, nenhuma surpresa aí. Mas isso significa que não há como eu normalizar os arquivos 'só dessa vez' e terminar com isso. - Por isso eu uso um filtro git em primeiro lugar.)
Muito bem, pensei e testei esta invocação para removê-los: sed -z -e 's/\"\n\"//'
.
É para concatenar quaisquer linhas encapsuladas em 'msgid' e 'msgstr', de modo que as ferramentas possam encapsulá-las como quiserem, cada dia de uma forma diferente, pelo que me importa.
- Ele funciona de forma independente:
sed -z -e 's/\"\n\"//' test.po
imprime a saída esperada. - Funciona quando canalizado para from cat:
cat test.po | sed -z -e 's/\"\n\"//'
imprime a saída esperada. - No entanto, quando adicionado ao script existente, a etapa sed não tem efeito.
Parece que ele recebe a entrada linha por linha. Tentei colocá-lo na frente do grep sem melhora, e não consigo movê-lo na frente dos outros dois, pois o msgcat e o msgattrib têm o problema "Eu gosto dos meus wrappers aleatórios" que deu início a toda essa provação.
Posso transmitir a saída do grep ou, mais genericamente, a saída de um pipe baseado em linha , para que meu editor de fluxo possa fazer seu trabalho?
(Nota: Há muitas respostas neste site que dizem "sed não pode fazer isso" - mas sed é projetado especificamente para não se importar com quebras de linha, então isso parece desinformação. Da página do manual:
Sed é um editor de fluxo. Um editor de fluxo é usado para executar transformações básicas de texto em um fluxo de entrada (um arquivo ou entrada de um pipeline). [...] sed funciona fazendo apenas uma passagem sobre a(s) entrada(s) [.]
ênfase minha
O problema é bem claro que há mais de uma entrada, a mesma string que eu quero substituir, dividida entre elas.)
Pipes são sempre fluxos contínuos – o leitor geralmente não consegue distinguir limites de gravação. (O programa de origem pode decidir armazenar em buffer sua saída e liberá-la linha por linha ou bloco por bloco, mas isso raramente é distinguível.)
Parece que você tem o problema oposto, ou seja,
-z
efetivamente diz ao 'sed' para tratar toda a sua entrada como uma única "linha" muito longa e, por padrão, suas//
operação substitui apenas a primeira correspondência nessa "linha".Adicione a
/g
opção para alterar isso: